[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