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

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


Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage-context-state-v2
Changeset: r955:92d182dabea1
Date: 2014-07-25 16:33 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/92d182dabea1/

Log:	Added the rest of the refactoring.

diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -1,7 +1,7 @@
 import os
 
 from spyvm.shadow import MethodContextShadow, ActiveContext, InactiveContext, DirtyContext
-from spyvm import model, constants, wrapper, objspace, interpreter_bytecodes
+from spyvm import model, constants, wrapper, objspace, interpreter_bytecodes, error
 
 from rpython.rlib import jit, rstackovf, unroll
 
@@ -17,6 +17,16 @@
         self.s_target_context = s_target_context
         self.is_local = is_local
 
+class NonVirtualReturn(Exception):
+    _attrs_ = ["s_target_context", "s_current_context", "value"]
+    def __init__(self, s_target_context, s_current_context, w_result):
+        self.value = w_result
+        self.s_target_context = s_target_context
+        self.s_current_context = s_current_context
+    
+    def print_trace(self):
+        print "\n====== Sender Chain Manipulation, contexts forced to heap at: %s" % self.s_current_context.short_str()
+
 class LocalReturn(Exception):
     _attrs_ = ["value"]
     def __init__(self, value):
@@ -25,14 +35,13 @@
 class ContextSwitchException(Exception):
     """General Exception that causes the interpreter to leave
     the current context."""
-    
     _attrs_ = ["s_new_context"]
     type = "ContextSwitch"
     def __init__(self, s_new_context):
         self.s_new_context = s_new_context
     
