[pypy-svn] r64095 - in pypy/trunk/pypy/translator/stackless: . test

arigo at codespeak.net arigo at codespeak.net
Wed Apr 15 14:55:38 CEST 2009


Author: arigo
Date: Wed Apr 15 14:55:37 2009
New Revision: 64095

Modified:
   pypy/trunk/pypy/translator/stackless/code.py
   pypy/trunk/pypy/translator/stackless/frame.py
   pypy/trunk/pypy/translator/stackless/test/test_coroutine_reconstruction.py
   pypy/trunk/pypy/translator/stackless/test/test_depth.py
   pypy/trunk/pypy/translator/stackless/transform.py
Log:
(niko, arigo)
Keep track of the stack depth in the STATE_HEADER structures.
For now only used to make stack_frames_depth() constant-time.


Modified: pypy/trunk/pypy/translator/stackless/code.py
==============================================================================
--- pypy/trunk/pypy/translator/stackless/code.py	(original)
+++ pypy/trunk/pypy/translator/stackless/code.py	Wed Apr 15 14:55:37 2009
@@ -35,10 +35,11 @@
         sourcestate = lltype.malloc(EMPTY_STATE).header
         sourcestate.f_back = mystate.f_back
         sourcestate.f_restart = INDEX_SWITCH + 1
+        sourcestate.f_depth = mystate.f_depth
         global_state.top = targetstate
         global_state.retval_ref = lltype.cast_opaque_ptr(SAVED_REFERENCE,
                                                          sourcestate)
-        raise UnwindException()   # this jumps to targetstate
+        raise SwitchException()   # this jumps to targetstate
     else:
         # STATE 1: switching back into a tasklet suspended by
         # a call to switch()
@@ -71,15 +72,17 @@
         ycftc_state = global_state.top
         our_caller_state = ycftc_state.f_back
         caller_state = our_caller_state.f_back
+        caller_state.f_depth = ycftc_state.f_depth - 2
         # when our immediate caller finishes (which is later, when the
         # tasklet finishes), then we will jump to 'STATE 1' below
         endstate = lltype.malloc(EMPTY_STATE).header
         endstate.f_restart = INDEX_YCFTC + 1
         our_caller_state.f_back = endstate
+        our_caller_state.f_depth = 1
         global_state.top = caller_state
         global_state.retval_ref = lltype.cast_opaque_ptr(SAVED_REFERENCE,
                                                          our_caller_state)
-        raise UnwindException()  # this goes to the caller's caller
+        raise SwitchException()  # this goes to the caller's caller
 
     elif global_state.restart_substate == 1:
         # STATE 1: this is a slight abuse of yield_current_frame_to_caller(),
@@ -91,7 +94,7 @@
         # return a NULL state pointer to the target of the implicit switch
         global_state.top = next_state
         global_state.retval_ref = frame.null_saved_ref
-        raise UnwindException()  # this goes to the switch target given by
+        raise SwitchException()  # this goes to the switch target given by
                                  # the 'return' at the end of our caller
 
     else:
@@ -123,11 +126,7 @@
         cur = global_state.top
         global_state.top = frame.null_state
         global_state.restart_substate = -1
