[pypy-svn] r28366 - in pypy/dist/pypy: module/stackless translator/stackless translator/stackless/test
mwh at codespeak.net
mwh at codespeak.net
Tue Jun 6 13:19:47 CEST 2006
Author: mwh
Date: Tue Jun 6 13:19:45 2006
New Revision: 28366
Added:
pypy/dist/pypy/translator/stackless/test/test_coroutine_reconstruction.py (contents, props changed)
Modified:
pypy/dist/pypy/module/stackless/interp_coroutine.py
pypy/dist/pypy/translator/stackless/code.py
pypy/dist/pypy/translator/stackless/transform.py
Log:
(mwh, pedronis)
A test and implementation of building a coroutine by hand using the
resume_point machinery.
* add two resume_points in interp_coroutine.
* add names (for passing to resume_state_create) to all the prebuilt
restart points.
* this required making the stackless helpers and regular code use the same
frame types when the saved state erases to the same types.
* we advise against reading some of the new code in
StacklessTransfomer.__init__ (will clean up soon).
Modified: pypy/dist/pypy/module/stackless/interp_coroutine.py
==============================================================================
--- pypy/dist/pypy/module/stackless/interp_coroutine.py (original)
+++ pypy/dist/pypy/module/stackless/interp_coroutine.py Tue Jun 6 13:19:45 2006
@@ -30,7 +30,7 @@
"""
from pypy.interpreter.baseobjspace import Wrappable
-from pypy.rpython.rstack import yield_current_frame_to_caller
+from pypy.rpython.rstack import yield_current_frame_to_caller, resume_point
import sys, os
@@ -127,6 +127,7 @@
try:
costate.do_things_to_do()
thunk.call()
+ resume_point("coroutine__bind", self, state)
except CoroutineExit:
# ignore a shutdown exception
pass
@@ -146,6 +147,7 @@
raise CoroutineDamage
state = self.costate
incoming_frame = state.update(self).switch()
+ resume_point("coroutine_switch", self, state, returns=incoming_frame)
left = state.last
left.frame = incoming_frame
left.goodbye()
Modified: pypy/dist/pypy/translator/stackless/code.py
==============================================================================
--- pypy/dist/pypy/translator/stackless/code.py (original)
+++ pypy/dist/pypy/translator/stackless/code.py Tue Jun 6 13:19:45 2006
@@ -181,17 +181,14 @@
INDEX_CAPTURE = frame.RestartInfo.add_prebuilt(ll_stack_capture,
[EMPTY_STATE])
-RESUME_AFTER_STATE = frame.make_state_header_type('resume_after_state',
- ('c', lltype.Ptr(STATE_HEADER)),)
-
def resume_after_void(state, retvalue):
if global_state.restart_substate == -1:
# normal entry point for a call to state.switch()
# first unwind the stack
u = UnwindException()
- s = lltype.malloc(RESUME_AFTER_STATE)
+ s = lltype.malloc(SWITCH_STATE)
s.header.f_restart = INDEX_RESUME_AFTER_VOID
- s.c = lltype.cast_opaque_ptr(lltype.Ptr(STATE_HEADER), state)
+ s.c = lltype.cast_opaque_ptr(SAVED_REFERENCE, state)
add_frame_state(u, s.header)
raise u
elif global_state.restart_substate == 0:
@@ -201,8 +198,8 @@
# the 'targetstate' local is garbage here, it must be read back from
# 's.c' where we saved it by the normal entry point above
mystate = global_state.top
- s = lltype.cast_pointer(lltype.Ptr(RESUME_AFTER_STATE), mystate)
- targetstate = s.c
+ s = lltype.cast_pointer(lltype.Ptr(SWITCH_STATE), mystate)
+ targetstate = lltype.cast_opaque_ptr(lltype.Ptr(STATE_HEADER), s.c)
resume_bottom = targetstate
while resume_bottom.f_back:
resume_bottom = resume_bottom.f_back
@@ -212,7 +209,7 @@
resume_after_void.stackless_explicit = True
INDEX_RESUME_AFTER_VOID = frame.RestartInfo.add_prebuilt(resume_after_void,
- [RESUME_AFTER_STATE,
+ [SWITCH_STATE,
EMPTY_STATE])
@@ -221,9 +218,9 @@
# normal entry point for a call to state.switch()
# first unwind the stack
u = UnwindException()
- s = lltype.malloc(RESUME_AFTER_STATE)
+ s = lltype.malloc(SWITCH_STATE)
s.header.f_restart = INDEX_RESUME_AFTER_RAISING
- s.c = lltype.cast_opaque_ptr(lltype.Ptr(STATE_HEADER), state)
+ s.c = lltype.cast_opaque_ptr(SAVED_REFERENCE, state)
add_frame_state(u, s.header)
global_state.exception = exception
raise u
@@ -234,8 +231,8 @@
# the 'targetstate' local is garbage here, it must be read back from
# 's.c' where we saved it by the normal entry point above
mystate = global_state.top
- s = lltype.cast_pointer(lltype.Ptr(RESUME_AFTER_STATE), mystate)
- targetstate = s.c
+ s = lltype.cast_pointer(lltype.Ptr(SWITCH_STATE), mystate)
+ targetstate = lltype.cast_opaque_ptr(lltype.Ptr(STATE_HEADER), s.c)
resume_bottom = targetstate
while resume_bottom.f_back:
resume_bottom = resume_bottom.f_back
@@ -245,7 +242,7 @@
resume_after_raising.stackless_explicit = True
INDEX_RESUME_AFTER_RAISING = frame.RestartInfo.add_prebuilt(resume_after_raising,
- [RESUME_AFTER_STATE,
+ [SWITCH_STATE,
EMPTY_STATE])
template = """\
@@ -254,9 +251,9 @@
# normal entry point for a call to state.switch()
# first unwind the stack
u = UnwindException()
- s = lltype.malloc(RESUME_AFTER_STATE)
+ s = lltype.malloc(SWITCH_STATE)
s.header.f_restart = INDEX_RESUME_AFTER_%(TYPENAME)s
- s.c = lltype.cast_opaque_ptr(lltype.Ptr(STATE_HEADER), state)
+ s.c = lltype.cast_opaque_ptr(SAVED_REFERENCE, state)
global_state.retval_%(typename)s = retvalue
add_frame_state(u, s.header)
raise u
@@ -267,8 +264,8 @@
# the 'targetstate' local is garbage here, it must be read back from
# 's.c' where we saved it by the normal entry point above
mystate = global_state.top
- s = lltype.cast_pointer(lltype.Ptr(RESUME_AFTER_STATE), mystate)
- targetstate = s.c
+ s = lltype.cast_pointer(lltype.Ptr(SWITCH_STATE), mystate)
+ targetstate = lltype.cast_opaque_ptr(lltype.Ptr(STATE_HEADER), s.c)
resume_bottom = targetstate
while resume_bottom.f_back:
resume_bottom = resume_bottom.f_back
@@ -279,7 +276,7 @@
resume_after_%(typename)s.stackless_explicit = True
INDEX_RESUME_AFTER_%(TYPENAME)s = frame.RestartInfo.add_prebuilt(resume_after_%(typename)s,
- [RESUME_AFTER_STATE,
+ [SWITCH_STATE,
EMPTY_STATE])
"""
Added: pypy/dist/pypy/translator/stackless/test/test_coroutine_reconstruction.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/stackless/test/test_coroutine_reconstruction.py Tue Jun 6 13:19:45 2006
@@ -0,0 +1,61 @@
+from pypy.module.stackless import interp_coroutine
+from pypy.rpython import rstack
+from pypy.rpython.rstack import resume_state_create
+from pypy.translator.stackless.test.test_transform import llinterp_stackless_function
+from pypy.rpython.lltypesystem.lloperation import llop
+from pypy.rpython.lltypesystem import lltype
+
+class TestCoroutineReconstruction:
+
+ def setup_meth(self):
+ interp_coroutine.costate.__init__()
+
+ def test_simple_ish(self):
+
+ output = []
+ def f(coro, n, x):
+ if n == 0:
+ coro.switch()
+ rstack.resume_point("f_0")
+ return
+ f(coro, n-1, 2*x)
+ rstack.resume_point("f_1", coro, n, x)
+ output.append(x)
+
+ class T(interp_coroutine.AbstractThunk):
+ def __init__(self, arg_coro, arg_n, arg_x):
+ self.arg_coro = arg_coro
+ self.arg_n = arg_n
+ self.arg_x = arg_x
+ def call(self):
+ f(self.arg_coro, self.arg_n, self.arg_x)
+
+ def example():
+ main_coro = interp_coroutine.costate.main
+ sub_coro = interp_coroutine.Coroutine()
+ thunk_f = T(main_coro, 5, 1)
+ sub_coro.bind(thunk_f)
+ sub_coro.switch()
+
+ new_coro = interp_coroutine.Coroutine()
+ new_thunk_f = T(main_coro, 5, 1)
+ new_coro.bind(new_thunk_f)
+
+ bottom = resume_state_create(None, "yield_current_frame_to_caller_1")
+ _bind_frame = resume_state_create(bottom, "coroutine__bind", new_coro, interp_coroutine.costate)
+ f_frame_1 = resume_state_create(_bind_frame, "f_1", main_coro, 5, 1)
+ f_frame_2 = resume_state_create(f_frame_1, "f_1", main_coro, 4, 2)
+ f_frame_3 = resume_state_create(f_frame_2, "f_1", main_coro, 3, 4)
+ f_frame_4 = resume_state_create(f_frame_3, "f_1", main_coro, 2, 8)
+ f_frame_5 = resume_state_create(f_frame_4, "f_1", main_coro, 1, 16)
+ f_frame_0 = resume_state_create(f_frame_5, "f_0")
+ switch_frame = resume_state_create(f_frame_0, "coroutine_switch", new_coro, interp_coroutine.costate)
+
+ new_coro.frame = switch_frame
+
+ new_coro.switch()
+ return output == [16, 8, 4, 2, 1]
+
+ res = llinterp_stackless_function(example)
+ assert res == 1
+
Modified: pypy/dist/pypy/translator/stackless/transform.py
==============================================================================
--- pypy/dist/pypy/translator/stackless/transform.py (original)
+++ pypy/dist/pypy/translator/stackless/transform.py Tue Jun 6 13:19:45 2006
@@ -83,11 +83,11 @@
def __init__(self):
self.frametypes = {}
- def frame_type_for_vars(self, vars):
+ def _key_fieldnames_for_types(self, types):
fieldnames = []
counts = {}
- for v in vars:
- t = storage_type(v.concretetype)
+ for tt in types:
+ t = storage_type(tt)
if t is lltype.Void:
fieldnames.append(None)
else:
@@ -95,12 +95,31 @@
fieldnames.append('state_%s_%d' % (STORAGE_FIELDS[t], n))
counts[t] = n + 1
key = lltype.frozendict(counts)
+ return key, fieldnames
+
+
+ def frame_type_for_vars(self, vars):
+ key, fieldnames = self._key_fieldnames_for_types([v.concretetype for v in vars])
if key in self.frametypes:
T = self.frametypes[key]
+ it = iter(T._names[1:])
+ rfieldnames = []
+ for name in fieldnames:
+ if name is None:
+ rfieldnames.append(None)
+ else:
+ rfieldnames.append(it.next())
+ try:
+ it.next()
+ except StopIteration:
+ pass
+ else:
+ assert False, "field name count mismatch"
+ return T, rfieldnames
else:
fields = []
for t in STORAGE_TYPES:
- for j in range(counts.get(t, 0)):
+ for j in range(key.get(t, 0)):
fields.append(('state_%s_%d' % (STORAGE_FIELDS[t], j), t))
T = frame.make_state_header_type("FrameState", *fields)
self.frametypes[key] = T
@@ -299,8 +318,25 @@
self.symbolic_restart_numbers = {}
- # register the prebuilt restartinfos
+ # register the prebuilt restartinfos & give them names for use
+ # with resume_state_create
+ # the mauling of frame_typer internals should be a method on FrameTyper.
for restartinfo in frame.RestartInfo.prebuilt:
+ name = restartinfo.func_or_graph.__name__
+ for i in range(len(restartinfo.frame_types)):
+ label = name + '_' + str(i)
+ assert label not in self.symbolic_restart_numbers
+ # XXX we think this is right:
+ self.symbolic_restart_numbers[label] = SymbolicRestartNumber(
+ label, len(self.masterarray1) + i)
+ frame_type = restartinfo.frame_types[i]
+ self.explicit_resume_point_data[label] = frame_type
+ key, fieldnames = self.frametyper._key_fieldnames_for_types(
+ [frame_type._flds[n] for n in frame_type._names[1:]])
+ assert len(fieldnames) <= 1, "nasty field ordering issues need to be solved XXX mwh, pedronis"
+ if key in self.frametyper.frametypes:
+ assert self.frametyper.frametypes[key] is frame_type
+ self.frametyper.frametypes[key] = frame_type
self.register_restart_info(restartinfo)
def transform_all(self):
@@ -475,12 +511,12 @@
for a in args:
if a not in parms:
raise Exception, "not covered needed value at resume_point"
- if parms[0] is not None: # returns= case
- res = parms[0]
- args = [arg for arg in args if arg is not res]
- else:
- args = args
- res = op.result
+ if parms[0] is not None: # returns= case
+ res = parms[0]
+ args = [arg for arg in args if arg is not res]
+ else:
+ args = args
+ res = op.result
(frame_type,
fieldnames) = self.frametyper.frame_type_for_vars(parms[1:])
More information about the Pypy-commit
mailing list