# HG changeset patch # User Paul Boddie # Date 1214778774 -7200 # Node ID 3b25077049575b86833a500e23202638af031b38 # Parent 78240b642d1fbdca94b615b1123d49a7e44a9303 Attempted to improve invocations by adopting explicitly populated frames. Attempted to resolve the context generation and validation strategy. Attempted to improve optimisations, incorporating constant storage optimisations into the new_op method and adding better tests for side-effect-resistant operations suitable for stack optimisations, incorporating last invocation tracking. Changed the internal stack operation descriptions to use explicit classes, since a distinct StackLoad instruction is now used (as opposed to StackPull which was previously StackLoad, and StackPush which was previously StackSave). Added LoadAddressContext and StoreAddressContext to address the issue of loading class-originating attributes via an instance (predicted using self). Removed various obsolete instructions and added stack operations to others. Added a test of for loops. diff -r 78240b642d1f -r 3b2507704957 docs/invocation.txt --- a/docs/invocation.txt Sat Jun 28 20:46:45 2008 +0200 +++ b/docs/invocation.txt Mon Jun 30 00:32:54 2008 +0200 @@ -53,7 +53,7 @@ # f(obj, 1, 2) # f known as C.m at compile-time: # m(obj "assert isinstance(obj, C)", 1, 2) - # f not known at compiler-time: + # f not known at compile-time: # f(, obj, 1, 2) for instance-accessed methods # f(obj, 1, 2) for class-accessed methods # f(obj, 1, 2) for functions @@ -61,6 +61,51 @@ (Could either have universal context usage even for functions, which would ignore them, or attempt to remove contexts when functions are called.) +Argument lists for functions: + + f(obj, 1, 2) # f known as function at compile-time + + f -> don't get any context information + obj -> argument #1 + 1 -> argument #2 + 2 -> argument #3 + +Argument lists for methods: + + f(obj, 1, 2) # f known as C.m at compile-time (context is C) + + f -> C.m - don't get any context information + obj -> argument #1 + 1 -> argument #2 + 2 -> argument #3 + +Argument lists for methods: + + f(obj, 1, 2) # f known as C.m at compile-time (context is an instance) + + f -> C.m + -> context is argument #1 + obj -> argument #2 + 1 -> argument #3 + 2 -> argument #4 + +Argument lists for unknown callables: + + f(obj, 1, 2) # f not known at compile-time + + f -> f + -> load context for argument #1 + obj -> argument #2 + 1 -> argument #3 + 2 -> argument #4 + + Then, check the context and shift the frame if necessary: + + is module or class: + (, obj, 1, 2) -> (obj, 1, 2) + + is instance: no change + Functions as methods: def f(x, y, z): ... diff -r 78240b642d1f -r 3b2507704957 micropython/ast.py --- a/micropython/ast.py Sat Jun 28 20:46:45 2008 +0200 +++ b/micropython/ast.py Mon Jun 30 00:32:54 2008 +0200 @@ -33,6 +33,9 @@ supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "constant_test", "stack_access"] + attribute_load_instructions = (LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex) + attribute_store_instructions = (StoreAddress, StoreAddressContext, StoreAttr, StoreAttrIndex) + def __init__(self, module, importer, optimisations=None): """ @@ -72,6 +75,7 @@ # and the presumed state of the value stack. self.code = None + self.last_invocation = None self.temp_position = 0 self.stack = [] self.suspended_frame = [] @@ -86,6 +90,7 @@ self.unit = self.module self.code = [] + self.last_invocation = None self.temp_position = self.unit.stack_local_usage self.stack = [] @@ -100,6 +105,7 @@ self.unit = unit self.code = [] + self.last_invocation = None self.temp_position = self.unit.stack_local_usage self.stack = [] @@ -226,10 +232,18 @@ "Add 'op' to the generated code." - position = len(self.code) + # Optimise stack access by incorporating the source data directly into + # instructions. + self._optimise_stack_access(op) + + # Optimise away constant storage if appropriate. + # The target and value loading operations are also removed. + + if self._optimise_constant_storage(op): + return + self.adjust_stack(op) - self.code.append(op) def new_ops(self, ops): @@ -288,6 +302,12 @@ except IndexError: return None + def set_last_invocation(self): + + "Set this location as the point after the last invocation." + + self.last_invocation = len(self.code) + # Internal helper methods. def _visitAttr(self, node, classes): @@ -306,7 +326,7 @@ Generate code for the access to 'attrname' using the given 'classes'. """ - AddressInstruction, AttrInstruction, AttrIndexInstruction = classes + AddressInstruction, AddressContextInstruction, AttrInstruction, AttrIndexInstruction = classes last = self.last_op() @@ -315,12 +335,6 @@ if self._have_constant_input(0): - # Optimise away the constant storage if appropriate. - # The target and value loading operations are removed. - - if self._optimise_constant_storage(AddressInstruction, 1): - return - # Get the details of the access. if isinstance(last.attr, Const): @@ -362,7 +376,7 @@ # see if the attribute is acceptably positioned and produce a direct # access to the attribute. - elif self._optimise_self_access(attrname, (AddressInstruction, AttrInstruction)): + elif self._optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction)): return # Otherwise, perform a normal operation. @@ -419,21 +433,13 @@ temp = self._optimise_temp_storage() - # Where a target or context are not known, load the target and context. + # 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: + if context is None or isinstance(context, Instance): self.new_ops(temp) self.new_op(LoadContext()) - - # Check to see if the context is needed for the target. - - self.new_op(CheckContext()) - - # Where an instance is known to be the context, load the context. - - elif isinstance(context, Instance): - self.new_ops(temp) - self.new_op(LoadContext()) + self.new_op(StoreFrame(0)) # Otherwise omit the context. @@ -455,12 +461,17 @@ employed_positions = set() extra_keywords = [] - # NOTE: Fix context for self-accessed methods. + # Note the presence of the context in the frame where appropriate. - if context is not None and isinstance(context, Instance): + if context is None or isinstance(context, Instance): ncontext = 1 + expect_context = 0 + elif isinstance(context, Class): + ncontext = 0 + expect_context = 1 else: ncontext = 0 + expect_context = 0 first = 1 frame_pos = ncontext @@ -503,22 +514,11 @@ employed_positions.add(pos) - # Add space for arguments appearing before this one. - - if frame_pos < pos: - self.new_op(ReserveFrame(pos - frame_pos)) - frame_pos = pos - # Generate code for the keyword and the positioning # operation. self.dispatch(arg.expr) - - # If the position corresponds to the current frame element, - # skip generating the store instruction. - - if frame_pos > pos: - self.new_op(StoreFrame(pos)) + self.new_op(StoreFrame(pos)) # Otherwise, generate the code needed to obtain the details of # the parameter location. @@ -550,12 +550,13 @@ else: self.dispatch(arg) - employed_positions.add(frame_pos + ncontext) + self.new_op(StoreFrame(frame_pos)) + employed_positions.add(frame_pos) # Check to see if the first argument is appropriate (compatible with - # the # target where methods are being invoked via classes). + # the target where methods are being invoked via classes). - if first and context is None: + if first and expect_context: continue_label = self.new_label() self.new_op(CheckSelf()) self.new_op(JumpIfTrue(continue_label)) @@ -612,21 +613,15 @@ for pos in range(nargs_min, nargs_max): if pos not in employed_positions: - #self.new_op(LoadConst(target)) - #self.new_op(LoadAttr(target.default_attrs[pos - nargs_min])) self.new_op(LoadAddress(target.default_attrs[pos - nargs_min])) - - # If the position corresponds to the current frame element, - # skip generating the instruction. - - if frame_pos != pos: - self.new_op(StoreFrame(pos)) + self.new_op(StoreFrame(pos)) frame_pos += 1 # Or generate instructions to do this at run-time. # NOTE: CheckFrame has to check the number of arguments and to fill in - # NOTE: defaults. + # NOTE: defaults; it also has to shift the invocation frame according to + # NOTE: the context in use. else: self.new_op(CheckFrame()) @@ -644,6 +639,10 @@ # NOTE: Exception handling required. + # Note this as the most recent invocation. + + self.set_last_invocation() + self.new_op(DropFrame()) if keep_frame: self.suspend_frame() @@ -679,12 +678,6 @@ NameInstruction, AddressInstruction = classes - # Optimise away the constant storage if appropriate. - # The target and value loading operations are removed. - - if self._optimise_constant_storage(NameInstruction, 0): - return - if scope == "local": unit = self.unit if isinstance(unit, Function): @@ -735,34 +728,92 @@ def _should_optimise_stack_access(self): return "stack_access" in self.optimisations + # Simple tests. + + def _is_constant_input(self, instruction): + + "Return whether 'instruction' provides a constant input." + + return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \ + isinstance(instruction, LoadConst) + + def _is_local_input(self, instruction): + + "Return whether 'instruction' provides a local input." + + return isinstance(instruction, (LoadName, LoadTemp)) + + def _is_unaffected(self, instruction, position): + + """ + Return whether 'instruction' is unaffected by side-effects since it + occurs at a 'position' later than the last invocation. + """ + + return isinstance(instruction, (LoadResult, LoadAddress)) and ( + self.last_invocation is None or position >= self.last_invocation) + + # Convenience tests. + def _have_constant_input(self, n): + + "Return whether the last 'n' instructions provide constant inputs." + last = self.last_ops(n+1) - return len(last) > n and (isinstance(last[n], LoadAddress) and last[n].attr.assignments == 1 or - isinstance(last[n], LoadConst)) + return len(last) > n and self._is_constant_input(last[n]) def _have_known_target(self): + + "Return whether the last instruction is a known target." + return self._have_constant_input(0) def _have_self_input(self): + + "Return whether the last instruction is a reference to self." + last = self.last_op() return isinstance(self.unit, Function) and \ self.unit.is_method() and isinstance(last, LoadName) and \ last.attr.name == "self" def _have_temp_compatible_access(self): + + """ + Indicate whether the last instruction can be used in place of access to + a temporary variable retaining the result of the last instruction. + """ + last = self.last_op() # NOTE: Should expand to cover LoadAttr and LoadAttrIndex, but this # NOTE: would require inspection of the stack operations. return isinstance(last, (LoadName, LoadTemp, LoadAddress, LoadConst)) - def _have_fixed_sources(self, instruction): + def _get_access_instructions(self, instruction): + + """ + Get the stack access instructions employed by the given 'instruction'. + It is assumed that the source of the data communicated through the stack + is not modified since the storage of the data. However, since the stack + should only be employed within statements, there should be no risk of + side-effects for local storage. + """ + access_ops = [] for stack_op in instruction.accesses: - if isinstance(stack_op, StackLoad): + if isinstance(stack_op, (StackLoad, StackPull)): position, op = self.stack[stack_op.n] - if not isinstance(op, (LoadName, LoadTemp, LoadAddress, LoadConst)): + + # Insist on constants, locals or other things which should not + # have been changed. + + if not self._is_constant_input(op) and not self._is_local_input(op) and \ + not self._is_unaffected(op, position): + return None + access_ops.append((op, stack_op)) + return access_ops # Optimisation methods. See the supported_optimisations class attribute. @@ -779,6 +830,10 @@ and the appropriate LoadTemp instruction is returned. All returned instructions are provided in a list. + + Restriction: for use only in situations where the source of the + temporary data will not be disturbed between its first access and its + subsequent use. """ if self._should_optimise_temp_storage() and \ @@ -792,7 +847,7 @@ self.new_op(StoreTemp(temp_position)) return [LoadTemp(temp_position)] - def _optimise_constant_storage(self, instruction, n): + def _optimise_constant_storage(self, instruction): """ Where this operation should store a constant into a target which is @@ -800,11 +855,9 @@ """ if self._should_optimise_constant_storage() and \ - instruction in (StoreAddress, StoreName) and \ - self._have_constant_input(n) and \ - (n == 0 or self._have_constant_input(n-1)): + isinstance(instruction, (StoreName, StoreAddress)) and \ + instruction.attr.assignments == 1: - self.remove_ops(n+1) return 1 else: return 0 @@ -862,7 +915,7 @@ directly. """ - AddressInstruction, AttrInstruction = classes + AddressInstruction, AddressContextInstruction, AttrInstruction = classes if self._should_optimise_self_access() and self._have_self_input() and \ not self.unit.is_relocated(attrname): @@ -878,7 +931,7 @@ except KeyError: attr = self.unit.parent.all_attributes()[attrname] new_attr = attr.via_instance() - self.replace_op(AddressInstruction(new_attr)) + self.new_op(AddressContextInstruction(new_attr)) return 1 else: @@ -892,9 +945,8 @@ """ if self._should_optimise_stack_access(): - ops = self._have_fixed_sources(instruction) + ops = self._get_access_instructions(instruction) if ops is not None: - #print "Optimised", instruction.accesses, "->", ops instruction.accesses = [] for op, stack_op in ops: if self.remove_op_using_stack(op): @@ -939,7 +991,7 @@ # Get the method on temp. - self._generateAttr(node, method, (LoadAddress, LoadAttr, LoadAttrIndex)) + self._generateAttr(node, method, self.attr_load_instructions) # Add exception handling to the method acquisition instructions where # the attribute access cannot be resolved at compile-time. @@ -1016,7 +1068,7 @@ # Get left method on temp1. - self._generateAttr(node, left_method, (LoadAddress, LoadAttr, LoadAttrIndex)) + self._generateAttr(node, left_method, self.attr_load_instructions) # Add exception handling to the method acquisition instructions where # the attribute access cannot be resolved at compile-time. @@ -1058,7 +1110,7 @@ # Get right method on temp2. - self._generateAttr(node, right_method, (LoadAddress, LoadAttr, LoadAttrIndex)) + self._generateAttr(node, right_method, self.attr_load_instructions) # Add exception handling to the method acquisition instructions where # the attribute access cannot be resolved at compile-time. @@ -1118,7 +1170,7 @@ self.dispatch(n) def visitAssAttr(self, node): - self._visitAttr(node, (StoreAddress, StoreAttr, StoreAttrIndex)) + self._visitAttr(node, self.attribute_store_instructions) def visitAssList(self, node): pass @@ -1223,13 +1275,18 @@ self._startCallFunc() self.dispatch(node.list) - self._generateAttr(node, "__iter__", (LoadAddress, LoadAttr, LoadAttrIndex)) + self._generateAttr(node, "__iter__", self.attr_load_instructions) temp = self._generateCallFunc([], node) self._doCallFunc(temp) self._endCallFunc(temp) # Iterator on stack. + temp_iterator_position = self.reserve_temp(1) + temp_iterator = [LoadTemp(temp_iterator_position)] + + self.new_op(StoreTemp(temp_iterator_position)) + # In the loop... self.set_label(next_label) @@ -1237,8 +1294,8 @@ # Use the iterator to get the next value. self._startCallFunc() - self.new_op(Duplicate()) - self._generateAttr(node, "next", (LoadAddress, LoadAttr, LoadAttrIndex)) + self.new_ops(temp_iterator) + self._generateAttr(node, "next", self.attr_load_instructions) temp = self._generateCallFunc([], node) self._doCallFunc(temp) self._endCallFunc(temp) @@ -1272,10 +1329,14 @@ self.set_label(exit_label) self.dispatch(node.else_) - # Pop the iterator. + # After the loop... self.set_label(exit_label) + # Compilation duties... + + self.discard_temp(temp_iterator) + def visitFrom(self, node): pass def visitFunction(self, node): @@ -1309,7 +1370,7 @@ def visitGenExprInner(self, node): pass def visitGetattr(self, node): - self._visitAttr(node, (LoadAddress, LoadAttr, LoadAttrIndex)) + self._visitAttr(node, self.attribute_load_instructions) def visitGlobal(self, node): pass diff -r 78240b642d1f -r 3b2507704957 micropython/data.py --- a/micropython/data.py Sat Jun 28 20:46:45 2008 +0200 +++ b/micropython/data.py Mon Jun 30 00:32:54 2008 +0200 @@ -700,12 +700,12 @@ def __repr__(self): if self.location is not None: - return "Function(%r, %s, %r, %r, %r, %r, location=%r)" % ( - self.name, shortrepr(self.parent), self.argnames, self.defaults, self.has_star, self.has_dstar, self.location + return "Function(%r, %s, %r, location=%r, code_location=%r)" % ( + self.name, shortrepr(self.parent), self.argnames, self.location, self.code_location ) else: - return "Function(%r, %s, %r, %r, %r, %r)" % ( - self.name, shortrepr(self.parent), self.argnames, self.defaults, self.has_star, self.has_dstar + return "Function(%r, %s, %r)" % ( + self.name, shortrepr(self.parent), self.argnames ) def __shortrepr__(self): diff -r 78240b642d1f -r 3b2507704957 micropython/rsvp.py --- a/micropython/rsvp.py Sat Jun 28 20:46:45 2008 +0200 +++ b/micropython/rsvp.py Mon Jun 30 00:32:54 2008 +0200 @@ -41,13 +41,13 @@ "A generic instruction." - stack_storage = 0 - stack_access = 0 + stack_storage = [] + stack_access = [] def __init__(self, attr=None): self.attr = attr - self.accesses = [StackLoad(-1 - n) for n in range(0, self.stack_access)] - self.results = [StackSave(n) for n in range(0, self.stack_storage)] + self.accesses = [op(-1 - n) for n, op in enumerate(self.stack_access)] + self.results = [op(n) for n, op in enumerate(self.stack_storage)] def copy(self): return self.__class__(self.attr) @@ -172,6 +172,43 @@ Immediate = ImmediateInstruction +# Internal stack and frame operations for instructions. + +class StackOp: + + "A generic stack operation." + + def __init__(self, n): + self.n = n + self.level = None + + def fix_stack(self, level): + self.level = self.n + level + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, self.level == 0 and "0" or self.level or self.n) + +class StackPull(StackOp): + + "Load a value from the stack." + + def get_effect(self): + return -1 + +class StackPush(StackOp): + + "Save a value onto the stack." + + def get_effect(self): + return 1 + +class StackLoad(StackOp): + + "Load a value from the stack." + + def get_effect(self): + return 0 + # Mix-in classes for stack effects. class StackAdd: @@ -181,35 +218,34 @@ instruction. """ - stack_storage = 1 + stack_storage = [StackPush] class StackRemove: "Indicate that the stack must shrink as an effect of this instruction." - stack_storage = -1 - stack_access = 1 + stack_access = [StackPull] class StackRemove2: "Indicate that the stack must shrink as an effect of this instruction." - stack_storage = -2 - stack_access = 2 + stack_access = [StackPull, StackPull] -class StackReplace: +class StackReplace(StackAdd, StackRemove): """ Indicate that the stack remains at the same level due to the replacement of the topmost element. """ - stack_storage = 1 - stack_access = 1 + pass + +class StackInspect: -# Instructions operating on the value stack. + "Indicate that the stack is inspected but unchanged by this instruction." -class Duplicate(StackAdd, Instruction): "Duplicate the top of the stack." + stack_access = [StackLoad] # Access to stored constant data. @@ -222,41 +258,43 @@ class LoadTemp(StackAdd, Immediate): "Load the object from the given temporary location." class StoreTemp(StackRemove, Immediate): "Store the object in the given temporary location." +# Access to static data. + +class LoadAddress(StackAdd, Address): "Load the object from the given fixed attribute address." +class StoreAddress(StackRemove, Address): "Store an object in the given fixed attribute address." +class LoadAddressContext(StackReplace, Address):"Load the object from the given fixed attribute address, changing the context." +class StoreAddressContext(StackRemove2, Address):"Store an object in the given fixed attribute address, changing the context." +class MakeObject(StackAdd, Instruction): "Make a new object. There isn't a complementary DropObject." + # Access to address-relative data. -class MakeObject(StackAdd, Instruction): "Make a new object. There isn't a complementary DropObject." class LoadAttr(StackReplace, AR): "Load the object from the given attribute." class StoreAttr(StackRemove2, AR): "Store an object in the given attribute." class LoadAttrIndex(StackReplace, Immediate): "Load the object for the attribute with the given index." class StoreAttrIndex(StackRemove2, Immediate): "Store an object in the attribute with the given index." -class LoadAddress(StackAdd, Address): "Load the object from the given fixed attribute address." -class StoreAddress(StackRemove, Address): "Store an object in the given fixed attribute address." # Access to invocation frames in preparation. class MakeFrame(Instruction): "Make a new invocation frame." -class ReserveFrame(Immediate): "Reserve the given number of entries for the invocation frame." -class StoreFrame(StackRemove, Immediate): "Store an argument at the given frame location." +class DropFrame(Instruction): "Drop an invocation frame." +class StoreFrame(StackRemove, Immediate): "Store an argument for the parameter with the given position." class StoreFrameIndex(StackRemove, Immediate): "Store an argument for the parameter with the given index." -class LoadCallable(Instruction): "Load the target of an invocation." +class LoadCallable(StackInspect, Instruction): "Load the target of an invocation." class LoadContext(StackReplace, Instruction): "Load the context of an invocation." -class CheckFrame(Instruction): "Check the invocation frame for the target." -class CheckSelf(Instruction): "Check the first argument of an invocation against the target." -class CheckContext(Instruction): """Check the context of an invocation against the target, - potentially discarding the context.""" +class CheckFrame(Instruction): "Check the invocation frame and context for the target." +class CheckSelf(StackAdd, Instruction): "Check the first argument of an invocation against the target." # Invocation-related instructions, using a special result "register". -class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the callable found on the stack." -class DropFrame(Instruction): "Drop an invocation frame." +class JumpWithFrame(StackRemove, Instruction): "Jump, adopting the invocation frame, to the callable found on the stack." class Return(StackRemove, Instruction): "Return a value from a subprogram." class LoadResult(StackAdd, Instruction): "Load a returned value." # Branch-related instructions. class Jump(Address): "Jump unconditionally." -class JumpIfFalse(Address): "Jump if the last evaluation gave a false result." -class JumpIfTrue(Address): "Jump if the last evaluation gave a true result." +class JumpIfFalse(StackRemove, Address): "Jump if the last evaluation gave a false result." +class JumpIfTrue(StackRemove, Address): "Jump if the last evaluation gave a true result." # Exception-related instructions, using a special exception "register". @@ -269,37 +307,4 @@ class TestIdentity(Instruction): "Test whether the two topmost stack values are identical." class TestIdentityAddress(Address): "Test whether the topmost stack value is identical to the given address." -# Internal stack operations for instructions. - -class StackOp: - - "A generic stack operation." - - def __init__(self, n): - self.n = n - self.level = None - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, self.level == 0 and "0" or self.level or self.n) - -class StackLoad(StackOp): - - "Load a value from the stack." - - def fix_stack(self, level): - self.level = self.n + level - - def get_effect(self): - return -1 - -class StackSave(StackOp): - - "Save a value onto the stack." - - def fix_stack(self, level): - self.level = self.n + level - - def get_effect(self): - return 1 - # vim: tabstop=4 expandtab shiftwidth=4 diff -r 78240b642d1f -r 3b2507704957 rsvp.py --- a/rsvp.py Sat Jun 28 20:46:45 2008 +0200 +++ b/rsvp.py Mon Jun 30 00:32:54 2008 +0200 @@ -101,15 +101,15 @@ self.memory.append(None) return addr - def push(self, data): + def stack_save(self, n, data): - "Push 'data' onto the value stack." + "Save to location 'n' on the value stack the given 'data'." self.value_stack.append(data) - def pull(self): + def stack_load(self, n): - "Pull a value from the value stack and return it." + "Load a value from the value stack at location 'n'." return self.value_stack.pop() @@ -191,57 +191,22 @@ # Instructions. - def Pop(self): - self.pull() - self.pc += 1 - - def MakeFrame(self): - top = len(self.value_stack) - self.add_frame(top) - self.pc += 1 - - def ReserveFrame(self): - n = self.load(self.pc).get_operand() - while n > 0: - self.push(None) - n -= 1 - self.pc += 1 - - def DropFrame(self): - result = self.pull() - frame = self.pull_frame() - self.value_stack = self.value_stack[:frame] # reset stack before call - self.push(result) - self.pc += 1 - - def JumpWithFrame(self): - attr = self.pull() - self.frame_sp += 1 # adopt the added frame - target_location = attr[0] - target = self.load(target_location) - self.jump(target.code_location, self.pc + 1) # return to the instruction after this one - - def LoadContext(self): + def LoadConst(self): """ - LoadContext - Load context from top of stack: get the context from the value on the - top of the stack, pushing it onto the stack. + LoadConst addr + Load the reference to memory: get the address addr, push the value onto + the stack as a value without context. + + This is useful for loading constants. + NOTE: This assumes that constants are encoded with context. """ - attr = self.value_stack[-1] - self.push((attr[1], None)) - self.pc += 1 - - def CheckContext(self): - - """ - CheckContext - Check the context: check the context on the top of the stack - """ - - attr = self.value_stack[-1] - # NOTE: To be written. + op = self.load(self.pc) + addr = op.get_operand() + value = (addr, None) + for result in op.results: + self.stack_save(result.level, value) self.pc += 1 def LoadName(self): @@ -273,22 +238,6 @@ LoadTemp = LoadName StoreTemp = StoreName - def LoadConst(self): - - """ - LoadConst addr - Load the reference to memory: get the address addr, push the value onto - the stack as a value without context. - - This is useful for loading constants. - NOTE: This assumes that constants are encoded with context. - """ - - addr = self.load(self.pc).get_operand() - value = (addr, None) - self.push(value) - self.pc += 1 - def LoadAttr(self): """ @@ -319,6 +268,10 @@ self.save(ref + n, value) self.pc += 1 + def LoadAttrIndex(self): pass + + def StoreAttrIndex(self): pass + def LoadAddress(self): """ @@ -346,6 +299,58 @@ self.save(addr, value) self.pc += 1 + def MakeFrame(self): + n = self.load(self.pc).get_operand() + top = len(self.value_stack) + self.add_frame(top) + while n > 0: + self.push(None) + n -= 1 + self.pc += 1 + + def DropFrame(self): + result = self.pull() + frame = self.pull_frame() + self.value_stack = self.value_stack[:frame] # reset stack before call + self.push(result) + self.pc += 1 + + def LoadCallable(self): pass + + def LoadContext(self): + + """ + LoadContext + Load context from top of stack: get the context from the value on the + top of the stack, pushing it onto the stack. + """ + + attr = self.value_stack[-1] + self.push((attr[1], None)) + self.pc += 1 + + def CheckFrame(self): pass + + def CheckSelf(self): pass + + def CheckContext(self): + + """ + CheckContext + Check the context: check the context on the top of the stack + """ + + attr = self.value_stack[-1] + # NOTE: To be written. + self.pc += 1 + + def JumpWithFrame(self): + attr = self.pull() + self.frame_sp += 1 # adopt the added frame + target_location = attr[0] + target = self.load(target_location) + self.jump(target.code_location, self.pc + 1) # return to the instruction after this one + def Return(self): """ @@ -356,6 +361,10 @@ self.pc = self.pull_pc() + def LoadResult(self): pass + + def Jump(self): pass + def JumpIfTrue(self): """ diff -r 78240b642d1f -r 3b2507704957 tests/for.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/for.py Mon Jun 30 00:32:54 2008 +0200 @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +for i in range(0, 100, 10): + for j in range(0, 10): + k = i + j + +# vim: tabstop=4 expandtab shiftwidth=4