[pypy-commit] pypy continulet-pickle: Refactoring: replace the dummy_pycode with a real one that contains

arigo noreply at buildbot.pypy.org
Wed Sep 14 18:24:13 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: continulet-pickle
Changeset: r47268:e85840b1268d
Date: 2011-09-14 17:36 +0200
http://bitbucket.org/pypy/pypy/changeset/e85840b1268d/

Log:	Refactoring: replace the dummy_pycode with a real one that contains
	the start-up logic. Should be easier to pickle.

diff --git a/pypy/module/_continuation/interp_continuation.py b/pypy/module/_continuation/interp_continuation.py
--- a/pypy/module/_continuation/interp_continuation.py
+++ b/pypy/module/_continuation/interp_continuation.py
@@ -28,19 +28,28 @@
     def descr_init(self, w_callable, __args__):
         if self.sthread is not None:
             raise geterror(self.space, "continulet already __init__ialized")
+        #
+        # hackish: build the frame "by hand", passing it the correct arguments
+        space = self.space
+        w_args, w_kwds = __args__.topacked()
+        bottomframe = space.createframe(get_entrypoint_pycode(space),
+                                        get_w_module_dict(space), None)
+        bottomframe.locals_stack_w[0] = space.wrap(self)
+        bottomframe.locals_stack_w[1] = w_callable
+        bottomframe.locals_stack_w[2] = w_args
+        bottomframe.locals_stack_w[3] = w_kwds
+        self.bottomframe = bottomframe
+        #
         global_state.origin = self
-        global_state.w_callable = w_callable
-        global_state.args = __args__
-        self.bottomframe = make_fresh_frame(self.space)
-        self.sthread = build_sthread(self.space)
+        sthread = build_sthread(self.space)
+        self.sthread = sthread
         try:
-            self.h = self.sthread.new(new_stacklet_callback)
-            if self.sthread.is_empty_handle(self.h):    # early return
-                raise MemoryError
+            h = sthread.new(new_stacklet_callback)
         except MemoryError:
-            self.sthread = None
             global_state.clear()
             raise getmemoryerror(self.space)
+        #
+        post_switch(sthread, h)
 
     def switch(self, w_to):
         sthread = self.sthread
@@ -77,12 +86,12 @@
             global_state.destination = to
         #
         try:
-            do_switch(sthread, global_state.destination.h)
+            h = sthread.switch(global_state.destination.h)
         except MemoryError:
             global_state.clear()
             raise getmemoryerror(self.space)
         #
-        return get_result()
+        return post_switch(sthread, h)
 
     def descr_switch(self, w_value=None, w_to=None):
         global_state.w_value = w_value
@@ -161,15 +170,29 @@
 class State:
     def __init__(self, space):
         from pypy.interpreter.astcompiler.consts import CO_OPTIMIZED
-        self.space = space 
+        self.space = space
         w_module = space.getbuiltinmodule('_continuation')
         self.w_error = space.getattr(w_module, space.wrap('error'))
         self.w_memoryerror = OperationError(space.w_MemoryError, space.w_None)
-        self.dummy_pycode = PyCode(space, 0, 0, 0, CO_OPTIMIZED,
-                                   '', [], [], [], '',
-                                   '<bottom of continulet>', 0, '', [], [],
-                                   hidden_applevel=True)
+        # the following function switches away immediately, so that
+        # continulet.__init__() doesn't immediately run func(), but it
+        # also has the hidden purpose of making sure we have a single
+        # bottomframe for the whole duration of the continulet's run.
+        # Hackish: only the func_code is used, and used in the context
+        # of w_globals == this module, so we can access the name
+        # 'continulet' directly.
+        w_code = space.appexec([], '''():
+            def start(c, func, args, kwds):
+                if continulet.switch(c) is not None:
+                    raise TypeError(
+                     "can\'t send non-None value to a just-started continulet")
+                return func(c, *args, **kwds)
+            return start.func_code
+        ''')
+        self.entrypoint_pycode = space.interp_w(PyCode, w_code)
+        self.entrypoint_pycode.hidden_applevel = True
         self.w_unpickle = w_module.get('_p')
+        self.w_module_dict = w_module.getdict(space)
 
 def geterror(space, message):
     cs = space.fromcache(State)
@@ -179,9 +202,13 @@
     cs = space.fromcache(State)
     return cs.w_memoryerror
 
-def make_fresh_frame(space):
+def get_entrypoint_pycode(space):
     cs = space.fromcache(State)
-    return space.FrameClass(space, cs.dummy_pycode, None, None)
+    return cs.entrypoint_pycode
+
+def get_w_module_dict(space):
+    cs = space.fromcache(State)
+    return cs.w_module_dict
 
 def getunpickle(space):
     cs = space.fromcache(State)
@@ -206,8 +233,6 @@
     def clear(self):
         self.origin = None
         self.destination = None
-        self.w_callable = None
-        self.args = None
         self.w_value = None
         self.propagate_exception = None
 global_state = GlobalState()
@@ -215,27 +240,13 @@
 
 
 def new_stacklet_callback(h, arg):
-    self       = global_state.origin
-    w_callable = global_state.w_callable
-    args       = global_state.args
+    self = global_state.origin
+    self.h = h
     global_state.clear()
-    try:
-        do_switch(self.sthread, h)
-    except MemoryError:
-        return h       # oups!  do an early return in this case
-    #
     space = self.space
     try:
-        assert self.sthread.ec.topframeref() is None
-        self.sthread.ec.topframeref = jit.non_virtual_ref(self.bottomframe)
-        if global_state.propagate_exception is not None:
-            raise global_state.propagate_exception  # just propagate it further
-        if global_state.w_value is not space.w_None:
-            raise OperationError(space.w_TypeError, space.wrap(
-                "can't send non-None value to a just-started continulet"))
-
-        args = args.prepend(self.space.wrap(self))
-        w_result = space.call_args(w_callable, args)
+        frame = self.bottomframe
+        w_result = frame.execute_frame()
     except Exception, e:
         global_state.propagate_exception = e
     else:
@@ -246,8 +257,7 @@
     return self.h
 
 
-def do_switch(sthread, h):
-    h = sthread.switch(h)
+def post_switch(sthread, h):
     origin = global_state.origin
     self = global_state.destination
     global_state.origin = None
@@ -258,6 +268,8 @@
     sthread.ec.topframeref = self.bottomframe.f_backref
     self.bottomframe.f_backref = origin.bottomframe.f_backref
     origin.bottomframe.f_backref = current
+    #
+    return get_result()
 
 def get_result():
     if global_state.propagate_exception:
diff --git a/pypy/module/_continuation/test/test_stacklet.py b/pypy/module/_continuation/test/test_stacklet.py
--- a/pypy/module/_continuation/test/test_stacklet.py
+++ b/pypy/module/_continuation/test/test_stacklet.py
@@ -13,7 +13,7 @@
         from _continuation import continulet
         #
         def empty_callback(c):
-            pass
+            never_called
         #
         c = continulet(empty_callback)
         assert type(c) is continulet


More information about the pypy-commit mailing list