[pypy-svn] r27522 - in pypy/branch/explicit_resume_pt_experiment: annotation rpython rpython/lltypesystem translator/stackless translator/stackless/test
pedronis at codespeak.net
pedronis at codespeak.net
Sun May 21 04:36:54 CEST 2006
Author: pedronis
Date: Sun May 21 04:36:43 2006
New Revision: 27522
Added:
pypy/branch/explicit_resume_pt_experiment/translator/stackless/test/test_resume_point.py (contents, props changed)
Modified:
pypy/branch/explicit_resume_pt_experiment/annotation/builtin.py
pypy/branch/explicit_resume_pt_experiment/rpython/llinterp.py
pypy/branch/explicit_resume_pt_experiment/rpython/lltypesystem/lloperation.py
pypy/branch/explicit_resume_pt_experiment/rpython/lltypesystem/rbuiltin.py
pypy/branch/explicit_resume_pt_experiment/rpython/objectmodel.py
pypy/branch/explicit_resume_pt_experiment/translator/stackless/code.py
pypy/branch/explicit_resume_pt_experiment/translator/stackless/transform.py
Log:
rough experiment on explicit resume points with stackless transformed code:
primitives:
resume_point(LABEL, values to restore vars, [returs=var])
resume_after(TYP, LABEL, values for var to restore [returns=value for return])
the first test in test_resume_point works on the llinterp.
too unpolished/incomplete for the trunk tough. there are also some open issues. There may be oversights
and some things are quite hackish: I wanted to quickly explore how hard this would be.
Modified: pypy/branch/explicit_resume_pt_experiment/annotation/builtin.py
==============================================================================
--- pypy/branch/explicit_resume_pt_experiment/annotation/builtin.py (original)
+++ pypy/branch/explicit_resume_pt_experiment/annotation/builtin.py Sun May 21 04:36:43 2006
@@ -298,6 +298,13 @@
def robjmodel_hint(s, **kwds_s):
return s
+def robjmodel_resume_point(label, *args_s, **kwds_s):
+ return immutablevalue(None)
+
+def robjmodel_resume_after(s_typ, label, *args_s, **kwds_s):
+ assert s_typ.is_constant()
+ return getbookkeeper().valueoftype(s_typ.const)
+
def llmemory_cast_ptr_to_adr(s):
return SomeAddress()
@@ -357,6 +364,8 @@
BUILTIN_ANALYZERS[pypy.rpython.objectmodel.hlinvoke] = robjmodel_hlinvoke
BUILTIN_ANALYZERS[pypy.rpython.objectmodel.keepalive_until_here] = robjmodel_keepalive_until_here
BUILTIN_ANALYZERS[pypy.rpython.objectmodel.hint] = robjmodel_hint
+BUILTIN_ANALYZERS[pypy.rpython.objectmodel.resume_point] = robjmodel_resume_point
+BUILTIN_ANALYZERS[pypy.rpython.objectmodel.resume_after] = robjmodel_resume_after
BUILTIN_ANALYZERS[pypy.rpython.lltypesystem.llmemory.cast_ptr_to_adr] = llmemory_cast_ptr_to_adr
BUILTIN_ANALYZERS[pypy.rpython.lltypesystem.llmemory.cast_adr_to_ptr] = llmemory_cast_adr_to_ptr
BUILTIN_ANALYZERS[pypy.rpython.lltypesystem.llmemory.cast_adr_to_int] = llmemory_cast_adr_to_int
Modified: pypy/branch/explicit_resume_pt_experiment/rpython/llinterp.py
==============================================================================
--- pypy/branch/explicit_resume_pt_experiment/rpython/llinterp.py (original)
+++ pypy/branch/explicit_resume_pt_experiment/rpython/llinterp.py Sun May 21 04:36:43 2006
@@ -423,6 +423,9 @@
def op_hint(self, x, hints):
return x
+ def op_resume_point(self, *args):
+ pass
+
def op_decode_arg(self, fname, i, name, vargs, vkwds):
raise NotImplementedError("decode_arg")
Modified: pypy/branch/explicit_resume_pt_experiment/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/explicit_resume_pt_experiment/rpython/lltypesystem/lloperation.py (original)
+++ pypy/branch/explicit_resume_pt_experiment/rpython/lltypesystem/lloperation.py Sun May 21 04:36:43 2006
@@ -343,6 +343,9 @@
'yield_current_frame_to_caller': LLOp(canraise=(StackException,)),
# can always unwind, not just if stackless gc
+ 'resume_point': LLOp(canraise=(StackException,)),
+ 'resume_after': LLOp(canraise=(Exception, StackException)),
+
# __________ misc operations __________
'keepalive': LLOp(),
Modified: pypy/branch/explicit_resume_pt_experiment/rpython/lltypesystem/rbuiltin.py
==============================================================================
--- pypy/branch/explicit_resume_pt_experiment/rpython/lltypesystem/rbuiltin.py (original)
+++ pypy/branch/explicit_resume_pt_experiment/rpython/lltypesystem/rbuiltin.py Sun May 21 04:36:43 2006
@@ -59,8 +59,46 @@
c = hop.inputconst(pyobj_repr, __import__)
return hop.genop('simple_call', [c] + args_v, resulttype = pyobj_repr)
+def rtype_resume_point(hop, **kwds_i):
+ assert hop.args_s[0].is_constant()
+ c_label = hop.inputconst(lltype.Void, hop.args_s[0].const)
+ args_v = hop.args_v[1:]
+ if 'i_returns' in kwds_i:
+ assert len(kwds_i) == 1
+ returns_index = kwds_i['i_returns']
+ v_return = args_v.pop(returns_index-1)
+ else:
+ assert not kwds_i
+ v_return = hop.inputconst(lltype.Void, None)
+
+ hop.exception_is_here()
+ return hop.genop('resume_point', [c_label, v_return] + args_v,
+ hop.r_result)
+
+def rtype_resume_after(hop, **kwds_i):
+ # xxx hack, can do this in transform
+ assert hop.args_s[1].is_constant()
+ c_label = hop.inputconst(lltype.Void, hop.args_s[1].const)
+ args_v = hop.args_v[2:]
+ if 'i_returns' in kwds_i:
+ assert len(kwds_i) == 1
+ returns_index = kwds_i['i_returns']
+ v_return = args_v.pop(returns_index-1)
+ else:
+ assert not kwds_i
+ v_return = hop.inputconst(lltype.Void, None)
+
+ from pypy.rpython.lltypesystem import llmemory
+ v_state = hop.genop('resume_after_prepare', [c_label] + args_v,
+ llmemory.GCREF)
+ hop.exception_is_here()
+ return hop.genop('resume_after', [v_state, v_return],
+ hop.r_result)
+
BUILTIN_TYPER = {}
BUILTIN_TYPER[objectmodel.instantiate] = rtype_instantiate
BUILTIN_TYPER[isinstance] = rtype_builtin_isinstance
BUILTIN_TYPER[hasattr] = rtype_builtin_hasattr
BUILTIN_TYPER[__import__] = rtype_builtin___import__
+BUILTIN_TYPER[objectmodel.resume_point] = rtype_resume_point
+BUILTIN_TYPER[objectmodel.resume_after] = rtype_resume_after
Modified: pypy/branch/explicit_resume_pt_experiment/rpython/objectmodel.py
==============================================================================
--- pypy/branch/explicit_resume_pt_experiment/rpython/objectmodel.py (original)
+++ pypy/branch/explicit_resume_pt_experiment/rpython/objectmodel.py Sun May 21 04:36:43 2006
@@ -53,6 +53,11 @@
def hint(x, **kwds):
return x
+def resume_point(label, *args, **kwds):
+ pass
+
+def resume_after(typ, label, *args, **kwds):
+ pass
class FREED_OBJECT(object):
def __getattribute__(self, attr):
Modified: pypy/branch/explicit_resume_pt_experiment/translator/stackless/code.py
==============================================================================
--- pypy/branch/explicit_resume_pt_experiment/translator/stackless/code.py (original)
+++ pypy/branch/explicit_resume_pt_experiment/translator/stackless/code.py Sun May 21 04:36:43 2006
@@ -190,6 +190,48 @@
# ____________________________________________________________
+# xxx combination mess
+
+def resume_after_long(state, retvalue):
+ return 0
+
+resume_after_long.stackless_explicit = True
+INDEX_RESUME_AFTER_LONG = frame.RestartInfo.add_prebuilt(resume_after_long,
+ [EMPTY_STATE])
+
+RESUME_AFTER_STATE = frame.make_state_header_type('resume_after_state',
+ ('c', SAVED_REFERENCE),)
+
+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.header.f_restart = INDEX_RESUME_AFTER_VOID
+ s.c = state
+ add_frame_state(u, s.header)
+ raise u
+ elif global_state.restart_substate == 0:
+ # STATE 0: we didn't do anything so far, but the stack is unwound
+ global_state.restart_substate = -1
+ # grab the frame corresponding to ourself
+ # 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 = lltype.cast_opaque_ptr(lltype.Ptr(STATE_HEADER), s.c)
+ targetstate.f_back = mystate.f_back
+ global_state.top = targetstate
+ raise UnwindException()
+ else:
+ return 0
+
+resume_after_void.stackless_explicit = True
+INDEX_RESUME_AFTER_VOID = frame.RestartInfo.add_prebuilt(resume_after_void,
+ [RESUME_AFTER_STATE,
+ EMPTY_STATE])
+
class StacklessData:
def __init__(self):
self.top = frame.null_state
Added: pypy/branch/explicit_resume_pt_experiment/translator/stackless/test/test_resume_point.py
==============================================================================
--- (empty file)
+++ pypy/branch/explicit_resume_pt_experiment/translator/stackless/test/test_resume_point.py Sun May 21 04:36:43 2006
@@ -0,0 +1,72 @@
+from pypy.rpython.objectmodel import resume_point, resume_after
+from pypy.translator.stackless.transform import StacklessTransformer
+from pypy.translator.stackless.test.test_transform import llinterp_stackless_function, rtype_stackless_function, one
+from pypy import conftest
+import py
+from pypy.rpython import rstack
+
+def transform_stackless_function(fn):
+ def wrapper(argv):
+ return fn()
+ t = rtype_stackless_function(wrapper)
+ st = StacklessTransformer(t, wrapper, False)
+ st.transform_all()
+ if conftest.option.view:
+ t.view()
+
+def test_no_call():
+ def f(x, y):
+ x = x-1
+ resume_point("rp0", x, y)
+ r = x+y
+ rstack.stack_unwind()
+ return r
+ def example():
+ v1 = f(one(),one()+one())
+ v2 = resume_after(int, "rp0", one(), one()+one()+one())
+ return v1*10 + v2
+ res = llinterp_stackless_function(example, assert_unwind=False)
+ assert res == 24
+
+def test_call():
+ def g(x,y):
+ return x*y
+ def f(x, y):
+ z = g(x,y)
+ resume_point("rp1", y, returns=z)
+ return z+y
+ def example():
+ f(one(),one()+one())
+ return 0
+ transform_stackless_function(example)
+
+def test_call_exception_handling():
+ def g(x,y):
+ if x == 0:
+ raise KeyError
+ return x*y
+ def f(x, y):
+ try:
+ z = g(x,y)
+ resume_point("rp1", y, returns=z)
+ except KeyError:
+ return 0
+ return z+y
+ def example():
+ f(one(),one()+one())
+ return 0
+ transform_stackless_function(example)
+
+def test_call_uncovered():
+ def g(x,y):
+ return x*y
+ def f(x, y):
+ z = g(x,y)
+ resume_point("rp1", y, returns=z)
+ return z+y+x
+ def example():
+ f(one(),one()+one())
+ return 0
+ e = py.test.raises(Exception, transform_stackless_function, example)
+ assert e.value.args == ('not covered needed value at resume_point',)
+
Modified: pypy/branch/explicit_resume_pt_experiment/translator/stackless/transform.py
==============================================================================
--- pypy/branch/explicit_resume_pt_experiment/translator/stackless/transform.py (original)
+++ pypy/branch/explicit_resume_pt_experiment/translator/stackless/transform.py Sun May 21 04:36:43 2006
@@ -100,6 +100,10 @@
def operation_is_true(self, op):
if op.opname == 'yield_current_frame_to_caller':
return True
+ if op.opname == 'resume_point':
+ return True
+ if op.opname.startswith('resume_after'):
+ return True
return self.stackless_gc and LL_OPERATIONS[op.opname].canunwindgc
def analyze_external_call(self, op):
@@ -210,6 +214,15 @@
self.yield_current_frame_to_caller_ptr = mixlevelannotator.constfunc(
code.yield_current_frame_to_caller, [], s_StatePtr)
+ # resume_after
+ self.resume_after_long_ptr = mixlevelannotator.constfunc(
+ code.resume_after_long, [annmodel.SomePtr(llmemory.GCREF),
+ annmodel.SomeInteger()],
+ annmodel.SomeInteger())
+ self.resume_after_void_ptr = mixlevelannotator.constfunc(
+ code.resume_after_void, [annmodel.SomePtr(llmemory.GCREF),
+ annmodel.s_None],
+ annmodel.SomeInteger())
mixlevelannotator.finish()
@@ -232,6 +245,10 @@
self.reccopyannotator = MixLevelHelperAnnotator(translator.rtyper)
+ self.explicit_resume_points = {}
+
+ self.explicit_resume_after = []
+
# register the prebuilt restartinfos
for restartinfo in frame.RestartInfo.prebuilt:
self.register_restart_info(restartinfo)
@@ -407,9 +424,75 @@
if op.opname == 'yield_current_frame_to_caller':
op = replace_with_call(self.yield_current_frame_to_caller_ptr)
stackless_op = True
+ if op.opname == 'resume_after': # xxx
+ if op.result.concretetype != lltype.Signed:
+ raise NotImplementedError
+ v_returns = op.args[1]
+ if v_returns.concretetype == lltype.Signed:
+ raise NotImplementedError
+ elif v_returns.concretetype == lltype.Void:
+ args = [self.resume_after_void_ptr] + op.args
+ newop = model.SpaceOperation('direct_call', args, op.result)
+ block.operations[i] = newop
+ else:
+ raise NotImplementedError
+ stackeless_op = True
if (op.opname in ('direct_call', 'indirect_call')
or self.analyzer.operation_is_true(op)):
+ # XXX special casing with duplication for now
+ if op.opname == 'resume_point':
+ if i == len(block.operations) - 1:
+ link = block.exits[0]
+ else:
+ link = support.split_block_with_keepalive(block, i+1)
+ parms = op.args[1:]
+ if not isinstance(parms[0], model.Variable):
+ assert parms[0].value is None
+ parms[0] = None
+
+ args = []
+ for l in block.exits:
+ for arg in l.args:
+ if isinstance(arg, model.Variable) \
+ and arg.concretetype is not lltype.Void \
+ and arg is not op.result \
+ and arg not in args \
+ and arg not in [l.last_exception, l.last_exc_value]:
+ args.append(arg)
+ if arg 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
+
+ (frame_type,
+ fieldnames) = self.frametyper.frame_type_for_vars(args)
+
+ self.resume_points.append(
+ ResumePoint(res, args, tuple(block.exits),
+ frame_type, fieldnames))
+
+ field2parm = {}
+ for arg, fieldname in zip(args, fieldnames):
+ p = parms.index(arg)
+ field2parm[fieldname] = p-1 # ignore parm[0]
+
+ label = op.args[0].value
+ self.explicit_resume_points[label] = {
+ 'restart': len(self.masterarray1) + len(self.resume_points)-1,
+ 'frame_type': frame_type,
+ 'restype': res.concretetype,
+ 'field2parm': field2parm,
+ }
+ block = link.target
+ i = 0
+ continue
+
+
# trap calls to stackless-related suggested primitives
if op.opname == 'direct_call':
func = getattr(op.args[0].value._obj, '_callable', None)
@@ -487,6 +570,9 @@
block.recloseblock(*newexits)
self.translator.rtyper._convert_link(block, newlink)
+ if op.opname == "resume_after_prepare":
+ self.explicit_resume_after.append((block, i))
+
block = link.target
i = 0
else:
@@ -594,6 +680,34 @@
# (shorter, though)
ll_global_state = self.ll_global_state.value
ll_global_state.inst_masterarray = masterarray
+
+ # XXX when to do this properly with genc is a bit open
+ # xxx attach exception handling properly to malloc
+ for block, i in self.explicit_resume_after:
+ assert len(block.operations) == i+1
+ op = block.operations[i]
+ llops = LowLevelOpList()
+ label = op.args[0].value
+ data = self.explicit_resume_points[label]
+ FRAME = data['frame_type']
+ c_FRAME = model.Constant(FRAME, lltype.Void)
+ v_state = llops.genop('malloc', [c_FRAME],
+ resulttype = lltype.Ptr(FRAME))
+ for fieldname, p in data['field2parm'].items():
+ llops.genop('setfield', [v_state,
+ model.Constant(fieldname, lltype.Void),
+ op.args[1+p]])
+ v_state = llops.genop('cast_pointer', [v_state],
+ resulttype = lltype.Ptr(frame.STATE_HEADER))
+ llops.genop('setfield', [v_state,
+ model.Constant('f_restart', lltype.Void),
+ model.Constant(data['restart'], lltype.Signed)])
+ v_state = llops.genop('cast_opaque_ptr', [v_state],
+ resulttype = llmemory.GCREF)
+ llops.append(model.SpaceOperation('same_as', [v_state], op.result))
+ block.operations = block.operations[:-1] + llops
+
+
return [masterarray]
def transform_gc_nocollect(self, graph):
More information about the Pypy-commit
mailing list