# HG changeset patch # User Paul Boddie # Date 1243117301 -7200 # Node ID d63a8400ce56d5ee6f8cdb4311dd73c069ea8845 # Parent 1ecd4a4b2a0599292201a8b2a48fa725ad460a4d Moved logic from CheckFrame into separate CheckContext, CheckClassContext instructions used in a sequence of generated instructions. Fixed usage of the exception register in the RSVP machine. diff -r 1ecd4a4b2a05 -r d63a8400ce56 docs/concepts.txt --- a/docs/concepts.txt Sat May 23 02:46:04 2009 +0200 +++ b/docs/concepts.txt Sun May 24 00:21:41 2009 +0200 @@ -9,6 +9,7 @@ * Objects and structures * Parameters and lookups * Instantiation + * Register usage Namespaces and Attribute Definition =================================== @@ -419,3 +420,17 @@ resulting instance, along with locations for the attributes of the instance. Since the instance header contains data common to all instances of a class, a template header is copied to the start of the newly reserved memory region. + +Register Usage +============== + +During code generation, much of the evaluation produces results which are +implicitly recorded in the "active value" register, and various instructions +will consume the active value. In addition, some instructions will consume a +separate "active source value" from a register, typically those which are +assigning the result of an expression to an assignment target. + +Since values often need to be retained for later use, a set of temporary +storage locations are typically employed. However, optimisations may reduce +the need to use such temporary storage where instructions which provide the +"active value" can be re-executed and will produce the same result. diff -r 1ecd4a4b2a05 -r d63a8400ce56 micropython/ast.py --- a/micropython/ast.py Sat May 23 02:46:04 2009 +0200 +++ b/micropython/ast.py Sun May 24 00:21:41 2009 +0200 @@ -588,8 +588,8 @@ if self.unit is not node.unit: self.new_op(LoadConst(node.unit)) + self.record_value() - self.record_value() self._visitName(node, self.name_store_instructions) # AssName equivalent self.set_source() self.discard_value() @@ -600,6 +600,7 @@ else: body_block = self.new_block() + check_block = self.new_block() # Check frames using the function's details. @@ -607,6 +608,12 @@ nparams = len(fn.positional_names) ndefaults = len(fn.defaults) + self._generateFunctionContextTest(node, check_block, body_block) + + # Check the number of parameters and defaults. + + self.set_block(check_block) + self.new_op(CheckFrame((nparams, ndefaults, fn.has_star))) if ndefaults > 0: self.new_op(FillDefaults((nparams, ndefaults, fn))) @@ -670,6 +677,7 @@ else: body_block = self.new_block() + check_block = self.new_block() # Check frames using the function's details. @@ -677,6 +685,12 @@ nparams = len(fn.positional_names) ndefaults = len(fn.defaults) + self._generateFunctionContextTest(node, check_block, body_block) + + # Check the number of parameters and defaults. + + self.set_block(check_block) + self.new_op(CheckFrame((nparams, ndefaults, fn.has_star))) if ndefaults > 0: self.new_op(FillDefaults((nparams, ndefaults, fn))) diff -r 1ecd4a4b2a05 -r d63a8400ce56 micropython/opt.py --- a/micropython/opt.py Sat May 23 02:46:04 2009 +0200 +++ b/micropython/opt.py Sun May 24 00:21:41 2009 +0200 @@ -189,6 +189,7 @@ LoadCallable, TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands CheckException, CheckFrame, MakeObject, + CheckContext, CheckClassContext, LoadContext # as the object providing the result )) diff -r 1ecd4a4b2a05 -r d63a8400ce56 micropython/rsvp.py --- a/micropython/rsvp.py Sat May 23 02:46:04 2009 +0200 +++ b/micropython/rsvp.py Sun May 24 00:21:41 2009 +0200 @@ -203,6 +203,9 @@ # Access to invocation frames upon dispatch. +class CheckContext(Instruction): "Check to see if the context is valid." +class CheckClassContext(Instruction): + "Check the context to see if it should be used to validate the first argument." class CheckFrame(Immediate): "Check the invocation frame and context for the target." class FillDefaults(Immediate): "Fill frame positions with defaults, if appropriate." diff -r 1ecd4a4b2a05 -r d63a8400ce56 micropython/trans.py --- a/micropython/trans.py Sat May 23 02:46:04 2009 +0200 +++ b/micropython/trans.py Sun May 24 00:21:41 2009 +0200 @@ -151,7 +151,10 @@ def set_source(self): - "Set the source of an assignment using the current assignment value." + """ + Set the source of an assignment using the current assignment value. This + sets the source input for the current instruction. + """ self.optimiser.set_source(self.expr_temp[-1]) @@ -206,6 +209,7 @@ temp_position = 0 else: temp_position = max(self.temp_positions) + 1 + self.temp_positions.add(temp_position) self.max_temp_position = max(self.max_temp_position, temp_position) return self.unit.all_local_usage + temp_position # position in frame @@ -852,6 +856,52 @@ else: return None + def _generateFunctionContextTest(self, node, check_block, body_block): + + """ + Generate code to test the context for 'node', jumping to 'check_block' + and 'body_block' from this code. + """ + + adjust_block = self.new_block() + + # Check the context. + + temp = LoadName(Attr(0, None, None)) + + # No usable context => remove the context and continue. + + self.new_op(temp) + self.new_op(CheckContext()) + self.new_op(JumpIfFalse(adjust_block)) + + # Check for a class as the context. + # Not a class as context => preserve the context and continue. + + self.new_op(temp) + self.new_op(CheckClassContext()) + self.new_op(JumpIfFalse(check_block)) + + # Check the context's compatibility with the first parameter. + # Compatible class => remove the context and continue. + # NOTE: Handle insufficient arguments. + + self.new_op(LoadName(Attr(1, None, None))) + self.new_op(CheckSelf()) + self.optimiser.set_source(temp) + self.new_op(JumpIfTrue(adjust_block)) + + # Incompatible class => type error. + + self.make_exception("TypeError", node) + self.new_op(StoreException()) + self.new_op(RaiseException()) + + # Remove the context from the parameters. + + self.set_block(adjust_block) + self.new_op(AdjustFrame(1)) + def _visitName(self, node, classes): """ diff -r 1ecd4a4b2a05 -r d63a8400ce56 rsvp.py --- a/rsvp.py Sat May 23 02:46:04 2009 +0200 +++ b/rsvp.py Sun May 24 00:21:41 2009 +0200 @@ -256,9 +256,10 @@ print "Execution terminated", if self.exception is not None: - context, ref = self.exception + ref = self.exception + addr = self.load(ref + 1) print "with exception:", self.load(ref) - print "at address:", self.load(ref + 1) + print "At address %d: %r" % (addr, self.load(addr)) else: print "successfully." @@ -412,8 +413,7 @@ else: self.value = self.load(ref + offset) else: - exc = self._MakeObject(2, self.attr_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.attr_error_instance) return self.RaiseException() def LoadAttrIndexContext(self): @@ -425,8 +425,7 @@ loaded_context, loaded_ref = self.load(offset) # offset is address of class attribute self.value = ref, loaded_ref else: - exc = self._MakeObject(2, self.attr_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.attr_error_instance) return self.RaiseException() def LoadAttrIndexContextCond(self): @@ -441,8 +440,7 @@ else: self.value = self.load(ref + offset) else: - exc = self._MakeObject(2, self.attr_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.attr_error_instance) return self.RaiseException() def StoreAttrIndex(self): @@ -452,14 +450,12 @@ attr_index, class_attr, offset = element if attr_index == self.operand: if class_attr: - exc = self._MakeObject(2, self.type_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.type_error_instance) return self.RaiseException() else: self.save(ref + offset, self.source) else: - exc = self._MakeObject(2, self.attr_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.attr_error_instance) return self.RaiseException() # NOTE: LoadAttrIndexContext is a possibility if a particular attribute can always be overridden. @@ -490,8 +486,7 @@ if param_index == self.operand: self.frame_stack[frame + offset + 1] = self.source # add 1 to skip the context always generated else: - exc = self._MakeObject(2, self.type_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.type_error_instance) return self.RaiseException() def LoadCallable(self): @@ -511,6 +506,20 @@ # NOTE: self() inside methods impossible. self.value = context, context + def CheckContext(self): + self.status = self.value[1] is not None + + def CheckClassContext(self): + context_context, context_ref = self.value + context_data = self.load(context_ref) + + # Classes are not themselves usable as the self argument. + # NOTE: This may change at some point. + # However, where classes appear as the context, instance + # compatibility is required in the first argument. + + self.status = context_data.attrcode is None # absent attrcode == class + def CheckFrame(self): (nargs, ndefaults, has_star) = self.operand @@ -551,13 +560,11 @@ self_context, self_ref = self.frame_stack[frame + 1] if not self._CheckInstance(self_ref, context_context): #raise Exception, "CheckFrame %r (%r vs. %r)" % (self.operand, self.load(self_ref), self.load(context_context)) - exc = self._MakeObject(2, self.type_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.type_error_instance) return self.RaiseException() else: #raise Exception, "CheckFrame %r (no self argument)" % self.operand - exc = self._MakeObject(2, self.type_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.type_error_instance) return self.RaiseException() # Test the frame size. @@ -565,8 +572,7 @@ if not ((nargs - ndefaults) <= nlocals and (nlocals <= nargs or has_star)): #raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (self.operand, nargs - ndefaults, nlocals, nargs) - exc = self._MakeObject(2, self.type_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.type_error_instance) return self.RaiseException() def FillDefaults(self): @@ -644,7 +650,7 @@ def RaiseException(self): # NOTE: Adding the program counter as the first attribute. - self.save(self.exception[1] + 1, self.pc) + self.save(self.exception + 1, self.pc) # Jumping to the current handler. return self.handler_stack[-1] @@ -726,8 +732,7 @@ # Test operand suitability. if not self._CheckInstance(left, self.int_class) and self._CheckInstance(right, self.int_class): - exc = self._MakeObject(2, self.type_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.type_error_instance) return self.RaiseException() # NOTE: Assume single location for data. @@ -759,8 +764,7 @@ # Test operand suitability. if not self._CheckInstance(left, self.int_class): - exc = self._MakeObject(2, self.type_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.type_error_instance) return self.RaiseException() # NOTE: Assume single location for data. @@ -785,8 +789,7 @@ # Test operand suitability. if not self._CheckInstance(left, self.int_class): - exc = self._MakeObject(2, self.type_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.type_error_instance) return self.RaiseException() # NOTE: Assume single location for data. @@ -848,8 +851,7 @@ elif item_pos < 0 and item_pos >= -nelements: item_pos = nelements + item_pos else: - exc = self._MakeObject(2, self.index_error_instance) - self.exception = exc, exc + self.exception = self._MakeObject(2, self.index_error_instance) return self.RaiseException() self.result = self.load(obj + 1 + item_pos)