1.1 --- a/micropython/ast.py Tue Jul 15 21:16:17 2008 +0200
1.2 +++ b/micropython/ast.py Fri Jul 18 00:49:53 2008 +0200
1.3 @@ -31,7 +31,7 @@
1.4
1.5 "A translated module."
1.6
1.7 - supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "constant_test", "stack_access"]
1.8 + supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage"]
1.9
1.10 attribute_load_instructions = (LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex)
1.11 attribute_store_instructions = (StoreAddress, StoreAddressContext, StoreAttr, StoreAttrIndex)
1.12 @@ -63,6 +63,12 @@
1.13
1.14 self.unit = None
1.15
1.16 + # The current "active" instruction.
1.17 + # As a rule, this will become the last instruction, but some
1.18 + # control-flow operations will flush the "active" instruction.
1.19 +
1.20 + self.active = None
1.21 +
1.22 # Wiring within the code.
1.23
1.24 self.labels = {}
1.25 @@ -71,15 +77,10 @@
1.26 self.exception_labels = []
1.27
1.28 # The code itself. This is limited to the code for a particular block
1.29 - # being processed. Also retained is information about temporary values
1.30 - # and the presumed state of the value stack.
1.31 + # being processed. Also retained is information about temporary values.
1.32
1.33 self.code = None
1.34 - self.last_invocation = None
1.35 self.temp_position = 0
1.36 - self.stack = []
1.37 - self.suspended_frame = []
1.38 - self.frame_positions = []
1.39
1.40 def __repr__(self):
1.41 return "Translation(%r)" % self.module
1.42 @@ -90,9 +91,7 @@
1.43
1.44 self.unit = self.module
1.45 self.code = []
1.46 - self.last_invocation = None
1.47 - self.temp_position = self.unit.stack_local_usage
1.48 - self.stack = []
1.49 + self.temp_position = 0
1.50
1.51 if self.module.module is not None:
1.52 self.dispatch(self.module.module)
1.53 @@ -105,15 +104,15 @@
1.54
1.55 self.unit = unit
1.56 self.code = []
1.57 - self.last_invocation = None
1.58 - self.temp_position = self.unit.stack_local_usage
1.59 - self.stack = []
1.60 + self.temp_position = 0
1.61
1.62 if unit.astnode is not None:
1.63 self.dispatch(unit.astnode)
1.64
1.65 return self.code
1.66
1.67 + # Name-related methods.
1.68 +
1.69 def get_scope(self, name):
1.70
1.71 "Return the scope for the given 'name'."
1.72 @@ -125,61 +124,28 @@
1.73 else:
1.74 return "builtins"
1.75
1.76 - # Code feature methods.
1.77 -
1.78 - def reset_stack(self):
1.79 -
1.80 - "Reset the stack for the current unit."
1.81 + def load_builtin(self, name, node):
1.82
1.83 - self.stack = []
1.84 -
1.85 - def adjust_stack(self, op):
1.86 -
1.87 - "Adjust the stack according to the effect of 'op'."
1.88 + "Generate an instruction loading 'name' for the given 'node'."
1.89
1.90 - position = len(self.code)
1.91 - stack_level = len(self.stack)
1.92 -
1.93 - op.fix_stack(stack_level)
1.94 - effect = op.get_effect()
1.95 + self.new_op(LoadAddress(self.get_builtin(name, node)))
1.96
1.97 - if effect == 1:
1.98 - self.stack.append((position, op))
1.99 - elif effect < 0:
1.100 - while effect != 0:
1.101 - self.stack.pop()
1.102 - effect += 1
1.103 -
1.104 - # Update the stack levels.
1.105 + def get_builtin(self, name, node):
1.106
1.107 - self.unit.stack_usage = max(self.unit.stack_usage, stack_level)
1.108 -
1.109 - def revert_stack(self, op):
1.110 -
1.111 - "Revert the stack affected by 'op'."
1.112 -
1.113 - effect = op.get_effect()
1.114 + """
1.115 + Return the built-in module definition for the given 'name', used by the
1.116 + given 'node'.
1.117 + """
1.118
1.119 - if effect > 0:
1.120 - while effect != 0:
1.121 - self.stack.pop()
1.122 - effect -= 1
1.123 - elif effect < 0:
1.124 - raise ProcessingError, "Cannot remove instructions which reduce the stack."
1.125 -
1.126 - def make_frame(self):
1.127 - self.frame_positions.append(len(self.stack))
1.128 + if self.builtins is not None:
1.129 + try:
1.130 + return self.builtins[name]
1.131 + except KeyError:
1.132 + raise TranslateError(self.module.full_name(), node, "No __builtins__ definition is available for name %r." % name)
1.133 + else:
1.134 + raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name)
1.135
1.136 - def suspend_frame(self):
1.137 - self.suspended_frame = self.stack[self.frame_positions[-1]:]
1.138 - self.stack = self.stack[:self.frame_positions[-1]]
1.139 -
1.140 - def resume_frame(self):
1.141 - self.stack += self.suspended_frame
1.142 - self.suspended_frame = []
1.143 -
1.144 - def drop_frame(self):
1.145 - self.stack = self.stack[:self.frame_positions.pop()]
1.146 + # Code feature methods.
1.147
1.148 def new_label(self):
1.149
1.150 @@ -218,10 +184,20 @@
1.151 def drop_exception_labels(self):
1.152 self.exception_labels.pop()
1.153
1.154 + def get_temp(self):
1.155 +
1.156 + """
1.157 + Add a temporary storage instruction for the current value and return a
1.158 + sequence of access instructions.
1.159 + """
1.160 +
1.161 + temp_position = self.reserve_temp(1)
1.162 + self.new_op(StoreTemp(temp_position))
1.163 + return [LoadTemp(temp_position)]
1.164 +
1.165 def reserve_temp(self, n):
1.166 temp_position = self.temp_position
1.167 self.temp_position += n
1.168 - self.unit.stack_temp_usage = max(self.unit.stack_temp_usage, self.temp_position)
1.169 return temp_position
1.170
1.171 def discard_temp(self, instructions):
1.172 @@ -235,19 +211,14 @@
1.173
1.174 "Add 'op' to the generated code."
1.175
1.176 - # Optimise stack access by incorporating the source data directly into
1.177 - # instructions.
1.178 -
1.179 - self._optimise_stack_access(op)
1.180 -
1.181 # Optimise away constant storage if appropriate.
1.182 # The target and value loading operations are also removed.
1.183
1.184 if self._optimise_constant_storage(op):
1.185 return
1.186
1.187 - self.adjust_stack(op)
1.188 self.code.append(op)
1.189 + self.active = op
1.190
1.191 def new_ops(self, ops):
1.192
1.193 @@ -259,43 +230,20 @@
1.194 for op in ops:
1.195 self.new_op(op.copy())
1.196
1.197 - def remove_ops(self, n):
1.198 -
1.199 - "Remove the last 'n' instructions."
1.200 + def remove_op(self):
1.201
1.202 - for i in range(0, n):
1.203 - op = self.code.pop()
1.204 - self.revert_stack(op)
1.205 + "Remove the last instruction."
1.206 +
1.207 + op = self.code.pop()
1.208 + self.active = None
1.209
1.210 def replace_op(self, op):
1.211
1.212 "Replace the last added instruction with 'op'."
1.213
1.214 - self.remove_ops(1)
1.215 + self.remove_op()
1.216 self.new_op(op)
1.217
1.218 - def remove_op_using_stack(self, op):
1.219 -
1.220 - "Remove the instruction which created the top stack position."
1.221 -
1.222 - position, op = self.stack[-1]
1.223 -
1.224 - # NOTE: Prevent removal of non-end instructions.
1.225 -
1.226 - if position < len(self.code) - 1:
1.227 - return 0
1.228 - else:
1.229 - self.remove_ops(1)
1.230 - return 1
1.231 -
1.232 - def last_ops(self, n):
1.233 -
1.234 - "Return the last 'n' added instructions in reverse chronological order."
1.235 -
1.236 - ops = self.code[-n:]
1.237 - ops.reverse()
1.238 - return ops
1.239 -
1.240 def last_op(self):
1.241
1.242 "Return the last added instruction."
1.243 @@ -305,12 +253,6 @@
1.244 except IndexError:
1.245 return None
1.246
1.247 - def set_last_invocation(self):
1.248 -
1.249 - "Set this location as the point after the last invocation."
1.250 -
1.251 - self.last_invocation = len(self.code)
1.252 -
1.253 # Internal helper methods.
1.254
1.255 def _visitAttr(self, node, classes):
1.256 @@ -331,12 +273,11 @@
1.257
1.258 AddressInstruction, AddressContextInstruction, AttrInstruction, AttrIndexInstruction = classes
1.259
1.260 - last = self.last_op()
1.261 -
1.262 # Where the last operation (defining the attribute owner) yields a
1.263 # constant...
1.264
1.265 - if self._have_constant_input(0):
1.266 + if self._have_constant_input():
1.267 + last = self.active
1.268
1.269 # Get the details of the access.
1.270
1.271 @@ -392,12 +333,23 @@
1.272
1.273 self.new_op(AttrIndexInstruction(index))
1.274
1.275 + # Invocations involve the following:
1.276 + #
1.277 + # 1. Reservation of a frame for the arguments
1.278 + # 2. Identification of the target which is then held in temporary storage
1.279 + # 3. Optional inclusion of a context (important for methods)
1.280 + # 4. Preparation of the argument frame
1.281 + # 5. Invocation of the target
1.282 + # 6. Discarding of the frame
1.283 + #
1.284 + # In order to support nested invocations - eg. a(b(c)) - use of the
1.285 + # temporary storage is essential.
1.286 +
1.287 def _startCallFunc(self):
1.288
1.289 "Record the location of the invocation."
1.290
1.291 self.new_op(MakeFrame()) # records the start of the frame
1.292 - self.make_frame()
1.293
1.294 def _generateCallFunc(self, args, node):
1.295
1.296 @@ -549,7 +501,7 @@
1.297
1.298 # use (callable+0)+paramindex+table
1.299 # checks embedded offset against (callable+0)
1.300 - # moves the top of stack to frame+position
1.301 + # moves the current value to frame+position
1.302
1.303 else:
1.304 self.dispatch(arg)
1.305 @@ -569,20 +521,12 @@
1.306
1.307 self.new_op(DropFrame())
1.308
1.309 - # Pretend that the frame is now gone, generating suitable stack
1.310 - # operations.
1.311 -
1.312 - self.suspend_frame()
1.313 self.new_op(LoadResult())
1.314
1.315 - self.dispatch(compiler.ast.Name("TypeError"))
1.316 + self.load_builtin("TypeError", node)
1.317 self.new_op(RaiseException())
1.318 self.set_label(continue_label)
1.319
1.320 - # Obtain the suspended frame for subsequent outcomes.
1.321 -
1.322 - self.resume_frame()
1.323 -
1.324 first = 0
1.325 frame_pos += 1
1.326
1.327 @@ -636,24 +580,12 @@
1.328 self.new_ops(instructions)
1.329 self.new_op(JumpWithFrame())
1.330
1.331 - def _endCallFunc(self, instructions=None, keep_frame=0):
1.332 + def _endCallFunc(self, instructions=None):
1.333
1.334 "Finish the invocation and tidy up afterwards."
1.335
1.336 - # NOTE: Exception handling required.
1.337 -
1.338 - # Note this as the most recent invocation.
1.339 -
1.340 - self.set_last_invocation()
1.341 -
1.342 self.new_op(DropFrame())
1.343 - if keep_frame:
1.344 - self.suspend_frame()
1.345 - else:
1.346 - self.drop_frame()
1.347 self.new_op(LoadResult())
1.348 - if keep_frame:
1.349 - self.resume_frame()
1.350
1.351 # Discard any temporary storage instructions.
1.352
1.353 @@ -700,25 +632,13 @@
1.354 raise TranslateError(self.module.full_name(), node, "Module %r has no attribute %r." % (self.module, name))
1.355
1.356 else:
1.357 - self.new_op(AddressInstruction(self._get_builtin(name, node)))
1.358 -
1.359 - def _get_builtin(self, name, node):
1.360 - if self.builtins is not None:
1.361 - try:
1.362 - return self.builtins[name]
1.363 - except KeyError:
1.364 - raise TranslateError(self.module.full_name(), node, "No __builtins__ definition is available for name %r." % name)
1.365 - else:
1.366 - raise TranslateError(self.module.full_name(), node, "No __builtins__ module is available for name %r." % name)
1.367 + self.new_op(AddressInstruction(self.get_builtin(name, node)))
1.368
1.369 # Optimisation tests.
1.370
1.371 def _should_optimise_constant_storage(self):
1.372 return "constant_storage" in self.optimisations
1.373
1.374 - def _should_optimise_constant_test(self):
1.375 - return "constant_test" in self.optimisations
1.376 -
1.377 def _should_optimise_known_target(self):
1.378 return "known_target" in self.optimisations
1.379
1.380 @@ -728,9 +648,6 @@
1.381 def _should_optimise_temp_storage(self):
1.382 return "temp_storage" in self.optimisations
1.383
1.384 - def _should_optimise_stack_access(self):
1.385 - return "stack_access" in self.optimisations
1.386 -
1.387 # Simple tests.
1.388
1.389 def _is_constant_input(self, instruction):
1.390 @@ -740,84 +657,45 @@
1.391 return isinstance(instruction, LoadAddress) and instruction.attr.assignments == 1 or \
1.392 isinstance(instruction, LoadConst)
1.393
1.394 + def _is_constant_target(self, instruction):
1.395 +
1.396 + "Return whether 'instruction' provides a constant target."
1.397 +
1.398 + return isinstance(instruction, (StoreName, StoreAddress)) and \
1.399 + instruction.attr.assignments == 1
1.400 +
1.401 def _is_local_input(self, instruction):
1.402
1.403 "Return whether 'instruction' provides a local input."
1.404
1.405 return isinstance(instruction, (LoadName, LoadTemp))
1.406
1.407 - def _is_unaffected(self, instruction, position):
1.408 -
1.409 - """
1.410 - Return whether 'instruction' is unaffected by side-effects since it
1.411 - occurs at a 'position' later than the last invocation.
1.412 - """
1.413 -
1.414 - return isinstance(instruction, (LoadResult, LoadAddress)) and (
1.415 - self.last_invocation is None or position >= self.last_invocation)
1.416 -
1.417 # Convenience tests.
1.418
1.419 - def _have_constant_input(self, n):
1.420 + def _have_constant_input(self):
1.421
1.422 - "Return whether the last 'n' instructions provide constant inputs."
1.423 + "Return whether the active instruction provides a constant input."
1.424
1.425 - last = self.last_ops(n+1)
1.426 - return len(last) > n and self._is_constant_input(last[n])
1.427 + return self._is_constant_input(self.active)
1.428
1.429 - def _have_known_target(self):
1.430 -
1.431 - "Return whether the last instruction is a known target."
1.432 -
1.433 - return self._have_constant_input(0)
1.434 + _have_known_target = _have_constant_input
1.435
1.436 def _have_self_input(self):
1.437
1.438 - "Return whether the last instruction is a reference to self."
1.439 + "Return whether the active instruction is a reference to self."
1.440
1.441 - last = self.last_op()
1.442 return isinstance(self.unit, Function) and \
1.443 - self.unit.is_method() and isinstance(last, LoadName) and \
1.444 - last.attr.name == "self"
1.445 + self.unit.is_method() and isinstance(self.active, LoadName) and \
1.446 + self.active.attr.name == "self"
1.447
1.448 def _have_temp_compatible_access(self):
1.449
1.450 """
1.451 - Indicate whether the last instruction can be used in place of access to
1.452 - a temporary variable retaining the result of the last instruction.
1.453 + Indicate whether the active instruction can be used in place of access
1.454 + to a temporary variable retaining the result of the last instruction.
1.455 """
1.456
1.457 - last = self.last_op()
1.458 - # NOTE: Should expand to cover LoadAttr and LoadAttrIndex, but this
1.459 - # NOTE: would require inspection of the stack operations.
1.460 - return isinstance(last, (LoadName, LoadTemp, LoadAddress, LoadConst))
1.461 -
1.462 - def _get_access_instructions(self, instruction):
1.463 -
1.464 - """
1.465 - Get the stack access instructions employed by the given 'instruction'.
1.466 - It is assumed that the source of the data communicated through the stack
1.467 - is not modified since the storage of the data. However, since the stack
1.468 - should only be employed within statements, there should be no risk of
1.469 - side-effects for local storage.
1.470 - """
1.471 -
1.472 - access_ops = []
1.473 - for stack_op in instruction.accesses:
1.474 - if isinstance(stack_op, (StackLoad, StackPull)):
1.475 - position, op = self.stack[stack_op.n]
1.476 -
1.477 - # Insist on constants, locals or other things which should not
1.478 - # have been changed.
1.479 -
1.480 - if not self._is_constant_input(op) and not self._is_local_input(op) and \
1.481 - not self._is_unaffected(op, position):
1.482 -
1.483 - return None
1.484 -
1.485 - access_ops.append((op, stack_op))
1.486 -
1.487 - return access_ops
1.488 + return isinstance(self.active, (LoadName, LoadTemp, LoadAddress, LoadConst))
1.489
1.490 # Optimisation methods. See the supported_optimisations class attribute.
1.491
1.492 @@ -843,12 +721,10 @@
1.493 self._have_temp_compatible_access():
1.494
1.495 last = self.last_op()
1.496 - self.remove_ops(1)
1.497 + self.remove_op()
1.498 return [last]
1.499 else:
1.500 - temp_position = self.reserve_temp(1)
1.501 - self.new_op(StoreTemp(temp_position))
1.502 - return [LoadTemp(temp_position)]
1.503 + return self.get_temp()
1.504
1.505 def _optimise_constant_storage(self, instruction):
1.506
1.507 @@ -858,27 +734,10 @@
1.508 """
1.509
1.510 if self._should_optimise_constant_storage() and \
1.511 - isinstance(instruction, (StoreName, StoreAddress)) and \
1.512 - instruction.attr.assignments == 1:
1.513 -
1.514 - return 1
1.515 - else:
1.516 - return 0
1.517 -
1.518 - def _optimise_constant_test(self, instruction):
1.519 + self._is_constant_target(instruction) and \
1.520 + self._have_constant_input():
1.521
1.522 - """
1.523 - Where this operation tests the topmost stack value which happens to be
1.524 - a constant against another stack value, merge the last instruction which
1.525 - loaded the constant into the current 'instruction'.
1.526 - """
1.527 -
1.528 - if self._should_optimise_constant_test() and \
1.529 - instruction is TestIdentity and \
1.530 - self._have_constant_input(0):
1.531 -
1.532 - last = self.last_op()
1.533 - self.replace_op(TestIdentityAddress(last.attr))
1.534 + self.remove_op()
1.535 return 1
1.536 else:
1.537 return 0
1.538 @@ -940,27 +799,6 @@
1.539 else:
1.540 return 0
1.541
1.542 - def _optimise_stack_access(self, instruction):
1.543 -
1.544 - """
1.545 - Optimise stack access for the given 'instruction', replacing stack
1.546 - operations with instructions directly accessing the required data.
1.547 - """
1.548 -
1.549 - if self._should_optimise_stack_access():
1.550 - ops = self._get_access_instructions(instruction)
1.551 - if ops is not None:
1.552 - instruction.accesses = []
1.553 - for op, stack_op in ops:
1.554 - if self.remove_op_using_stack(op):
1.555 - instruction.accesses.append(op)
1.556 -
1.557 - # Remove the stack side-effects of these accesses.
1.558 -
1.559 - op.remove_results()
1.560 - else:
1.561 - instruction.accesses.append(stack_op)
1.562 -
1.563 # Visitor methods.
1.564
1.565 def default(self, node, *args):
1.566 @@ -1000,7 +838,7 @@
1.567 # the attribute access cannot be resolved at compile-time.
1.568
1.569 if not self._optimise_known_target():
1.570 - self.dispatch(compiler.ast.Name("AttributeError"))
1.571 + self.load_builtin("AttributeError", node)
1.572 self.new_op(CheckException())
1.573 self.new_op(JumpIfTrue(end_call_label))
1.574
1.575 @@ -1011,7 +849,7 @@
1.576
1.577 self.new_ops(temp) # Explicit context as first argument.
1.578 self._doCallFunc(temp_method)
1.579 - self._endCallFunc(temp_method, keep_frame=1)
1.580 + self._endCallFunc(temp_method)
1.581 self.new_op(Jump(end_label))
1.582
1.583 # End method attempt.
1.584 @@ -1021,7 +859,7 @@
1.585
1.586 # Raise a TypeError.
1.587
1.588 - self.dispatch(compiler.ast.Name("TypeError"))
1.589 + self.load_builtin("TypeError", node)
1.590 self.new_op(RaiseException())
1.591
1.592 self.set_label(end_label)
1.593 @@ -1077,7 +915,7 @@
1.594 # the attribute access cannot be resolved at compile-time.
1.595
1.596 if not self._optimise_known_target():
1.597 - self.dispatch(compiler.ast.Name("AttributeError"))
1.598 + self.load_builtin("AttributeError", node)
1.599 self.new_op(CheckException())
1.600 self.new_op(JumpIfTrue(end_left_label))
1.601
1.602 @@ -1089,14 +927,12 @@
1.603 self.new_ops(temp1) # Explicit context as first argument.
1.604 self.new_ops(temp2)
1.605 self._doCallFunc(temp_method)
1.606 - self._endCallFunc(temp_method, keep_frame=1)
1.607 + self._endCallFunc(temp_method)
1.608
1.609 # Test for NotImplemented.
1.610 # Don't actually raise an exception.
1.611
1.612 - self.dispatch(compiler.ast.Name("NotImplemented"))
1.613 - if not self._optimise_constant_test(TestIdentity):
1.614 - self.new_op(TestIdentity())
1.615 + self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node)))
1.616 self.new_op(JumpIfTrue(right_label))
1.617 self.new_op(Jump(end_label))
1.618
1.619 @@ -1119,7 +955,7 @@
1.620 # the attribute access cannot be resolved at compile-time.
1.621
1.622 if not self._optimise_known_target():
1.623 - self.dispatch(compiler.ast.Name("AttributeError"))
1.624 + self.load_builtin("AttributeError", node)
1.625 self.new_op(CheckException())
1.626 self.new_op(JumpIfTrue(end_right_label))
1.627
1.628 @@ -1131,14 +967,12 @@
1.629 self.new_ops(temp2) # Explicit context as first argument.
1.630 self.new_ops(temp1)
1.631 self._doCallFunc(temp_method)
1.632 - self._endCallFunc(temp_method, keep_frame=1)
1.633 + self._endCallFunc(temp_method)
1.634
1.635 # Test for NotImplemented.
1.636 # Don't actually raise an exception.
1.637
1.638 - self.dispatch(compiler.ast.Name("NotImplemented"))
1.639 - if not self._optimise_constant_test(TestIdentity):
1.640 - self.new_op(TestIdentity())
1.641 + self.new_op(TestIdentityAddress(self.get_builtin("NotImplemented", node)))
1.642 self.new_op(JumpIfTrue(type_error_label))
1.643 self.new_op(Jump(end_label))
1.644
1.645 @@ -1150,7 +984,7 @@
1.646 # Raise a TypeError.
1.647
1.648 self.set_label(type_error_label)
1.649 - self.dispatch(compiler.ast.Name("TypeError"))
1.650 + self.load_builtin("TypeError", node)
1.651 self.new_op(RaiseException())
1.652
1.653 self.set_label(end_label)
1.654 @@ -1163,15 +997,32 @@
1.655 def visitAdd(self, node):
1.656 self._visitBinary(node, "__add__", "__radd__")
1.657
1.658 - def visitAnd(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "And")
1.659 + def visitAnd(self, node):
1.660 + next_label = self.new_label()
1.661 +
1.662 + for n in node.nodes[:-1]:
1.663 + self.dispatch(n)
1.664 + self.new_op(TestBoolean())
1.665 + self.new_op(JumpIfFalse(next_label))
1.666 +
1.667 + self.dispatch(node.nodes[-1])
1.668 + self.set_label(next_label)
1.669 +
1.670 + # Prevent incorrect optimisation.
1.671 +
1.672 + self.active = None
1.673
1.674 def visitAssert(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Assert")
1.675
1.676 def visitAssign(self, node):
1.677 self.dispatch(node.expr)
1.678 + temp = self.get_temp()
1.679 +
1.680 for n in node.nodes:
1.681 self.dispatch(n)
1.682
1.683 + self.discard_temp(temp)
1.684 +
1.685 def visitAssAttr(self, node):
1.686 self._visitAttr(node, self.attribute_store_instructions)
1.687
1.688 @@ -1283,12 +1134,7 @@
1.689 self._doCallFunc(temp)
1.690 self._endCallFunc(temp)
1.691
1.692 - # Iterator on stack.
1.693 -
1.694 - temp_iterator_position = self.reserve_temp(1)
1.695 - temp_iterator = [LoadTemp(temp_iterator_position)]
1.696 -
1.697 - self.new_op(StoreTemp(temp_iterator_position))
1.698 + temp_iterator = self._optimise_temp_storage()
1.699
1.700 # In the loop...
1.701
1.702 @@ -1305,7 +1151,7 @@
1.703
1.704 # Test for StopIteration.
1.705
1.706 - self.dispatch(compiler.ast.Name("StopIteration"))
1.707 + self.load_builtin("StopIteration", node)
1.708 self.new_op(CheckException())
1.709 if node.else_ is not None:
1.710 self.new_op(JumpIfTrue(else_label))
1.711 @@ -1432,9 +1278,38 @@
1.712 else:
1.713 self._visitName(node, (LoadName, LoadAddress))
1.714
1.715 - def visitNot(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Not")
1.716 + def visitNot(self, node):
1.717 + next_label = self.new_label()
1.718 + true_label = self.new_label()
1.719 +
1.720 + self.dispatch(node.expr)
1.721 + self.new_op(TestBoolean())
1.722 + self.new_op(JumpIfTrue(true_label))
1.723 + self.load_builtin("True", node)
1.724 + self.new_op(Jump(next_label))
1.725 +
1.726 + self.set_label(true_label)
1.727 + self.load_builtin("False", node)
1.728 + self.set_label(next_label)
1.729 +
1.730 + # Prevent incorrect optimisation.
1.731
1.732 - def visitOr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Or")
1.733 + self.active = None
1.734 +
1.735 + def visitOr(self, node):
1.736 + next_label = self.new_label()
1.737 +
1.738 + for n in node.nodes[:-1]:
1.739 + self.dispatch(n)
1.740 + self.new_op(TestBoolean())
1.741 + self.new_op(JumpIfTrue(next_label))
1.742 +
1.743 + self.dispatch(node.nodes[-1])
1.744 + self.set_label(next_label)
1.745 +
1.746 + # Prevent incorrect optimisation.
1.747 +
1.748 + self.active = None
1.749
1.750 def visitPass(self, node): pass
1.751
1.752 @@ -1470,7 +1345,6 @@
1.753 def visitStmt(self, node):
1.754 for n in node.nodes:
1.755 self.dispatch(n)
1.756 - self.reset_stack()
1.757
1.758 def visitSub(self, node):
1.759 self._visitBinary(node, "__sub__", "__rsub__")
1.760 @@ -1564,6 +1438,10 @@
1.761 self.set_label(exit_label)
1.762 self.drop_loop_labels()
1.763
1.764 + # Prevent incorrect optimisation.
1.765 +
1.766 + self.active = None
1.767 +
1.768 def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With")
1.769
1.770 def visitYield(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Yield")
2.1 --- a/micropython/rsvp.py Tue Jul 15 21:16:17 2008 +0200
2.2 +++ b/micropython/rsvp.py Fri Jul 18 00:49:53 2008 +0200
2.3 @@ -41,68 +41,29 @@
2.4
2.5 "A generic instruction."
2.6
2.7 - stack_storage = []
2.8 - stack_access = []
2.9 -
2.10 def __init__(self, attr=None):
2.11 self.attr = attr
2.12 - self.accesses = [op(-1 - n) for n, op in enumerate(self.stack_access)]
2.13 - self.results = [op(n) for n, op in enumerate(self.stack_storage)]
2.14
2.15 def copy(self):
2.16 return self.__class__(self.attr)
2.17
2.18 - def remove_results(self):
2.19 -
2.20 - "Remove the stack side-effects for instructions replacing stack operations."
2.21 -
2.22 - self.results = []
2.23 -
2.24 - def fix_stack(self, level):
2.25 -
2.26 - """
2.27 - Use the given 'level' to fix the details of this instruction's internal
2.28 - stack operations.
2.29 - """
2.30 + def __repr__(self):
2.31 + if self.attr is not None:
2.32 + return "%s(%r)" % (self.__class__.__name__, self.attr)
2.33 + else:
2.34 + return "%s()" % (self.__class__.__name__)
2.35
2.36 - effect = 0
2.37 - for stack_op in self.accesses:
2.38 - stack_op.fix_stack(level)
2.39 - effect += stack_op.get_effect()
2.40 -
2.41 - level += effect
2.42 - for stack_op in self.results:
2.43 - stack_op.fix_stack(level)
2.44 +class FrameRelativeInstruction(Instruction):
2.45
2.46 - def get_effect(self):
2.47 - effect = 0
2.48 - for stack_op in self.accesses + self.results:
2.49 - effect += stack_op.get_effect()
2.50 - return effect
2.51 -
2.52 - def show_stack_ops(self):
2.53 - return "%s%s" % (
2.54 - self.accesses and (" <- %s" % self.accesses) or "",
2.55 - self.results and (" -> %s" % self.results) or ""
2.56 - )
2.57 + "An instruction operating on the current frame."
2.58
2.59 def __repr__(self):
2.60 - if self.attr is not None:
2.61 - return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_stack_ops())
2.62 - else:
2.63 - return "%s()%s" % (self.__class__.__name__, self.show_stack_ops())
2.64 -
2.65 -class StackRelativeInstruction(Instruction):
2.66 -
2.67 - "An instruction operating on the local value stack."
2.68 -
2.69 - def __repr__(self):
2.70 - return "%s(%r)%s" % (self.__class__.__name__, self.get_operand(), self.show_stack_ops())
2.71 + return "%s(%r)" % (self.__class__.__name__, self.get_operand())
2.72
2.73 def get_operand(self):
2.74 return self.attr.position
2.75
2.76 -SR = StackRelativeInstruction
2.77 +FR = FrameRelativeInstruction
2.78
2.79 class AddressRelativeInstruction(Instruction):
2.80
2.81 @@ -111,9 +72,9 @@
2.82 def __repr__(self):
2.83 position = self.get_operand()
2.84 if position is not None:
2.85 - return "%s(%r)%s # %s" % (self.__class__.__name__, position, self.show_stack_ops(), name(self.attr))
2.86 + return "%s(%r) # %s" % (self.__class__.__name__, position, name(self.attr))
2.87 else:
2.88 - return "%s(%r)%s" % (self.__class__.__name__, self.show_stack_ops(), name(self.attr))
2.89 + return "%s(%r)" % (self.__class__.__name__, name(self.attr))
2.90
2.91 def get_operand(self):
2.92 return self.attr.position
2.93 @@ -127,14 +88,14 @@
2.94 def __repr__(self):
2.95 location, position, result = self.get_operands()
2.96 if location is not None:
2.97 - return "%s(%r)%s # %r, %r (%s)" % (
2.98 - self.__class__.__name__, result, self.show_stack_ops(), location, position, name(self.attr))
2.99 + return "%s(%r) # %r, %r (%s)" % (
2.100 + self.__class__.__name__, result, location, position, name(self.attr))
2.101 elif result is not None:
2.102 - return "%s(%r)%s # %s" % (
2.103 - self.__class__.__name__, result, self.show_stack_ops(), name(self.attr))
2.104 + return "%s(%r) # %s" % (
2.105 + self.__class__.__name__, result, name(self.attr))
2.106 else:
2.107 - return "%s(...)%s # %s" % (
2.108 - self.__class__.__name__, self.show_stack_ops(), name(self.attr))
2.109 + return "%s(...) # %s" % (
2.110 + self.__class__.__name__, name(self.attr))
2.111
2.112 def get_operands(self):
2.113 if isinstance(self.attr, Attr):
2.114 @@ -165,146 +126,71 @@
2.115 "An instruction employing a constant."
2.116
2.117 def __repr__(self):
2.118 - return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_stack_ops())
2.119 + return "%s(%r)" % (self.__class__.__name__, self.attr)
2.120
2.121 def get_operand(self):
2.122 return self.attr
2.123
2.124 Immediate = ImmediateInstruction
2.125
2.126 -# Internal stack and frame operations for instructions.
2.127 -
2.128 -class StackOp:
2.129 -
2.130 - "A generic stack operation."
2.131 -
2.132 - def __init__(self, n):
2.133 - self.n = n
2.134 - self.level = None
2.135 -
2.136 - def fix_stack(self, level):
2.137 - self.level = self.n + level
2.138 -
2.139 - def __repr__(self):
2.140 - return "%s(%s)" % (self.__class__.__name__, self.level == 0 and "0" or self.level or self.n)
2.141 -
2.142 -class StackPull(StackOp):
2.143 -
2.144 - "Load a value from the stack."
2.145 -
2.146 - def get_effect(self):
2.147 - return -1
2.148 -
2.149 -class StackPush(StackOp):
2.150 -
2.151 - "Save a value onto the stack."
2.152 -
2.153 - def get_effect(self):
2.154 - return 1
2.155 -
2.156 -class StackLoad(StackOp):
2.157 -
2.158 - "Load a value from the stack."
2.159 -
2.160 - def get_effect(self):
2.161 - return 0
2.162 -
2.163 -# Mix-in classes for stack effects.
2.164 -
2.165 -class StackAdd:
2.166 -
2.167 - """
2.168 - Indicate that the stack must grow to accommodate the result of this
2.169 - instruction.
2.170 - """
2.171 -
2.172 - stack_storage = [StackPush]
2.173 -
2.174 -class StackRemove:
2.175 -
2.176 - "Indicate that the stack must shrink as an effect of this instruction."
2.177 -
2.178 - stack_access = [StackPull]
2.179 -
2.180 -class StackRemove2:
2.181 -
2.182 - "Indicate that the stack must shrink as an effect of this instruction."
2.183 -
2.184 - stack_access = [StackPull, StackPull]
2.185 -
2.186 -class StackReplace(StackAdd, StackRemove):
2.187 -
2.188 - """
2.189 - Indicate that the stack remains at the same level due to the replacement of
2.190 - the topmost element.
2.191 - """
2.192 -
2.193 - pass
2.194 -
2.195 -class StackInspect:
2.196 -
2.197 - "Indicate that the stack is inspected but unchanged by this instruction."
2.198 -
2.199 - stack_access = [StackLoad]
2.200 -
2.201 # Access to stored constant data.
2.202
2.203 -class LoadConst(StackAdd, Address): "Load the constant, class, function, module from the specified location."
2.204 +class LoadConst(Address): "Load the constant, class, function, module from the specified location."
2.205
2.206 # Access within an invocation frame.
2.207
2.208 -class LoadName(StackAdd, SR): "Load the object from the given local attribute/variable."
2.209 -class StoreName(StackRemove, SR): "Store the object in the given local attribute/variable."
2.210 -class LoadTemp(StackAdd, Immediate): "Load the object from the given temporary location."
2.211 -class StoreTemp(StackRemove, Immediate): "Store the object in the given temporary location."
2.212 +class LoadName(FR): "Load the object from the given local attribute/variable."
2.213 +class StoreName(FR): "Store the object in the given local attribute/variable."
2.214 +class LoadTemp(Immediate): "Load the object from the given temporary location."
2.215 +class StoreTemp(Immediate): "Store the object in the given temporary location."
2.216
2.217 # Access to static data.
2.218
2.219 -class LoadAddress(StackAdd, Address): "Load the object from the given fixed attribute address."
2.220 -class StoreAddress(StackRemove, Address): "Store an object in the given fixed attribute address."
2.221 -class LoadAddressContext(StackReplace, Address):"Load the object from the given fixed attribute address, changing the context."
2.222 -class StoreAddressContext(StackRemove2, Address):"Store an object in the given fixed attribute address, changing the context."
2.223 -class MakeObject(StackAdd, Instruction): "Make a new object. There isn't a complementary DropObject."
2.224 +class LoadAddress(Address): "Load the object from the given fixed attribute address."
2.225 +class StoreAddress(Address): "Store an object in the given fixed attribute address."
2.226 +class LoadAddressContext(Address): "Load the object from the given fixed attribute address, changing the context."
2.227 +class StoreAddressContext(Address): "Store an object in the given fixed attribute address, changing the context."
2.228 +class MakeObject(Instruction): "Make a new object. There isn't a complementary DropObject."
2.229
2.230 # Access to address-relative data.
2.231
2.232 -class LoadAttr(StackReplace, AR): "Load the object from the given attribute."
2.233 -class StoreAttr(StackRemove2, AR): "Store an object in the given attribute."
2.234 -class LoadAttrIndex(StackReplace, Immediate): "Load the object for the attribute with the given index."
2.235 -class StoreAttrIndex(StackRemove2, Immediate): "Store an object in the attribute with the given index."
2.236 +class LoadAttr(AR): "Load the object from the given attribute."
2.237 +class StoreAttr(AR): "Store an object in the given attribute."
2.238 +class LoadAttrIndex(Immediate): "Load the object for the attribute with the given index."
2.239 +class StoreAttrIndex(Immediate): "Store an object in the attribute with the given index."
2.240
2.241 # Access to invocation frames in preparation.
2.242
2.243 -class MakeFrame(Instruction): "Make a new invocation frame."
2.244 -class DropFrame(Instruction): "Drop an invocation frame."
2.245 -class StoreFrame(StackRemove, Immediate): "Store an argument for the parameter with the given position."
2.246 -class StoreFrameIndex(StackRemove, Immediate): "Store an argument for the parameter with the given index."
2.247 -class LoadCallable(StackInspect, Instruction): "Load the target of an invocation."
2.248 -class LoadContext(StackReplace, Instruction): "Load the context of an invocation."
2.249 -class CheckFrame(Instruction): "Check the invocation frame and context for the target."
2.250 -class CheckSelf(StackAdd, Instruction): "Check the first argument of an invocation against the target."
2.251 +class MakeFrame(Instruction): "Make a new invocation frame."
2.252 +class DropFrame(Instruction): "Drop an invocation frame."
2.253 +class StoreFrame(Immediate): "Store an argument for the parameter with the given position."
2.254 +class StoreFrameIndex(Immediate): "Store an argument for the parameter with the given index."
2.255 +class LoadCallable(Instruction): "Load the target of an invocation."
2.256 +class LoadContext(Instruction): "Load the context of an invocation."
2.257 +class CheckFrame(Instruction): "Check the invocation frame and context for the target."
2.258 +class CheckSelf(Instruction): "Check the first argument of an invocation against the target."
2.259
2.260 # Invocation-related instructions, using a special result "register".
2.261
2.262 -class JumpWithFrame(StackRemove, Instruction): "Jump, adopting the invocation frame, to the callable found on the stack."
2.263 -class Return(StackRemove, Instruction): "Return a value from a subprogram."
2.264 -class LoadResult(StackAdd, Instruction): "Load a returned value."
2.265 +class JumpWithFrame(Instruction): "Jump, adopting the invocation frame, to the callable found as the current value."
2.266 +class Return(Instruction): "Return a value from a subprogram."
2.267 +class LoadResult(Instruction): "Load a returned value."
2.268
2.269 # Branch-related instructions.
2.270
2.271 -class Jump(Address): "Jump unconditionally."
2.272 -class JumpIfFalse(StackRemove, Address): "Jump if the last evaluation gave a false result."
2.273 -class JumpIfTrue(StackRemove, Address): "Jump if the last evaluation gave a true result."
2.274 +class Jump(Address): "Jump unconditionally."
2.275 +class JumpIfFalse(Address): "Jump if the last evaluation gave a false result."
2.276 +class JumpIfTrue(Address): "Jump if the last evaluation gave a true result."
2.277
2.278 # Exception-related instructions, using a special exception "register".
2.279
2.280 -class LoadException(StackAdd, Instruction): "Load the raised exception."
2.281 -class RaiseException(StackRemove, Instruction): "Raise an exception."
2.282 -class CheckException(Instruction): "Check the raised exception against another."
2.283 +class LoadException(Instruction): "Load the raised exception."
2.284 +class RaiseException(Instruction): "Raise an exception."
2.285 +class CheckException(Instruction): "Check the raised exception against another."
2.286
2.287 # General instructions.
2.288
2.289 -class TestIdentity(Instruction): "Test whether the two topmost stack values are identical."
2.290 -class TestIdentityAddress(Address): "Test whether the topmost stack value is identical to the given address."
2.291 +class TestBoolean(Instruction): "Test whether the current value is a true value."
2.292 +class TestIdentityAddress(Address): "Test whether the current value is identical to the given address."
2.293
2.294 # vim: tabstop=4 expandtab shiftwidth=4