1.1 --- a/micropython/ast.py Sun Jun 22 02:21:39 2008 +0200
1.2 +++ b/micropython/ast.py Sat Jun 28 20:46:45 2008 +0200
1.3 @@ -74,6 +74,8 @@
1.4 self.code = None
1.5 self.temp_position = 0
1.6 self.stack = []
1.7 + self.suspended_frame = []
1.8 + self.frame_positions = []
1.9
1.10 def __repr__(self):
1.11 return "Translation(%r)" % self.module
1.12 @@ -156,6 +158,20 @@
1.13 elif effect < 0:
1.14 raise ProcessingError, "Cannot remove instructions which reduce the stack."
1.15
1.16 + def make_frame(self):
1.17 + self.frame_positions.append(len(self.stack))
1.18 +
1.19 + def suspend_frame(self):
1.20 + self.suspended_frame = self.stack[self.frame_positions[-1]:]
1.21 + self.stack = self.stack[:self.frame_positions[-1]]
1.22 +
1.23 + def resume_frame(self):
1.24 + self.stack += self.suspended_frame
1.25 + self.suspended_frame = []
1.26 +
1.27 + def drop_frame(self):
1.28 + self.stack = self.stack[:self.frame_positions.pop()]
1.29 +
1.30 def new_label(self):
1.31
1.32 "Return a new label object for use with set_label."
1.33 @@ -241,23 +257,19 @@
1.34 self.remove_ops(1)
1.35 self.new_op(op)
1.36
1.37 - def remove_op_using_stack(self):
1.38 + def remove_op_using_stack(self, op):
1.39
1.40 "Remove the instruction which created the top stack position."
1.41
1.42 - position, op = self.stack.pop()
1.43 + position, op = self.stack[-1]
1.44
1.45 - # NOTE: For now, just erase the instruction.
1.46 -
1.47 - self.code[position] = None
1.48 + # NOTE: Prevent removal of non-end instructions.
1.49
1.50 - op = self.code[-1]
1.51 - while op is None:
1.52 - del self.code[-1]
1.53 - if self.code:
1.54 - op = self.code[-1]
1.55 - else:
1.56 - break
1.57 + if position < len(self.code) - 1:
1.58 + return 0
1.59 + else:
1.60 + self.remove_ops(1)
1.61 + return 1
1.62
1.63 def last_ops(self, n):
1.64
1.65 @@ -368,6 +380,7 @@
1.66 "Record the location of the invocation."
1.67
1.68 self.new_op(MakeFrame()) # records the start of the frame
1.69 + self.make_frame()
1.70
1.71 def _generateCallFunc(self, args, node):
1.72
1.73 @@ -551,10 +564,21 @@
1.74 # raise an exception.
1.75
1.76 self.new_op(DropFrame())
1.77 +
1.78 + # Pretend that the frame is now gone, generating suitable stack
1.79 + # operations.
1.80 +
1.81 + self.suspend_frame()
1.82 + self.new_op(LoadResult())
1.83 +
1.84 self.dispatch(compiler.ast.Name("TypeError"))
1.85 self.new_op(RaiseException())
1.86 self.set_label(continue_label)
1.87
1.88 + # Obtain the suspended frame for subsequent outcomes.
1.89 +
1.90 + self.resume_frame()
1.91 +
1.92 first = 0
1.93 frame_pos += 1
1.94
1.95 @@ -607,17 +631,32 @@
1.96 else:
1.97 self.new_op(CheckFrame())
1.98
1.99 - def _endCallFunc(self, temp):
1.100 + def _doCallFunc(self, instructions):
1.101 +
1.102 + "Make the invocation."
1.103
1.104 - "Make the invocation and tidy up afterwards."
1.105 + self.new_ops(instructions)
1.106 + self.new_op(JumpWithFrame())
1.107
1.108 - self.new_ops(temp)
1.109 - self.new_op(JumpWithFrame())
1.110 + def _endCallFunc(self, instructions=None, keep_frame=0):
1.111 +
1.112 + "Finish the invocation and tidy up afterwards."
1.113
1.114 # NOTE: Exception handling required.
1.115
1.116 self.new_op(DropFrame())
1.117 - self.discard_temp(temp)
1.118 + if keep_frame:
1.119 + self.suspend_frame()
1.120 + else:
1.121 + self.drop_frame()
1.122 + self.new_op(LoadResult())
1.123 + if keep_frame:
1.124 + self.resume_frame()
1.125 +
1.126 + # Discard any temporary storage instructions.
1.127 +
1.128 + if instructions is not None:
1.129 + self.discard_temp(instructions)
1.130
1.131 def _visitName(self, node, classes):
1.132
1.133 @@ -716,13 +755,14 @@
1.134 # NOTE: would require inspection of the stack operations.
1.135 return isinstance(last, (LoadName, LoadTemp, LoadAddress, LoadConst))
1.136
1.137 - def _have_fixed_sources(self, access):
1.138 + def _have_fixed_sources(self, instruction):
1.139 access_ops = []
1.140 - for i in xrange(0, access):
1.141 - position, op = self.stack[-1 - i]
1.142 - if not isinstance(op, (LoadName, LoadTemp, LoadAddress, LoadConst)):
1.143 - return 0
1.144 - access_ops.append(op)
1.145 + for stack_op in instruction.accesses:
1.146 + if isinstance(stack_op, StackLoad):
1.147 + position, op = self.stack[stack_op.n]
1.148 + if not isinstance(op, (LoadName, LoadTemp, LoadAddress, LoadConst)):
1.149 + return None
1.150 + access_ops.append((op, stack_op))
1.151 return access_ops
1.152
1.153 # Optimisation methods. See the supported_optimisations class attribute.
1.154 @@ -852,17 +892,19 @@
1.155 """
1.156
1.157 if self._should_optimise_stack_access():
1.158 - ops = self._have_fixed_sources(instruction.stack_access)
1.159 - if ops:
1.160 + ops = self._have_fixed_sources(instruction)
1.161 + if ops is not None:
1.162 #print "Optimised", instruction.accesses, "->", ops
1.163 - for i in range(0, instruction.stack_access):
1.164 - self.remove_op_using_stack()
1.165 - instruction.accesses = ops
1.166 + instruction.accesses = []
1.167 + for op, stack_op in ops:
1.168 + if self.remove_op_using_stack(op):
1.169 + instruction.accesses.append(op)
1.170
1.171 - # Remove the stack side-effects of these accesses.
1.172 + # Remove the stack side-effects of these accesses.
1.173
1.174 - for op in ops:
1.175 - op.remove_results()
1.176 + op.remove_results()
1.177 + else:
1.178 + instruction.accesses.append(stack_op)
1.179
1.180 # Visitor methods.
1.181
1.182 @@ -913,13 +955,14 @@
1.183 # NOTE: No support for defaults.
1.184
1.185 self.new_ops(temp) # Explicit context as first argument.
1.186 - self._endCallFunc(temp_method)
1.187 + self._doCallFunc(temp_method)
1.188 + self._endCallFunc(temp_method, keep_frame=1)
1.189 self.new_op(Jump(end_label))
1.190
1.191 # End method attempt.
1.192
1.193 self.set_label(end_call_label)
1.194 - self.new_op(DropFrame()) # From the method call.
1.195 + self._endCallFunc() # From the method call.
1.196
1.197 # Raise a TypeError.
1.198
1.199 @@ -990,7 +1033,8 @@
1.200
1.201 self.new_ops(temp1) # Explicit context as first argument.
1.202 self.new_ops(temp2)
1.203 - self._endCallFunc(temp_method)
1.204 + self._doCallFunc(temp_method)
1.205 + self._endCallFunc(temp_method, keep_frame=1)
1.206
1.207 # Test for NotImplemented.
1.208 # Don't actually raise an exception.
1.209 @@ -1004,7 +1048,7 @@
1.210 # End left method attempt.
1.211
1.212 self.set_label(end_left_label)
1.213 - self.new_op(DropFrame()) # From the left method call.
1.214 + self._endCallFunc() # From the left method call.
1.215
1.216 # Right method.
1.217
1.218 @@ -1031,7 +1075,8 @@
1.219
1.220 self.new_ops(temp2) # Explicit context as first argument.
1.221 self.new_ops(temp1)
1.222 - self._endCallFunc(temp_method)
1.223 + self._doCallFunc(temp_method)
1.224 + self._endCallFunc(temp_method, keep_frame=1)
1.225
1.226 # Test for NotImplemented.
1.227 # Don't actually raise an exception.
1.228 @@ -1045,7 +1090,7 @@
1.229 # End right method attempt.
1.230
1.231 self.set_label(end_right_label)
1.232 - self.new_op(DropFrame()) # From the right method call.
1.233 + self._endCallFunc() # From the right method call.
1.234
1.235 # Raise a TypeError.
1.236
1.237 @@ -1111,6 +1156,7 @@
1.238 self._startCallFunc()
1.239 self.dispatch(node.node)
1.240 temp = self._generateCallFunc(node.args, node)
1.241 + self._doCallFunc(temp)
1.242 self._endCallFunc(temp)
1.243
1.244 def visitClass(self, node):
1.245 @@ -1179,6 +1225,7 @@
1.246 self.dispatch(node.list)
1.247 self._generateAttr(node, "__iter__", (LoadAddress, LoadAttr, LoadAttrIndex))
1.248 temp = self._generateCallFunc([], node)
1.249 + self._doCallFunc(temp)
1.250 self._endCallFunc(temp)
1.251
1.252 # Iterator on stack.
1.253 @@ -1193,6 +1240,7 @@
1.254 self.new_op(Duplicate())
1.255 self._generateAttr(node, "next", (LoadAddress, LoadAttr, LoadAttrIndex))
1.256 temp = self._generateCallFunc([], node)
1.257 + self._doCallFunc(temp)
1.258 self._endCallFunc(temp)
1.259
1.260 # Test for StopIteration.
1.261 @@ -1333,7 +1381,15 @@
1.262
1.263 def visitPrintnl(self, node): pass
1.264
1.265 - def visitRaise(self, node): pass
1.266 + def visitRaise(self, node):
1.267 + # NOTE: expr1 only => instance provided
1.268 + self.dispatch(node.expr1)
1.269 +
1.270 + if node.expr2 is not None:
1.271 + self.dispatch(node.expr2)
1.272 + self._doCallFunc()
1.273 +
1.274 + self.new_op(RaiseException())
1.275
1.276 def visitReturn(self, node):
1.277 if node.value is not None:
1.278 @@ -1396,6 +1452,7 @@
1.279
1.280 # Unhandled exceptions.
1.281
1.282 + self.new_op(LoadException())
1.283 self.new_op(RaiseException())
1.284
1.285 # After exception
3.1 --- a/micropython/rsvp.py Sun Jun 22 02:21:39 2008 +0200
3.2 +++ b/micropython/rsvp.py Sat Jun 28 20:46:45 2008 +0200
3.3 @@ -236,24 +236,32 @@
3.4
3.5 class MakeFrame(Instruction): "Make a new invocation frame."
3.6 class ReserveFrame(Immediate): "Reserve the given number of entries for the invocation frame."
3.7 -class DropFrame(Instruction): "Drop an invocation frame."
3.8 class StoreFrame(StackRemove, Immediate): "Store an argument at the given frame location."
3.9 class StoreFrameIndex(StackRemove, Immediate): "Store an argument for the parameter with the given index."
3.10 +class LoadCallable(Instruction): "Load the target of an invocation."
3.11 +class LoadContext(StackReplace, Instruction): "Load the context of an invocation."
3.12 class CheckFrame(Instruction): "Check the invocation frame for the target."
3.13 +class CheckSelf(Instruction): "Check the first argument of an invocation against the target."
3.14 +class CheckContext(Instruction): """Check the context of an invocation against the target,
3.15 + potentially discarding the context."""
3.16 +
3.17 +# Invocation-related instructions, using a special result "register".
3.18 +
3.19 class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the callable found on the stack."
3.20 +class DropFrame(Instruction): "Drop an invocation frame."
3.21 +class Return(StackRemove, Instruction): "Return a value from a subprogram."
3.22 +class LoadResult(StackAdd, Instruction): "Load a returned value."
3.23
3.24 -# Invocation-related instructions.
3.25 +# Branch-related instructions.
3.26
3.27 class Jump(Address): "Jump unconditionally."
3.28 class JumpIfFalse(Address): "Jump if the last evaluation gave a false result."
3.29 class JumpIfTrue(Address): "Jump if the last evaluation gave a true result."
3.30 -class LoadCallable(Instruction): "Load the target of an invocation."
3.31 -class LoadContext(StackReplace, Instruction): "Load the context of an invocation."
3.32 -class CheckContext(Instruction): """Check the context of an invocation against the target,
3.33 - potentially discarding the context."""
3.34 -class CheckSelf(Instruction): "Check the first argument of an invocation against the target."
3.35 +
3.36 +# Exception-related instructions, using a special exception "register".
3.37 +
3.38 +class LoadException(StackAdd, Instruction): "Load the raised exception."
3.39 class RaiseException(StackRemove, Instruction): "Raise an exception."
3.40 -class Return(StackRemove, Instruction): "Return a value from a subprogram."
3.41 class CheckException(Instruction): "Check the raised exception against another."
3.42
3.43 # General instructions.