# HG changeset patch # User Paul Boddie # Date 1220811790 -7200 # Node ID 7bdf1b4636b8ecba3ca3578c314387dedbfcd8a7 # Parent 1c6a86066472461f42c8ac6304cb123261d8851e Tidied up the exception code generation to ensure that referenced exceptions are obtained. Fixed the exception handling in the RSVP implementation to test exceptions using the isinstance-like testing employed by the CheckSelf instruction. Introduced additional stacks to ensure that frames and return addresses are properly discarded. Added an "isinstance" flag to the object header details in order to support CheckFrame - this would be efficiently encoded, perhaps in the classcode field, in any low-level implementation. diff -r 1c6a86066472 -r 7bdf1b4636b8 micropython/ast.py --- a/micropython/ast.py Sun Sep 07 18:43:40 2008 +0200 +++ b/micropython/ast.py Sun Sep 07 20:23:10 2008 +0200 @@ -93,7 +93,7 @@ a load operation from a CPU register or special memory location. """ - return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress)) + return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadException, LoadAddress)) def is_simple_input_user(self, instruction): @@ -109,7 +109,7 @@ StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced LoadCallable, TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands - CheckFrame, MakeObject, + CheckException, CheckFrame, MakeObject, LoadContext # as the object providing the result )) @@ -187,7 +187,8 @@ # could be updated since first being referenced. return isinstance(self.translation.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst)) or \ - isinstance(self.translation.active_value, LoadResult) and self.translation.active_value is self.translation.active + isinstance(self.translation.active_value, LoadResult) and self.translation.active_value is self.translation.active or \ + isinstance(self.translation.active_value, LoadException) and self.translation.active_value is self.translation.active def have_correct_self_for_target(self, context): @@ -2048,13 +2049,20 @@ if name is not None: self.dispatch(name) + self.new_op(CheckException()) self.new_op(JumpIfFalse(next_label)) - # Handle assignment to exception variable. - - if assignment is not None: - self.dispatch(assignment) + # Handle assignment to exception variable. + + if assignment is not None: + self.new_op(LoadException()) + + # Record the value to be assigned. + + self.record_value() + self.dispatch(assignment) + self.discard_value() # Produce the handler code, then jump to the exit. @@ -2065,7 +2073,6 @@ # Unhandled exceptions. - #self.new_op(LoadException()) self.new_op(RaiseException()) # Optional else clause. diff -r 1c6a86066472 -r 7bdf1b4636b8 micropython/rsvp.py --- a/micropython/rsvp.py Sun Sep 07 18:43:40 2008 +0200 +++ b/micropython/rsvp.py Sun Sep 07 20:23:10 2008 +0200 @@ -25,11 +25,15 @@ def raw(code, objtable, paramtable): new_code = [] for item in code: + if isinstance(item, Attr): new_code.append(( item.context and item.context.location, item.value and item.value.location # no useful context is provided )) + + # Using classcode, attrcode, codeaddr, codedetails, instance. + elif isinstance(item, Class): # NOTE: Need initialiser details! new_code.append(( @@ -39,14 +43,20 @@ ( len(item.get_instantiator().positional_names), len(item.get_instantiator().defaults) - ))) + ), + 0 + )) + elif isinstance(item, Const): # NOTE: Need class details! new_code.append(( None, #objtable.as_list().get_code(item.full_name()), None, #objtable.get_index(item.full_name()), - None, None + None, + None, + 1 )) + elif isinstance(item, Function): # NOTE: Need class and parameter details! Should arguably be types.FunctionType. new_code.append(( @@ -56,9 +66,13 @@ ( len(item.positional_names), len(item.defaults) - ))) + ), + 0 + )) + else: new_code.append(item) + return new_code def name(attr): diff -r 1c6a86066472 -r 7bdf1b4636b8 micropython/table.py --- a/micropython/table.py Sun Sep 07 18:43:40 2008 +0200 +++ b/micropython/table.py Sun Sep 07 20:23:10 2008 +0200 @@ -167,7 +167,7 @@ # Support descendants. if isinstance(attr, Class): - return attr_index + return (attr_index, None, None, None) if attr.parent is not None: location = attr.parent.location or 0 diff -r 1c6a86066472 -r 7bdf1b4636b8 rsvp.py --- a/rsvp.py Sun Sep 07 18:43:40 2008 +0200 +++ b/rsvp.py Sun Sep 07 20:23:10 2008 +0200 @@ -24,22 +24,32 @@ The execution model of the virtual processor involves the following things: - * Memory - * PC (program counter) stack - * Frame stack (containing invocation frames in use and in preparation plus - temporary storage) - * Local frame pointer stack + * Memory contains constants, global variable + references and program code + + * PC (program counter) stack contains the return address associated + with each function invocation + + * Frame stack contains invocation frames in use and in + preparation plus temporary storage + + * Local frame pointer stack refers to the frames in the frame stack + * Invocation frame pointer stack + * Exception handler stack - * Registers: current value, boolean status value, source value, result, - current exception, current callable -The memory contains constants, global variable references and program code. + * Exception handler locals stack refers to the state of the local frame + pointer stack + + * Exception handler PC stack refers to the state of the PC stack -The PC stack contains the return address associated with each function -invocation. - -The frame pointer stack tracks the position of frames within the frame stack. + * Registers: current value, + boolean status value, + source value, + current result, + current exception, + current callable """ class IllegalInstruction(Exception): @@ -77,7 +87,9 @@ self.frame_stack = [] self.local_sp_stack = [0] self.invocation_sp_stack = [] - self.handler_stack = [] + self.handler_stack = [len(self.memory) - 1] # final handler is the end of the code + self.handler_local_sp_stack = [] + self.handler_pc_stack = [] # Registers. @@ -97,6 +109,8 @@ print "Local stack pointers", self.local_sp_stack print "Invocation stack pointers", self.invocation_sp_stack print "Handler stack", self.handler_stack + print "Handler frame stack", self.handler_local_sp_stack + print "Handler PC stack", self.handler_pc_stack print print "Instruction", self.instruction print "Operand", self.operand @@ -265,10 +279,10 @@ def MakeObject(self): size = self.operand context, ref = self.value - classcode, attrcode, codeaddr, codedetails = self.load(ref) + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) addr = self.new(size) # Set the header to resemble the class. - self.save(addr, (classcode, attrcode, None, None)) # NOTE: __call__ method not yet provided. + self.save(addr, (classcode, attrcode, None, None, 1)) # NOTE: __call__ method not yet provided. # Introduce null context for new object. self.value = None, addr @@ -284,7 +298,7 @@ def LoadAttrIndex(self): context, ref = self.value - classcode, attrcode, codeaddr, codedetails = self.load(ref) + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) element = self.objlist[classcode + self.operand] attr_index, class_attr, replace_context, offset = element if attr_index == self.operand: @@ -302,7 +316,7 @@ def StoreAttrIndex(self): context, ref = self.value - classcode, attrcode, codeaddr, codedetails = self.load(ref) + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) element = self.objlist[classcode + self.operand] attr_index, class_attr, replace_context, offset = element if attr_index == self.operand: @@ -336,7 +350,7 @@ def StoreFrameIndex(self): frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame - classcode, attrcode, codeaddr, codedetails = self.load(ref) + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) element = self.objlist[classcode + self.operand] attr_index, offset = element if attr_index == self.operand: @@ -347,14 +361,14 @@ def LoadCallable(self): context, ref = self.value - classcode, attrcode, codeaddr, codedetails = self.load(ref) + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) self.callable = codeaddr, codedetails def StoreCallable(self): context, ref = self.value # NOTE: Should improve the representation and permit direct saving. - classcode, attrcode, codeaddr, codedetails = self.load(ref) - self.save(ref, (classcode, attrcode) + self.callable) + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) + self.save(ref, (classcode, attrcode) + self.callable + (instance,)) def LoadContext(self): context, ref = self.value @@ -364,7 +378,7 @@ operand = self.operand frame = self.invocation_sp_stack[-1] context, ref = self.value - classcode, attrcode, codeaddr, codedetails = self.load(ref) + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) # Support sliding of the frame to exclude any inappropriate context. @@ -372,7 +386,8 @@ self.invocation_sp_stack[-1] += 1 operand -= 1 else: - if contexttype == self.typetype: + context_classcode, context_attrcode, context_codeaddr, context_codedetails, context_instance = self.load(context) + if not context_instance: self.invocation_sp_stack[-1] += 1 operand -= 1 @@ -386,19 +401,9 @@ context, ref = self.value target_context, target_ref = self.source - # Load the details of the proposed context and the target's context. - - classcode, attrcode, codeaddr, codedetails = self.load(ref) - target_classcode, target_attrcode, target_codeaddr, target_codedetails = self.load(target_context) - - # Find the table entry for the descendant. + # Check the details of the proposed context and the target's context. - element = self.objlist[target_classcode + attrcode] - attr_index, class_attr, replace_context, offset = element - if attr_index == attrcode: - self.status = 1 - else: - self.status = 0 + self._CheckInstance(ref, target_context) def JumpWithFrame(self): codeaddr, codedetails = self.callable @@ -437,25 +442,31 @@ return self.operand def LoadException(self): - self.value = self.exception + self.value = None, self.exception def StoreException(self): - self.exception = self.value + self.exception = self.value[1] def RaiseException(self): - return self.handler_stack.pop() + return self.handler_stack[-1] def PushHandler(self): self.handler_stack.append(self.operand) + self.handler_local_sp_stack.append(len(self.local_sp_stack)) + self.handler_pc_stack.append(len(self.pc_stack)) def PopHandler(self): + # Reduce the local frame pointer stack to refer to the handler's frame. + self.local_sp_stack = self.local_sp_stack[:self.handler_local_sp_stack.pop()] + # Reduce the PC stack to discard all superfluous return addresses. + self.pc_stack = self.pc_stack[:self.handler_pc_stack.pop()] self.handler_stack.pop() def CheckException(self): - self.status = self.value[1] == self.exception + self._CheckInstance(self.exception, self.value[1]) def TestIdentity(self): - self.status = self.value[1] == self.source + self.status = self.value[1] == self.source[1] def TestIdentityAddress(self): self.status = self.value[1] == self.operand @@ -466,4 +477,19 @@ def InvertBoolean(self): self.status = not self.status + # Common implementation details. + + def _CheckInstance(self, ref, cls): + classcode, attrcode, codeaddr, codedetails, instance = self.load(ref) + target_classcode, target_attrcode, target_codeaddr, target_codedetails, target_instance = self.load(cls) + + # Find the table entry for the descendant. + + element = self.objlist[target_classcode + attrcode] + attr_index, class_attr, replace_context, offset = element + if attr_index == attrcode: + self.status = 1 + else: + self.status = 0 + # vim: tabstop=4 expandtab shiftwidth=4 diff -r 1c6a86066472 -r 7bdf1b4636b8 test.py --- a/test.py Sun Sep 07 18:43:40 2008 +0200 +++ b/test.py Sun Sep 07 20:23:10 2008 +0200 @@ -27,7 +27,7 @@ print "%6d" % (len(table_slice) - table_slice.count(None)), \ "".join(entry and "#" or "_" for entry in table_slice) -def machine(importer, with_builtins=0, optimisations=None): +def machine(importer, with_builtins=0, optimisations=None, debug=0): print "Making the image..." make(importer, with_builtins, optimisations) print "Getting raw structures..." @@ -37,7 +37,7 @@ paramlist = pt.as_raw() rc = raw(importer.get_image(), ot, pt) print "Initialising the machine..." - rm = rsvp.RSVPMachine(rc, objlist, paramlist) + rm = rsvp.RSVPMachine(rc, objlist, paramlist, debug=debug) rm.pc = importer.code_location return rm diff -r 1c6a86066472 -r 7bdf1b4636b8 tests/exception.py --- a/tests/exception.py Sun Sep 07 18:43:40 2008 +0200 +++ b/tests/exception.py Sun Sep 07 20:23:10 2008 +0200 @@ -13,4 +13,6 @@ def g(x): raise E, x +f(1, 2) + # vim: tabstop=4 expandtab shiftwidth=4