1.1 --- a/TO_DO.txt Sun Aug 07 23:01:35 2011 +0200
1.2 +++ b/TO_DO.txt Sun Aug 21 14:24:28 2011 +0200
1.3 @@ -1,6 +1,10 @@
1.4 Low-Level Instructions and Macro Instructions
1.5 =============================================
1.6
1.7 +Instructions manipulated through the temporary infrastructure are reused and can be
1.8 +corrupted by set_source and set_target operations. It might be better if such operations
1.9 +cloned the instructions or if new instructions were explicitly created.
1.10 +
1.11 Have contexts and values stored separately in memory. This involves eliminating DataValue
1.12 and storing attributes using two words.
1.13
1.14 @@ -10,6 +14,18 @@
1.15 Consider introducing classic machine level instructions (word addition, subtraction, and
1.16 so on) in order to implement all current RSVP instructions.
1.17
1.18 +Move common code sequences to a library routine, such as the context checking that occurs
1.19 +in functions and methods.
1.20 +
1.21 +Return Value Optimisations
1.22 +==========================
1.23 +
1.24 +Attempt to use result data directly instead of transferring it explicitly to the working
1.25 +registers and then using it.
1.26 +
1.27 +Perhaps store resultant working values on Block instances in order to better track active
1.28 +values.
1.29 +
1.30 Class and Module Attribute Assignment
1.31 =====================================
1.32
2.1 --- a/docs/concepts.txt Sun Aug 07 23:01:35 2011 +0200
2.2 +++ b/docs/concepts.txt Sun Aug 21 14:24:28 2011 +0200
2.3 @@ -565,15 +565,26 @@
2.4 ==============
2.5
2.6 During code generation, much of the evaluation produces results which are
2.7 -implicitly recorded in the "active value" register, and various instructions
2.8 -will consume the active value. In addition, some instructions will consume a
2.9 -separate "active source value" from a register, typically those which are
2.10 -assigning the result of an expression to an assignment target.
2.11 +implicitly recorded in the "active value" or "working" register, and various
2.12 +instructions will consume this active value. In addition, some instructions
2.13 +will consume a separate "active source value" from a register, typically those
2.14 +which are assigning the result of an expression to an assignment target.
2.15
2.16 Since values often need to be retained for later use, a set of temporary
2.17 storage locations are typically employed. However, optimisations may reduce
2.18 the need to use such temporary storage where instructions which provide the
2.19 -"active value" can be re-executed and will produce the same result.
2.20 +"active value" can be re-executed and will produce the same result. Whether
2.21 +re-use of instructions is possible or not, values still need to be loaded into
2.22 +a "source" register to be accessed by an assignment instruction.
2.23 +
2.24 +RSVP instructions generally have the notion of working, target and source
2.25 +registers (see registers.txt). These register "roles" are independent from the
2.26 +actual registers defined for the RSVP machine itself, even though the naming
2.27 +is similar. Generally, instructions do regard the RSVP "working" registers as
2.28 +the class of register in the "working" role, although some occurrences of
2.29 +instruction usage may employ other registers (such as the "result" registers)
2.30 +and thus take advantage of the generality of the RSVP implementation of such
2.31 +instructions.
2.32
2.33 List and Tuple Representations
2.34 ==============================
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/docs/instructions.txt Sun Aug 21 14:24:28 2011 +0200
3.3 @@ -0,0 +1,54 @@
3.4 +Register Usage in RSVP Instructions
3.5 +===================================
3.6 +
3.7 + operand working target source memory access
3.8 + ------- ------- ------ ------ -------------
3.9 +Transfer * *
3.10 +LoadConst * *
3.11 +LoadClass * *
3.12 +LoadFunction * *
3.13 +LoadName * * frame
3.14 +LoadTemp * * frame
3.15 +LoadAddress * * memory
3.16 +LoadAddressContext * * * memory
3.17 +LoadAddressContextCond * * * memory
3.18 +LoadAttr * * * memory
3.19 +LoadAttrIndex * * * memory
3.20 +LoadAttrIndexContextCond * * * memory
3.21 +LoadCallable * * memory
3.22 +StoreName * * frame
3.23 +StoreTemp * * frame
3.24 +StoreAddress * * memory
3.25 +StoreAddressContext * * * memory
3.26 +StoreAttr * * * memory
3.27 +StoreAttrIndex * * * memory
3.28 +StoreCallable * * memory
3.29 +StoreFrame * * frame
3.30 +StoreFrameIndex * * frame
3.31 +CheckContext * *
3.32 +CheckClass * * memory
3.33 +CheckInstance * * * memory
3.34 +CheckFrame * * frame
3.35 +CheckExtra * frame
3.36 +CheckException * * memory
3.37 +JumpInFrame *
3.38 +JumpWithFrame *
3.39 +JumpWithFrameDirect *
3.40 +Jump *
3.41 +JumpIfFalse * *
3.42 +JumpIfTrue * *
3.43 +Return stack
3.44 +MakeInstance * * * memory
3.45 +MakeFragment * * memory
3.46 +MakeFrame * frame
3.47 +DropFrame frame
3.48 +AdjustFrame * frame
3.49 +ExtendFrame * frame
3.50 +FillDefaults * * frame/memory
3.51 +CopyExtra * * frame/memory
3.52 +RaiseException E handlers/memory
3.53 +PushHandler * handlers
3.54 +PopHandler * frame/handlers
3.55 +TestIdentity * * *
3.56 +TestIdentityAddress * * *
3.57 +InvertBoolean * *
4.1 --- a/docs/optimisations.txt Sun Aug 07 23:01:35 2011 +0200
4.2 +++ b/docs/optimisations.txt Sun Aug 21 14:24:28 2011 +0200
4.3 @@ -267,9 +267,7 @@
4.4 constant_storage value instruction references a constant;
4.5 (guidance) storage instruction references a constant;
4.6 | indicate whether both instructions satisfy the
4.7 - | preconditions and should be removed (although
4.8 - | this currently involves just a single merged
4.9 - | instruction)
4.10 + | preconditions and should be removed/omitted
4.11
4.12 constant_accessor value instruction references a constant;
4.13 (guidance) | target name provided (for use in producing an
4.14 @@ -291,12 +289,6 @@
4.15 | instruction in place of a temporary storage
4.16 | reference
4.17
4.18 -load_operations value instruction is a simple input operation;
4.19 -(merge) value instruction is the last instruction;
4.20 - current instruction uses simple input;
4.21 - | remove the value instruction, make the value
4.22 - | instruction the input to the current instruction
4.23 -
4.24 no_operations input to the current instruction loads from the
4.25 (guidance) destination of the current instruction;
4.26 | indicate that the current instruction should be
5.1 --- a/lib/builtins.py Sun Aug 07 23:01:35 2011 +0200
5.2 +++ b/lib/builtins.py Sun Aug 21 14:24:28 2011 +0200
5.3 @@ -313,7 +313,12 @@
5.4 def __add__(self, other): pass
5.5 def __iadd__(self, other): pass
5.6 def __str__(self): pass
5.7 - def __bool__(self): pass
5.8 +
5.9 + def __bool__(self):
5.10 +
5.11 + "Lists are true if non-empty."
5.12 +
5.13 + return self.__len__() != 0
5.14
5.15 def __iter__(self):
5.16
5.17 @@ -410,7 +415,12 @@
5.18 def __len__(self): pass
5.19 def __add__(self, other): pass
5.20 def __str__(self): pass
5.21 - def __bool__(self): pass
5.22 +
5.23 + def __bool__(self):
5.24 +
5.25 + "Tuples are true if non-empty."
5.26 +
5.27 + return self.__len__() != 0
5.28
5.29 def __iter__(self):
5.30
6.1 --- a/micropython/ast.py Sun Aug 07 23:01:35 2011 +0200
6.2 +++ b/micropython/ast.py Sun Aug 21 14:24:28 2011 +0200
6.3 @@ -159,8 +159,7 @@
6.4
6.5 # Store the object as the result.
6.6
6.7 - self.new_op(LoadTemp(0)) # load the context from the locals
6.8 - self.new_op(LoadValueIntoResult())
6.9 + self.new_op(LoadTemp(0, target="result")) # load the context from the locals
6.10 self.new_op(Return())
6.11
6.12 self.unit.blocks = self.blocks
6.13 @@ -199,20 +198,23 @@
6.14 def visitAnd(self, node):
6.15 end_block = self.new_block()
6.16 temp_pos = self.reserve_temp()
6.17 - temp = LoadTemp(temp_pos)
6.18
6.19 for n in node.nodes[:-1]:
6.20 self.dispatch(n)
6.21 self.new_op(StoreTemp(temp_pos))
6.22
6.23 - self._generateTestBoolean(n, temp)
6.24 - self.new_op(JumpIfFalse(end_block))
6.25 + self._generateTestBoolean(n, LoadTemp(temp_pos))
6.26 + self.new_op(JumpIfFalse(end_block, working="status"))
6.27
6.28 self.dispatch(node.nodes[-1])
6.29 self.new_op(StoreTemp(temp_pos))
6.30
6.31 self.set_block(end_block)
6.32
6.33 + # Make a separate instruction to prevent previous temp accesses from
6.34 + # being altered by set_source.
6.35 +
6.36 + temp = LoadTemp(temp_pos)
6.37 self.new_op(temp)
6.38 self.discard_temp(temp)
6.39
6.40 @@ -223,26 +225,29 @@
6.41 self._generateTestBoolean(node.expr, temp)
6.42 self.discard_temp(temp)
6.43
6.44 - self.new_op(InvertBoolean())
6.45 + self.new_op(InvertBoolean(source="status", target="status"))
6.46 self._generateLoadBoolean(node)
6.47
6.48 def visitOr(self, node):
6.49 end_block = self.new_block()
6.50 temp_pos = self.reserve_temp()
6.51 - temp = LoadTemp(temp_pos)
6.52
6.53 for n in node.nodes[:-1]:
6.54 self.dispatch(n)
6.55 self.new_op(StoreTemp(temp_pos))
6.56
6.57 - self._generateTestBoolean(n, temp)
6.58 - self.new_op(JumpIfTrue(end_block))
6.59 + self._generateTestBoolean(n, LoadTemp(temp_pos))
6.60 + self.new_op(JumpIfTrue(end_block, working="status"))
6.61
6.62 self.dispatch(node.nodes[-1])
6.63 self.new_op(StoreTemp(temp_pos))
6.64
6.65 self.set_block(end_block)
6.66
6.67 + # Make a separate instruction to prevent previous temp accesses from
6.68 + # being altered by set_source.
6.69 +
6.70 + temp = LoadTemp(temp_pos)
6.71 self.new_op(temp)
6.72 self.discard_temp(temp)
6.73
6.74 @@ -296,7 +301,7 @@
6.75 self.new_op(temp1)
6.76 self.record_value()
6.77 self.new_op(temp2)
6.78 - self.new_op(TestIdentity())
6.79 + self.new_op(TestIdentity(target="status"))
6.80 self.set_source()
6.81 self.discard_value()
6.82
6.83 @@ -318,12 +323,12 @@
6.84 self.discard_temp(temp_result)
6.85
6.86 if op_name.find("not") != -1:
6.87 - self.new_op(InvertBoolean())
6.88 + self.new_op(InvertBoolean(source="status", target="status"))
6.89
6.90 # Test the result and jump to the end block if false.
6.91
6.92 if op is not last_op:
6.93 - self.new_op(JumpIfFalse(end_block))
6.94 + self.new_op(JumpIfFalse(end_block, working="status"))
6.95
6.96 # Compilation duties...
6.97
6.98 @@ -699,11 +704,11 @@
6.99 # Test for StopIteration.
6.100
6.101 self.load_builtin("StopIteration", node)
6.102 - self.new_op(CheckException())
6.103 + self.new_op(CheckException(target="status"))
6.104 if node.else_ is not None:
6.105 - self.new_op(JumpIfTrue(else_block))
6.106 + self.new_op(JumpIfTrue(else_block, working="status"))
6.107 else:
6.108 - self.new_op(JumpIfTrue(exit_block))
6.109 + self.new_op(JumpIfTrue(exit_block, working="status"))
6.110
6.111 # Re-raise the exception otherwise.
6.112
6.113 @@ -732,7 +737,7 @@
6.114
6.115 if node.else_ is not None:
6.116 self.set_block(else_block)
6.117 - self.new_op(ClearException())
6.118 + self.new_op(ClearException(target="exception"))
6.119 self.dispatch(node.else_)
6.120
6.121 # After the loop...
6.122 @@ -743,7 +748,7 @@
6.123 # After the loop...
6.124
6.125 self.set_block(exit_block)
6.126 - self.new_op(ClearException())
6.127 + self.new_op(ClearException(target="exception"))
6.128
6.129 # Compilation duties...
6.130
6.131 @@ -773,7 +778,7 @@
6.132 self._generateTestBoolean(node, temp)
6.133
6.134 next_block = self.new_block()
6.135 - self.new_op(JumpIfFalse(next_block))
6.136 + self.new_op(JumpIfFalse(next_block, working="status"))
6.137
6.138 self.dispatch(body)
6.139 first = 0
6.140 @@ -809,7 +814,7 @@
6.141
6.142 self.discard_temp(temp_arg)
6.143
6.144 - self.new_op(StoreException())
6.145 + self.set_target("exception")
6.146
6.147 self.new_op(RaiseException())
6.148
6.149 @@ -819,10 +824,14 @@
6.150 else:
6.151 self.dispatch(compiler.ast.Name("None"))
6.152
6.153 - self.new_op(LoadValueIntoResult())
6.154 + # NOTE: Cannot guarantee that all active instructions can be set.
6.155 + #self.set_target("result")
6.156 +
6.157 + self.new_op(Transfer(source="working", target="result"))
6.158 + self.new_op(Transfer(source="working_context", target="result_context"))
6.159
6.160 if self.in_exception_handler:
6.161 - self.new_op(ClearException())
6.162 + self.new_op(ClearException(target="exception"))
6.163
6.164 # NOTE: Support finally blocks here.
6.165
6.166 @@ -867,13 +876,13 @@
6.167 if name is not None:
6.168 self.dispatch(name)
6.169
6.170 - self.new_op(CheckException())
6.171 - self.new_op(JumpIfFalse(next_block))
6.172 + self.new_op(CheckException(target="status"))
6.173 + self.new_op(JumpIfFalse(next_block, working="status"))
6.174
6.175 # Handle assignment to exception variable.
6.176
6.177 if assignment is not None:
6.178 - self.new_op(LoadException())
6.179 + self.new_op(Transfer(source="working", target="exception"))
6.180
6.181 # Record the value to be assigned.
6.182
6.183 @@ -904,7 +913,7 @@
6.184 # Clear the exception.
6.185
6.186 self.set_block(exit_block)
6.187 - self.new_op(ClearException())
6.188 + self.new_op(ClearException(target="exception"))
6.189
6.190 def visitTryFinally(self, node):
6.191
6.192 @@ -930,9 +939,9 @@
6.193 self._generateTestBoolean(node, temp)
6.194
6.195 if node.else_ is not None:
6.196 - self.new_op(JumpIfFalse(else_block))
6.197 + self.new_op(JumpIfFalse(else_block, working="status"))
6.198 else:
6.199 - self.new_op(JumpIfFalse(exit_block))
6.200 + self.new_op(JumpIfFalse(exit_block, working="status"))
6.201
6.202 self.add_loop_blocks(next_block, exit_block)
6.203
7.1 --- a/micropython/code.py Sun Aug 07 23:01:35 2011 +0200
7.2 +++ b/micropython/code.py Sun Aug 21 14:24:28 2011 +0200
7.3 @@ -135,19 +135,41 @@
7.4
7.5 self.discard_temp(self.expr_temp.pop())
7.6
7.7 - def set_source(self):
7.8 + def set_source(self, expr=None):
7.9
7.10 """
7.11 - Set the source of an assignment using the current assignment value. This
7.12 - sets the source input for the current instruction.
7.13 + Set the source of an assignment using 'expr' or the current assignment
7.14 + value. This sets the source register of the current instruction.
7.15 """
7.16
7.17 - self.optimiser.set_source(self.expr_temp[-1])
7.18 + if expr is None:
7.19 + expr = self.expr_temp[-1]
7.20 +
7.21 + # Optimise away constant storage if appropriate.
7.22 +
7.23 + if self.optimiser.optimise_constant_storage(expr):
7.24 + self.remove_op()
7.25 + return
7.26 +
7.27 + # Otherwise, insert the assignment source.
7.28
7.29 - # Optimise away constant storage if appropriate.
7.30 + if expr is not None:
7.31 + expr = expr.copy()
7.32 + expr.target = "source"
7.33 + self.insert_op(-1, expr)
7.34 + self.last_op().source = "source"
7.35
7.36 - if self.optimiser.optimise_constant_storage():
7.37 - self.remove_op()
7.38 + def set_working(self, expr):
7.39 + if expr is not None:
7.40 + expr.target = "working"
7.41 + self.insert_op(-1, expr)
7.42 + self.last_op().source = "working"
7.43 +
7.44 + def set_target(self, target):
7.45 +
7.46 + "Reset the target of the active instruction to 'target'."
7.47 +
7.48 + self.optimiser.set_target(target)
7.49
7.50 def is_immediate_user(self, node):
7.51
7.52 @@ -253,7 +275,6 @@
7.53
7.54 # Optimise load operations employed by this instruction.
7.55
7.56 - self.optimiser.optimise_load_operations(op)
7.57 if self.optimiser.optimise_away_no_operations(op) or self.optimiser.optimise_unused_handlers(op):
7.58 return 0
7.59
7.60 @@ -263,6 +284,12 @@
7.61 self.optimiser.set_new(op)
7.62 return 1
7.63
7.64 + def insert_op(self, i, op):
7.65 +
7.66 + "Insert at index 'i' in the current block the instruction 'op'."
7.67 +
7.68 + self.blocks[-1].code.insert(i, op)
7.69 +
7.70 def remove_op(self):
7.71
7.72 "Remove the last instruction."
8.1 --- a/micropython/opt.py Sun Aug 07 23:01:35 2011 +0200
8.2 +++ b/micropython/opt.py Sun Aug 21 14:24:28 2011 +0200
8.3 @@ -3,7 +3,7 @@
8.4 """
8.5 Optimise code produced by the AST translator.
8.6
8.7 -Copyright (C) 2007, 2008, 2009, 2010 Paul Boddie <paul@boddie.org.uk>
8.8 +Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>
8.9
8.10 This program is free software; you can redistribute it and/or modify it under
8.11 the terms of the GNU General Public License as published by the Free Software
8.12 @@ -30,7 +30,7 @@
8.13 supported_optimisations = [
8.14 # Code generation optimisations:
8.15 "constant_storage", "constant_accessor", "known_target", "self_access",
8.16 - "temp_storage", "load_operations", "no_operations", "unused_results",
8.17 + "temp_storage", "no_operations", "unused_results",
8.18 "unused_handlers", "accesses_by_usage",
8.19 # Inspection optimisations:
8.20 "unused_objects"
8.21 @@ -93,7 +93,7 @@
8.22
8.23 "Set the value-providing active instruction."
8.24
8.25 - if isinstance(op, current_value_instructions):
8.26 + if isinstance(op, current_value_instructions) and op.target == "working":
8.27 self.active_value = op
8.28
8.29 def clear_active_value(self):
8.30 @@ -116,12 +116,12 @@
8.31 else:
8.32 return None
8.33
8.34 - def set_source(self, expr):
8.35 + def set_target(self, target):
8.36
8.37 - "Set the source of the active instruction to 'expr'."
8.38 + "Set the target of the active instruction to 'target'."
8.39
8.40 if self.active is not None:
8.41 - self.active.source = expr
8.42 + self.active.target = target
8.43
8.44 def set_active(self, op):
8.45
8.46 @@ -131,7 +131,7 @@
8.47
8.48 def clear_active(self):
8.49
8.50 - "Clear the active instruction."
8.51 + "Clear the active instructions."
8.52
8.53 self.active = None
8.54
8.55 @@ -152,9 +152,6 @@
8.56 def should_optimise_temp_storage(self):
8.57 return "temp_storage" in self.optimisations
8.58
8.59 - def should_optimise_load_operations(self):
8.60 - return "load_operations" in self.optimisations
8.61 -
8.62 def should_optimise_away_no_operations(self):
8.63 return "no_operations" in self.optimisations
8.64
8.65 @@ -196,19 +193,9 @@
8.66 """
8.67
8.68 return isinstance(instruction, (LoadConst, LoadClass, LoadFunction,
8.69 - LoadName, LoadTemp, LoadResultIntoValue, LoadException, LoadAddress
8.70 + LoadName, LoadTemp, LoadAddress
8.71 ))
8.72
8.73 - def is_simple_input_user(self, instruction):
8.74 -
8.75 - """
8.76 - Return whether 'instruction' can use simple input from the current
8.77 - value. Such instructions would, in a low-level implementation, be able
8.78 - to have the simple input registers as operands.
8.79 - """
8.80 -
8.81 - return isinstance(instruction, simple_input_user_instructions)
8.82 -
8.83 def is_resultant_no_operation(self, instruction):
8.84
8.85 """
8.86 @@ -217,17 +204,9 @@
8.87 """
8.88
8.89 return (
8.90 - isinstance(instruction.input, LoadTemp) and isinstance(instruction, StoreTemp) and
8.91 - instruction.input.attr == instruction.attr) or (
8.92 - isinstance(instruction.input, LoadResultIntoValue) and isinstance(instruction, LoadValueIntoResult)
8.93 + isinstance(instruction, StoreTemp) and instruction.target == instruction.source
8.94 )
8.95
8.96 - def is_input(self, instruction):
8.97 -
8.98 - "Return whether 'instruction' provides an input."
8.99 -
8.100 - return isinstance(instruction, current_value_instructions)
8.101 -
8.102 # Convenience tests on outputs.
8.103
8.104 def have_constant_target(self):
8.105 @@ -236,11 +215,11 @@
8.106
8.107 return self.is_constant_target(self.active)
8.108
8.109 - def have_constant_source(self):
8.110 + def have_constant_source(self, expr):
8.111
8.112 - "Return whether the active instruction has a constant source."
8.113 + "Return whether the active assignment source instruction is constant."
8.114
8.115 - return self.is_constant_input(self.active.source)
8.116 + return self.is_constant_input(expr)
8.117
8.118 # Convenience tests on inputs.
8.119
8.120 @@ -258,12 +237,6 @@
8.121
8.122 return self.is_simple_input(self.active_value)
8.123
8.124 - def have_input(self):
8.125 -
8.126 - "Return whether the active instruction provides an input."
8.127 -
8.128 - return self.is_input(self.active_value)
8.129 -
8.130 def have_self_input(self, unit):
8.131
8.132 """
8.133 @@ -282,12 +255,7 @@
8.134 to a temporary variable retaining the result of the last instruction.
8.135 """
8.136
8.137 - # LoadResultIntoValue cannot be relied upon in general since the result register
8.138 - # could be updated since first being referenced.
8.139 -
8.140 - return isinstance(self.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst, LoadClass, LoadFunction)) or \
8.141 - isinstance(self.active_value, LoadResultIntoValue) and self.active_value is self.active or \
8.142 - isinstance(self.active_value, LoadException) and self.active_value is self.active
8.143 + return isinstance(self.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst, LoadClass, LoadFunction))
8.144
8.145 def have_correct_self_for_target(self, context, unit):
8.146
8.147 @@ -312,7 +280,7 @@
8.148
8.149 # Optimisation methods. See the supported_optimisations class attribute.
8.150
8.151 - def optimise_constant_storage(self):
8.152 + def optimise_constant_storage(self, expr=None):
8.153
8.154 """
8.155 Where the last operation stores a constant into a target which is also
8.156 @@ -321,7 +289,7 @@
8.157
8.158 return self.should_optimise_constant_storage() and \
8.159 self.have_constant_target() and \
8.160 - self.have_constant_source()
8.161 + self.have_constant_source(expr)
8.162
8.163 def optimise_constant_accessor(self):
8.164
8.165 @@ -336,7 +304,7 @@
8.166 # Get the details of the access.
8.167
8.168 if isinstance(value.attr, Const):
8.169 - target_name = value.attr.value_type_name()
8.170 + return value.attr, value.attr.value_type_name()
8.171 else:
8.172 target = value.attr.get_value()
8.173
8.174 @@ -405,26 +373,14 @@
8.175 # Remove the active value contributor.
8.176
8.177 removed = self.remove_active_value()
8.178 -
8.179 - # Extend the lifetime of any temporary storage location.
8.180 + if removed is not None:
8.181
8.182 - self.translation.ensure_temp(removed)
8.183 - return removed
8.184 - else:
8.185 - return self.translation.get_temp()
8.186 -
8.187 - def optimise_load_operations(self, instruction):
8.188 + # Extend the lifetime of any temporary storage location.
8.189
8.190 - """
8.191 - Incorporate previous load operations into other operations.
8.192 - """
8.193 + self.translation.ensure_temp(removed)
8.194 + return removed
8.195
8.196 - if self.should_optimise_load_operations() and \
8.197 - self.have_simple_input() and \
8.198 - self.is_simple_input_user(instruction):
8.199 -
8.200 - self.remove_active_value()
8.201 - instruction.input = self.active_value
8.202 + return self.translation.get_temp()
8.203
8.204 def optimise_away_no_operations(self, instruction):
8.205
9.1 --- a/micropython/rsvp.py Sun Aug 07 23:01:35 2011 +0200
9.2 +++ b/micropython/rsvp.py Sun Aug 21 14:24:28 2011 +0200
9.3 @@ -297,30 +297,37 @@
9.4
9.5 "A generic instruction."
9.6
9.7 - def __init__(self, attr=None):
9.8 + # NOTE: Ultimately, instructions apart from Transfer will use specific
9.9 + # NOTE: registers such as "working_value" and "working_context".
9.10 +
9.11 + def __init__(self, attr=None, working="working", target="working", source=None):
9.12 self.attr = attr
9.13 - self.input = None
9.14 - self.source = None # for storage instructions
9.15 + self.working = working
9.16 + self.target = target
9.17 + self.source = source
9.18
9.19 def copy(self):
9.20 - return self.__class__(self.attr)
9.21 + return self.__class__(self.attr, self.working, self.target, self.source)
9.22
9.23 def __repr__(self):
9.24 - if self.attr is not None:
9.25 - return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_input())
9.26 - else:
9.27 - return "%s()%s" % (self.__class__.__name__, self.show_input())
9.28 + return "%s(%s%s%s%s)" % (self.__class__.__name__,
9.29 + self.format_operand(),
9.30 + self.format_working(),
9.31 + self.format_source(),
9.32 + self.format_target())
9.33
9.34 - def show_input(self):
9.35 - if self.input is not None:
9.36 - if self.source is not None:
9.37 - return " <- (%r, %r)" % (self.input, self.source)
9.38 - else:
9.39 - return " <- %r" % self.input
9.40 - elif self.source is not None:
9.41 - return " <-- %r" % self.source
9.42 - else:
9.43 - return ""
9.44 + def format_operand(self):
9.45 + operand = self.get_operand()
9.46 + return repr(operand)
9.47 +
9.48 + def format_working(self):
9.49 + return self.working != "working" and (", working=%r" % self.working) or ""
9.50 +
9.51 + def format_source(self):
9.52 + return self.source is not None and (", source=%r" % self.source) or ""
9.53 +
9.54 + def format_target(self):
9.55 + return self.target != "working" and (", target=%r" % self.target) or ""
9.56
9.57 def get_operand(self):
9.58 return None
9.59 @@ -329,9 +336,6 @@
9.60
9.61 "An instruction operating on the current frame."
9.62
9.63 - def __repr__(self):
9.64 - return "%s(%r)%s" % (self.__class__.__name__, self.get_operand(), self.show_input())
9.65 -
9.66 def get_operand(self):
9.67 return self.attr.position
9.68
9.69 @@ -341,12 +345,8 @@
9.70
9.71 "An instruction accessing an object's attribute."
9.72
9.73 - def __repr__(self):
9.74 - position = self.get_operand()
9.75 - if position is not None:
9.76 - return "%s(%r)%s # %s" % (self.__class__.__name__, position, self.show_input(), name(self.attr))
9.77 - else:
9.78 - return "%s(%r)%s" % (self.__class__.__name__, name(self.attr), self.show_input())
9.79 + def format_operand(self):
9.80 + return "%s, name=%r" % (Instruction.format_operand(self), name(self.attr))
9.81
9.82 def get_operand(self):
9.83 return self.attr.position
9.84 @@ -357,17 +357,15 @@
9.85
9.86 "An instruction loading an address directly."
9.87
9.88 - def __repr__(self):
9.89 + def format_operand(self):
9.90 location, position, result = self.get_operands()
9.91 if location is not None:
9.92 - return "%s(%r)%s # %r, %r (%s)" % (
9.93 - self.__class__.__name__, result, self.show_input(), location, position, name(self.attr))
9.94 + return "%s, location=%s, position=%s, name=%s" % (
9.95 + result, location, position, name(self.attr))
9.96 elif result is not None:
9.97 - return "%s(%r)%s # %s" % (
9.98 - self.__class__.__name__, result, self.show_input(), name(self.attr))
9.99 + return "%s, name=%s" % (result, name(self.attr))
9.100 else:
9.101 - return "%s(...)%s # %s" % (
9.102 - self.__class__.__name__, self.show_input(), name(self.attr))
9.103 + return "name=%s" % name(self.attr)
9.104
9.105 def get_operands(self):
9.106 if isinstance(self.attr, Attr):
9.107 @@ -395,8 +393,8 @@
9.108
9.109 "An instruction loading the address of an invocation target."
9.110
9.111 - def __repr__(self):
9.112 - return "%s(%r) # %r" % (self.__class__.__name__, self.get_operand(), name(self.attr))
9.113 + def format_operand(self):
9.114 + return "%s, name=%r" % (Instruction.format_operand(self), name(self.attr))
9.115
9.116 def get_operand(self):
9.117 return self.attr.code_body_location
9.118 @@ -407,14 +405,17 @@
9.119
9.120 "An instruction employing a constant."
9.121
9.122 - def __repr__(self):
9.123 - return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_input())
9.124 -
9.125 def get_operand(self):
9.126 return self.attr
9.127
9.128 Immediate = ImmediateInstruction
9.129
9.130 +# Low-level instructions.
9.131 +
9.132 +class Transfer(Instruction):
9.133 + "Transfer a register's contents into another."
9.134 + cost = 1
9.135 +
9.136 # Access to stored constant data.
9.137
9.138 class LoadConst(Address):
9.139 @@ -537,10 +538,6 @@
9.140 "Store the source value as an argument of the current value for the parameter with the given index."
9.141 cost = 6
9.142
9.143 -class LoadContextIntoValue(Instruction):
9.144 - "Load the context of an invocation."
9.145 - cost = 2
9.146 -
9.147 # Context-related tests.
9.148
9.149 class CheckContext(Instruction):
9.150 @@ -558,10 +555,6 @@
9.151 """
9.152 cost = 6
9.153
9.154 -class CheckType(Instruction):
9.155 - "Check the current value as an instance of a specific class only."
9.156 - cost = 5
9.157 -
9.158 # Access to frames upon invocation.
9.159
9.160 class CheckFrame(Immediate):
9.161 @@ -602,14 +595,6 @@
9.162 "Return from a subprogram."
9.163 cost = 2
9.164
9.165 -class LoadResultIntoValue(Instruction):
9.166 - "Load into the current value a returned value."
9.167 - cost = 1
9.168 -
9.169 -class LoadValueIntoResult(Instruction):
9.170 - "Store the current value as a value to be returned."
9.171 - cost = 1
9.172 -
9.173 # Branch-related instructions.
9.174
9.175 class Jump(Address):
9.176 @@ -626,18 +611,6 @@
9.177
9.178 # Exception-related instructions, using a special exception "register".
9.179
9.180 -class LoadException(Instruction):
9.181 - "Load the raised exception."
9.182 - cost = 1
9.183 -
9.184 -class StoreException(Instruction):
9.185 - "Store the current object in the exception register."
9.186 - cost = 1
9.187 -
9.188 -class ClearException(Instruction):
9.189 - "Reset the exception register."
9.190 - cost = 1
9.191 -
9.192 class RaiseException(Instruction):
9.193 "Raise an exception, jumping to the active handler."
9.194 cost = 2
9.195 @@ -654,6 +627,10 @@
9.196 "Check the raised exception against another."
9.197 cost = 6
9.198
9.199 +class ClearException(Instruction):
9.200 + "Clear any raised exception."
9.201 + cost = 1
9.202 +
9.203 # Test instructions, operating on the boolean status register.
9.204
9.205 class TestIdentity(Instruction):
9.206 @@ -668,32 +645,18 @@
9.207 "Invert the boolean status."
9.208 cost = 1
9.209
9.210 -# Instructions which affect the current value. (LoadAttrIndexContext not defined.)
9.211 +# Instructions which can affect the current value. (LoadAttrIndexContext not defined.)
9.212
9.213 current_value_instructions = (
9.214 - LoadConst, LoadClass, LoadFunction, LoadName, LoadTemp,
9.215 + Transfer,
9.216 + LoadConst, LoadClass, LoadFunction,
9.217 + LoadName, LoadTemp,
9.218 LoadAddress, LoadAddressContext, LoadAddressContextCond,
9.219 LoadAttr, LoadAttrIndex, LoadAttrIndexContextCond,
9.220 - LoadCallable, LoadContextIntoValue, LoadResultIntoValue,
9.221 - LoadException, MakeInstance, MakeFragment,
9.222 - CopyExtra
9.223 - )
9.224 -
9.225 -# Instructions which use the current value. (LoadAttrIndexContext not defined.)
9.226 -
9.227 -simple_input_user_instructions = (
9.228 - StoreTemp, StoreFrame, LoadValueIntoResult, StoreException, # as the value being stored
9.229 - LoadAddressContext, LoadAddressContextCond, # as the object being referenced
9.230 - LoadAttr, LoadAttrIndex, LoadAttrIndexContextCond, # as the object being referenced
9.231 - StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced
9.232 - StoreFrameIndex, # as the object being referenced
9.233 - StoreAddressContext, # as the context
9.234 LoadCallable,
9.235 - TestIdentity, TestIdentityAddress, CheckInstance, # as one of the operands
9.236 - CheckException, CheckFrame, FillDefaults,
9.237 - MakeInstance,
9.238 - CheckContext, CheckClass, CheckType,
9.239 - LoadContextIntoValue # as the object providing the result
9.240 + MakeInstance, MakeFragment,
9.241 + CopyExtra,
9.242 + CheckClass, CheckContext, CheckException, CheckInstance, CheckFrame, CheckExtra
9.243 )
9.244
9.245 # vim: tabstop=4 expandtab shiftwidth=4
10.1 --- a/micropython/trans.py Sun Aug 07 23:01:35 2011 +0200
10.2 +++ b/micropython/trans.py Sun Aug 21 14:24:28 2011 +0200
10.3 @@ -130,8 +130,7 @@
10.4
10.5 after_test_block = self.new_block()
10.6
10.7 - self.new_op(LoadClass(obj))
10.8 - temp_target = self.optimiser.optimise_temp_storage()
10.9 + self.new_op(LoadClass(obj, target="source"))
10.10
10.11 # For only static attributes, classes are acceptable.
10.12
10.13 @@ -140,12 +139,11 @@
10.14 # Generate name is target (for classes).
10.15
10.16 self.dispatch(compiler.ast.Name(name))
10.17 - self.new_op(TestIdentity())
10.18 - self.optimiser.set_source(temp_target)
10.19 + self.new_op(TestIdentity(source="source", target="status"))
10.20
10.21 # Jump to the next guard or the code if successful.
10.22
10.23 - self.new_op(JumpIfTrue(after_test_block))
10.24 + self.new_op(JumpIfTrue(after_test_block, working="status"))
10.25
10.26 # Where instance attributes are involved, only instances are
10.27 # acceptable.
10.28 @@ -153,17 +151,16 @@
10.29 # Generate isinstance(name, target).
10.30
10.31 self.dispatch(compiler.ast.Name(name))
10.32 - self.new_op(CheckInstance())
10.33 - self.optimiser.set_source(temp_target)
10.34 + self.new_op(CheckInstance(source="source", target="status"))
10.35
10.36 # Jump to the next guard or the code if successful.
10.37
10.38 - self.new_op(JumpIfTrue(after_test_block))
10.39 + self.new_op(JumpIfTrue(after_test_block, working="status"))
10.40
10.41 # Where the type is inappropriate, raise an exception.
10.42
10.43 self.make_exception("TypeError")
10.44 - self.new_op(StoreException())
10.45 + self.set_target("exception")
10.46 self.new_op(RaiseException())
10.47
10.48 self.set_block(after_test_block)
10.49 @@ -341,20 +338,20 @@
10.50
10.51 # Remember the accessor.
10.52
10.53 - temp_accessor = self.optimiser.optimise_temp_storage()
10.54 + temp_accessor = self.get_temp()
10.55
10.56 attr_block = self.new_block()
10.57 end_block = self.new_block()
10.58
10.59 - self.new_op(CheckClass())
10.60 - self.new_op(JumpIfFalse(attr_block))
10.61 + self.new_op(CheckClass(target="status"))
10.62 + self.new_op(JumpIfFalse(attr_block, working="status"))
10.63 self.load_builtin("type", node)
10.64 self.new_op(Jump(end_block))
10.65 self.set_block(attr_block)
10.66
10.67 # Recall the accessor.
10.68
10.69 - self.new_op(temp_accessor)
10.70 + self.new_op(temp_accessor.copy())
10.71
10.72 # Otherwise, perform a normal operation.
10.73
10.74 @@ -383,6 +380,7 @@
10.75
10.76 if attrname == "__class__":
10.77 self.set_block(end_block)
10.78 + self.discard_temp(temp_accessor)
10.79
10.80 # Invocations involve the following:
10.81 #
10.82 @@ -451,7 +449,7 @@
10.83
10.84 if target is None or isinstance(context, Instance):
10.85 self.new_op(temp_target)
10.86 - self.new_op(LoadContextIntoValue())
10.87 + self.new_op(Transfer(source="working_context", target="working"))
10.88 temp_context = self.optimiser.optimise_temp_storage()
10.89 self.new_op(StoreFrame(0))
10.90
10.91 @@ -461,7 +459,7 @@
10.92
10.93 elif isinstance(context, Class):
10.94 self.new_op(temp_target)
10.95 - self.new_op(LoadContextIntoValue())
10.96 + self.new_op(Transfer(source="working_context", target="working"))
10.97 temp_context = self.optimiser.optimise_temp_storage()
10.98
10.99 # Otherwise omit the context.
10.100 @@ -759,17 +757,18 @@
10.101 # Adjust the frame if a replaceable context is provided.
10.102
10.103 self.new_op(temp_context)
10.104 - self.new_op(CheckContext())
10.105 - self.new_op(JumpIfFalse(adjust_block))
10.106 + self.new_op(CheckContext(target="status"))
10.107 + self.new_op(JumpIfFalse(adjust_block, working="status"))
10.108
10.109 # Skip adjustment and tests if the context is not a class.
10.110 # Classes themselves employ a placeholder context so that
10.111 # instantiators can be callable with a context which will be
10.112 # overwritten in the frame.
10.113
10.114 - self.new_op(temp_context)
10.115 - self.new_op(CheckClass())
10.116 - self.new_op(JumpIfFalse(continue_block))
10.117 + # Here, the working value should still refer to the context.
10.118 +
10.119 + self.new_op(CheckClass(target="status"))
10.120 + self.new_op(JumpIfFalse(continue_block, working="status"))
10.121
10.122 if temp_first_argument is not None:
10.123 self.new_op(temp_first_argument)
10.124 @@ -777,19 +776,20 @@
10.125 # Check the current value (the argument) against the known context
10.126 # (given as the source).
10.127
10.128 - self.new_op(CheckInstance())
10.129 - self.optimiser.set_source(temp_context)
10.130 + self.new_op(CheckInstance(target="status"))
10.131 + self.set_working(temp_context)
10.132
10.133 - self.new_op(JumpIfTrue(adjust_block))
10.134 + self.new_op(JumpIfTrue(adjust_block, working="status"))
10.135
10.136 # Where the context is inappropriate, drop the incomplete frame and
10.137 # raise an exception.
10.138
10.139 self.new_op(DropFrame())
10.140 - self.new_op(LoadResultIntoValue())
10.141 + self.new_op(Transfer(source="result", target="working"))
10.142 + self.new_op(Transfer(source="result_context", target="working_context"))
10.143
10.144 self.make_exception("TypeError")
10.145 - self.new_op(StoreException())
10.146 + self.set_target("exception")
10.147 self.new_op(RaiseException())
10.148
10.149 if target is None or temp_first_argument is not None:
10.150 @@ -806,7 +806,7 @@
10.151 # obtained via the class.
10.152
10.153 if isinstance(target, (Class, Function)):
10.154 - self.new_op(JumpWithFrameDirect(target))
10.155 + self.new_op(JumpWithFrameDirect(target, working="status"))
10.156 else:
10.157 self.new_op(temp_target)
10.158 self.new_op(LoadCallable())
10.159 @@ -825,7 +825,8 @@
10.160
10.161 self.new_op(DropFrame())
10.162 if load_result:
10.163 - self.new_op(LoadResultIntoValue())
10.164 + self.new_op(Transfer(source="result", target="working"))
10.165 + self.new_op(Transfer(source="result_context", target="working_context"))
10.166
10.167 # Discard any temporary storage instructions.
10.168
10.169 @@ -851,9 +852,9 @@
10.170
10.171 if temp is not None:
10.172 self.new_op(LoadConst(fn))
10.173 - self.new_op(LoadCallable())
10.174 + self.new_op(LoadCallable(target="source"))
10.175 self.new_op(temp)
10.176 - self.new_op(StoreCallable())
10.177 + self.new_op(StoreCallable(source="source"))
10.178
10.179 self.new_op(temp)
10.180 #self.discard_temp(temp)
10.181 @@ -878,7 +879,7 @@
10.182
10.183 # Check the number of parameters and defaults.
10.184
10.185 - self.new_op(CheckFrame((nparams, ndefaults)))
10.186 + self.new_op(CheckFrame((nparams, ndefaults), target="status"))
10.187
10.188 if ndefaults > 0:
10.189 if fn.is_dynamic():
10.190 @@ -900,7 +901,7 @@
10.191
10.192 # Ensure that the star parameter has a slot in the frame.
10.193
10.194 - self.new_op(CheckExtra(nparams))
10.195 + self.new_op(CheckExtra(nparams, target="status"))
10.196 self.new_op(StoreTemp(nparams))
10.197
10.198 # Extend the frame for local usage.
10.199 @@ -930,7 +931,12 @@
10.200 if not fn.is_lambda():
10.201 self.dispatch(compiler.ast.Name("None"))
10.202
10.203 - self.new_op(LoadValueIntoResult())
10.204 + # NOTE: Cannot guarantee that all active instructions can be set.
10.205 + #self.set_target("result")
10.206 +
10.207 + self.new_op(Transfer(source="working", target="result"))
10.208 + self.new_op(Transfer(source="working_context", target="result_context"))
10.209 +
10.210 self.new_op(Return())
10.211
10.212 # Make sure that enough frame space is reserved from the start.
10.213 @@ -1016,7 +1022,7 @@
10.214 self.discard_value()
10.215
10.216 if dynamic:
10.217 - return temp
10.218 + return temp.copy()
10.219 else:
10.220 return None
10.221
10.222 @@ -1199,8 +1205,8 @@
10.223
10.224 if not (self.optimiser.should_optimise_known_target() and self.optimiser.is_constant_input(temp_method)):
10.225 self.load_builtin("AttributeError", node)
10.226 - self.new_op(CheckException())
10.227 - self.new_op(JumpIfTrue(handled_block))
10.228 + self.new_op(CheckException(target="status"))
10.229 + self.new_op(JumpIfTrue(handled_block, working="status"))
10.230 self.new_op(RaiseException())
10.231
10.232 def _generateTuple(self, node):
10.233 @@ -1216,7 +1222,7 @@
10.234
10.235 self._populateSequence(temp, node)
10.236
10.237 - self.new_op(temp)
10.238 + self.new_op(temp.copy())
10.239 self.discard_temp(temp)
10.240
10.241 def _generateList(self, node):
10.242 @@ -1240,7 +1246,7 @@
10.243 self.set_source()
10.244 self.discard_value()
10.245
10.246 - self.new_op(list_temp)
10.247 + self.new_op(list_temp.copy())
10.248 self.discard_temp(temp)
10.249 self.discard_temp(list_temp)
10.250
10.251 @@ -1286,7 +1292,7 @@
10.252
10.253 # Convert result to boolean (a StoreBoolean operation).
10.254
10.255 - self.new_op(TestIdentityAddress(self.importer.get_predefined_constant("True")))
10.256 + self.new_op(TestIdentityAddress(self.importer.get_predefined_constant("True"), target="status"))
10.257
10.258 def _generateLoadBoolean(self, node):
10.259
10.260 @@ -1298,7 +1304,7 @@
10.261 true_block = self.new_block()
10.262 end_block = self.new_block()
10.263
10.264 - self.new_op(JumpIfTrue(true_block))
10.265 + self.new_op(JumpIfTrue(true_block, working="status"))
10.266 self.new_op(LoadConst(self.importer.get_predefined_constant("False")))
10.267 self.new_op(Jump(end_block))
10.268
11.1 --- a/rsvp.py Sun Aug 07 23:01:35 2011 +0200
11.2 +++ b/rsvp.py Sun Aug 21 14:24:28 2011 +0200
11.3 @@ -44,12 +44,11 @@
11.4
11.5 * Exception handler PC stack refers to the state of the PC stack
11.6
11.7 - * Registers: current context/value,
11.8 - source context/value,
11.9 + * Registers: working context/value,
11.10 + assignment source context/value,
11.11 current result context/value,
11.12 current exception value,
11.13 - boolean status value,
11.14 - current callable
11.15 + boolean status value
11.16 """
11.17
11.18 from micropython.program import DataValue, ReplaceableContext, PlaceholderContext, FragmentObject
11.19 @@ -121,22 +120,26 @@
11.20
11.21 # Registers.
11.22
11.23 - self.value = None
11.24 - self.context = None
11.25 + self.register_names = (
11.26 + "working",
11.27 + "working_context",
11.28 + "source",
11.29 + "source_context",
11.30 + "result",
11.31 + "result_context",
11.32 + "exception",
11.33 + "status"
11.34 + )
11.35 + self.registers = {}
11.36
11.37 - self.source_value = None
11.38 - self.source_context = None
11.39 -
11.40 - self.result_value = None
11.41 - self.result_context = None
11.42 -
11.43 - self.exception = None
11.44 + for name in self.register_names:
11.45 + self.registers[name] = None
11.46
11.47 self.instruction = None
11.48 - self.status = None
11.49 - self.callable = None
11.50
11.51 # Constants.
11.52 + # NOTE: These should eventually be removed once the code using them has
11.53 + # NOTE: been migrated to the native code library.
11.54
11.55 cls = self._get_class("__builtins__", "AttributeError")
11.56 self.attr_error = cls.location
11.57 @@ -179,20 +182,12 @@
11.58 print "Handler frame stack", self.handler_local_sp_stack
11.59 print "Handler PC stack", self.handler_pc_stack
11.60 print
11.61 - print "Value", self.value
11.62 - print "Context", self.context
11.63 + print "Registers:"
11.64 print
11.65 - print "Source value", self.source_value
11.66 - print "Source context", self.source_context
11.67 - print
11.68 - print "Result value", self.result_value
11.69 - print "Result context", self.result_context
11.70 - print
11.71 - print "Exception", self.exception
11.72 + for name in self.register_names:
11.73 + print "%s: %s" % (name, self.registers[name])
11.74 print
11.75 print "Instruction", self.instruction
11.76 - print "Status", self.status
11.77 - print "Callable", self.callable
11.78
11.79 def show(self, start=None, end=None):
11.80 self.show_memory(self.memory[start:end], self.coverage[start:end], start or 0)
11.81 @@ -294,14 +289,14 @@
11.82 breakpoint = 1
11.83
11.84 print "Execution terminated",
11.85 - if self.exception is not None:
11.86 - ref = self.exception
11.87 + if breakpoint:
11.88 + print "with breakpoint."
11.89 + print "At address", self.pc
11.90 + elif self.registers["exception"] is not None:
11.91 + ref = self.registers["exception"]
11.92 addr = self.load(ref + Library.instance_data_offset)
11.93 print "with exception:", self.load(ref)
11.94 print "At address %d: %r" % (addr, self.load(addr))
11.95 - elif breakpoint:
11.96 - print "with breakpoint."
11.97 - print "At address", self.pc
11.98 else:
11.99 print "successfully."
11.100 print "After", self.counter, "instructions at cost", self.cost, "units."
11.101 @@ -316,15 +311,15 @@
11.102 self.run()
11.103 success = 1
11.104
11.105 - if self.exception is None:
11.106 + if self.registers["exception"] is None:
11.107 for name in module.keys():
11.108 if name.startswith("result"):
11.109 label, expected = name.split("_")
11.110 attr = module[name]
11.111
11.112 - # NOTE: Assumptions about headers and content made.
11.113 + # Need to skip the header to get at the members.
11.114
11.115 - attr_location = module.location + 1 + attr.position
11.116 + attr_location = module.location + Library.instance_data_offset + attr.position
11.117 value = self.load(attr_location)
11.118
11.119 if value is not None:
11.120 @@ -349,10 +344,6 @@
11.121
11.122 self.instruction = self.load(self.pc)
11.123
11.124 - # Process any inputs of the instruction.
11.125 -
11.126 - self.process_inputs()
11.127 -
11.128 # Perform the instruction itself.
11.129
11.130 next_pc = self.perform(self.instruction)
11.131 @@ -380,32 +371,15 @@
11.132 raise IllegalInstruction, (self.pc, instruction_name)
11.133 return method
11.134
11.135 - def perform(self, instruction, is_input=0):
11.136 + def perform(self, instruction):
11.137
11.138 "Perform the 'instruction', returning the next PC value or None."
11.139
11.140 - if not is_input:
11.141 - self.counter += 1
11.142 - self.cost += instruction.cost
11.143 + self.counter += 1
11.144 + self.cost += instruction.cost
11.145 operand = instruction.get_operand()
11.146 method = self.get_method(instruction)
11.147 - return method(operand)
11.148 -
11.149 - def process_inputs(self):
11.150 -
11.151 - """
11.152 - Process any inputs of the current instruction. This permits any directly
11.153 - connected sub-instructions to produce the effects that separate
11.154 - instructions would otherwise have.
11.155 - """
11.156 -
11.157 - value, context = self.value, self.context
11.158 - if self.instruction.source is not None:
11.159 - self.perform(self.instruction.source, 1)
11.160 - self.source_value, self.source_context = self.value, self.context
11.161 - self.value, self.context = value, context
11.162 - if self.instruction.input is not None:
11.163 - self.perform(self.instruction.input, 1)
11.164 + return method(operand, instruction)
11.165
11.166 def jump(self, addr, next):
11.167
11.168 @@ -428,104 +402,123 @@
11.169 self.push_pc(self.pc + 1)
11.170 return addr
11.171
11.172 + # Helper methods.
11.173 +
11.174 + def context_of(self, register):
11.175 + return "%s_context" % register
11.176 +
11.177 + def load_from_frame(self, operand):
11.178 + frame = self.local_sp_stack[-1]
11.179 + return self.frame_stack[frame + operand]
11.180 +
11.181 # Low-level instructions.
11.182
11.183 - def LoadValue(self, operand):
11.184 - self.value = operand
11.185 -
11.186 - def LoadContext(self, operand):
11.187 - self.context = operand
11.188 + def LoadImmediate(self, operand, target):
11.189 + self.registers[target] = operand
11.190
11.191 - def LoadSourceValue(self, operand):
11.192 - self.source_value = operand
11.193 -
11.194 - def LoadSourceContext(self, operand):
11.195 - self.source_context = operand
11.196 + def LoadMemory(self, operand, target, source):
11.197 + self.registers[target] = self.load(
11.198 + self.registers[source] + (operand is not None and operand or 0)
11.199 + )
11.200
11.201 # Instructions.
11.202
11.203 - def LoadConst(self, operand):
11.204 - self.LoadContext(operand)
11.205 - self.LoadValue(operand)
11.206 + def Transfer(self, operand, instruction):
11.207 + self.registers[instruction.target] = self.registers[instruction.source]
11.208
11.209 - def LoadClass(self, operand):
11.210 - self.LoadContext(PlaceholderContext)
11.211 - self.LoadValue(operand)
11.212 + def LoadConst(self, operand, instruction):
11.213 + self.LoadImmediate(operand, self.context_of(instruction.target))
11.214 + self.LoadImmediate(operand, instruction.target)
11.215 +
11.216 + def LoadClass(self, operand, instruction):
11.217 + self.LoadImmediate(PlaceholderContext, self.context_of(instruction.target))
11.218 + self.LoadImmediate(operand, instruction.target)
11.219
11.220 - def LoadFunction(self, operand):
11.221 - self.LoadContext(ReplaceableContext)
11.222 - self.LoadValue(operand)
11.223 + def LoadFunction(self, operand, instruction):
11.224 + self.LoadImmediate(ReplaceableContext, self.context_of(instruction.target))
11.225 + self.LoadImmediate(operand, instruction.target)
11.226
11.227 - def LoadName(self, operand):
11.228 + def LoadName(self, operand, instruction):
11.229 + data = self.load_from_frame(operand)
11.230 + self.LoadImmediate(data.context, self.context_of(instruction.target))
11.231 + self.LoadImmediate(data.ref, instruction.target)
11.232 +
11.233 + def StoreName(self, operand, instruction):
11.234 frame = self.local_sp_stack[-1]
11.235 - data = self.frame_stack[frame + operand]
11.236 - self.LoadContext(data.context)
11.237 - self.LoadValue(data.ref)
11.238 -
11.239 - def StoreName(self, operand):
11.240 - frame = self.local_sp_stack[-1]
11.241 - self.frame_stack[frame + operand] = DataValue(self.source_context, self.source_value)
11.242 + self.frame_stack[frame + operand] = DataValue(
11.243 + self.registers[self.context_of(instruction.source)],
11.244 + self.registers[instruction.source])
11.245
11.246 LoadTemp = LoadName
11.247
11.248 - def StoreTemp(self, operand):
11.249 + def StoreTemp(self, operand, instruction):
11.250 frame = self.local_sp_stack[-1]
11.251 - self.frame_stack[frame + operand] = DataValue(self.context, self.value)
11.252 + self.frame_stack[frame + operand] = DataValue(
11.253 + self.registers[self.context_of(instruction.working)],
11.254 + self.registers[instruction.working])
11.255
11.256 - def LoadAddress(self, operand):
11.257 + def LoadAddress(self, operand, instruction):
11.258 # Preserve context (potentially null).
11.259 data = self.load(operand)
11.260 - self.LoadContext(data.context)
11.261 - self.LoadValue(data.ref)
11.262 + self.LoadImmediate(data.context, self.context_of(instruction.target))
11.263 + self.LoadImmediate(data.ref, instruction.target)
11.264
11.265 - def LoadAddressContext(self, operand):
11.266 + def LoadAddressContext(self, operand, instruction):
11.267 # Value becomes context.
11.268 data = self.load(operand)
11.269 - self.LoadContext(self.value)
11.270 - self.LoadValue(data.ref)
11.271 + self.LoadImmediate(self.registers[instruction.working], self.context_of(instruction.target))
11.272 + self.LoadImmediate(data.ref, instruction.target)
11.273
11.274 - def LoadAddressContextCond(self, operand):
11.275 + def LoadAddressContextCond(self, operand, instruction):
11.276 data = self.load(operand)
11.277 - data = self._LoadAddressContextCond(data.context, data.ref, self.value)
11.278 - self.LoadContext(data.context)
11.279 - self.LoadValue(data.ref)
11.280 + data = self._LoadAddressContextCond(data.context, data.ref, self.registers[instruction.working])
11.281 + self.LoadImmediate(data.context, self.context_of(instruction.target))
11.282 + self.LoadImmediate(data.ref, instruction.target)
11.283
11.284 - def StoreAddress(self, operand):
11.285 + def StoreAddress(self, operand, instruction):
11.286 # Preserve context.
11.287 - self.save(operand, DataValue(self.source_context, self.source_value))
11.288 + self.save(operand, DataValue(
11.289 + self.registers[self.context_of(instruction.source)],
11.290 + self.registers[instruction.source]))
11.291
11.292 - def StoreAddressContext(self, operand):
11.293 + def StoreAddressContext(self, operand, instruction):
11.294 # Overwrite context if null.
11.295 - self._StoreAddressContext(operand, self.context, self.value, self.source_context, self.source_value)
11.296 + self._StoreAddressContext(operand,
11.297 + self.registers[self.context_of(instruction.working)],
11.298 + self.registers[instruction.working],
11.299 + self.registers[self.context_of(instruction.source)],
11.300 + self.registers[instruction.source])
11.301
11.302 - def MakeInstance(self, size):
11.303 + def MakeInstance(self, size, instruction):
11.304 # NOTE: Referencing the instance template.
11.305 - addr = self._MakeObject(size, self.value - Library.instance_template_size)
11.306 + addr = self._MakeObject(size, self.registers[instruction.working] - Library.instance_template_size)
11.307 # Introduce object as context for the new object.
11.308 - self.LoadContext(addr)
11.309 - self.LoadValue(addr)
11.310 + self.LoadImmediate(addr, self.context_of(instruction.target))
11.311 + self.LoadImmediate(addr, instruction.target)
11.312
11.313 - def MakeFragment(self, size):
11.314 + def MakeFragment(self, size, instruction):
11.315 # Reserve twice the amount of space.
11.316 addr = self._MakeFragment(size, size * 2)
11.317 # NOTE: Context is not relevant for fragments.
11.318 - self.LoadContext(None)
11.319 - self.LoadValue(addr)
11.320 + self.LoadImmediate(None, self.context_of(instruction.target))
11.321 + self.LoadImmediate(addr, instruction.target)
11.322
11.323 - def LoadAttr(self, pos):
11.324 + def LoadAttr(self, pos, instruction):
11.325 # Retrieved context should already be appropriate for the instance.
11.326 - # NOTE: Adding 1 to skip any header.
11.327 - data = self.load(self.value + pos + 1)
11.328 - self.LoadContext(data.context)
11.329 - self.LoadValue(data.ref)
11.330 + # Skip any header.
11.331 + data = self.load(self.registers[instruction.working] + Library.instance_data_offset + pos)
11.332 + self.LoadImmediate(data.context, self.context_of(instruction.target))
11.333 + self.LoadImmediate(data.ref, instruction.target)
11.334
11.335 - def StoreAttr(self, pos):
11.336 + def StoreAttr(self, pos, instruction):
11.337 # Target should already be an instance.
11.338 - # NOTE: Adding 1 to skip any header.
11.339 - self.save(self.value + pos + 1, DataValue(self.source_context, self.source_value))
11.340 + # Skip any header.
11.341 + self.save(self.registers[instruction.working] + Library.instance_data_offset + pos , DataValue(
11.342 + self.registers[self.context_of(instruction.source)],
11.343 + self.registers[instruction.source]))
11.344
11.345 - def LoadAttrIndex(self, index):
11.346 - data = self.load(self.value)
11.347 + def LoadAttrIndex(self, index, instruction):
11.348 + data = self.load(self.registers[instruction.working])
11.349 element = self.objlist[data.classcode + index]
11.350
11.351 if element is not None:
11.352 @@ -534,18 +527,18 @@
11.353 if static_attr:
11.354 data = self.load(offset) # offset is address of class/module attribute
11.355 else:
11.356 - data = self.load(self.value + offset)
11.357 - self.LoadContext(data.context)
11.358 - self.LoadValue(data.ref)
11.359 + data = self.load(self.registers[instruction.working] + offset)
11.360 + self.LoadImmediate(data.context, self.context_of(instruction.target))
11.361 + self.LoadImmediate(data.ref, instruction.target)
11.362 return
11.363
11.364 - self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance)
11.365 + self.registers["exception"] = self._MakeObject(Library.instance_size, self.attr_error_instance)
11.366 return self.RaiseException()
11.367
11.368 # LoadAttrIndexContext not defined.
11.369
11.370 - def LoadAttrIndexContextCond(self, index):
11.371 - data = self.load(self.value)
11.372 + def LoadAttrIndexContextCond(self, index, instruction):
11.373 + data = self.load(self.registers[instruction.working])
11.374 element = self.objlist[data.classcode + index]
11.375
11.376 if element is not None:
11.377 @@ -555,95 +548,102 @@
11.378 loaded_data = self.load(offset) # offset is address of class/module attribute
11.379 # Absent attrcode == class/module.
11.380 if data.attrcode is not None:
11.381 - loaded_data = self._LoadAddressContextCond(loaded_data.context, loaded_data.ref, self.value)
11.382 + loaded_data = self._LoadAddressContextCond(
11.383 + loaded_data.context, loaded_data.ref,
11.384 + self.registers[instruction.working])
11.385 else:
11.386 - loaded_data = self.load(self.value + offset)
11.387 - self.LoadContext(loaded_data.context)
11.388 - self.LoadValue(loaded_data.ref)
11.389 + loaded_data = self.load(self.registers[instruction.working] + offset)
11.390 + self.LoadImmediate(loaded_data.context, self.context_of(instruction.target))
11.391 + self.LoadImmediate(loaded_data.ref, instruction.target)
11.392 return
11.393
11.394 - self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance)
11.395 + self.registers["exception"] = self._MakeObject(Library.instance_size, self.attr_error_instance)
11.396 return self.RaiseException()
11.397
11.398 - def StoreAttrIndex(self, index):
11.399 - data = self.load(self.value)
11.400 + def StoreAttrIndex(self, index, instruction):
11.401 + data = self.load(self.registers[instruction.working])
11.402 element = self.objlist[data.classcode + index]
11.403
11.404 if element is not None:
11.405 attr_index, static_attr, offset = element
11.406 if attr_index == index:
11.407 if static_attr:
11.408 - self._StoreAddressContext(offset, self.context, self.value, self.source_context, self.source_value)
11.409 + self._StoreAddressContext(offset,
11.410 + self.registers[self.context_of(instruction.working)],
11.411 + self.registers[instruction.working],
11.412 + self.registers[self.context_of(instruction.source)],
11.413 + self.registers[instruction.source])
11.414 return
11.415 else:
11.416 - self.save(self.value + offset, DataValue(self.source_context, self.source_value))
11.417 + self.save(self.registers[instruction.working] + offset, DataValue(
11.418 + self.registers[self.context_of(instruction.source)],
11.419 + self.registers[instruction.source]))
11.420 return
11.421
11.422 - self.exception = self._MakeObject(Library.instance_size, self.attr_error_instance)
11.423 + self.registers["exception"] = self._MakeObject(Library.instance_size, self.attr_error_instance)
11.424 return self.RaiseException()
11.425
11.426 # NOTE: LoadAttrIndexContext is a possibility if a particular attribute can always be overridden.
11.427
11.428 - def MakeFrame(self, size):
11.429 + def MakeFrame(self, size, instruction):
11.430 self.invocation_sp_stack.append(len(self.frame_stack))
11.431 self.frame_stack.extend([None] * size)
11.432
11.433 - def DropFrame(self, operand=None):
11.434 + def DropFrame(self, operand, instruction):
11.435 self.local_sp_stack.pop()
11.436 frame = self.invocation_sp_stack.pop()
11.437 del self.frame_stack[frame:] # reset stack before call
11.438
11.439 - def StoreFrame(self, pos):
11.440 + def StoreFrame(self, pos, instruction):
11.441 frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame
11.442 - self.frame_stack[frame + pos] = DataValue(self.context, self.value)
11.443 + self.frame_stack[frame + pos] = DataValue(
11.444 + self.registers[self.context_of(instruction.working)],
11.445 + self.registers[instruction.working])
11.446
11.447 - def StoreFrameIndex(self, index):
11.448 + def StoreFrameIndex(self, index, instruction):
11.449 frame = self.invocation_sp_stack[-1] # different from the current frame after MakeFrame
11.450 - data = self.load(self.value)
11.451 + data = self.load(self.registers[instruction.working])
11.452 element = self.paramlist[data.funccode + index]
11.453
11.454 if element is not None:
11.455 # NOTE: Need to ensure correct positioning where a context has been generated.
11.456 param_index, offset = element
11.457 if param_index == index:
11.458 - self.frame_stack[frame + offset] = DataValue(self.source_context, self.source_value)
11.459 + self.frame_stack[frame + offset] = DataValue(
11.460 + self.registers[self.context_of(instruction.source)],
11.461 + self.registers[instruction.source])
11.462 return
11.463
11.464 - self.exception = self._MakeObject(Library.instance_size, self.type_error_instance)
11.465 + self.registers["exception"] = self._MakeObject(Library.instance_size, self.type_error_instance)
11.466 return self.RaiseException()
11.467
11.468 - def LoadCallable(self, operand=None):
11.469 - data = self.load(self.value)
11.470 - self.callable = data.codeaddr
11.471 -
11.472 - def StoreCallable(self, operand=None):
11.473 - # NOTE: Should improve the representation and permit direct saving.
11.474 - data = self.load(self.value)
11.475 - self.save(self.value, data.with_callable(self.callable))
11.476 + def LoadCallable(self, operand, instruction):
11.477 + data = self.load(self.registers[instruction.working])
11.478 + self.registers[instruction.target] = data.codeaddr
11.479
11.480 - def LoadContextIntoValue(self, operand=None):
11.481 - # NOTE: Omission of the context of the context would make things like
11.482 - # NOTE: self() inside methods impossible.
11.483 - self.LoadValue(self.context)
11.484 + def StoreCallable(self, operand, instruction):
11.485 + # NOTE: Should improve the representation and permit direct saving.
11.486 + data = self.load(self.registers[instruction.working])
11.487 + self.save(self.registers[instruction.working], data.with_callable(self.registers[instruction.source]))
11.488
11.489 - def CheckContext(self, operand=None):
11.490 - self.status = self.value is not ReplaceableContext
11.491 + def CheckContext(self, operand, instruction):
11.492 + self.registers[instruction.target] = self.registers[instruction.working] is not ReplaceableContext
11.493
11.494 - def CheckClass(self, operand=None):
11.495 - if self.value in (ReplaceableContext, PlaceholderContext):
11.496 - self.status = 0
11.497 + def CheckClass(self, operand, instruction):
11.498 + if self.registers[instruction.working] in (ReplaceableContext, PlaceholderContext):
11.499 + self.registers[instruction.target] = 0
11.500 return
11.501
11.502 - data = self.load(self.value)
11.503 + data = self.load(self.registers[instruction.working])
11.504
11.505 # Classes are not themselves usable as the self argument.
11.506 # NOTE: This may change at some point.
11.507 # However, where classes appear as the context, instance
11.508 # compatibility is required in the first argument.
11.509
11.510 - self.status = data.attrcode is None # absent attrcode == class
11.511 + self.registers[instruction.target] = data.attrcode is None # absent attrcode == class
11.512
11.513 - def CheckFrame(self, operand):
11.514 + def CheckFrame(self, operand, instruction):
11.515 (nargs, ndefaults) = operand
11.516
11.517 # The frame is actually installed as the locals.
11.518 @@ -654,10 +654,10 @@
11.519
11.520 if not ((nargs - ndefaults) <= nlocals):
11.521 raise Exception, "CheckFrame %r (%r <= %r <= %r)" % (operand, nargs - ndefaults, nlocals, nargs)
11.522 - self.exception = self._MakeObject(Library.instance_size, self.type_error_instance)
11.523 + self.registers["exception"] = self._MakeObject(Library.instance_size, self.type_error_instance)
11.524 return self.RaiseException()
11.525
11.526 - def CheckExtra(self, nargs):
11.527 + def CheckExtra(self, nargs, instruction):
11.528
11.529 # The frame is actually installed as the locals.
11.530 # Retrieve the context from the first local.
11.531 @@ -670,7 +670,7 @@
11.532 if nlocals == nargs:
11.533 self.frame_stack.extend([None]) # ExtendFrame(1)
11.534
11.535 - def FillDefaults(self, operand):
11.536 + def FillDefaults(self, operand, instruction):
11.537 (nargs, ndefaults) = operand
11.538
11.539 # The frame is actually installed as the locals.
11.540 @@ -686,11 +686,14 @@
11.541 pos = nlocals
11.542
11.543 while pos < nargs:
11.544 - self.frame_stack[frame + pos] = self.load(self.value + default + 1) # skip header
11.545 +
11.546 + # Skip any header.
11.547 +
11.548 + self.frame_stack[frame + pos] = self.load(self.registers[instruction.working] + Library.instance_data_offset + default)
11.549 default += 1
11.550 pos += 1
11.551
11.552 - def CopyExtra(self, start):
11.553 + def CopyExtra(self, start, instruction):
11.554
11.555 # The frame is the source of the extra arguments.
11.556
11.557 @@ -705,84 +708,74 @@
11.558 pos = start
11.559
11.560 while pos < nlocals:
11.561 - self.save(ref + extra + 1, self.frame_stack[frame + pos]) # skip header when storing
11.562 +
11.563 + # Skip any header.
11.564 +
11.565 + self.save(ref + Library.instance_data_offset + extra, self.frame_stack[frame + pos])
11.566 extra += 1
11.567 pos += 1
11.568
11.569 - self.LoadContext(ref)
11.570 - self.LoadValue(ref)
11.571 + self.LoadImmediate(ref, self.context_of(instruction.working))
11.572 + self.LoadImmediate(ref, instruction.working)
11.573
11.574 - def CheckInstance(self, operand=None):
11.575 + def CheckInstance(self, operand, instruction):
11.576 # For the 'self' parameter in an invoked function, the proposed context
11.577 # ('self') is checked against the target's context.
11.578 - self.status = self._CheckInstance(self.value, self.source_value)
11.579 + self.registers[instruction.target] = self._CheckInstance(
11.580 + self.registers[instruction.working],
11.581 + self.registers[instruction.source])
11.582
11.583 - def JumpInFrame(self, operand=None):
11.584 - codeaddr = self.callable
11.585 + def JumpInFrame(self, operand, instruction):
11.586 + codeaddr = self.registers[instruction.working]
11.587 return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one
11.588
11.589 - def JumpWithFrame(self, operand=None):
11.590 - codeaddr = self.callable
11.591 + def JumpWithFrame(self, operand, instruction):
11.592 + codeaddr = self.registers[instruction.working]
11.593 self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame
11.594 return self.jump(codeaddr, self.pc + 1) # return to the instruction after this one
11.595
11.596 - def JumpWithFrameDirect(self, addr):
11.597 + def JumpWithFrameDirect(self, addr, instruction):
11.598 self.local_sp_stack.append(self.invocation_sp_stack[-1]) # adopt the invocation frame
11.599 return self.jump(addr, self.pc + 1) # return to the instruction after this one
11.600
11.601 - def ExtendFrame(self, size):
11.602 + def ExtendFrame(self, size, instruction):
11.603 self.frame_stack.extend([None] * size)
11.604
11.605 - def AdjustFrame(self, size):
11.606 + def AdjustFrame(self, size, instruction):
11.607 self.invocation_sp_stack[-1] += size
11.608
11.609 - def Return(self, operand=None):
11.610 + def Return(self, operand, instruction):
11.611 return self.pull_pc()
11.612
11.613 - def LoadResultIntoValue(self, operand=None):
11.614 - self.LoadContext(self.result_context)
11.615 - self.LoadValue(self.result_value)
11.616 -
11.617 - def LoadValueIntoResult(self, operand=None):
11.618 - self.result_context = self.context
11.619 - self.result_value = self.value
11.620 -
11.621 - def Jump(self, addr):
11.622 + def Jump(self, addr, instruction):
11.623 return addr
11.624
11.625 - def JumpIfTrue(self, addr):
11.626 - if self.status:
11.627 - return addr
11.628 -
11.629 - def JumpIfFalse(self, addr):
11.630 - if not self.status:
11.631 + def JumpIfTrue(self, addr, instruction):
11.632 + if self.registers[instruction.working]:
11.633 return addr
11.634
11.635 - def LoadException(self, operand=None):
11.636 - self.LoadContext(self.exception)
11.637 - self.LoadValue(self.exception)
11.638 -
11.639 - def StoreException(self, operand=None):
11.640 - self.exception = self.value
11.641 + def JumpIfFalse(self, addr, instruction):
11.642 + if not self.registers[instruction.working]:
11.643 + return addr
11.644
11.645 - def ClearException(self, operand=None):
11.646 - self.exception = None
11.647 + def ClearException(self, operand, instruction):
11.648 + self.LoadImmediate(None, instruction.target)
11.649
11.650 - def RaiseException(self, operand=None):
11.651 + def RaiseException(self, operand=None, instruction=None):
11.652 # NOTE: Adding the program counter as the first attribute after __class__.
11.653 - self.save(self.exception + Library.instance_data_offset, self.pc)
11.654 + self.save(self.registers["exception"] + Library.instance_data_offset, self.pc)
11.655 # Jumping to the current handler.
11.656 if self.abort_upon_exception:
11.657 raise Exception
11.658 return self.handler_stack[-1]
11.659
11.660 - def PushHandler(self, addr):
11.661 + def PushHandler(self, addr, instruction):
11.662 self.handler_stack.append(addr)
11.663 self.handler_local_sp_stack.append(len(self.local_sp_stack))
11.664 self.handler_invocation_sp_stack.append(len(self.invocation_sp_stack))
11.665 self.handler_pc_stack.append(len(self.pc_stack))
11.666
11.667 - def PopHandler(self, nframes):
11.668 + def PopHandler(self, nframes, instruction):
11.669 # Get the new local frame pointer and PC stack references.
11.670 local_sp_top = self.handler_local_sp_stack[-nframes]
11.671 invocation_sp_top = self.handler_invocation_sp_stack[-nframes]
11.672 @@ -799,20 +792,18 @@
11.673 del self.handler_invocation_sp_stack[-nframes:]
11.674 del self.handler_stack[-nframes:]
11.675
11.676 - def CheckException(self, operand=None):
11.677 - self.status = self.exception is not None and self._CheckInstance(self.exception, self.value)
11.678 -
11.679 - def TestIdentity(self, operand=None):
11.680 - self.status = self.value == self.source_value
11.681 + def CheckException(self, operand, instruction):
11.682 + self.registers[instruction.target] = self.registers["exception"] is not None and \
11.683 + self._CheckInstance(self.registers["exception"], self.registers[instruction.working])
11.684
11.685 - def TestIdentityAddress(self, addr):
11.686 - self.status = self.value == addr
11.687 + def TestIdentity(self, operand, instruction):
11.688 + self.registers[instruction.target] = self.registers[instruction.working] == self.registers[instruction.source]
11.689
11.690 - # LoadBoolean is implemented in the generated code.
11.691 - # StoreBoolean is implemented by testing against the True value.
11.692 + def TestIdentityAddress(self, addr, instruction):
11.693 + self.registers[instruction.target] = self.registers[instruction.working] == addr
11.694
11.695 - def InvertBoolean(self, operand=None):
11.696 - self.status = not self.status
11.697 + def InvertBoolean(self, operand, instruction):
11.698 + self.registers[instruction.target] = not self.registers[instruction.source]
11.699
11.700 # Common implementation details.
11.701
12.1 --- a/rsvplib.py Sun Aug 07 23:01:35 2011 +0200
12.2 +++ b/rsvplib.py Sun Aug 21 14:24:28 2011 +0200
12.3 @@ -2,6 +2,9 @@
12.4
12.5 """
12.6 A native function library for a really simple virtual processor.
12.7 +NOTE: Ultimately, this should only implement only operations at the lowest
12.8 +NOTE: possible level, with generated native methods providing the functionality
12.9 +NOTE: instead.
12.10
12.11 Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>
12.12
12.13 @@ -56,9 +59,6 @@
12.14 self.attr_error_instance = self.machine.attr_error_instance
12.15 self.type_error_instance = self.machine.type_error_instance
12.16
12.17 - self.frame_stack = self.machine.frame_stack
12.18 - self.local_sp_stack = self.machine.local_sp_stack
12.19 -
12.20 def _get_builtin_class_and_template(self, name):
12.21 cls = self.machine._get_class("__builtins__", name)
12.22 if cls is not None:
12.23 @@ -75,10 +75,10 @@
12.24 pass
12.25
12.26 def native_int_arithmetic_op(self, op):
12.27 - self.machine.LoadName(0) # left value
12.28 - left_data = self.machine.value + self.instance_data_offset
12.29 - self.machine.LoadName(1) # right value
12.30 - right_data = self.machine.value + self.instance_data_offset
12.31 + left = self.machine.load_from_frame(0)
12.32 + left_data = left.ref + self.instance_data_offset
12.33 + right = self.machine.load_from_frame(1)
12.34 + right_data = right.ref + self.instance_data_offset
12.35
12.36 # Make a new object.
12.37
12.38 @@ -92,24 +92,24 @@
12.39 # Return the new object.
12.40 # Introduce object as context for the new object.
12.41
12.42 - self.machine.result_context = addr
12.43 - self.machine.result_value = addr
12.44 + self.machine.LoadImmediate(addr, "result_context")
12.45 + self.machine.LoadImmediate(addr, "result")
12.46
12.47 def native_logical_op(self, op):
12.48 - self.machine.LoadName(0) # left value
12.49 - left_data = self.machine.value + self.instance_data_offset
12.50 - self.machine.LoadName(1) # right value
12.51 - right_data = self.machine.value + self.instance_data_offset
12.52 + left = self.machine.load_from_frame(0)
12.53 + left_data = left.ref + self.instance_data_offset
12.54 + right = self.machine.load_from_frame(1)
12.55 + right_data = right.ref + self.instance_data_offset
12.56
12.57 # Test the data.
12.58 # NOTE: The data is considered ready to use.
12.59
12.60 if op(self.machine.load(left_data), self.machine.load(right_data)):
12.61 - self.machine.result_context = self.constants[True]
12.62 - self.machine.result_value = self.constants[True]
12.63 + self.machine.LoadImmediate(self.constants[True], "result_context")
12.64 + self.machine.LoadImmediate(self.constants[True], "result")
12.65 else:
12.66 - self.machine.result_context = self.constants[False]
12.67 - self.machine.result_value = self.constants[False]
12.68 + self.machine.LoadImmediate(self.constants[False], "result_context")
12.69 + self.machine.LoadImmediate(self.constants[False], "result")
12.70
12.71 # Operators.
12.72 # Although this takes a short-cut by using the operator module, testing is
12.73 @@ -152,8 +152,8 @@
12.74 # Specific operator methods.
12.75
12.76 def builtins_int_neg(self):
12.77 - self.machine.LoadName(0) # left value
12.78 - left_data = self.machine.value + self.instance_data_offset
12.79 + left = self.machine.load_from_frame(0)
12.80 + left_data = left.ref + self.instance_data_offset
12.81
12.82 # Make a new object.
12.83
12.84 @@ -167,17 +167,14 @@
12.85 # Return the new object.
12.86 # Introduce object as context for the new object.
12.87
12.88 - self.machine.result_context = addr
12.89 - self.machine.result_value = addr
12.90 + self.machine.LoadImmediate(addr, "result_context")
12.91 + self.machine.LoadImmediate(addr, "result")
12.92
12.93 # Various built-in methods.
12.94
12.95 def builtins_list_new(self):
12.96 - frame = self.local_sp_stack[-1]
12.97 -
12.98 - # The first parameter should be the instance.
12.99 -
12.100 - list_value = self.frame_stack[frame]
12.101 + list_value = self.machine.load_from_frame(0)
12.102 + list_addr = list_value.ref + self.instance_data_offset
12.103
12.104 # Make a new sequence.
12.105 # NOTE: Using an arbitrary size.
12.106 @@ -187,23 +184,17 @@
12.107 # Complete the list instance by saving the fragment reference.
12.108 # NOTE: This requires an attribute in the list structure.
12.109
12.110 - addr = list_value.ref + self.instance_data_offset
12.111 - self.machine.save(addr, DataValue(None, new_fragment))
12.112 + self.machine.save(list_addr, DataValue(None, new_fragment))
12.113
12.114 def builtins_list_get_single_item(self):
12.115 - frame = self.local_sp_stack[-1]
12.116 -
12.117 - # Get the operand address.
12.118 -
12.119 - item_value = self.frame_stack[frame + 1]
12.120 -
12.121 - # Get the list address.
12.122 -
12.123 - obj_value = self.frame_stack[frame]
12.124 + obj_value = self.machine.load_from_frame(0)
12.125 + fragment_member = obj_value.ref + self.instance_data_offset
12.126 + item_value = self.machine.load_from_frame(1)
12.127 + item_pos_member = item_value.ref + self.instance_data_offset
12.128
12.129 # Get the fragment address.
12.130
12.131 - fragment = self.machine.load(obj_value.ref + self.instance_data_offset)
12.132 + fragment = self.machine.load(fragment_member)
12.133
12.134 # Get the fragment header.
12.135
12.136 @@ -212,28 +203,25 @@
12.137
12.138 # Get the item position.
12.139
12.140 - item_pos = self.machine.load(item_value.ref + self.instance_data_offset)
12.141 + item_pos = self.machine.load(item_pos_member)
12.142
12.143 if not self._check_index(item_pos, nelements):
12.144 - self.machine.exception = self.machine._MakeObject(self.instance_size, self.index_error_instance)
12.145 + self.machine.LoadImmediate(self.machine._MakeObject(self.instance_size, self.index_error_instance), "exception")
12.146 return self.machine.RaiseException()
12.147
12.148 # Get the item itself.
12.149
12.150 data = self.machine.load(fragment.ref + self.fragment_data_offset + item_pos)
12.151 - self.machine.result_context = data.context
12.152 - self.machine.result_value = data.ref
12.153 + self.machine.LoadImmediate(data.context, "result_context")
12.154 + self.machine.LoadImmediate(data.ref, "result")
12.155
12.156 def builtins_list_len(self):
12.157 - frame = self.local_sp_stack[-1]
12.158 -
12.159 - # Get the list address.
12.160 -
12.161 - obj_value = self.frame_stack[frame]
12.162 + obj_value = self.machine.load_from_frame(0)
12.163 + fragment_member = obj_value.ref + self.instance_data_offset
12.164
12.165 # Get the fragment address.
12.166
12.167 - fragment = self.machine.load(obj_value.ref + self.instance_data_offset)
12.168 + fragment = self.machine.load(fragment_member)
12.169
12.170 # Get the fragment header.
12.171
12.172 @@ -252,23 +240,17 @@
12.173 # Return the new object.
12.174 # Introduce object as context for the new object.
12.175
12.176 - self.machine.result_context = addr
12.177 - self.machine.result_value = addr
12.178 + self.machine.LoadImmediate(addr, "result_context")
12.179 + self.machine.LoadImmediate(addr, "result")
12.180
12.181 def builtins_list_append(self):
12.182 - frame = self.local_sp_stack[-1]
12.183 -
12.184 - # Get operand address.
12.185 -
12.186 - arg_value = self.frame_stack[frame + 1]
12.187 -
12.188 - # Get the list address.
12.189 -
12.190 - obj_value = self.frame_stack[frame]
12.191 + obj_value = self.machine.load_from_frame(0)
12.192 + fragment_member = obj_value.ref + self.instance_data_offset
12.193 + arg_value = self.machine.load_from_frame(1)
12.194
12.195 # Get the fragment address.
12.196
12.197 - fragment = self.machine.load(obj_value.ref + self.instance_data_offset)
12.198 + fragment = self.machine.load(fragment_member)
12.199
12.200 # Get the fragment header.
12.201
12.202 @@ -296,10 +278,9 @@
12.203 # Set the new fragment in the object.
12.204 # NOTE: The old fragment could be deallocated.
12.205
12.206 - self.machine.save(obj_value.ref + self.instance_data_offset, DataValue(None, new_fragment))
12.207 + self.machine.save(fragment_member, DataValue(None, new_fragment))
12.208
12.209 def builtins_tuple_new(self):
12.210 - frame = self.local_sp_stack[-1]
12.211
12.212 # Get the sequence address.
12.213 # The first argument should be empty since this function acts as an
12.214 @@ -307,34 +288,34 @@
12.215 # that it can be filled in for the call to an initialiser without
12.216 # allocating a new frame.
12.217
12.218 - obj_value = self.frame_stack[frame + 1]
12.219 + obj_value = self.machine.load_from_frame(1)
12.220 return self._builtins_tuple(obj_value)
12.221
12.222 def builtins_tuple(self):
12.223 - frame = self.local_sp_stack[-1]
12.224
12.225 # Get the sequence address.
12.226
12.227 - obj_value = self.frame_stack[frame]
12.228 + obj_value = self.machine.load_from_frame(0)
12.229 return self._builtins_tuple(obj_value)
12.230
12.231 def _builtins_tuple(self, obj_value):
12.232 + fragment_member = obj_value.ref + self.instance_data_offset
12.233
12.234 if self.machine._CheckInstance(obj_value.ref, self.tuple_class):
12.235 - self.machine.result_context = obj_value.context
12.236 - self.machine.result_value = obj_value.ref
12.237 + self.machine.LoadImmediate(obj_value.context, "result_context")
12.238 + self.machine.LoadImmediate(obj_value.ref, "result")
12.239 return
12.240
12.241 # Reject non-list, non-tuple types.
12.242 # NOTE: This should probably accept any sequence.
12.243
12.244 elif not self.machine._CheckInstance(obj_value.ref, self.list_class):
12.245 - self.machine.exception = self.machine._MakeObject(self.instance_size, self.type_error_instance)
12.246 + self.machine.LoadImmediate(self.machine._MakeObject(self.instance_size, self.type_error_instance), "exception")
12.247 return self.machine.RaiseException()
12.248
12.249 # Get the fragment address.
12.250
12.251 - fragment = self.machine.load(obj_value.ref + self.instance_data_offset)
12.252 + fragment = self.machine.load(fragment_member)
12.253
12.254 # Get the fragment header.
12.255
12.256 @@ -353,15 +334,11 @@
12.257 # Return the new object.
12.258 # Introduce object as context for the new object.
12.259
12.260 - self.machine.result_context = addr
12.261 - self.machine.result_value = addr
12.262 + self.machine.LoadImmediate(addr, "result_context")
12.263 + self.machine.LoadImmediate(addr, "result")
12.264
12.265 def builtins_tuple_len(self):
12.266 - frame = self.local_sp_stack[-1]
12.267 -
12.268 - # Get the tuple address.
12.269 -
12.270 - obj_value = self.frame_stack[frame]
12.271 + obj_value = self.machine.load_from_frame(0)
12.272
12.273 # Get the header.
12.274
12.275 @@ -380,19 +357,14 @@
12.276 # Return the new object.
12.277 # Introduce object as context for the new object.
12.278
12.279 - self.machine.result_context = addr
12.280 - self.machine.result_value = addr
12.281 + self.machine.LoadImmediate(addr, "result_context")
12.282 + self.machine.LoadImmediate(addr, "result")
12.283
12.284 def builtins_tuple_get_single_item(self):
12.285 - frame = self.local_sp_stack[-1]
12.286 -
12.287 - # Get the operand address.
12.288 -
12.289 - item_value = self.frame_stack[frame + 1]
12.290 -
12.291 - # Get the tuple address.
12.292 -
12.293 - obj_value = self.frame_stack[frame]
12.294 + obj_value = self.machine.load_from_frame(0)
12.295 + fragment_member = obj_value.ref + self.instance_data_offset
12.296 + item_value = self.machine.load_from_frame(1)
12.297 + item_pos_member = item_value.ref + self.instance_data_offset
12.298
12.299 # Get the header.
12.300
12.301 @@ -401,33 +373,30 @@
12.302
12.303 # NOTE: Assume single location for data and header.
12.304
12.305 - item_pos = self.machine.load(item_value.ref + self.instance_data_offset)
12.306 + item_pos = self.machine.load(item_pos_member)
12.307
12.308 if not self._check_index(item_pos, nelements):
12.309 - self.machine.exception = self.machine._MakeObject(self.instance_size, self.index_error_instance)
12.310 + self.machine.LoadImmediate(self.machine._MakeObject(self.instance_size, self.index_error_instance), "exception")
12.311 return self.machine.RaiseException()
12.312
12.313 # Get the item.
12.314
12.315 - data = self.machine.load(obj_value.ref + self.instance_data_offset + item_pos)
12.316 - self.machine.result_context = data.context
12.317 - self.machine.result_value = data.ref
12.318 + data = self.machine.load(fragment_member + item_pos)
12.319 + self.machine.LoadImmediate(data.context, "result_context")
12.320 + self.machine.LoadImmediate(data.ref, "result")
12.321
12.322 def builtins_getattr(self):
12.323 - frame = self.local_sp_stack[-1]
12.324 -
12.325 - # Get the object, attribute name.
12.326 -
12.327 - obj_value = self.frame_stack[frame]
12.328 - name_value = self.frame_stack[frame + 1]
12.329 + obj_value = self.machine.load_from_frame(0)
12.330 + name_value = self.machine.load_from_frame(1)
12.331 + index_member = name_value.ref + self.instance_data_offset + 1
12.332
12.333 if not self.machine._CheckInstance(name_value.ref, self.accessor_class):
12.334 - self.machine.exception = self.machine._MakeObject(self.instance_size, self.attr_error_instance)
12.335 + self.machine.LoadImmediate(self.machine._MakeObject(self.instance_size, self.attr_error_instance), "exception")
12.336 return self.machine.RaiseException()
12.337
12.338 # Get the object table index from the name. It is a bare integer, not a reference.
12.339
12.340 - index = self.machine.load(name_value.ref + self.instance_data_offset + 1)
12.341 + index = self.machine.load(index_member)
12.342
12.343 # NOTE: This is very much like LoadAttrIndexContextCond.
12.344
12.345 @@ -443,27 +412,23 @@
12.346 loaded_data = self.machine._LoadAddressContextCond(loaded_data.context, loaded_data.ref, obj_value.ref)
12.347 else:
12.348 loaded_data = self.machine.load(obj_value.ref + offset)
12.349 - self.machine.result_context = loaded_data.context
12.350 - self.machine.result_value = loaded_data.ref
12.351 + self.machine.LoadImmediate(loaded_data.context, "result_context")
12.352 + self.machine.LoadImmediate(loaded_data.ref, "result")
12.353 return
12.354
12.355 - self.machine.exception = self.machine._MakeObject(self.instance_size, self.attr_error_instance)
12.356 + self.machine.LoadImmediate(self.machine._MakeObject(self.instance_size, self.attr_error_instance), "exception")
12.357 return self.machine.RaiseException()
12.358
12.359 def builtins_isinstance(self):
12.360 - frame = self.local_sp_stack[-1]
12.361 -
12.362 - # Get the operand addresses.
12.363 -
12.364 - obj_value = self.frame_stack[frame]
12.365 - cls_value = self.frame_stack[frame + 1]
12.366 + obj_value = self.machine.load_from_frame(0)
12.367 + cls_value = self.machine.load_from_frame(1)
12.368
12.369 if self.machine._CheckInstance(obj_value.ref, cls_value.ref):
12.370 - self.machine.result_context = self.constants[True]
12.371 - self.machine.result_value = self.constants[True]
12.372 + self.machine.LoadImmediate(self.constants[True], "result_context")
12.373 + self.machine.LoadImmediate(self.constants[True], "result")
12.374 else:
12.375 - self.machine.result_context = self.constants[False]
12.376 - self.machine.result_value = self.constants[False]
12.377 + self.machine.LoadImmediate(self.constants[False], "result_context")
12.378 + self.machine.LoadImmediate(self.constants[False], "result")
12.379
12.380 def builtins_print(self):
12.381 # NOTE: Do nothing for now.
12.382 @@ -477,43 +442,43 @@
12.383
12.384 # Native method implementations:
12.385
12.386 - "native._int_add" : native_int_add,
12.387 - "native._int_sub" : native_int_sub,
12.388 - "native._int_pow" : native_int_pow,
12.389 - "native._int_and" : native_int_and,
12.390 - "native._int_or" : native_int_or,
12.391 - "native._int_lt" : native_int_lt,
12.392 - "native._int_gt" : native_int_gt,
12.393 - "native._int_eq" : native_int_eq,
12.394 - "native._str_lt" : native_str_lt,
12.395 - "native._str_gt" : native_str_gt,
12.396 - "native._str_eq" : native_str_eq,
12.397 - "__builtins__.int.__neg__" : builtins_int_neg,
12.398 - "__builtins__.list.__get_single_item__" : builtins_list_get_single_item,
12.399 - "__builtins__.list.__len__" : builtins_list_len,
12.400 - "__builtins__.list.append" : builtins_list_append,
12.401 - "__builtins__.tuple" : builtins_tuple_new,
12.402 - "__builtins__.tuple.__len__" : builtins_tuple_len,
12.403 - "__builtins__.tuple.__get_single_item__" : builtins_tuple_get_single_item,
12.404 + "native._int_add" : native_int_add,
12.405 + "native._int_sub" : native_int_sub,
12.406 + "native._int_pow" : native_int_pow,
12.407 + "native._int_and" : native_int_and,
12.408 + "native._int_or" : native_int_or,
12.409 + "native._int_lt" : native_int_lt,
12.410 + "native._int_gt" : native_int_gt,
12.411 + "native._int_eq" : native_int_eq,
12.412 + "native._str_lt" : native_str_lt,
12.413 + "native._str_gt" : native_str_gt,
12.414 + "native._str_eq" : native_str_eq,
12.415 + "__builtins__.int.__neg__" : builtins_int_neg,
12.416 + "__builtins__.list.__get_single_item__" : builtins_list_get_single_item,
12.417 + "__builtins__.list.__len__" : builtins_list_len,
12.418 + "__builtins__.list.append" : builtins_list_append,
12.419 + "__builtins__.tuple" : builtins_tuple_new,
12.420 + "__builtins__.tuple.__len__" : builtins_tuple_len,
12.421 + "__builtins__.tuple.__get_single_item__" : builtins_tuple_get_single_item,
12.422
12.423 # Native initialisers:
12.424
12.425 - "__builtins__.BaseException.__init__" : builtins_no_op, # NOTE: To be made distinct, potentially in the builtins module.
12.426 + "__builtins__.BaseException.__init__" : builtins_no_op, # NOTE: To be made distinct, potentially in the builtins module.
12.427
12.428 # Native functions:
12.429
12.430 - "__builtins__._getattr" : builtins_getattr,
12.431 + "__builtins__._getattr" : builtins_getattr,
12.432
12.433 # Native instantiator helpers:
12.434
12.435 - "__builtins__.list.__new__" : builtins_list_new,
12.436 + "__builtins__.list.__new__" : builtins_list_new,
12.437
12.438 # Native helper functions:
12.439
12.440 - "__builtins__._isinstance" : builtins_isinstance,
12.441 - "__builtins__._print" : builtins_print,
12.442 - "__builtins__._printnl" : builtins_printnl,
12.443 - "__builtins__._tuple" : builtins_tuple,
12.444 + "__builtins__._isinstance" : builtins_isinstance,
12.445 + "__builtins__._print" : builtins_print,
12.446 + "__builtins__._printnl" : builtins_printnl,
12.447 + "__builtins__._tuple" : builtins_tuple,
12.448 }
12.449
12.450 # vim: tabstop=4 expandtab shiftwidth=4
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/tests/instance_class_attr.py Sun Aug 21 14:24:28 2011 +0200
13.3 @@ -0,0 +1,9 @@
13.4 +#!/usr/bin/env python
13.5 +
13.6 +class A:
13.7 + pass
13.8 +
13.9 +a = A()
13.10 +result_1 = a.__class__ is not type and 1 or 0
13.11 +
13.12 +# vim: tabstop=4 expandtab shiftwidth=4