[pypy-commit] lang-smalltalk storage-context-state-v3: Added LocalReturn. this is where it breaks.

anton_gulenko noreply at buildbot.pypy.org
Mon Jul 28 10:11:31 CEST 2014


Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage-context-state-v3
Changeset: r994:3bd27f741c83
Date: 2014-07-27 00:25 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/3bd27f741c83/

Log:	Added LocalReturn. this is where it breaks.

diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -12,10 +12,15 @@
 
 class Return(Exception):
     _attrs_ = ["value", "s_target_context", "is_local"]
-    def __init__(self, s_target_context, w_result):
+    def __init__(self, s_target_context, w_result, is_local):
         self.value = w_result
         self.s_target_context = s_target_context
-        self.is_local = False
+        self.is_local = is_local
+
+class LocalReturn(Exception):
+    _attrs_ = ["value"]
+    def __init__(self, value):
+        self.value = value
 
 class ContextSwitchException(Exception):
     """General Exception that causes the interpreter to leave
@@ -104,14 +109,16 @@
                 if self.is_tracing() or self.trace_important:
                     e.print_trace(s_new_context)
                 s_new_context = e.s_new_context
+            except LocalReturn, nlr:
+                s_new_context = s_sender
+                s_new_context.push(nlr.value)
             except Return, nlr:
-                assert nlr.s_target_context or nlr.is_local
+                assert nlr.s_target_context and not nlr.is_local
                 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
+                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)
     
     # This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame
@@ -124,6 +131,12 @@
                 s_frame.store_s_sender(s_sender, raise_error=False)
             # Now (continue to) execute the context bytecodes
             self.loop_bytecodes(s_frame, may_context_switch)
+        except Return, ret:
+            s_frame._activate_unwind_context(self)
+            if ret.s_target_context is s_sender or ret.is_local:
+                raise LocalReturn(ret.value)
+            else:
+                raise ret
         except rstackovf.StackOverflow:
             rstackovf.check_stack_overflow()
             raise StackOverflow(s_frame)
@@ -151,16 +164,8 @@
                 s_context=s_context)
             try:
                 self.step(s_context)
-            except Return, nlr:
-                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
+            except LocalReturn, ret:
+                s_context.push(ret.value)
 
     def step(self, context):
         bytecode = context.fetch_next_bytecode()
diff --git a/spyvm/interpreter_bytecodes.py b/spyvm/interpreter_bytecodes.py
--- a/spyvm/interpreter_bytecodes.py
+++ b/spyvm/interpreter_bytecodes.py
@@ -394,8 +394,10 @@
             # it will find the sender as a local, and we don't have to
             # force the reference
             s_return_to = None
+            is_local = True
             return_from_top = self.s_sender() is None
         else:
+            is_local = False
             s_return_to = self.s_home().s_sender()
             return_from_top = s_return_to is None
         
@@ -405,7 +407,7 @@
             raise ReturnFromTopLevel(return_value)
         else:
             from spyvm.interpreter import Return
-            raise Return(s_return_to, return_value)
+            raise Return(s_return_to, return_value, is_local)
 
     # ====== Send/Return bytecodes ======
 
@@ -508,13 +510,11 @@
         if self.gettemp(1).is_nil(self.space):
             self.settemp(1, self.space.w_true) # mark unwound
             self.push(self.gettemp(0)) # push the first argument
-            from spyvm.interpreter import Return
+            from spyvm.interpreter import LocalReturn
             try:
                 self.bytecodePrimValue(interp, 0)
-            except Return, nlr:
-                assert nlr.s_target_context or nlr.is_local
-                if self is not nlr.s_target_context and not nlr.is_local:
-                    raise nlr
+            except LocalReturn:
+                pass # Ignore local return value of ensure block.
             finally:
                 self.mark_returned()
 


More information about the pypy-commit mailing list