# HG changeset patch # User Paul Boddie # Date 1372533171 -7200 # Node ID 33be6c2eb9b6207c4e5255d78819b43149c8b761 # Parent b772a168a2ba6c8bb777a91fb3cffcccc3780629 Separated handling of getattr attribute usage from normal program unit usage, tracking only newly introduced program constants when evaluating the effects of getattr usage, and thus limiting the amount of work done identifying new program units to investigate on each occasion. diff -r b772a168a2ba -r 33be6c2eb9b6 micropython/__init__.py --- a/micropython/__init__.py Sat Jun 29 01:28:12 2013 +0200 +++ b/micropython/__init__.py Sat Jun 29 21:12:51 2013 +0200 @@ -247,6 +247,7 @@ self.constant_values = {} self.constants_used = set() + self.all_constants_used = set() self.constant_references = {} self.init_predefined_constants() @@ -264,7 +265,7 @@ self.attribute_users_visited = set() self.attributes_to_visit = {} - self.attribute_users_seen = 0 + self.collecting_dynamic = False # Attribute usage type deduction failures. @@ -445,7 +446,8 @@ # to be used. if "__builtins__.getattr" in self.attribute_users_visited: - self._collect_attributes("__builtins__.getattr", objtable) + self.collecting_dynamic = True + self._collect_attributes_from_getattr(objtable) def add_attribute_to_visit(self, objname, attrname): @@ -473,6 +475,38 @@ self.inferred_name_references[from_name].add((objname, attrname)) self._collect_attributes(objname + "." + attrname, objtable) + def _collect_attributes_from_getattr(self, objtable): + + """ + The getattr function is a special case: it can potentially reference + any known attribute. Since accessor attributes must be known + constants, the intersection of known constants and attributes is used + to build a set of objects that might be referenced by getattr. + """ + + all_attributes = set(objtable.attribute_names()) + all_string_constants = set([const.get_value() for const in self.constants_used + if const.value_type_name() == "__builtins__.str"]) + all_attribute_constants = all_attributes.intersection(all_string_constants) + + self.all_constants_used.update(self.constants_used) + self.constants_used = set() + + # Get the types supporting each attribute and visit the referenced + # objects. + + all_objtypes = set() + + for attrname in all_attribute_constants: + objtypes = objtable.any_possible_objects_plus_status([attrname]) + all_objtypes.update(objtypes) + + # Attribute assignment does not take place, so an empty list of + # values is given. + + self._collect_attributes_for_types("__builtins__.getattr", objtable, all_objtypes, + [{attrname : []} for attrname in all_attribute_constants]) + def _collect_attributes(self, from_name, objtable): """ @@ -481,47 +515,21 @@ types. """ - if from_name != "__builtins__.getattr" and from_name in self.attribute_users_visited or \ - from_name == "__builtins__.getattr" and len(self.attribute_users_visited) == self.attribute_users_seen: + if from_name != "__builtins__.getattr" and from_name in self.attribute_users_visited: return self.attribute_users_visited.add(from_name) + if from_name == "__builtins__.getattr": + if self.collecting_dynamic: + self._collect_attributes_from_getattr(objtable) + return + # Get constant references. for const in self.constant_references.get(from_name, []): self.constants_used.add(const) - # The getattr function is a special case: it can potentially reference - # any known attribute. Since accessor attributes must be known - # constants, the intersection of known constants and attributes is used - # to build a set of objects that might be referenced by getattr. - - if from_name == "__builtins__.getattr": - - # Note the number of attribute users visited at this point. - - self.attribute_users_seen = len(self.attribute_users_visited) - - all_attributes = set(objtable.attribute_names()) - all_string_constants = set([const.get_value() for const in self.constants() if const.value_type_name() == "__builtins__.str"]) - all_attribute_constants = all_attributes.intersection(all_string_constants) - - # Get the types supporting each attribute and visit the referenced - # objects. - - all_objtypes = set() - - for attrname in all_attribute_constants: - objtypes = objtable.any_possible_objects_plus_status([attrname]) - all_objtypes.update(objtypes) - - # Attribute assignment does not take place, so an empty list of - # values is given. - - self._collect_attributes_for_types(from_name, objtable, all_objtypes, - [{attrname : []} for attrname in all_attribute_constants]) - # Get name references and find possible objects which support such # combinations of attribute names. @@ -729,7 +737,7 @@ "Return a list of constants." - return self.constants_used + return self.all_constants_used # Import methods.