[pypy-commit] lang-smalltalk storage: 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:30 CEST 2014


Author: Tim Felgentreff <timfelgentreff at gmail.com>
Branch: storage
Changeset: r889:50071fb31ad9
Date: 2014-07-10 14:08 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/50071fb31ad9/

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
@@ -72,11 +72,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.s_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.s_sender()
+                        s_new_context._activate_unwind_context(self)
+                        s_new_context = s_sender
                 s_new_context.push(nlr.value)
             except ProcessSwitch, p:
                 assert not self.space.suppress_process_switch[0], "ProcessSwitch should be disabled..."
@@ -106,11 +108,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.
@@ -224,10 +231,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
@@ -623,7 +631,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()
 
@@ -631,36 +639,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.s_sender() is 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):
@@ -741,7 +760,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
@@ -777,6 +777,9 @@
     def is_closure_context(self):
         raise NotImplementedError()
 
+    def home_is_self(self):
+        raise NotImplementedError()
+
     # === Other properties of Contexts ===
 
     def mark_returned(self):
@@ -995,6 +998,9 @@
     def is_closure_context(self):
         return True
 
+    def home_is_self(self):
+        return False
+
     # === Temporary variables ===
 
     def gettemp(self, index):
@@ -1186,6 +1192,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