-        depth = 0
-        while cur:
-            depth += 1
-            cur = cur.f_back
-        return depth
+        return cur.f_depth
 stack_frames_depth.stackless_explicit = True
 
 INDEX_DEPTH = frame.RestartInfo.add_prebuilt(stack_frames_depth,
@@ -205,7 +204,7 @@
              resume_bottom = resume_bottom.f_back
         resume_bottom.f_back = mystate.f_back
         global_state.top = targetstate
-        raise UnwindException()
+        raise SwitchException()
 
 resume_after_void.stackless_explicit = True
 INDEX_RESUME_AFTER_VOID = frame.RestartInfo.add_prebuilt(resume_after_void,
@@ -238,7 +237,7 @@
              resume_bottom = resume_bottom.f_back
         resume_bottom.f_back = mystate.f_back
         global_state.top = targetstate
-        raise UnwindException()
+        raise SwitchException()
 
 resume_after_raising.stackless_explicit = True
 INDEX_RESUME_AFTER_RAISING = frame.RestartInfo.add_prebuilt(resume_after_raising,
@@ -271,7 +270,7 @@
              resume_bottom = resume_bottom.f_back
         resume_bottom.f_back = mystate.f_back
         global_state.top = targetstate
-        raise UnwindException()
+        raise SwitchException()
 
 
 resume_after_%(typename)s.stackless_explicit = True
@@ -351,23 +350,32 @@
         # UnwindException first, to empty the C stack, and then issues a
         # (XXX complete this comment)
         self.frame_bottom = frame.null_state
+        self.depth = 0
     __init__.stackless_explicit = True
 
-def slp_main_loop():
+class SwitchException(lloperation.StackException):
+    pass
+
+def slp_main_loop(depth):
     """
     slp_main_loop() keeps resuming...
     """
     pending = global_state.top
+    pending.f_depth = depth        # this starts after the first Unwind
     
     while True:
+        prevdepth = pending.f_depth - 1
         back = pending.f_back
         decoded = frame.decodestate(pending.f_restart)
         (fn, global_state.restart_substate, signature_index) = decoded
         try:
             call_function(fn, signature_index)
         except UnwindException, u:   #XXX annotation support needed
-            if u.frame_bottom:
-                u.frame_bottom.f_back = back
+            u.frame_bottom.f_back = back
+            pending = global_state.top
+            pending.f_depth = prevdepth + u.depth
+            continue
+        except SwitchException:
             pending = global_state.top
             continue
         except Exception, e:
@@ -378,6 +386,7 @@
             if not back:
                 return
         global_state.top = pending = back
+        pending.f_depth = prevdepth
 
 slp_main_loop.stackless_explicit = True
 
@@ -387,6 +396,7 @@
     else:
         u.frame_bottom.f_back = frame_state
         u.frame_bottom = frame_state
+    u.depth += 1
 add_frame_state.stackless_explicit = True
 
 def fetch_retval_void():

Modified: pypy/trunk/pypy/translator/stackless/frame.py
==============================================================================
--- pypy/trunk/pypy/translator/stackless/frame.py	(original)
+++ pypy/trunk/pypy/translator/stackless/frame.py	Wed Apr 15 14:55:37 2009
@@ -64,7 +64,8 @@
 
 STATE_HEADER = lltype.GcStruct('state_header',
                            ('f_back', lltype.Ptr(lltype.GcForwardReference())),
-                           ('f_restart', lltype.Signed))
+                           ('f_restart', lltype.Signed),
+                           ('f_depth', lltype.Signed))
 STATE_HEADER.f_back.TO.become(STATE_HEADER)
 
 null_state = lltype.nullptr(STATE_HEADER)

Modified: pypy/trunk/pypy/translator/stackless/test/test_coroutine_reconstruction.py
==============================================================================
--- pypy/trunk/pypy/translator/stackless/test/test_coroutine_reconstruction.py	(original)
+++ pypy/trunk/pypy/translator/stackless/test/test_coroutine_reconstruction.py	Wed Apr 15 14:55:37 2009
@@ -17,6 +17,7 @@
             if n == 0:
                 coro.switch()
                 rstack.resume_point("f_0")
+                assert rstack.stack_frames_depth() == 9
                 return
             f(coro, n-1, 2*x)
             rstack.resume_point("f_1", coro, n, x)

Modified: pypy/trunk/pypy/translator/stackless/test/test_depth.py
==============================================================================
--- pypy/trunk/pypy/translator/stackless/test/test_depth.py	(original)
+++ pypy/trunk/pypy/translator/stackless/test/test_depth.py	Wed Apr 15 14:55:37 2009
@@ -114,3 +114,66 @@
         return count10 - count0
     res = llinterp_stackless_function(fn)
     assert res == 0
+
+
+def test_depth_bug():
+    def g(base):
+        print rstack.stack_frames_depth()
+        return rstack.stack_frames_depth() - base
+    def fn():
+        base = rstack.stack_frames_depth()
+        print base
+        base = rstack.stack_frames_depth()
+        print base
+        return g(base) + 100
+    res = llinterp_stackless_function(fn)
+    assert res == 101
+
+def test_depth_along_yield_frame():
+
+    def h():
+        x = rstack.stack_frames_depth()
+        x += 1      # don't remove! otherwise it becomes a tail call
+        x -= 1
+        return x
+
+    def g(base, lst):
+        lst.append(rstack.stack_frames_depth() - base)
+        #print lst
+        frametop_before_5 = rstack.yield_current_frame_to_caller()
+        lst.append(h())
+        frametop_before_7 = frametop_before_5.switch()
+        lst.append(rstack.stack_frames_depth())
+        return frametop_before_7
+
+    def f(base):
+        lst = [rstack.stack_frames_depth() - base]
+        #print lst
+        frametop_before_4 = g(base, lst)
+        lst.append(rstack.stack_frames_depth() - base)
+        #print lst
+        frametop_before_6 = frametop_before_4.switch()
+        lst.append(h() - base)
+        frametop_after_return = frametop_before_6.switch()
+        lst.append(rstack.stack_frames_depth() - base)
+        assert not frametop_after_return
+        n = 0
+        for i in lst:
+            n = n*10 + i
+        return n
+
+    def loop(base, n):
+        if n > 0:
+            return loop(base, n-1) + 1
+        else:
+            return f(base) + 1
+
+    def entrypoint():
+        base = rstack.stack_frames_depth()
+        return loop(base, 5) - 6
+
+    data = llinterp_stackless_function(entrypoint)
+    assert data == 7874837
+
+    res = run_stackless_function(entrypoint)
+    assert res == 7874837

Modified: pypy/trunk/pypy/translator/stackless/transform.py
==============================================================================
--- pypy/trunk/pypy/translator/stackless/transform.py	(original)
+++ pypy/trunk/pypy/translator/stackless/transform.py	Wed Apr 15 14:55:37 2009
@@ -243,9 +243,8 @@
 
 
 class StacklessAnalyzer(graphanalyze.GraphAnalyzer):
-    def __init__(self, translator, unwindtype, stackless_gc):
+    def __init__(self, translator, stackless_gc):
         graphanalyze.GraphAnalyzer.__init__(self, translator)
-        self.unwindtype = unwindtype
         self.stackless_gc = stackless_gc
 
     def operation_is_true(self, op):
@@ -303,9 +302,7 @@
         self.unwind_exception_type = getinstancerepr(
             self.translator.rtyper,
             bk.getuniqueclassdef(code.UnwindException)).lowleveltype
-        self.analyzer = StacklessAnalyzer(translator,
-                                          self.unwind_exception_type,
-                                          stackless_gc)
+        self.analyzer = StacklessAnalyzer(translator, stackless_gc)
 
         # the point of this little dance is to not annotate
         # code.global_state.masterarray as a constant.
@@ -322,7 +319,7 @@
                 try:
                     r = entrypoint(argv)
                 except code.UnwindException, u:
-                    code.slp_main_loop()
+                    code.slp_main_loop(u.depth)
                     return code.global_state.retval_long
                 else:
                     assert False, "entrypoint never unwound the stack"
@@ -333,7 +330,7 @@
                 try:
                     r = entrypoint(argv)
                 except code.UnwindException, u:
-                    code.slp_main_loop()
+                    code.slp_main_loop(u.depth)
                     return code.global_state.retval_long
                 return r
             slp_entry_point.stackless_explicit = True
@@ -423,6 +420,17 @@
         self.exception_type = getinstancerepr(
             self.translator.rtyper, exception_def).lowleveltype
 
+        def set_back_pointer(frame, back):
+            frame.f_back = back
+            if back:
+                frame.f_depth = back.f_depth + 1
+            else:
+                frame.f_depth = 0
+        self.set_back_pointer_ptr = mixlevelannotator.constfunc(
+            set_back_pointer,
+            [s_hdrptr, s_hdrptr],
+            annmodel.s_None)
+
         mixlevelannotator.finish()
 
         s_global_state = bk.immutablevalue(code.global_state)
@@ -653,6 +661,9 @@
         c_flags = model.Constant({'flavor': 'gc'}, lltype.Void)
         v_exc = llops.genop('malloc', [c_EXC, c_flags],
                             resulttype = self.unwind_exception_type)
+        llops.genop('setfield', [v_exc,
+                                 model.Constant('inst_depth', lltype.Void),
+                                 model.Constant(0, lltype.Signed)])
 
         realvarsforcall = []
         for v in varsforcall:
@@ -672,9 +683,8 @@
                     [self.ll_global_state, self.c_inst_top_name, self.c_null_state])
 
         v_prevstate = gen_cast(llops, lltype.Ptr(frame.STATE_HEADER), op.args[0])
-        llops.genop('setfield', [v_state_hdr,
-                                 model.Constant('f_back', lltype.Void),
-                                 v_prevstate])
+        llops.genop('direct_call', [self.set_back_pointer_ptr,
+                                    v_state_hdr, v_prevstate])
         llops.append(model.SpaceOperation('cast_opaque_ptr', [v_state_hdr], op.result))
         block.operations[i:i+1] = llops
 



More information about the Pypy-commit mailing list