[pypy-commit] lang-smalltalk storage-vrefs-rstackovf-localreturn: avoid forcing s_sender for local returns (that is, all returns from methods and return top from block)

timfel noreply at buildbot.pypy.org
Thu Jul 10 15:29:26 CEST 2014


Author: Tim Felgentreff <timfelgentreff at gmail.com>
Branch: storage-vrefs-rstackovf-localreturn
Changeset: r886:71d4742bcc58
Date: 2014-07-10 14:08 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/71d4742bcc58/

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
 


More information about the pypy-commit mailing list