[pypy-commit] lang-smalltalk default: Switched from a context return based implementation to Exception Raising returns.

lwassermann noreply at buildbot.pypy.org
Wed Mar 6 21:16:28 CET 2013


Author: Lars Wassermann <lars.wassermann at gmail.com>
Branch: 
Changeset: r121:079f6dd1e62f
Date: 2013-03-05 17:14 +0100
http://bitbucket.org/pypy/lang-smalltalk/changeset/079f6dd1e62f/

Log:	Switched from a context return based implementation to Exception
	Raising returns. This way, contexts are not manipulated during
	return, but on catching the exception.

diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -28,8 +28,8 @@
     _last_indent = ""
     jit_driver = jit.JitDriver(
         greens=['pc', 'self', 'method'],
-        reds=['s_active_context'],
-        #virtualizables=['s_active_context'],
+        reds=['mark', 's_context'],
+        #virtualizables=['s_context'],
         get_printable_location=get_printable_location
     )
     
@@ -60,25 +60,31 @@
         s_new_context = w_active_context.as_context_get_shadow(self.space)
         while True:
             try:
-                s_new_context = self.c_loop(s_new_context)
+                s_new_context = self.c_loop(s_new_context, mark=False)
             except StackOverflow, e:
                 self.remaining_stack_depth = self.max_stack_depth
                 s_new_context = e.s_context
+            except Return, nlr:
+                while s_new_context is not nlr.s_target_context:
+                    s_new_context, _ = s_new_context.s_sender(), s_new_context.mark_returned()
+                s_new_context.push(nlr.value)
 
-    def c_loop(self, s_context):
-        s_active_context = s_context
+    def c_loop(self, s_context, mark=True):
         while True:
-            pc = s_active_context._pc
-            method = s_active_context.s_method()
+            pc = s_context._pc
+            method = s_context.s_method()
 
             self.jit_driver.jit_merge_point(
                 pc=pc, self=self, method=method,
-                s_active_context=s_active_context)
-            s_return_to_context = self.step(s_active_context)
-            if (s_return_to_context is not None
-                    and s_return_to_context is not s_context):
-                s_active_context.mark_returned()
-                return s_return_to_context
+                mark=mark, s_context=s_context)
+            try:
+                self.step(s_context)
+            except Return, nlr:
+                if nlr.s_target_context is not s_context:
+                    if mark: s_context.mark_returned()
+                    raise nlr
+                else:
+                    s_context.push(nlr.value)
 
     def stack_frame(self, s_new_frame):
         if not self._loop:
@@ -88,8 +94,10 @@
             raise StackOverflow(s_new_frame)
 
         self.remaining_stack_depth -= 1
-        retval = self.c_loop(s_new_frame)
-        self.remaining_stack_depth += 1
+        try:
+            retval = self.c_loop(s_new_frame)
+        finally:
+            self.remaining_stack_depth += 1
         return retval
 
     def perform(self, w_receiver, selector, *arguments_w):
@@ -109,7 +117,11 @@
         s_frame.push(w_receiver)
         s_frame.push_all(list(arguments_w))
         try:
-            s_new_frame = s_frame._sendSelfSelector(w_selector, len(arguments_w), self)
+            try:
+                s_new_frame = s_frame._sendSelfSelector(w_selector, len(arguments_w), self)
+            except Return, nlr:
+                s_new_frame = nlr.s_target_context
+                nlr.s_target_context.push(nlr.value)
             if s_new_frame == None:
                 # which means that we tried to call a primitive method
                 return s_frame.pop()
@@ -125,6 +137,10 @@
 class StackOverflow(Exception):
     def __init__(self, s_top_context):
         self.s_context = s_top_context
+class Return(Exception):
+    def __init__(self, object, s_context):
+        self.value = object
+        self.s_target_context = s_context
 
 def make_call_primitive_bytecode(primitive, selector, argcount):
     def callPrimitive(self, interp, current_bytecode):
@@ -281,11 +297,7 @@
         # unfortunately, the assert below is not true for some tests
         # assert self._stack_ptr == self.tempsize()
         
-        # make this context a returned one
-        self.mark_returned()
-
-        s_return_to.push(return_value)
-        return s_return_to
+        raise Return(return_value, s_return_to)
 
     def returnReceiver(self, interp, current_bytecode):
         return self._return(self.w_receiver(), interp, self.s_home().s_sender())
@@ -695,7 +707,7 @@
         code.append("    %sif %s:" % (prefix, cond, ))
         code.append("        return context.%s(self, bytecode)" % (entry[-1], ))
         prefix = "el"
-    code.append("bytecode_step_translated._always_inline_ = True")
+    # code.append("bytecode_step_translated._always_inline_ = True")
     source = py.code.Source("\n".join(code))
     #print source
     miniglob = {}
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
@@ -8,10 +8,13 @@
 interp = interpreter.Interpreter(space)
 def step_in_interp(ctxt): # due to missing resets in between tests
     interp._loop = False
-    return_value = interp.step(ctxt)
-    if return_value is not None:
-        return return_value.w_self()
-    return None
+    try:
+        retval = interp.step(ctxt)
+        if retval is not None:
+            return retval.w_self()
+    except interpreter.Return, nlr:
+        nlr.s_target_context.push(nlr.value)
+        return nlr.s_target_context.w_self()
 
 # expose the bytecode's values as global constants.
 # Bytecodes that have a whole range are exposed as global functions:
@@ -988,9 +991,10 @@
         assert False
     try:
         interp = interpreter.Interpreter(space, None, "", max_stack_depth=10)
+        interp._loop = True
         interp.c_loop(w_method.as_compiledmethod_get_shadow(space).create_frame(space, space.wrap_int(0), []))
     except interpreter.StackOverflow, e:
-        assert e.w_context.getclass(space) is space.w_MethodContext
+        assert isinstance(e.s_context, shadow.MethodContextShadow)
     except interpreter.ReturnFromTopLevel, e:
         assert False
 


More information about the pypy-commit mailing list