# HG changeset patch # User Paul Boddie # Date 1258926804 -3600 # Node ID 499cf7a39015cec86c7ab7fdeff8ca279bdbc2d4 # Parent 4f3eebcf1024a9664869970c6c5e99fd37446a37 Introduced a test for classes as well as instances where specific types have been deduced. Replaced the active attributes set in namespaces with direct nomination of specific attributes found during inspection. Renamed CheckSelf to CheckInstance. Simplified some finalisation operations, previously specific to certain object types. Added an instruction counter to the RSVP machine. diff -r 4f3eebcf1024 -r 499cf7a39015 docs/optimisations.txt --- a/docs/optimisations.txt Sun Nov 22 21:21:41 2009 +0100 +++ b/docs/optimisations.txt Sun Nov 22 22:53:24 2009 +0100 @@ -228,7 +228,7 @@ result would resemble the following: def f(x, y): - if not isinstance(x, C): + if not isinstance(x, C) and x is not C: raise TypeError x.method(y) if x.something: diff -r 4f3eebcf1024 -r 499cf7a39015 micropython/__init__.py --- a/micropython/__init__.py Sun Nov 22 21:21:41 2009 +0100 +++ b/micropython/__init__.py Sun Nov 22 22:53:24 2009 +0100 @@ -447,16 +447,17 @@ self.name_references[from_name] = set() self.name_references[from_name].add(names) - def use_specific_name(self, specific_name, from_name): + def use_specific_name(self, objname, attrname, from_name): """ - Register the given 'specific_name' for an object as being used in the - program from within an object with the specified 'from_name'. + Register the given 'objname' (for an object) whose 'attrname' is being + used in the program from within an object with the specified + 'from_name'. """ if not self.specific_name_references.has_key(from_name): self.specific_name_references[from_name] = set() - self.specific_name_references[from_name].add(specific_name) + self.specific_name_references[from_name].add((objname, attrname)) # Name accounting products. @@ -517,9 +518,9 @@ # Get specific name references and visit the referenced objects. - for name in self.specific_name_references.get(from_name, []): - self.use_attribute(from_name, name) - self._collect_attributes(from_name + "." + name, objtable) + for objname, attrname in self.specific_name_references.get(from_name, []): + self.use_attribute(objname, attrname) + self._collect_attributes(objname + "." + attrname, objtable) # Constant accounting. diff -r 4f3eebcf1024 -r 499cf7a39015 micropython/data.py --- a/micropython/data.py Sun Nov 22 21:21:41 2009 +0100 +++ b/micropython/data.py Sun Nov 22 22:53:24 2009 +0100 @@ -289,14 +289,6 @@ # Attribute usage methods. - def get_active_attributes(self): - - """ - Return attributes on this object that are actually used. - """ - - return self.attributes_used[-1].get(None, []) - def get_all_attribute_usage(self): """ @@ -309,6 +301,9 @@ usage.add(tuple(names)) return usage + def use_attribute(self, name, attrname): + return self._use_attribute(name, attrname) + # These shadow various methods in the InspectedModule class, and provide # implementations generally. diff -r 4f3eebcf1024 -r 499cf7a39015 micropython/inspect.py --- a/micropython/inspect.py Sun Nov 22 21:21:41 2009 +0100 +++ b/micropython/inspect.py Sun Nov 22 22:53:24 2009 +0100 @@ -186,8 +186,6 @@ for names in namespace.get_all_attribute_usage(): self.importer.use_names(names, namespace.full_name()) - for name in namespace.get_active_attributes(): - self.importer.use_specific_name(name, namespace.full_name()) def vacuum(self): @@ -237,8 +235,7 @@ "Finalise the module." for obj in self.all_objects: - if isinstance(obj, (Class, Function)): # NOTE: Perhaps not required. - obj.finalise_attributes(reset=1) + obj.finalise_attributes(reset=1) def add_object(self, obj, any_scope=0): @@ -349,6 +346,14 @@ def use_attribute(self, name, attrname): return self.get_namespace()._use_attribute(name, attrname) + # Specific attribute usage, nominating specific attributes which can be + # resolved during inspection. + + def use_specific_attribute(self, objname, attrname): + from_name = self.get_namespace().full_name() + objname = objname or from_name + self.importer.use_specific_name(objname, attrname, from_name) + # Visitor methods. def default(self, node, *args): @@ -478,7 +483,7 @@ self.store_module_attr(node.attrname, expr.get_value()) print "Warning: attribute %r of module %r set outside the module." % (node.attrname, expr.get_value().name) - # Note usage of the attribute. + # Note usage of the attribute where a local is involved. if expr.parent is self.get_namespace(): node._attrnames = self.use_attribute(expr.name, node.attrname) @@ -504,7 +509,10 @@ self.store(node.name, self.expr) self.define_attribute_user(node) - self.use_attribute(None, node.name) # ensure the presence of the given name + + # Ensure the presence of the given name in this namespace. + + self.use_specific_attribute(None, node.name) return None visitAssTuple = visitAssList @@ -681,7 +689,7 @@ for name, alias in node.names: if name != "*": - if module is not None and module.namespace.has_key(name): + if module is not None and module.has_key(name): attr = module[name] self.store(alias or name, attr) if isinstance(attr.get_value(), Module) and not attr.get_value().loaded: @@ -693,7 +701,7 @@ self.store(alias or name, UnresolvedName(name, node.modname, self)) else: if module is not None: - for n in module.namespace.keys(): + for n in module.keys(): attr = module[n] self.store(n, attr) if isinstance(attr.get_value(), Module) and not attr.get_value().loaded: @@ -720,27 +728,32 @@ if isinstance(expr, Attr): value = expr.get_value() + + # Get the attribute and record its usage. + if isinstance(value, (Class, Module)): - attr = value.namespace.get(attrname) + attr = value.get(attrname) + self.use_specific_attribute(value.full_name(), attrname) + elif isinstance(value, UnresolvedName): attr = UnresolvedName(attrname, value.full_name(), self) + else: attr = None - # Note usage of the attribute. + # Note usage of the attribute where a local is involved. - if expr.parent is self.get_namespace(): - node._attrnames = self.use_attribute(expr.name, attrname) - else: - self.use_name(attrname) + if expr.parent is self.get_namespace(): + node._attrnames = self.use_attribute(expr.name, attrname) + else: + self.use_name(attrname) elif self.builtins is not None: attr = self.builtins.get(attrname) - self.use_name(attrname) + self.use_specific_attribute(self.builtins.full_name(), attrname) else: attr = UnresolvedName(attrname, value.full_name(), self) - self.use_name(attrname) return attr @@ -837,7 +850,7 @@ # Note usage of the local (potentially a class attribute). - node._attrnames = self.use_attribute(None, name) + self.use_specific_attribute(None, name) # Globals. @@ -846,16 +859,13 @@ # Note usage of the module attribute. - node._attrnames = self.use_attribute(None, name) + self.use_specific_attribute(self.full_name(), name) # Builtins. elif self.builtins is not None and self.builtins.has_key(name): attr = self.builtins[name] - - # Note usage of the module attribute. - - node._attrnames = self.builtins.use_attribute(None, name) + self.use_specific_attribute(self.builtins.full_name(), name) # Unknown. diff -r 4f3eebcf1024 -r 499cf7a39015 micropython/rsvp.py --- a/micropython/rsvp.py Sun Nov 22 21:21:41 2009 +0100 +++ b/micropython/rsvp.py Sun Nov 22 22:53:24 2009 +0100 @@ -433,7 +433,7 @@ class CheckContext(Instruction): "Check to see if the context is valid." class CheckClass(Instruction): "Check the current value to determine whether it is a class." -class CheckSelf(Instruction): "Check the first argument of an invocation against the target." +class CheckInstance(Instruction): "Check the current value as an instance of a specific class (used with 'self' in an invocation)." # Access to frames upon invocation. @@ -496,7 +496,7 @@ StoreFrameIndex, # as the object being referenced StoreAddressContext, # as the context LoadCallable, - TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands + TestIdentity, TestIdentityAddress, CheckInstance, # as one of the operands CheckException, CheckFrame, FillDefaults, MakeInstance, CheckContext, CheckClass, diff -r 4f3eebcf1024 -r 499cf7a39015 micropython/trans.py --- a/micropython/trans.py Sun Nov 22 21:21:41 2009 +0100 +++ b/micropython/trans.py Sun Nov 22 22:53:24 2009 +0100 @@ -336,12 +336,23 @@ after_test_block = self.new_block() + self.new_op(LoadClass(attr)) + temp_target = self.optimiser.optimise_temp_storage() + + # Generate name is target (for classes). + + self.dispatch(compiler.ast.Name(name)) + self.new_op(TestIdentity()) + self.optimiser.set_source(temp_target) + + # Jump to the next guard or the code if successful. + + self.new_op(JumpIfTrue(after_test_block)) + # Generate isinstance(name, target). - self.new_op(LoadClass(attr)) - temp_target = self.optimiser.optimise_temp_storage() self.dispatch(compiler.ast.Name(name)) - self.new_op(CheckSelf()) # NOTE: Should be CheckInstance. + self.new_op(CheckInstance()) self.optimiser.set_source(temp_target) # Jump to the next guard or the code if successful. @@ -922,7 +933,7 @@ # Check the current value (the argument) against the known context # (given as the source). - self.new_op(CheckSelf()) + self.new_op(CheckInstance()) self.optimiser.set_source(temp_context) self.new_op(JumpIfTrue(adjust_block)) diff -r 4f3eebcf1024 -r 499cf7a39015 rsvp.py --- a/rsvp.py Sun Nov 22 21:21:41 2009 +0100 +++ b/rsvp.py Sun Nov 22 22:53:24 2009 +0100 @@ -97,6 +97,7 @@ self.pc = pc or 0 self.debug = debug self.abort_upon_exception = abort_upon_exception + self.counter = 0 # Stacks. @@ -336,6 +337,7 @@ "Perform the 'instruction', returning the next PC value or None." + self.counter += 1 self.operand = instruction.get_operand() method = self.get_method(instruction) return method() @@ -651,13 +653,14 @@ self.value = DataValue(ref, ref) - def CheckSelf(self): + def CheckInstance(self): value = self.value - context_value = self.source + target_value = self.source - # Check the details of the proposed context and the target's context. + # For the 'self' parameter in an invoked function, the proposed context + # ('self') is checked against the target's context. - self.status = self._CheckInstance(value.ref, context_value.ref) + self.status = self._CheckInstance(value.ref, target_value.ref) def JumpInFrame(self): codeaddr = self.callable