[pypy-commit] lang-smalltalk storage: Moved SenderChainManipulation exception to interpreter.py, as subclass of ContextSwitchException.

anton_gulenko noreply at buildbot.pypy.org
Fri Jul 18 14:09:00 CEST 2014


Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage
Changeset: r917:25b23527e013
Date: 2014-07-18 13:34 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/25b23527e013/

Log:	Moved SenderChainManipulation exception to interpreter.py, as
	subclass of ContextSwitchException. Catching SenderChainManipulation
	explicitely in toplevel loop. Added "sender is not new_sender"
	condition to raising SenderChainManipulation. Fixed test.

diff --git a/spyvm/error.py b/spyvm/error.py
--- a/spyvm/error.py
+++ b/spyvm/error.py
@@ -30,7 +30,3 @@
     _attrs_ = ["msg"]
     def __init__(self, msg):
         self.msg = msg
-
-class SenderChainManipulation(Exception):
-    def __init__(self, manipulated_context):
-        self.s_context = manipulated_context
diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -70,6 +70,10 @@
                 if self.is_tracing():
                     print "====== StackOverflow, contexts forced to heap at: %s" % e.s_new_context.short_str()
                 s_new_context = e.s_new_context
+            except SenderChainManipulation, e:
+                if self.is_tracing():
+                    print "====== SenderChainManipulation, 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
@@ -198,13 +202,13 @@
 
     def interpret_toplevel(self, w_frame):
         try:
+            self.interrupt_check_counter = self.interrupt_counter_size
             self.loop(w_frame)
         except ReturnFromTopLevel, e:
             return e.object
 
     def perform(self, w_receiver, selector="", w_selector=None, w_arguments=[]):
         s_frame = self.create_toplevel_context(w_receiver, selector, w_selector, w_arguments)
-        self.interrupt_check_counter = self.interrupt_counter_size
         return self.interpret_toplevel(s_frame.w_self())
 
     def create_toplevel_context(self, w_receiver, selector="", w_selector=None, w_arguments=[]):
@@ -276,13 +280,18 @@
         self.s_new_context = s_new_context
 
 class StackOverflow(ContextSwitchException):
-    """This causes the current jit-loop to be left, thus avoiding stack overflows.
+    """This causes the current jit-loop to be left, dumping all virtualized objects to the heap.
     This breaks performance, so it should rarely happen.
     In case of severe performance problems, execute with -t and check if this occurrs."""
 
 class ProcessSwitch(ContextSwitchException):
-    """This causes the interpreter to switch the executed context."""
+    """This causes the interpreter to switch the executed context.
+    Triggered when switching the process."""
 
+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."""
 
 import rpython.rlib.unroll
 if hasattr(unroll, "unrolling_zero"):
@@ -753,15 +762,16 @@
             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 error.SenderChainManipulation, e:
-                raise StackOverflow(self)
+            except SenderChainManipulation, e:
+                raise SenderChainManipulation(self)
         elif opType == 6:
             try:
                 self.w_receiver().store(self.space, third, self.pop())
-            except error.SenderChainManipulation, e:
-                raise StackOverflow(self)
+            except SenderChainManipulation, e:
+                raise SenderChainManipulation(self)
         elif opType == 7:
             w_association = self.w_method().getliteral(third)
             association = wrapper.AssociationWrapper(self.space, w_association)
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -659,10 +659,11 @@
         self.instances_w = {}
 
     def copy_field_from(self, n0, other_shadow):
+        from spyvm.interpreter import SenderChainManipulation
         try:
             AbstractRedirectingShadow.copy_field_from(self, n0, other_shadow)
-        except error.SenderChainManipulation, e:
-            assert e.s_context == self
+        except SenderChainManipulation, e:
+            assert e.s_new_context == self
 
     def copy_from(self, other_shadow):
         # Some fields have to be initialized before the rest, to ensure correct initialization.
@@ -725,9 +726,11 @@
     # === Sender ===
 
     def store_s_sender(self, s_sender, raise_error=True):
-        self._s_sender = s_sender
-        if raise_error:
-            raise error.SenderChainManipulation(self)
+        if s_sender is not self._s_sender:
+            self._s_sender = s_sender
+            if raise_error:
+                from spyvm.interpreter import SenderChainManipulation
+                raise SenderChainManipulation(self)
 
     def w_sender(self):
         sender = self.s_sender()
diff --git a/spyvm/test/test_interpreter.py b/spyvm/test/test_interpreter.py
--- a/spyvm/test/test_interpreter.py
+++ b/spyvm/test/test_interpreter.py
@@ -983,4 +983,4 @@
     w_frame, s_frame = new_frame(bytes)
     s_frame.store_w_receiver(w_frame)
     s_frame.push(w_frame)
-    py.test.raises(interpreter.StackOverflow, step_in_interp, s_frame)
+    py.test.raises(interpreter.SenderChainManipulation, step_in_interp, s_frame)


More information about the pypy-commit mailing list