-    def print_trace(self, old_context):
-        print "====== %s, contexts forced to heap at: %s" % (self.type, self.s_new_context.short_str())
+    def print_trace(self):
+        print "\n====== %s at: %s" % (self.type, self.s_new_context.short_str())
     
 class StackOverflow(ContextSwitchException):
     """This causes the current jit-loop to be left, dumping all virtualized objects to the heap.
@@ -43,17 +52,8 @@
 class ProcessSwitch(ContextSwitchException):
     """This causes the interpreter to switch the executed context.
     Triggered when switching the process."""
+    type = "Process Switch"
     
-    def print_trace(self, old_context):
-        print "====== Switched process from: %s" % old_context.short_str()
-        print "====== to: %s " % self.s_new_context.short_str()
-    
-class SenderChainManipulation(ContextSwitchException):
-    """Manipulation of the sender chain can invalidate the jitted C stack.
-    We have to dump all virtual objects and rebuild the stack.
-    We try to raise this as rarely as possible and as late as possible."""
-    type = "Sender Manipulation"
-
 UNROLLING_BYTECODE_RANGES = unroll.unrolling_iterable(interpreter_bytecodes.BYTECODE_RANGES)
 
 def get_printable_location(pc, self, method):
@@ -98,23 +98,27 @@
 
     def loop(self, w_active_context):
         # This is the top-level loop and is not invoked recursively.
-        s_new_context = w_active_context.as_context_get_shadow(self.space)
+        s_context = w_active_context.as_context_get_shadow(self.space)
         while True:
-            s_sender = s_new_context.s_sender()
+            s_sender = s_context.s_sender()
             try:
-                self.stack_frame(s_new_context, None)
+                self.stack_frame(s_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
+                    e.print_trace()
+                s_context = e.s_new_context
             except LocalReturn, ret:
-                s_new_context = self.unwind_context_chain(s_sender, s_sender, ret.value)
+                s_context = self.unwind_context_chain(s_sender, s_sender, ret.value, "LocalReturn")
             except Return, ret:
-                s_new_context = self.unwind_context_chain(s_sender, ret.s_target_context, ret.value)
+                s_context = self.unwind_context_chain(s_sender, ret.s_target_context, ret.value, "Return")
+            except NonVirtualReturn, ret:
+                if self.is_tracing():
+                    ret.print_trace()
+                s_context = self.unwind_context_chain(ret.s_current_context, ret.s_target_context, ret.value, "NonVirtual")
     
-    # This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame
-    # and handles the stack overflow protection mechanism.
+    # This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame,
+    # handles the stack overflow protection mechanism and handles/dispatches Returns.
     def stack_frame(self, s_frame, s_sender, may_context_switch=True):
         try:
             if self.is_tracing():
@@ -129,17 +133,21 @@
             rstackovf.check_stack_overflow()
             raise StackOverflow(s_frame)
         except Return, ret:
-            if ret.is_local:
-                raise LocalReturn(ret.value)
+            if s_frame.state is DirtyContext:
+                s_sender = s_frame.s_sender() # The sender has changed!
+                s_frame._activate_unwind_context(self)
+                target_context = s_sender if ret.is_local else ret.s_target_context
+                raise NonVirtualReturn(target_context, s_sender, ret.value)
             else:
-                raise 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
         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
@@ -164,14 +172,22 @@
             except LocalReturn, ret:
                 s_context.push(ret.value)
     
-    def unwind_context_chain(self, start_context, target_context, return_value):
+    def unwind_context_chain(self, start_context, target_context, return_value, source=""):
         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."
+            if not context:
+                msg = "Context chain ended (source: %s) while trying to return\n%s\nfrom\n%s\n(pc %s)\nto\n%s\n(pc %s)" % (
+                        source,
+                        return_value.as_repr_string(),
+                        start_context.short_str(),
+                        start_context.pc(),
+                        target_context.short_str(),
+                        start_context.pc())
+                raise error.FatalError(msg)
             s_sender = context.s_sender()
             context._activate_unwind_context(self)
             context = s_sender
diff --git a/spyvm/interpreter_bytecodes.py b/spyvm/interpreter_bytecodes.py
--- a/spyvm/interpreter_bytecodes.py
+++ b/spyvm/interpreter_bytecodes.py
@@ -30,7 +30,8 @@
                 parameters += (self.fetch_next_bytecode(), )
                 i = i + 1
             # This is a good place to step through bytecodes.
-            self.debug_bytecode()
+            
+            self.debug_bytecode(interp)
             return actual_implementation_method(self, interp, current_bytecode, *parameters)
         bytecode_implementation_wrapper.func_name = actual_implementation_method.func_name
         return bytecode_implementation_wrapper
@@ -118,7 +119,7 @@
     def pushLiteralVariableBytecode(self, interp, current_bytecode):
         # this bytecode assumes that literals[index] is an Association
         # which is an object with two named vars, and fetches the second
-        # named var (the value).
+        # named var (the value).    
         index = current_bytecode & 31
         w_association = self.w_method().getliteral(index)
         association = wrapper.AssociationWrapper(self.space, w_association)
@@ -337,8 +338,6 @@
         # ######################################################################
         if interp.is_tracing():
             interp.print_padded('-> %s %s' % (special_selector, s_frame.short_str()))
-            if not objectmodel.we_are_translated():
-                import pdb; pdb.set_trace()
 
         return interp.stack_frame(s_frame, self)
 
@@ -445,7 +444,6 @@
 
     @bytecode_implementation(parameter_bytes=2)
     def doubleExtendedDoAnythingBytecode(self, interp, current_bytecode, second, third):
-        from spyvm.interpreter import SenderChainManipulation
         opType = second >> 5
         if opType == 0:
             # selfsend
@@ -467,16 +465,9 @@
             association = wrapper.AssociationWrapper(self.space, w_association)
             self.push(association.value())
         elif opType == 5:
-            # TODO - the following two special cases should not be necessary
-            try:
-                self.w_receiver().store(self.space, third, self.top())
-            except SenderChainManipulation, e:
-                raise SenderChainManipulation(self)
+            self.w_receiver().store(self.space, third, self.top())
         elif opType == 6:
-            try:
-                self.w_receiver().store(self.space, third, self.pop())
-            except SenderChainManipulation, e:
-                raise SenderChainManipulation(self)
+            self.w_receiver().store(self.space, third, self.pop())
         elif opType == 7:
             w_association = self.w_method().getliteral(third)
             association = wrapper.AssociationWrapper(self.space, w_association)
@@ -607,7 +598,7 @@
     bytecodePrimPointX = make_send_selector_bytecode("x", 0)
     bytecodePrimPointY = make_send_selector_bytecode("y", 0)
     
-    def debug_bytecode(self):
+    def debug_bytecode(self, interp):
         # Hook used in interpreter_debugging
         pass
     
diff --git a/spyvm/interpreter_debugging.py b/spyvm/interpreter_debugging.py
--- a/spyvm/interpreter_debugging.py
+++ b/spyvm/interpreter_debugging.py
@@ -49,8 +49,8 @@
     
     @patch_context
     def debug_bytecode(original):
-        def meth(self):
-            if self.step_bytecodes:
+        def meth(self, interp):
+            if interp.step_bytecodes:
                 _break() # Continue stepping from here to get to the current bytecode execution
         return meth
     


More information about the pypy-commit mailing list