# HG changeset patch # User Paul Boddie # Date 1247362308 -7200 # Node ID ec59a6790ccce532c6d07e6e698b5680f75bf156 # Parent 975fb793b0d518befd2031e16deeb11f13a2b3b6 Simplified active object detection by only using objects whose names are used in active sections of a program. A mapping of object names to referenced object names is traversed to identify such active sections, eliminating the referenced flag previously employed. diff -r 975fb793b0d5 -r ec59a6790ccc micropython/__init__.py --- a/micropython/__init__.py Sun Jul 12 03:28:40 2009 +0200 +++ b/micropython/__init__.py Sun Jul 12 03:31:48 2009 +0200 @@ -515,7 +515,8 @@ "Return whether the given 'name' is used." if self.names_used is None: - self.names_used = set(["__init__", "__call__", "__bool__"]) + self.names_used = set(["bool", "__init__", "__call__", "__bool__", "__builtins__", "__main__"]) + self._collect_names("__builtins__") self._collect_names("__main__") return name in self.names_used @@ -548,17 +549,18 @@ const = micropython.data.Const(value) return self.constant_values[const] + def get_constant_type_name(self, value): + return value.__class__.__name__ + def make_constant(self, value): "Make and return a constant for the given 'value'." # Ensure the presence of the constant's type. - name = value.__class__.__name__ + name = self.get_constant_type_name(value) if self.modules.has_key("__builtins__"): attr = self.modules["__builtins__"].get(name) - if attr is not None: - attr.set_referenced() # Make a constant object and return it. diff -r 975fb793b0d5 -r ec59a6790ccc micropython/ast.py --- a/micropython/ast.py Sun Jul 12 03:28:40 2009 +0200 +++ b/micropython/ast.py Sun Jul 12 03:31:48 2009 +0200 @@ -546,7 +546,7 @@ self.discard_temp(temp2) def visitClass(self, node): - if not node.unit.referenced: + if not node.unit.parent.has_key(node.unit.name): return # Store the name. @@ -569,7 +569,7 @@ def visitFrom(self, node): pass def visitFunction(self, node): - if not node.unit.referenced and (not node.unit.is_method() or not node.unit.parent.has_key(node.unit.name)): + if not node.unit.parent.has_key(node.unit.name): return # Only store the name when visiting this node from outside. diff -r 975fb793b0d5 -r ec59a6790ccc micropython/data.py --- a/micropython/data.py Sun Jul 12 03:28:40 2009 +0200 +++ b/micropython/data.py Sun Jul 12 03:31:48 2009 +0200 @@ -291,17 +291,6 @@ # Number of assignments per name. self.assignments = None - self.referenced = 0 - - def set_referenced(self): - - "Indicate that the contents are referenced via a namespace." - - self.referenced = 1 - - for value in self.get_values(): - if value is not None: - value.set_referenced() def get_contexts(self): return [c for (c, v) in self.context_values] @@ -343,13 +332,6 @@ else: self.assignments += AtLeast(1) - # Communicate referencing information. - - if self.referenced: - for context, value in context_values: - if value is not None: - value.set_referenced() - self.context_values.update(context_values) def is_static_attribute(self): @@ -466,15 +448,11 @@ def __init__(self): self.parent = None - self.referenced = 0 # Image generation details. self.location = None - def set_referenced(self): - self.referenced = 1 - def __repr__(self): return "Instance()" @@ -552,7 +530,6 @@ self.name = name self.parent = parent self.astnode = node - self.referenced = 0 # Superclasses, descendants and attributes. @@ -592,9 +569,6 @@ self.set("__class__", self) - def set_referenced(self): - self.referenced = 1 - def __repr__(self): if self.location is not None: return "Class(%r, %s, location=%r)" % (self.name, shortrepr(self.parent), self.location) @@ -954,7 +928,6 @@ self.has_star = has_star self.has_dstar = has_dstar self.astnode = node - self.referenced = 0 # For lambda functions with defaults, add a context argument. @@ -1000,9 +973,6 @@ self.local_usage = 0 self.all_local_usage = 0 - def set_referenced(self): - self.referenced = 1 - def _add_parameters(self, argnames): for name in argnames: if isinstance(name, tuple): @@ -1162,13 +1132,9 @@ self.name = name self.parent_name = parent_name self.parent = None - self.referenced = 0 self.descendants = set() - def set_referenced(self): - self.referenced = 1 - def add_descendant(self, cls): self.descendants.add(cls) @@ -1197,7 +1163,6 @@ NamespaceDict.__init__(self, self) self.name = name self.parent = None - self.referenced = 0 # Original location details. @@ -1223,9 +1188,6 @@ self.local_usage = 0 self.all_local_usage = 0 - def set_referenced(self): - self.referenced = 1 - def full_name(self): return self.name diff -r 975fb793b0d5 -r ec59a6790ccc micropython/inspect.py --- a/micropython/inspect.py Sun Jul 12 03:28:40 2009 +0200 +++ b/micropython/inspect.py Sun Jul 12 03:31:48 2009 +0200 @@ -176,67 +176,34 @@ names. """ - # Remove unreferenced objects. - if self.should_optimise_unused_objects(): - - for name, value in self.items(): - - # Remove entries for unreferenced objects. - # This, due to the nature of the referenced attribute, assumes - # that only explicitly mentioned classes and functions are - # employed in the final program. - - if isinstance(value, Attr): - - # Only remove entries for classes and functions, not methods. - - for attr_value in value.get_values(): - if (isinstance(attr_value, Function) and not attr_value.is_method() or - isinstance(attr_value, Class)) and not attr_value.referenced: - pass - else: - break - else: - del self[name] + self.vacuum_object(self) all_objects = list(self.all_objects) for obj in all_objects: - - # Only remove entries for classes and functions, not methods. - - if (isinstance(obj, Function) and not obj.is_method() or - isinstance(obj, Class)) and not obj.referenced: + if isinstance(obj, Class): + self.vacuum_object(obj) - self.all_objects.remove(obj) - obj_was_removed = 1 + def vacuum_object(self, obj, delete_all=0): - else: - obj_was_removed = 0 - - # Remove unused entries from classes plus associated methods. - - if isinstance(obj, Class): - for name, attr in obj.class_attributes().items(): + "Vacuum the given object 'obj'." - # In removed classes, all explicitly defined methods can - # be removed. + for name, attr in obj.items(): + if delete_all or not self.importer.uses_name(name): + del obj[name] + if attr.assignments == 1: + value = attr.get_value() - # In other classes, methods can only be removed if they - # are the only assigned object to the class for a - # particular attribute and are unreferenced. + # Delete any unambiguous attribute value. - if obj_was_removed and isinstance(attr.get_value(), Function) and attr.get_value().is_method() or \ - not self.importer.uses_name(name) and \ - attr.assignments == 1 and isinstance(attr.get_value(), Function) and \ - attr.get_value().is_method() and not attr.get_value().referenced: + if value is not obj and value in self.all_objects: + self.all_objects.remove(value) - method = attr.get_value() + # Delete class contents. - if method in self.all_objects: - self.all_objects.remove(method) - del obj[name] + if isinstance(value, Class): + self.vacuum_object(value, 1) def finalise(self): @@ -399,12 +366,6 @@ else: self.store_lambda(function) - # Lambda functions are always assumed to be referenced. This is - # because other means of discovering the referencing of objects rely - # on the original names inherent in the definition of those objects. - - function.set_referenced() - # Where defaults exist, an instance needs creating. Thus, it makes # no sense to return a reference to the function here, since the # recipient will not be referencing the function itself. @@ -472,6 +433,7 @@ def visitAssName(self, node): self.store(node.name, self.expr) + self.use_name(node.name) return None visitAssTuple = visitAssList @@ -585,6 +547,7 @@ # Register the constant, if necessary, returning the resulting object. + self.use_name(self.importer.get_constant_type_name(node.value)) return self.importer.make_constant(node.value) visitContinue = NOP @@ -622,9 +585,6 @@ def visitFrom(self, node): module = self.importer.load(node.modname, 1) - if module is not None: - module.set_referenced() - #if module is None: # print "Warning:", node.modname, "not imported." @@ -680,9 +640,6 @@ # Accounting. - if attr is not None: - attr.set_referenced() - self.use_name(attrname) return attr @@ -714,7 +671,6 @@ else: module = self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self) self.store(name.split(".")[0], module) - module.set_referenced() return None @@ -727,6 +683,7 @@ return None def visitLambda(self, node): + self.use_name(None) # lambda functions have no names but are assumed to be invoked return self._visitFunction(node, None) visitLeftShift = _visitBinary @@ -764,13 +721,7 @@ else: attr = None - # Accounting. - - if attr is not None: - attr.set_referenced() - self.use_name(name) - return attr visitNot = OP