# HG changeset patch # User Paul Boddie # Date 1209924706 -7200 # Node ID a550b84e0ea5d61d045b6af7ec3241785a7091e4 # Parent 259153134864cf36e15f4269f94aa94c736e52ce Made the temporary storage allocation and deallocation more adaptive so that entries are only reserved when actually required and discarded when actually used. Introduced temporary storage usage for invocation targets instead of having a LoadCallable instruction. diff -r 259153134864 -r a550b84e0ea5 micropython/ast.py --- a/micropython/ast.py Sun May 04 02:42:03 2008 +0200 +++ b/micropython/ast.py Sun May 04 20:11:46 2008 +0200 @@ -184,8 +184,10 @@ self.unit.stack_temp_usage = max(self.unit.stack_temp_usage, self.temp_position) return temp_position - def discard_temp(self, n): - self.temp_position -= n + def discard_temp(self, instructions): + for temp in instructions: + if isinstance(temp, LoadTemp): + self.temp_position -= 1 def new_op(self, op): @@ -315,6 +317,10 @@ else: target, context = None, None + # Store the target in temporary storage for subsequent referencing. + + temp = self._optimise_temp_storage() + # Where a target is known and has a known context, avoid generating any # first argument. Instance methods do not have a known target since they # are accessed via an instance whose identity cannot generally be known @@ -472,16 +478,19 @@ else: self.new_op(CheckFrame()) - def _endCallFunc(self): + return temp + + def _endCallFunc(self, temp): "Make the invocation and tidy up afterwards." - self.new_op(LoadCallable()) # uses the start of the frame to get the callable + self.new_op(temp) self.new_op(JumpWithFrame()) # NOTE: Exception handling required. self.new_op(DropFrame()) + self.discard_temp([temp]) def _visitName(self, node, classes): @@ -580,9 +589,12 @@ """ Where the next operation would involve storing a value into temporary - storage, record and remove any simple instruction which produced the - value such that instead of subsequently accessing the temporary storage, - that instruction is substituted. + storage at 'temp_position', record and remove any simple instruction + which produced the value to be stored such that instead of subsequently + accessing the temporary storage, that instruction is substituted. + + If no optimisation can be achieved, a StoreTemp instruction is produced + and the appropriate LoadTemp instruction is returned. """ if self._should_optimise_temp_storage() and \ @@ -592,7 +604,9 @@ self.remove_ops(1) return last else: - return None + temp_position = self.reserve_temp(1) + self.new_op(StoreTemp(temp_position)) + return LoadTemp(temp_position) def _optimise_constant_storage(self, instruction, n): @@ -703,23 +717,15 @@ type_error_label = self.new_label() end_label = self.new_label() - # NOTE: Potentially remove the reservation if optimised storage is used. - - temp_position = self.reserve_temp(2) + # Evaluate and store the left operand in temporary storage. self.dispatch(node.left) + temp1 = self._optimise_temp_storage() - temp1 = self._optimise_temp_storage() - if not temp1: - self.new_op(StoreTemp(temp_position)) - temp1 = LoadTemp(temp_position) + # Evaluate and store the right operand in temporary storage. self.dispatch(node.right) - temp2 = self._optimise_temp_storage() - if not temp2: - self.new_op(StoreTemp(temp_position + 1)) - temp2 = LoadTemp(temp_position + 1) # Left method. @@ -729,6 +735,7 @@ # Get left method on temp1. self._generateAttr(node, left_method, (LoadAddress, LoadAttr, LoadAttrIndex)) + temp_method = self._optimise_temp_storage() if not self._optimise_known_target(): self.dispatch(compiler.ast.Name("AttributeError")) @@ -739,7 +746,7 @@ self.new_op(temp1) # Explicit context as first argument. self.new_op(temp2) - self._endCallFunc() + self._endCallFunc(temp_method) # Test for NotImplemented. # Don't actually raise an exception. @@ -764,6 +771,7 @@ # Get right method on temp2. self._generateAttr(node, right_method, (LoadAddress, LoadAttr, LoadAttrIndex)) + temp_method = self._optimise_temp_storage() if not self._optimise_known_target(): self.dispatch(compiler.ast.Name("AttributeError")) @@ -774,7 +782,7 @@ self.new_op(temp2) # Explicit context as first argument. self.new_op(temp1) - self._endCallFunc() + self._endCallFunc(temp_method) # Test for NotImplemented. # Don't actually raise an exception. @@ -796,7 +804,7 @@ # Compilation duties... # NOTE: Potentially remove this when optimised away. - self.discard_temp(2) + self.discard_temp([temp1, temp2]) def visitAdd(self, node): self._visitBinary(node, "__add__", "__radd__") @@ -845,8 +853,8 @@ self._startCallFunc() self.dispatch(node.node) - self._generateCallFunc(node.args, node) - self._endCallFunc() + temp = self._generateCallFunc(node.args, node) + self._endCallFunc(temp) def visitClass(self, node): unit = self.unit @@ -905,8 +913,8 @@ self._startCallFunc() self.dispatch(node.list) self._generateAttr(node, "__iter__", (LoadAddress, LoadAttr, LoadAttrIndex)) - self._generateCallFunc([], node) - self._endCallFunc() + temp = self._generateCallFunc([], node) + self._endCallFunc(temp) # Iterator on stack. @@ -919,8 +927,8 @@ self._startCallFunc() self.new_op(Duplicate()) self._generateAttr(node, "next", (LoadAddress, LoadAttr, LoadAttrIndex)) - self._generateCallFunc([], node) - self._endCallFunc() + temp = self._generateCallFunc([], node) + self._endCallFunc(temp) # Test for StopIteration. diff -r 259153134864 -r a550b84e0ea5 tests/op_add.py --- a/tests/op_add.py Sun May 04 02:42:03 2008 +0200 +++ b/tests/op_add.py Sun May 04 20:11:46 2008 +0200 @@ -6,5 +6,6 @@ a = 1 b = 2 c = a + b +d = a + b + c # vim: tabstop=4 expandtab shiftwidth=4