Author: Tim Felgentreff <timfelgentr...@gmail.com> Branch: storage Changeset: r883:cb252f497113 Date: 2014-07-10 14:08 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/cb252f497113/
Log: avoid forcing s_sender for local returns (that is, all returns from methods and return top from block) diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -75,11 +75,13 @@ print "====== StackOverflow, contexts forced to heap at: %s" % e.s_new_context.short_str() s_new_context = e.s_new_context except Return, nlr: + assert nlr.s_target_context or nlr.is_local s_new_context = s_sender - while s_new_context is not nlr.s_target_context: - s_sender = s_new_context.direct_sender - s_new_context._activate_unwind_context(self) - s_new_context = s_sender + if not nlr.is_local: + while s_new_context is not nlr.s_target_context: + s_sender = s_new_context.direct_sender + s_new_context._activate_unwind_context(self) + s_new_context = s_sender s_new_context.push(nlr.value) except ProcessSwitch, p: if self.trace: @@ -108,11 +110,16 @@ try: self.step(s_context) except Return, nlr: - if nlr.s_target_context is not s_context: + if nlr.s_target_context is s_context or nlr.is_local: + s_context.push(nlr.value) + else: + if nlr.s_target_context is None: + # This is the case where we are returning to our sender. + # Mark the return as local, so our sender will take it + nlr.is_local = True s_context._activate_unwind_context(self) raise nlr - else: - s_context.push(nlr.value) + # This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame # and handles the stack overflow protection mechanism. @@ -237,10 +244,11 @@ self.object = object class Return(Exception): - _attrs_ = ["value", "s_target_context"] + _attrs_ = ["value", "s_target_context", "is_local"] def __init__(self, s_target_context, w_result): self.value = w_result self.s_target_context = s_target_context + self.is_local = False class ContextSwitchException(Exception): """General Exception that causes the interpreter to leave @@ -636,7 +644,7 @@ interp.padding(), code, w_method.safe_identifier_string(), w_selector.str_content()) raise e - def _return(self, return_value, interp, s_return_to): + def _return(self, return_value, interp, local_return=False): # unfortunately, this assert is not true for some tests. TODO fix this. # assert self._stack_ptr == self.tempsize() @@ -644,36 +652,47 @@ if interp.trace: print '%s<- %s' % (interp.padding(), return_value.as_repr_string()) - if s_return_to is None: - # This should never happen while executing a normal image. - raise ReturnFromTopLevel(return_value) + if self.home_is_self() or local_return: + # a local return just needs to go up the stack once. there + # it will find the sender as a local, and we don't have to + # force the reference + s_return_to = None + if self.direct_sender is None and self.virtual_sender is jit.vref_None: + # This should never happen while executing a normal image. + raise ReturnFromTopLevel(return_value) + else: + s_return_to = self.s_home().s_sender() + if s_return_to is None: + # This should never happen while executing a normal image. + raise ReturnFromTopLevel(return_value) + raise Return(s_return_to, return_value) # ====== Send/Return bytecodes ====== @bytecode_implementation() def returnReceiverBytecode(self, interp, current_bytecode): - return self._return(self.w_receiver(), interp, self.s_home().s_sender()) + return self._return(self.w_receiver(), interp) @bytecode_implementation() def returnTrueBytecode(self, interp, current_bytecode): - return self._return(interp.space.w_true, interp, self.s_home().s_sender()) + return self._return(interp.space.w_true, interp) @bytecode_implementation() def returnFalseBytecode(self, interp, current_bytecode): - return self._return(interp.space.w_false, interp, self.s_home().s_sender()) + return self._return(interp.space.w_false, interp) @bytecode_implementation() def returnNilBytecode(self, interp, current_bytecode): - return self._return(interp.space.w_nil, interp, self.s_home().s_sender()) + return self._return(interp.space.w_nil, interp) @bytecode_implementation() def returnTopFromMethodBytecode(self, interp, current_bytecode): - return self._return(self.pop(), interp, self.s_home().s_sender()) + return self._return(self.pop(), interp) @bytecode_implementation() def returnTopFromBlockBytecode(self, interp, current_bytecode): - return self._return(self.pop(), interp, self.s_sender()) + return self._return(self.pop(), interp, local_return=True) @bytecode_implementation() def sendLiteralSelectorBytecode(self, interp, current_bytecode): @@ -754,7 +773,8 @@ try: self.bytecodePrimValue(interp, 0) except Return, nlr: - if self is not nlr.s_target_context: + assert nlr.s_target_context or nlr.is_local + if self is not nlr.s_target_context and not nlr.is_local: raise nlr finally: self.mark_returned() diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -800,6 +800,9 @@ def is_closure_context(self): raise NotImplementedError() + def home_is_self(self): + raise NotImplementedError() + # === Other properties of Contexts === def mark_returned(self): @@ -1018,6 +1021,9 @@ def is_closure_context(self): return True + def home_is_self(self): + return False + # === Temporary variables === def gettemp(self, index): @@ -1209,6 +1215,9 @@ def is_closure_context(self): return self.closure is not None + def home_is_self(self): + return not self.is_closure_context() + # ______________________________________________________________________ # Marriage of MethodContextShadows with PointerObjects only when required _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit