[pypy-commit] lang-smalltalk storage-context-state-v2: Added part of the context state refactoring.

anton_gulenko noreply at buildbot.pypy.org
Sun Jul 27 12:22:17 CEST 2014


Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage-context-state-v2
Changeset: r954:7292a07cb139
Date: 2014-07-25 11:07 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/7292a07cb139/

Log:	Added part of the context state refactoring.

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
@@ -97,21 +102,44 @@
         while True:
             s_sender = s_new_context.s_sender()
             try:
-                self.loop_bytecodes(s_new_context)
+                self.stack_frame(s_new_context, None)
                 raise Exception("loop_bytecodes left without raising...")
             except ContextSwitchException, e:
                 if self.is_tracing():
                     e.print_trace(s_new_context)
                 s_new_context = e.s_new_context
-            except Return, nlr:
-                assert nlr.s_target_context or 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
-                s_new_context.push(nlr.value)
+            except LocalReturn, ret:
+                s_new_context = self.unwind_context_chain(s_sender, s_sender, ret.value)
+            except Return, ret:
+                s_new_context = self.unwind_context_chain(s_sender, ret.s_target_context, ret.value)
+    
+    # This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame
+    # and handles the stack overflow protection mechanism.
+    def stack_frame(self, s_frame, s_sender, may_context_switch=True):
+        try:
+            if self.is_tracing():
+                self.stack_depth += 1
+            if s_frame._s_sender is None and s_sender is not None:
+                s_frame.store_s_sender(s_sender)
+            # Now (continue to) execute the context bytecodes
+            assert s_frame.state is InactiveContext
+            s_frame.state = ActiveContext
+            self.loop_bytecodes(s_frame, may_context_switch)
+        except rstackovf.StackOverflow:
+            rstackovf.check_stack_overflow()
+            raise StackOverflow(s_frame)
+        except Return, ret:
+            if ret.is_local:
+                raise LocalReturn(ret.value)
+            else:
+                raise ret
+        finally:
+            if self.is_tracing():
+                self.stack_depth -= 1
+            dirty_frame = s_frame.state is DirtyContext
+            s_frame.state = InactiveContext
+            if dirty_frame:
+                raise SenderChainManipulation(s_frame)
     
     def loop_bytecodes(self, s_context, may_context_switch=True):
         old_pc = 0
@@ -133,39 +161,22 @@
                 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
-
-    # This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame
-    # and handles the stack overflow protection mechanism.
-    def stack_frame(self, s_frame, s_sender, may_context_switch=True):
-        try:
-            if self.is_tracing():
-                self.stack_depth += 1
-            if s_frame._s_sender is None and s_sender is not None:
-                s_frame.store_s_sender(s_sender)
-            # Now (continue to) execute the context bytecodes
-            assert s_frame.state is InactiveContext
-            s_frame.state = ActiveContext
-            self.loop_bytecodes(s_frame, may_context_switch)
-        except rstackovf.StackOverflow:
-            rstackovf.check_stack_overflow()
-            raise StackOverflow(s_frame)
-        finally:
-            if self.is_tracing():
-                self.stack_depth -= 1
-            dirty_frame = s_frame.state is DirtyContext
-            s_frame.state = InactiveContext
-            if dirty_frame:
-                raise SenderChainManipulation(s_frame)
+            except LocalReturn, ret:
+                s_context.push(ret.value)
+    
+    def unwind_context_chain(self, start_context, target_context, return_value):
+        if start_context is None:
+            # This is the toplevel frame. Execution ended.
+            raise ReturnFromTopLevel(return_value)
+        assert target_context
+        context = start_context
+        while context is not target_context:
+            assert context, "Sender chain ended without finding return-context."
+            s_sender = context.s_sender()
+            context._activate_unwind_context(self)
+            context = s_sender
+        context.push(return_value)
+        return context
     
     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,18 +394,13 @@
             # it will find the sender as a local, and we don't have to
             # force the reference
             s_return_to = None
-            return_from_top = self.s_sender() is None
+            is_local = True
         else:
             s_return_to = self.s_home().s_sender()
-            return_from_top = s_return_to is None
+            is_local = False
         
-        if return_from_top:
-            # This should never happen while executing a normal image.
-            from spyvm.interpreter import ReturnFromTopLevel
-            raise ReturnFromTopLevel(return_value)
-        else:
-            from spyvm.interpreter import Return
-            raise Return(s_return_to, return_value)
+        from spyvm.interpreter import Return
+        raise Return(s_return_to, return_value, is_local)
 
     # ====== Send/Return bytecodes ======
 
@@ -508,16 +503,15 @@
         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:
+                # Local return value of ensure: block is ignored
+                pass
             finally:
                 self.mark_returned()
-
+    
     @bytecode_implementation()
     def unknownBytecode(self, interp, current_bytecode):
         raise error.MissingBytecode("unknownBytecode")


More information about the pypy-commit mailing list