# HG changeset patch # User Paul Boddie # Date 1219539960 -7200 # Node ID dff32649a6d41877294251c27a84041fc7bc9b3a # Parent b62d613c3ca1c538a49de5af80b722592c2290fd Changed context loading conditions to depend on the target instead of a context of None (since this may occur for identified functions). Added source instruction tracking in order to provide an optimisation around intermediate source storage. Added ExtendFrame for temporary storage allocation. Added specific classes for the different table and list types. Provided more RSVP instruction implementations. Added a callable register to the RSVP implementation. diff -r b62d613c3ca1 -r dff32649a6d4 docs/structures.txt --- a/docs/structures.txt Sat Aug 23 22:32:17 2008 +0200 +++ b/docs/structures.txt Sun Aug 24 03:06:00 2008 +0200 @@ -202,8 +202,8 @@ 0 1 2 3 4 5 code for code code class attribute ... - function reference #args, function reference - #defaults reference + function reference #args, function (default) + #defaults reference reference Here, the code reference would lead to code for the function. Note that the function locals are completely distinct from this structure and are not diff -r b62d613c3ca1 -r dff32649a6d4 micropython/__init__.py --- a/micropython/__init__.py Sat Aug 23 22:32:17 2008 +0200 +++ b/micropython/__init__.py Sun Aug 24 03:06:00 2008 +0200 @@ -230,7 +230,7 @@ "Return a table with details of attributes for classes and modules." if self.objtable is None: - t = self.objtable = micropython.table.Table() + t = self.objtable = micropython.table.ObjectTable() for module in self.get_modules(): t.add(module.full_name(), module.module_attributes()) for obj in module.all_objects: @@ -244,7 +244,7 @@ "Return a table with details of class compatibility." if self.clstable is None: - t = self.clstable = micropython.table.Table() + t = self.clstable = micropython.table.ClassTable() for module in self.get_modules(): for obj in module.all_objects: if isinstance(obj, micropython.inspect.Class): @@ -263,7 +263,7 @@ objtable = self.get_object_table() if self.paramtable is None: - t = self.paramtable = micropython.table.Table() + t = self.paramtable = micropython.table.ParameterTable() # Visit each module, getting function and method details. diff -r b62d613c3ca1 -r dff32649a6d4 micropython/ast.py --- a/micropython/ast.py Sat Aug 23 22:32:17 2008 +0200 +++ b/micropython/ast.py Sun Aug 24 03:06:00 2008 +0200 @@ -32,7 +32,8 @@ "A translated module." supported_optimisations = [ - "constant_storage", "known_target", "self_access", "temp_storage", "load_operations", "no_operations", "unused_results" + "constant_storage", "source_storage", "known_target", "self_access", + "temp_storage", "load_operations", "no_operations", "unused_results" ] # Attribute access instructions, for use with the appropriate handlers. @@ -213,10 +214,12 @@ def record_value(self): self.expr_temp = self._optimise_temp_storage() + self.active_source = self.active def discard_value(self): self.discard_temp(self.expr_temp) self.expr_temp = None + self.active_source = None def set_source(self): if self.active is not None: @@ -322,12 +325,16 @@ self.active = None self.active_value = None + self.active_source = None # Optimisation tests. def _should_optimise_constant_storage(self): return "constant_storage" in self.optimisations + def _should_optimise_source_storage(self): + return "source_storage" in self.optimisations + def _should_optimise_known_target(self): return "known_target" in self.optimisations @@ -380,6 +387,7 @@ LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced TestIdentity, TestIdentityAddress, CheckSelf, # as one of the operands + CheckFrame, LoadContext, # as the object providing the result JumpWithFrame # as the target )) @@ -454,10 +462,11 @@ to a temporary variable retaining the result of the last instruction. """ - # LoadResult cannot be relied upon, since in general the result register + # LoadResult cannot be relied upon in general since the result register # could be updated since first being referenced. - return isinstance(self.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst)) + return isinstance(self.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst)) or \ + isinstance(self.active_value, LoadResult) and self.active_value is self.active def _have_correct_self_for_target(self, context): @@ -489,6 +498,25 @@ else: return 0 + def _optimise_source_storage(self): + + """ + Where the source value in an assignment can be inserted into the + eventual target without intermediate storage, optimise away the storage + instruction. + """ + + if self._should_optimise_source_storage() and \ + self.active_source is not None and \ + self.active_source.source is None and \ + self.active_source.input is None and \ + self.active_source is self.active: + + self.remove_op() + return 1 + else: + return 0 + def _optimise_known_target(self): """ @@ -779,7 +807,7 @@ # Where a target or context are not known or where an instance is known # to be the context, load the context. - if context is None or isinstance(context, Instance): + if target is None or isinstance(context, Instance): self.new_op(temp) self.new_op(LoadContext()) self.new_op(StoreFrame(0)) @@ -803,11 +831,20 @@ # Evaluate the arguments. employed_positions = set() + employed_keywords = set() extra_keywords = [] + # Find keyword arguments in advance in order to help resolve targets. + + for arg in args: + if isinstance(arg, compiler.ast.Keyword): + employed_keywords.add(arg.name) + + possible_targets = self.paramtable.all_possible_objects(employed_keywords) + # Note the presence of the context in the frame where appropriate. - if context is None or isinstance(context, Instance): + if target is None or isinstance(context, Instance): ncontext = 1 expect_context = 0 elif isinstance(context, Class): @@ -973,9 +1010,10 @@ else: max_pos = max(max(employed_positions or [-1]), max_keyword_pos, frame_pos - 1) - # Only check non-empty frames. + # Only check non-empty frames (using the callable's details). if employed_positions or max_pos >= 0: + self.new_op(temp) self.new_op(CheckFrame(max_pos + 1)) # Set the frame size. @@ -1403,8 +1441,13 @@ def visitAssList(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "AssList") def visitAssName(self, node): + + # Optimise away intermediate source storage. + + no_source = self._optimise_source_storage() self._visitName(node, self.name_store_instructions) - self.set_source() + if not no_source: + self.set_source() visitAssTuple = visitAssList @@ -1661,6 +1704,9 @@ # Visiting of the code occurs when get_code is invoked on this node. else: + extend = ExtendFrame() + self.new_op(extend) + self.dispatch(node.code) if not isinstance(self.last_op(), Return): self.dispatch(compiler.ast.Name("None")) @@ -1668,6 +1714,8 @@ self.new_op(Return()) + extend.attr = self.max_temp_position + 1 # NOTE: See get_code for similar code. + def visitGenExpr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExpr") def visitGenExprFor(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExprFor") diff -r b62d613c3ca1 -r dff32649a6d4 micropython/rsvp.py --- a/micropython/rsvp.py Sat Aug 23 22:32:17 2008 +0200 +++ b/micropython/rsvp.py Sun Aug 24 03:06:00 2008 +0200 @@ -186,6 +186,7 @@ # Invocation-related instructions, using a special result "register". class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the callable found as the current value." +class ExtendFrame(Immediate): "Extend the current frame for temporary storage use." class Return(Instruction): "Return from a subprogram." class LoadResult(Instruction): "Load into the current value a returned value." class StoreResult(Instruction): "Store the current value as a value to be returned." diff -r b62d613c3ca1 -r dff32649a6d4 micropython/table.py --- a/micropython/table.py Sat Aug 23 22:32:17 2008 +0200 +++ b/micropython/table.py Sun Aug 24 03:06:00 2008 +0200 @@ -143,27 +143,51 @@ if entry is None: result.append(None) else: - offset, attr = entry - if attr.parent is not None: - location = attr.parent.location or 0 - else: - location = 0 - if attr.position is not None: - position = attr.position + location + 1 # skip structure header - else: - position = None # NOTE: Should fix unpositioned attributes. - - # Class offset/code, attribute type, context instance override flag, location/position. - - result.append((offset, attr.is_class_attribute(), attr.defined_within_hierarchy(), position)) + result.append(self.entry_as_raw(entry)) return result +class ObjectList(List): + + "An object list." + + def entry_as_raw(self, entry): + offset, attr = entry + + if attr.parent is not None: + location = attr.parent.location or 0 + else: + location = 0 + if attr.position is not None: + position = attr.position + location + 1 # skip structure header + else: + position = None # NOTE: Should fix unpositioned attributes. + + # Class offset/code, attribute type, context instance override flag, location/position. + + return (offset, attr.is_class_attribute(), attr.defined_within_hierarchy(), position) + +class ClassList(List): + + "A class list." + + def entry_as_raw(self, entry): + offset, attr = entry + return offset + +class ParameterList(List): + + "A parameter list." + + def entry_as_raw(self, entry): + return entry + class Table: "A lookup table." TableError = TableError + list_class = None # overridden def __init__(self): self.attributes = set() @@ -275,7 +299,7 @@ """ if self.displaced_list is None: - self.displaced_list = List(self.attribute_names()) + self.displaced_list = self.list_class(self.attribute_names()) # Visit each row of the matrix. @@ -284,4 +308,22 @@ return self.displaced_list +class ObjectTable(Table): + + "An object table." + + list_class = ObjectList + +class ClassTable(Table): + + "A class table." + + list_class = ClassList + +class ParameterTable(Table): + + "A parameter table." + + list_class = ParameterList + # vim: tabstop=4 expandtab shiftwidth=4 diff -r b62d613c3ca1 -r dff32649a6d4 rsvp.py --- a/rsvp.py Sat Aug 23 22:32:17 2008 +0200 +++ b/rsvp.py Sun Aug 24 03:06:00 2008 +0200 @@ -32,7 +32,7 @@ * Invocation frame pointer stack * Exception handler stack * Registers: current value, boolean status value, source value, result, - current exception + current exception, current callable The memory contains constants, global variable references and program code. @@ -87,6 +87,7 @@ self.value = None self.status = None self.source = None + self.callable = None self.result = None self.exception = None @@ -289,13 +290,7 @@ self.invocation_sp_stack.append(len(self.frame_stack)) self.frame_stack.extend([None] * self.operand) - def JumpWithFrame(self): - self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame - context, ref = self.value - return self.jump(ref.code_location, self.pc + 1) # return to the instruction after this one - def DropFrame(self): - result = self.pull() self.local_sp_stack.pop() frame = self.invocation_sp_stack.pop() self.frame_stack = self.frame_stack[:frame] # reset stack before call @@ -315,15 +310,35 @@ # NOTE: This should cause an argument error. raise Exception, "StoreFrameIndex % r" % element - def CheckFrame(self): pass + def LoadCallable(self): + context, ref = self.value + self.callable = self.load(ref + 1) + + def StoreCallable(self): + context, ref = self.value + self.save(ref + 1, self.callable) + + def LoadContext(self): + context, ref = self.value + self.value = None, context + + def CheckFrame(self): + context, ref = self.value + nargs, ndefaults = self.load(ref + 2) + if not (nargs - ndefaults <= self.operand <= nargs): + raise Exception, "CheckFrame %r" % (nargs - ndefaults, self.operand, nargs) + # NOTE: Support population of defaults. + # NOTE: Support sliding of the frame to exclude any inappropriate context. def CheckSelf(self): pass - def LoadCallable(self): pass + def JumpWithFrame(self): + self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame + return self.jump(self.callable, self.pc + 1) # return to the instruction after this one - def LoadContext(self): - context, ref = self.value - self.push((None, context)) + def ExtendFrame(self): + frame = self.local_sp_stack[-1] + frame.extend([None] * self.operand) def Return(self): self.pc = self.pull_pc() @@ -372,4 +387,7 @@ # LoadBoolean is implemented in the generated code. # StoreBoolean is implemented by testing against the True value. + def InvertBoolean(self): + self.status = not self.status + # vim: tabstop=4 expandtab shiftwidth=4