1.1 --- a/micropython/ast.py Sun Aug 17 02:58:28 2008 +0200
1.2 +++ b/micropython/ast.py Sun Aug 17 20:46:49 2008 +0200
1.3 @@ -35,11 +35,21 @@
1.4 "constant_storage", "known_target", "self_access", "temp_storage", "load_operations", "no_operations", "unused_results"
1.5 ]
1.6
1.7 + # Attribute access instructions, for use with the appropriate handlers.
1.8 +
1.9 attribute_load_instructions = (LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex)
1.10 attribute_store_instructions = (None, None, StoreAttr, StoreAttrIndex)
1.11 +
1.12 + # Name access instructions, for use with the appropriate handlers.
1.13 +
1.14 name_load_instructions = (LoadName, LoadAddress)
1.15 name_store_instructions = (StoreName, StoreAddress)
1.16
1.17 + # Instructions which affect the current value.
1.18 +
1.19 + current_value_instructions = (LoadConst, LoadName, LoadTemp, LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex,
1.20 + LoadCallable, LoadContext, LoadResult, LoadException, LoadBoolean, MakeObject)
1.21 +
1.22 def __init__(self, module, importer, optimisations=None):
1.23
1.24 """
1.25 @@ -72,6 +82,7 @@
1.26 # control-flow operations will flush the "active" instruction.
1.27
1.28 self.active = None
1.29 + self.active_value = None
1.30
1.31 # The temporary storage used by the current assignment expression.
1.32
1.33 @@ -257,6 +268,11 @@
1.34 self.code.append(op)
1.35 self.active = op
1.36
1.37 + # Record specific types of instructions for optimisation.
1.38 +
1.39 + if isinstance(op, self.current_value_instructions):
1.40 + self.active_value = op
1.41 +
1.42 def remove_op(self):
1.43
1.44 "Remove the last instruction."
1.45 @@ -333,7 +349,7 @@
1.46 StoreTemp, StoreFrame, StoreResult, StoreException, # as the value being stored
1.47 LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced
1.48 StoreAttr, StoreAttrIndex, StoreCallable, # as the object being referenced
1.49 - TestIdentity # as one of the operands
1.50 + TestIdentity, CheckSelf # as one of the operands
1.51 ))
1.52
1.53 def _is_resultant_no_operation(self, instruction):
1.54 @@ -353,17 +369,9 @@
1.55
1.56 "Return whether 'instruction' provides an input."
1.57
1.58 - return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadBoolean) + self.attribute_load_instructions)
1.59 -
1.60 - # Convenience tests.
1.61 -
1.62 - def _have_constant_input(self):
1.63 -
1.64 - "Return whether the active instruction provides a constant input."
1.65 -
1.66 - return self._is_constant_input(self.active)
1.67 -
1.68 - _have_known_target = _have_constant_input
1.69 + return isinstance(instruction, self.current_value_instructions)
1.70 +
1.71 + # Convenience tests on outputs.
1.72
1.73 def _have_constant_target(self):
1.74
1.75 @@ -377,25 +385,35 @@
1.76
1.77 return self._is_constant_input(self.active.source)
1.78
1.79 + # Convenience tests on inputs.
1.80 +
1.81 + def _have_constant_input(self):
1.82 +
1.83 + "Return whether the active instruction provides a constant input."
1.84 +
1.85 + return self._is_constant_input(self.active_value)
1.86 +
1.87 + _have_known_target = _have_constant_input
1.88 +
1.89 def _have_simple_input(self):
1.90
1.91 "Return whether the active instruction provides a simple input."
1.92
1.93 - return self._is_simple_input(self.active)
1.94 + return self._is_simple_input(self.active_value)
1.95
1.96 def _have_input(self):
1.97
1.98 "Return whether the active instruction provides an input."
1.99
1.100 - return self._is_input(self.active)
1.101 + return self._is_input(self.active_value)
1.102
1.103 def _have_self_input(self):
1.104
1.105 "Return whether the active instruction is a reference to self."
1.106
1.107 return isinstance(self.unit, Function) and \
1.108 - self.unit.is_method() and isinstance(self.active, LoadName) and \
1.109 - self.active.attr.name == "self"
1.110 + self.unit.is_method() and isinstance(self.active_value, LoadName) and \
1.111 + self.active_value.attr.name == "self"
1.112
1.113 def _have_temp_compatible_access(self):
1.114
1.115 @@ -407,7 +425,19 @@
1.116 # LoadResult cannot be relied upon, since in general the result register
1.117 # could be updated since first being referenced.
1.118
1.119 - return isinstance(self.active, (LoadName, LoadTemp, LoadAddress, LoadConst))
1.120 + return isinstance(self.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst))
1.121 +
1.122 + def _have_correct_self_for_target(self, context):
1.123 +
1.124 + "Return whether the 'context' is compatible with the current value."
1.125 +
1.126 + if context is not None and self._have_self_input():
1.127 +
1.128 + parent = self.unit.parent
1.129 + if parent is context or parent.has_subclass(context) or context.has_subclass(parent):
1.130 + return 1
1.131 +
1.132 + return 0
1.133
1.134 # Optimisation methods. See the supported_optimisations class attribute.
1.135
1.136 @@ -540,9 +570,10 @@
1.137 self._have_simple_input() and \
1.138 self._is_simple_input_user(instruction):
1.139
1.140 - last = self.last_op()
1.141 - self.remove_op()
1.142 - instruction.input = last
1.143 + if self.active_value is self.active:
1.144 + self.remove_op()
1.145 +
1.146 + instruction.input = self.active_value
1.147
1.148 def _optimise_away_no_operations(self, instruction):
1.149
1.150 @@ -596,7 +627,7 @@
1.151 # Where the last operation (defining the attribute owner) yields a
1.152 # constant...
1.153
1.154 - if self._have_constant_input():
1.155 + if self._is_constant_input(self.active):
1.156 last = self.active
1.157
1.158 # Get the details of the access.
1.159 @@ -846,20 +877,25 @@
1.160 # the target where methods are being invoked via classes).
1.161
1.162 if first and expect_context:
1.163 - continue_label = self.new_label()
1.164 - self.new_op(CheckSelf())
1.165 - self.new_op(JumpIfTrue(continue_label))
1.166 -
1.167 - # Where the context is inappropriate, drop the incomplete frame and
1.168 - # raise an exception.
1.169 -
1.170 - self.new_op(DropFrame())
1.171 - self.new_op(LoadResult())
1.172 -
1.173 - self.load_builtin("TypeError", node)
1.174 - self.new_op(StoreException())
1.175 - self.new_op(RaiseException())
1.176 - self.set_label(continue_label)
1.177 +
1.178 + # Drop any test if the target and the context are known.
1.179 +
1.180 + if not self._have_correct_self_for_target(context):
1.181 +
1.182 + continue_label = self.new_label()
1.183 + self.new_op(CheckSelf())
1.184 + self.new_op(JumpIfTrue(continue_label))
1.185 +
1.186 + # Where the context is inappropriate, drop the incomplete frame and
1.187 + # raise an exception.
1.188 +
1.189 + self.new_op(DropFrame())
1.190 + self.new_op(LoadResult())
1.191 +
1.192 + self.load_builtin("TypeError", node)
1.193 + self.new_op(StoreException())
1.194 + self.new_op(RaiseException())
1.195 + self.set_label(continue_label)
1.196
1.197 first = 0
1.198 frame_pos += 1
1.199 @@ -1275,6 +1311,7 @@
1.200 # Prevent incorrect optimisation.
1.201
1.202 self.active = None
1.203 + self.active_value = None
1.204
1.205 def visitAssert(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "Assert")
1.206
1.207 @@ -1688,6 +1725,7 @@
1.208 # Prevent incorrect optimisation.
1.209
1.210 self.active = None
1.211 + self.active_value = None
1.212
1.213 def visitOr(self, node):
1.214 next_label = self.new_label()
1.215 @@ -1703,6 +1741,7 @@
1.216 # Prevent incorrect optimisation.
1.217
1.218 self.active = None
1.219 + self.active_value = None
1.220
1.221 def visitPass(self, node): pass
1.222
1.223 @@ -1850,6 +1889,7 @@
1.224 # Prevent incorrect optimisation.
1.225
1.226 self.active = None
1.227 + self.active_value = None
1.228
1.229 def visitWith(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "With")
1.230