[pypy-commit] pypy default: merge heads
arigo
noreply at buildbot.pypy.org
Wed May 25 20:36:57 CEST 2011
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r44486:bd222da26287
Date: 2011-05-25 20:48 +0200
http://bitbucket.org/pypy/pypy/changeset/bd222da26287/
Log: merge heads
diff --git a/lib_pypy/stackless.py b/lib_pypy/stackless.py
--- a/lib_pypy/stackless.py
+++ b/lib_pypy/stackless.py
@@ -200,14 +200,15 @@
# I can't think of a better solution without a real transform.
def rewrite_stackless_primitive(coro_state, alive, tempval):
- flags, state, thunk, parent = coro_state
- for i, frame in enumerate(state):
+ flags, frame, thunk, parent = coro_state
+ while frame is not None:
retval_expr = _stackless_primitive_registry.get(frame.f_code)
if retval_expr:
# this tasklet needs to stop pickling here and return its value.
tempval = eval(retval_expr, globals(), frame.f_locals)
- state = state[:i]
- coro_state = flags, state, thunk, parent
+ coro_state = flags, frame, thunk, parent
+ break
+ frame = frame.f_back
return coro_state, alive, tempval
#
@@ -492,23 +493,22 @@
assert two == ()
# we want to get rid of the parent thing.
# for now, we just drop it
- a, b, c, d = coro_state
-
+ a, frame, c, d = coro_state
+
# Removing all frames related to stackless.py.
# They point to stuff we don't want to be pickled.
- frame_list = list(b)
- new_frame_list = []
- for frame in frame_list:
+
+ pickleframe = frame
+ while frame is not None:
if frame.f_code == schedule.func_code:
# Removing everything including and after the
# call to stackless.schedule()
+ pickleframe = frame.f_back
break
- new_frame_list.append(frame)
- b = tuple(new_frame_list)
-
+ frame = frame.f_back
if d:
assert isinstance(d, coroutine)
- coro_state = a, b, c, None
+ coro_state = a, pickleframe, c, None
coro_state, alive, tempval = rewrite_stackless_primitive(coro_state, self.alive, self.tempval)
inst_dict = self.__dict__.copy()
inst_dict.pop('tempval', None)
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -102,18 +102,16 @@
# the following interface is for pickling and unpickling
def getstate(self, space):
- # XXX we could just save the top frame, which brings
- # the whole frame stack, but right now we get the whole stack
- items = [space.wrap(f) for f in self.getframestack()]
- return space.newtuple(items)
+ if self.topframe is None:
+ return space.w_None
+ return self.topframe
def setstate(self, space, w_state):
from pypy.interpreter.pyframe import PyFrame
- frames_w = space.unpackiterable(w_state)
- if len(frames_w) > 0:
- self.topframe = space.interp_w(PyFrame, frames_w[-1])
+ if space.is_w(w_state, space.w_None):
+ self.topframe = None
else:
- self.topframe = None
+ self.topframe = space.interp_w(PyFrame, w_state)
def getframestack(self):
lst = []
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -11,7 +11,7 @@
from pypy.rlib.jit import hint
from pypy.rlib.debug import make_sure_not_resized
from pypy.rlib.rarithmetic import intmask
-from pypy.rlib import jit, rstack
+from pypy.rlib import jit
from pypy.tool import stdlib_opcode
from pypy.tool.stdlib_opcode import host_bytecode_spec
@@ -157,8 +157,6 @@
try:
w_exitvalue = self.dispatch(self.pycode, next_instr,
executioncontext)
- rstack.resume_point("execute_frame", self, executioncontext,
- returns=w_exitvalue)
except Exception:
executioncontext.return_trace(self, self.space.w_None)
raise
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -11,7 +11,7 @@
from pypy.interpreter.pycode import PyCode
from pypy.tool.sourcetools import func_with_new_name
from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib import jit, rstackovf, rstack
+from pypy.rlib import jit, rstackovf
from pypy.rlib.rarithmetic import r_uint, intmask
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.debug import check_nonneg
@@ -83,16 +83,12 @@
try:
while True:
next_instr = self.handle_bytecode(co_code, next_instr, ec)
- rstack.resume_point("dispatch", self, co_code, ec,
- returns=next_instr)
except ExitFrame:
return self.popvalue()
def handle_bytecode(self, co_code, next_instr, ec):
try:
next_instr = self.dispatch_bytecode(co_code, next_instr, ec)
- rstack.resume_point("handle_bytecode", self, co_code, ec,
- returns=next_instr)
except OperationError, operr:
next_instr = self.handle_operation_error(ec, operr)
except Reraise:
@@ -248,9 +244,6 @@
# dispatch to the opcode method
meth = getattr(self, opdesc.methodname)
res = meth(oparg, next_instr)
- if opdesc.index == self.opcodedesc.CALL_FUNCTION.index:
- rstack.resume_point("dispatch_call", self, co_code,
- next_instr, ec)
# !! warning, for the annotator the next line is not
# comparing an int and None - you can't do that.
# Instead, it's constant-folded to either True or False
@@ -997,7 +990,6 @@
args)
else:
w_result = self.space.call_args(w_function, args)
- rstack.resume_point("call_function", self, returns=w_result)
self.pushvalue(w_result)
def CALL_FUNCTION(self, oparg, next_instr):
@@ -1008,8 +1000,6 @@
w_function = self.peekvalue(nargs)
try:
w_result = self.space.call_valuestack(w_function, nargs, self)
- rstack.resume_point("CALL_FUNCTION", self, nargs,
- returns=w_result)
finally:
self.dropvalues(nargs + 1)
self.pushvalue(w_result)
diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py
--- a/pypy/module/_stackless/interp_coroutine.py
+++ b/pypy/module/_stackless/interp_coroutine.py
@@ -28,7 +28,7 @@
from pypy.module.exceptions.interp_exceptions import W_SystemExit, _new_exception
-from pypy.rlib import rstack # for resume points
+from pypy.rlib import rstack, jit # for resume points
from pypy.tool import stdlib_opcode as pythonopcode
class _AppThunk(AbstractThunk):
@@ -47,9 +47,19 @@
def call(self):
costate = self.costate
w_result = self.space.call_args(self.w_func, self.args)
- rstack.resume_point("appthunk", costate, returns=w_result)
costate.w_tempval = w_result
+class _ResumeThunk(AbstractThunk):
+ def __init__(self, space, costate, w_frame):
+ self.space = space
+ self.costate = costate
+ self.w_frame = w_frame
+
+ def call(self):
+ w_result = resume_frame(self.space, self.w_frame)
+ # costate.w_tempval = w_result #XXX?
+
+
W_CoroutineExit = _new_exception('CoroutineExit', W_SystemExit,
"""Coroutine killed manually.""")
@@ -97,7 +107,6 @@
"cannot switch to an unbound Coroutine"))
state = self.costate
self.switch()
- rstack.resume_point("w_switch", state, space)
w_ret, state.w_tempval = state.w_tempval, space.w_None
return w_ret
@@ -217,75 +226,17 @@
self.parent = space.interp_w(AppCoroutine, w_parent)
ec = self.space.getexecutioncontext()
self.subctx.setstate(space, w_state)
- self.reconstruct_framechain()
if space.is_w(w_thunk, space.w_None):
- self.thunk = None
+ if space.is_w(w_state, space.w_None):
+ self.thunk = None
+ else:
+ self.bind(_ResumeThunk(space, self.costate, self.subctx.topframe))
else:
w_func, w_args, w_kwds = space.unpackiterable(w_thunk,
expected_length=3)
args = Arguments.frompacked(space, w_args, w_kwds)
self.bind(_AppThunk(space, self.costate, w_func, args))
- def reconstruct_framechain(self):
- from pypy.interpreter.pyframe import PyFrame
- from pypy.rlib.rstack import resume_state_create
- if self.subctx.topframe is None:
- self.frame = None
- return
-
- space = self.space
- ec = space.getexecutioncontext()
- costate = self.costate
- # now the big fun of recreating tiny things...
- bottom = resume_state_create(None, "yield_current_frame_to_caller_1")
- # ("coroutine__bind", state)
- _bind_frame = resume_state_create(bottom, "coroutine__bind", costate)
- # ("appthunk", costate, returns=w_result)
- appthunk_frame = resume_state_create(_bind_frame, "appthunk", costate)
- chain = appthunk_frame
- for frame in self.subctx.getframestack():
- assert isinstance(frame, PyFrame)
- # ("execute_frame", self, executioncontext, returns=w_exitvalue)
- chain = resume_state_create(chain, "execute_frame", frame, ec)
- code = frame.pycode.co_code
- # ("dispatch", self, co_code, ec, returns=next_instr)
- chain = resume_state_create(chain, "dispatch", frame, code, ec)
- # ("handle_bytecode", self, co_code, ec, returns=next_instr)
- chain = resume_state_create(chain, "handle_bytecode", frame, code,
- ec)
- instr = frame.last_instr
- opcode = ord(code[instr])
- map = pythonopcode.opmap
- call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'],
- map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']]
- assert opcode in call_ops
- # ("dispatch_call", self, co_code, next_instr, ec)
- chain = resume_state_create(chain, "dispatch_call", frame, code,
- instr+3, ec)
- instr += 1
- oparg = ord(code[instr]) | ord(code[instr + 1]) << 8
- nargs = oparg & 0xff
- nkwds = (oparg >> 8) & 0xff
- if space.config.objspace.opcodes.CALL_METHOD and opcode == map['CALL_METHOD']:
- if nkwds == 0: # only positional arguments
- chain = resume_state_create(chain, 'CALL_METHOD', frame,
- nargs)
- else: # includes keyword arguments
- chain = resume_state_create(chain, 'CALL_METHOD_KW', frame)
- elif opcode == map['CALL_FUNCTION'] and nkwds == 0:
- # Only positional arguments
- # case1: ("CALL_FUNCTION", f, nargs, returns=w_result)
- chain = resume_state_create(chain, 'CALL_FUNCTION', frame,
- nargs)
- else:
- # case2: ("call_function", f, returns=w_result)
- chain = resume_state_create(chain, 'call_function', frame)
-
- # ("w_switch", state, space)
- w_switch_frame = resume_state_create(chain, 'w_switch', costate, space)
- # ("coroutine_switch", state, returns=incoming_frame)
- switch_frame = resume_state_create(w_switch_frame, "coroutine_switch", costate)
- self.frame = switch_frame
# _mixin_ did not work
for methname in StacklessFlags.__dict__:
@@ -411,3 +362,45 @@
@unwrap_spec(limit=int)
def set_stack_depth_limit(space, limit):
rstack.set_stack_depth_limit(limit)
+
+
+# ___________________________________________________________________
+# unpickling trampoline
+
+def resume_frame(space, w_frame):
+ from pypy.interpreter.pyframe import PyFrame
+ frame = space.interp_w(PyFrame, w_frame, can_be_None=True)
+ w_result = space.w_None
+ operr = None
+ executioncontext = frame.space.getexecutioncontext()
+ while frame is not None:
+ code = frame.pycode.co_code
+ instr = frame.last_instr
+ opcode = ord(code[instr])
+ map = pythonopcode.opmap
+ call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'],
+ map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']]
+ assert opcode in call_ops
+ instr += 1
+ oparg = ord(code[instr]) | ord(code[instr + 1]) << 8
+ nargs = oparg & 0xff
+ nkwds = (oparg >> 8) & 0xff
+ if nkwds == 0: # only positional arguments
+ # fast paths leaves things on the stack, pop them
+ if space.config.objspace.opcodes.CALL_METHOD and opcode == map['CALL_METHOD']:
+ frame.dropvalues(nargs + 2)
+ elif opcode == map['CALL_FUNCTION']:
+ frame.dropvalues(nargs + 1)
+
+ # small hack: unlink frame out of the execution context, because
+ # execute_frame will add it there again
+ executioncontext.topframeref = jit.non_virtual_ref(frame.f_backref())
+ frame.last_instr = instr + 1 # continue after the call
+ try:
+ w_result = frame.execute_frame(w_result, operr)
+ except OperationError, operr:
+ pass
+ frame = frame.f_backref()
+ if operr:
+ raise operr
+ return w_result
diff --git a/pypy/module/_stackless/test/test_coroutine.py b/pypy/module/_stackless/test/test_coroutine.py
--- a/pypy/module/_stackless/test/test_coroutine.py
+++ b/pypy/module/_stackless/test/test_coroutine.py
@@ -8,33 +8,6 @@
space = gettestobjspace(usemodules=('_stackless',))
cls.space = space
- def test_pickle_coroutine_empty(self):
- # this test is limited to basic pickling.
- # real stacks can only tested with a stackless pypy build.
- import _stackless as stackless
- co = stackless.coroutine()
- import pickle
- pckl = pickle.dumps(co)
- co2 = pickle.loads(pckl)
- # the empty unpickled coroutine can still be used:
- result = []
- co2.bind(result.append, 42)
- co2.switch()
- assert result == [42]
-
- def test_pickle_coroutine_bound(self):
- import pickle
- import _stackless
- lst = [4]
- co = _stackless.coroutine()
- co.bind(lst.append, 2)
- pckl = pickle.dumps((co, lst))
-
- (co2, lst2) = pickle.loads(pckl)
- assert lst2 == [4]
- co2.switch()
- assert lst2 == [4, 2]
-
def test_raise_propagate(self):
import _stackless as stackless
co = stackless.coroutine()
diff --git a/pypy/module/_stackless/test/test_pickle.py b/pypy/module/_stackless/test/test_pickle.py
--- a/pypy/module/_stackless/test/test_pickle.py
+++ b/pypy/module/_stackless/test/test_pickle.py
@@ -19,9 +19,35 @@
class AppTestPickle:
def setup_class(cls):
- if not option.runappdirect:
- py.test.skip('pure appdirect test (run with -A)')
- cls.space = gettestobjspace(usemodules=('_stackless',))
+ cls.space = gettestobjspace(usemodules=('_stackless',), CALL_METHOD=True)
+
+ def test_pickle_coroutine_empty(self):
+ # this test is limited to basic pickling.
+ # real stacks can only tested with a stackless pypy build.
+ import _stackless as stackless
+ co = stackless.coroutine()
+ import pickle
+ pckl = pickle.dumps(co)
+ co2 = pickle.loads(pckl)
+ # the empty unpickled coroutine can still be used:
+ result = []
+ co2.bind(result.append, 42)
+ co2.switch()
+ assert result == [42]
+
+ def test_pickle_coroutine_bound(self):
+ import pickle
+ import _stackless
+ lst = [4]
+ co = _stackless.coroutine()
+ co.bind(lst.append, 2)
+ pckl = pickle.dumps((co, lst))
+
+ (co2, lst2) = pickle.loads(pckl)
+ assert lst2 == [4]
+ co2.switch()
+ assert lst2 == [4, 2]
+
def test_simple_ish(self):
@@ -58,6 +84,113 @@
finally:
del sys.modules['mod']
+ def test_pickle_again(self):
+
+ import new, sys
+
+ mod = new.module('mod')
+ sys.modules['mod'] = mod
+ try:
+ exec '''
+output = []
+import _stackless
+def f(coro, n, x):
+ if n == 0:
+ coro.switch()
+ return
+ f(coro, n-1, 2*x)
+ output.append(x)
+
+def example():
+ main_coro = _stackless.coroutine.getcurrent()
+ sub_coro = _stackless.coroutine()
+ sub_coro.bind(f, main_coro, 5, 1)
+ sub_coro.switch()
+
+ import pickle
+ pckl = pickle.dumps(sub_coro)
+ new_coro = pickle.loads(pckl)
+ pckl = pickle.dumps(new_coro)
+ newer_coro = pickle.loads(pckl)
+
+ newer_coro.switch()
+
+example()
+assert output == [16, 8, 4, 2, 1]
+''' in mod.__dict__
+ finally:
+ del sys.modules['mod']
+
+ def test_kwargs(self):
+
+ import new, sys
+
+ mod = new.module('mod')
+ sys.modules['mod'] = mod
+ try:
+ exec '''
+output = []
+import _stackless
+def f(coro, n, x, step=4):
+ if n == 0:
+ coro.switch()
+ return
+ f(coro, n-1, 2*x, step=1)
+ output.append(x)
+
+def example():
+ main_coro = _stackless.coroutine.getcurrent()
+ sub_coro = _stackless.coroutine()
+ sub_coro.bind(f, main_coro, 5, 1, 1)
+ sub_coro.switch()
+
+ import pickle
+ pckl = pickle.dumps(sub_coro)
+ new_coro = pickle.loads(pckl)
+
+ new_coro.switch()
+
+example()
+assert output == [16, 8, 4, 2, 1]
+''' in mod.__dict__
+ finally:
+ del sys.modules['mod']
+
+ def test_starstarargs(self):
+
+ import new, sys
+
+ mod = new.module('mod')
+ sys.modules['mod'] = mod
+ try:
+ exec '''
+output = []
+import _stackless
+def f(coro, n, x, step=4):
+ if n == 0:
+ coro.switch()
+ return
+ f(coro, n-1, 2*x, **{'step': 1})
+ output.append(x)
+
+def example():
+ main_coro = _stackless.coroutine.getcurrent()
+ sub_coro = _stackless.coroutine()
+ sub_coro.bind(f, main_coro, 5, 1, 1)
+ sub_coro.switch()
+
+ import pickle
+ pckl = pickle.dumps(sub_coro)
+ new_coro = pickle.loads(pckl)
+
+ new_coro.switch()
+
+example()
+assert output == [16, 8, 4, 2, 1]
+''' in mod.__dict__
+ finally:
+ del sys.modules['mod']
+
def test_closure(self):
import new, sys
@@ -130,8 +263,55 @@
finally:
del sys.modules['mod']
+ def test_exception_after_unpickling(self):
+
+ import new, sys
+
+ mod = new.module('mod')
+ sys.modules['mod'] = mod
+ try:
+ exec '''
+output = []
+import _stackless
+def f(coro, n, x):
+ if n == 0:
+ coro.switch()
+ raise ValueError
+ try:
+ f(coro, n-1, 2*x)
+ finally:
+ output.append(x)
+
+def example():
+ main_coro = _stackless.coroutine.getcurrent()
+ sub_coro = _stackless.coroutine()
+ sub_coro.bind(f, main_coro, 5, 1)
+ sub_coro.switch()
+
+ import pickle
+ pckl = pickle.dumps(sub_coro)
+ new_coro = pickle.loads(pckl)
+
+ try:
+ sub_coro.switch()
+ except ValueError:
+ pass
+ else:
+ assert 0
+ try:
+ new_coro.switch()
+ except ValueError:
+ pass
+ else:
+ assert 0
+
+example()
+assert output == [16, 8, 4, 2, 1] * 2
+''' in mod.__dict__
+ finally:
+ del sys.modules['mod']
+
def test_loop(self):
- #skip("happily segfaulting")
import new, sys
mod = new.module('mod')
diff --git a/pypy/module/_stackless/test/test_pickle_infrastructure.py b/pypy/module/_stackless/test/test_pickle_infrastructure.py
deleted file mode 100644
--- a/pypy/module/_stackless/test/test_pickle_infrastructure.py
+++ /dev/null
@@ -1,301 +0,0 @@
-from pypy.conftest import gettestobjspace
-from py.test import skip
-
-
-class BaseAppTestPicklePrerequisites(object):
- OPTIONS = {}
- def setup_class(cls):
- space = gettestobjspace(usemodules=('_stackless',), **cls.OPTIONS)
- cls.space = space
-
- def test_pickle_switch_function(object):
- import _stackless, pickle
-
- sw = _stackless.coroutine.switch.im_func
- dump = pickle.dumps(sw)
- res = pickle.loads(dump)
-
- assert res is sw
- assert res.func_code is sw.func_code
- assert res.func_doc is sw.func_doc
- assert res.func_globals is sw.func_globals
-
- def test_pickle_switch_function_code(object):
- import _stackless, pickle
-
- sw = _stackless.coroutine.switch.im_func.func_code
- dump = pickle.dumps(sw)
- res = pickle.loads(dump)
-
- assert res is sw
-
-class AppTestPicklePrerequisites(BaseAppTestPicklePrerequisites):
- pass
-
-class AppTestPicklePrerequisitesBuiltinShortcut(BaseAppTestPicklePrerequisites):
- OPTIONS = {"objspace.std.builtinshortcut": True}
-
-class FrameCheck(object):
-
- def __init__(self, name):
- self.name = name
-
- def __eq__(self, frame):
- return frame.pycode.co_name == self.name
-
-class BytecodeCheck(object):
-
- def __init__(self, code, op, arg):
- self.code = code
- self.op = chr(op)+chr(arg & 0xff) + chr(arg >> 8 & 0xff)
-
- def __eq__(self, pos):
- return self.code[pos-3:pos] == self.op
-
-class BaseTestReconstructFrameChain(object):
- OPTIONS = {}
-
- def setup_class(cls):
- space = gettestobjspace(usemodules=('_stackless',), **cls.OPTIONS)
- cls.space = space
-
- from pypy.rlib import rstack
- cls.old_resume_state_create = rstack.resume_state_create
-
- def tr(prevstate, label, *args):
- if prevstate is None:
- prevstate = []
- return prevstate+[(label, args)]
- rstack.resume_state_create = tr
-
- w_opmap = space.appexec([], """():
- import opcode
-
- return opcode.opmap
- """)
-
- opmap = space.unwrap(w_opmap)
- cls.CALL_FUNCTION = opmap['CALL_FUNCTION']
- cls.CALL_FUNCTION_VAR = opmap['CALL_FUNCTION_VAR']
- cls.CALL_METHOD = opmap['CALL_METHOD']
-
- cls.callmethod = getattr(cls, cls.callmethod_label)
-
- def teardown_class(cls):
- from pypy.rlib import rstack
- rstack.resume_state_create = cls.old_resume_state_create
-
- def start(self, w_coro):
- self.i = 0
- self.frame_to_check = w_coro.frame
- w_coro.frame = None # avoid exploding in kill > __del__
-
- def end(self):
- assert self.i == len(self.frame_to_check)
-
- def check_entry(self, label, *args):
- frame = self.frame_to_check
- assert frame[self.i] == (label, args)
- self.i += 1
-
-
- def test_two_frames_simple(self):
- space = self.space
-
- w_res = space.appexec([], """():
- import _stackless as stackless
- import pickle
-
- main = stackless.coroutine.getcurrent()
- d = {'main': main}
-
- exec \"\"\"
-def f():
- g(1)
-
-def g(x):
- main.switch()
-\"\"\" in d
- f = d['f']
- g = d['g']
-
- co = stackless.coroutine()
- co.bind(f)
- co.switch()
-
- s = pickle.dumps(co)
- co = pickle.loads(s)
-
- return co, f, g
- """)
-
- w_co, w_f, w_g = space.fixedview(w_res)
-
- ec = space.getexecutioncontext()
- fcode = w_f.code.co_code
- gcode = w_g.code.co_code
-
- self.start(w_co)
- e = self.check_entry
- e('yield_current_frame_to_caller_1')
- e('coroutine__bind', w_co.costate)
- e('appthunk', w_co.costate)
- # f
- e('execute_frame', FrameCheck('f'), ec)
- e('dispatch', FrameCheck('f'), fcode, ec)
- e('handle_bytecode', FrameCheck('f'), fcode, ec)
- e('dispatch_call', FrameCheck('f'), fcode,
- BytecodeCheck(fcode, self.CALL_FUNCTION, 1), ec)
- e('CALL_FUNCTION', FrameCheck('f'), 1)
- # g
- e('execute_frame', FrameCheck('g'), ec)
- e('dispatch', FrameCheck('g'), gcode, ec)
- e('handle_bytecode', FrameCheck('g'), gcode, ec)
- e('dispatch_call', FrameCheck('g'), gcode,
- BytecodeCheck(gcode, self.callmethod, 0), ec)
- e(self.callmethod_label, FrameCheck('g'), 0)
- e('w_switch', w_co.costate, space)
- e('coroutine_switch', w_co.costate)
- self.end()
-
- def test_two_frames_stararg(self):
- space = self.space
-
- w_res = space.appexec([], """():
- import _stackless as stackless
- import pickle
-
- main = stackless.coroutine.getcurrent()
- d = {'main': main}
-
- exec \"\"\"
-def f():
- g(4, 3, d=2, *(1,))
-
-def g(a, b, c, d):
- main.switch()
-\"\"\" in d
- f = d['f']
- g = d['g']
-
- co = stackless.coroutine()
- co.bind(f)
- co.switch()
-
- s = pickle.dumps(co)
- co = pickle.loads(s)
-
- return co, f, g
- """)
-
- w_co, w_f, w_g = space.fixedview(w_res)
-
- ec = space.getexecutioncontext()
- fcode = w_f.code.co_code
- gcode = w_g.code.co_code
-
- self.start(w_co)
- e = self.check_entry
- e('yield_current_frame_to_caller_1')
- e('coroutine__bind', w_co.costate)
- e('appthunk', w_co.costate)
- # f
- e('execute_frame', FrameCheck('f'), ec)
- e('dispatch', FrameCheck('f'), fcode, ec)
- e('handle_bytecode', FrameCheck('f'), fcode, ec)
- e('dispatch_call', FrameCheck('f'), fcode,
- BytecodeCheck(fcode, self.CALL_FUNCTION_VAR, 2+(1<<8)), ec)
- e('call_function', FrameCheck('f'))
- # g
- e('execute_frame', FrameCheck('g'), ec)
- e('dispatch', FrameCheck('g'), gcode, ec)
- e('handle_bytecode', FrameCheck('g'), gcode, ec)
- e('dispatch_call', FrameCheck('g'), gcode,
- BytecodeCheck(gcode, self.callmethod, 0), ec)
- e(self.callmethod_label, FrameCheck('g'), 0)
- e('w_switch', w_co.costate, space)
- e('coroutine_switch', w_co.costate)
- self.end()
-
- def test_two_frames_method(self):
- space = self.space
-
- w_res = space.appexec([], """():
- import _stackless as stackless
- import pickle
- import new, sys
-
- mod = new.module('mod')
- sys.modules['mod'] = mod
-
- main = stackless.coroutine.getcurrent()
- d = {'main': main}
-
- exec \"\"\"
-def f():
- a = A()
- a.m(1)
-
-def g(_, x):
- main.switch()
-
-class A(object):
- m = g
-\"\"\" in d
- f = d['f']
- g = d['g']
- A = d['A']
-
- # to make pickling work
- mod.A = A
- A.__module__ = 'mod'
-
- co = stackless.coroutine()
- co.bind(f)
- co.switch()
-
- s = pickle.dumps(co)
- co = pickle.loads(s)
-
- return co, f, g
- """)
-
- w_co, w_f, w_g = space.fixedview(w_res)
-
- ec = space.getexecutioncontext()
- fcode = w_f.code.co_code
- gcode = w_g.code.co_code
-
- self.start(w_co)
- e = self.check_entry
- e('yield_current_frame_to_caller_1')
- e('coroutine__bind', w_co.costate)
- e('appthunk', w_co.costate)
- # f
- e('execute_frame', FrameCheck('f'), ec)
- e('dispatch', FrameCheck('f'), fcode, ec)
- e('handle_bytecode', FrameCheck('f'), fcode, ec)
- e('dispatch_call', FrameCheck('f'), fcode,
- BytecodeCheck(fcode, self.callmethod, 1), ec)
- e(self.callmethod_label, FrameCheck('f'), 1)
- # g
- e('execute_frame', FrameCheck('g'), ec)
- e('dispatch', FrameCheck('g'), gcode, ec)
- e('handle_bytecode', FrameCheck('g'), gcode, ec)
- e('dispatch_call', FrameCheck('g'), gcode,
- BytecodeCheck(gcode, self.callmethod, 0), ec)
- e(self.callmethod_label, FrameCheck('g'), 0)
- e('w_switch', w_co.costate, space)
- e('coroutine_switch', w_co.costate)
- self.end()
-
-class TestReconstructFrameChain(BaseTestReconstructFrameChain):
- callmethod_label = 'CALL_FUNCTION'
-
-class TestReconstructFrameChain_CALL_METHOD(BaseTestReconstructFrameChain):
- OPTIONS = {"objspace.opcodes.CALL_METHOD": True,
- }
-
- callmethod_label = 'CALL_METHOD'
-
-
diff --git a/pypy/module/test_lib_pypy/test_stackless.py b/pypy/module/test_lib_pypy/test_stackless.py
--- a/pypy/module/test_lib_pypy/test_stackless.py
+++ b/pypy/module/test_lib_pypy/test_stackless.py
@@ -8,15 +8,12 @@
space = gettestobjspace(usemodules=('_stackless', '_socket'))
cls.space = space
# cannot test the unpickle part on top of py.py
- cls.w_can_unpickle = space.wrap(bool(option.runappdirect))
def test_pickle(self):
import new, sys
mod = new.module('mod')
sys.modules['mod'] = mod
- mod.can_unpickle = self.can_unpickle
- mod.skip = skip
try:
exec '''
import pickle, sys
@@ -45,8 +42,6 @@
t = stackless.tasklet(demo)(lev)
stackless.run()
assert seen == range(1, lev+1) + range(lev, 0, -1)
-if not can_unpickle:
- skip("cannot test the unpickling part on top of py.py")
print "now running the clone"
tt = pickle.loads(blob)
tt.insert()
@@ -64,8 +59,6 @@
mod = new.module('mod')
sys.modules['mod'] = mod
- mod.can_unpickle = self.can_unpickle
- mod.skip = skip
try:
exec '''
import pickle, sys
diff --git a/pypy/objspace/std/callmethod.py b/pypy/objspace/std/callmethod.py
--- a/pypy/objspace/std/callmethod.py
+++ b/pypy/objspace/std/callmethod.py
@@ -12,7 +12,7 @@
from pypy.interpreter import function
from pypy.objspace.descroperation import object_getattribute
-from pypy.rlib import jit, rstack # for resume points
+from pypy.rlib import jit
from pypy.objspace.std.mapdict import LOOKUP_METHOD_mapdict, \
LOOKUP_METHOD_mapdict_fill_cache_method
@@ -84,7 +84,6 @@
w_callable = f.peekvalue(n_args + (2 * n_kwargs) + 1)
try:
w_result = f.space.call_valuestack(w_callable, n, f)
- rstack.resume_point("CALL_METHOD", f, n_args, returns=w_result)
finally:
f.dropvalues(n_args + 2)
else:
@@ -109,7 +108,6 @@
w_result = f.space.call_args_and_c_profile(f, w_callable, args)
else:
w_result = f.space.call_args(w_callable, args)
- rstack.resume_point("CALL_METHOD_KW", f, returns=w_result)
f.pushvalue(w_result)
diff --git a/pypy/rlib/rcoroutine.py b/pypy/rlib/rcoroutine.py
--- a/pypy/rlib/rcoroutine.py
+++ b/pypy/rlib/rcoroutine.py
@@ -29,7 +29,7 @@
The type of a switch is determined by the target's costate.
"""
-from pypy.rlib.rstack import yield_current_frame_to_caller, resume_point
+from pypy.rlib.rstack import yield_current_frame_to_caller
from pypy.rlib.objectmodel import we_are_translated
from pypy.interpreter.error import OperationError
@@ -228,7 +228,6 @@
self.thunk = None
syncstate.switched(incoming_frame)
thunk.call()
- resume_point("coroutine__bind", state)
except Exception, e:
exc = e
raise
@@ -257,7 +256,6 @@
raise CoroutineDamage
state = self.costate
incoming_frame = state.update(self).switch()
- resume_point("coroutine_switch", state, returns=incoming_frame)
syncstate.switched(incoming_frame)
def kill(self):
diff --git a/pypy/rlib/rstack.py b/pypy/rlib/rstack.py
--- a/pypy/rlib/rstack.py
+++ b/pypy/rlib/rstack.py
@@ -140,111 +140,6 @@
return var
-def resume_point(label, *args, **kwds):
- pass
-
-
-
-class ResumePointFnEntry(ExtRegistryEntry):
- _about_ = resume_point
-
- def compute_result_annotation(self, s_label, *args_s, **kwds_s):
- from pypy.annotation import model as annmodel
- return annmodel.s_None
-
- def specialize_call(self, hop, **kwds_i):
- from pypy.rpython.lltypesystem import lltype
- from pypy.objspace.flow import model
-
- 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)
- assert isinstance(v_return, model.Variable), \
- "resume_point returns= argument must be a Variable"
- else:
- assert not kwds_i
- v_return = hop.inputconst(lltype.Void, None)
-
- for v in args_v:
- assert isinstance(v, model.Variable), "resume_point arguments must be Variables"
-
- hop.exception_is_here()
- return hop.genop('resume_point', [c_label, v_return] + args_v,
- hop.r_result)
-
-def resume_state_create(prevstate, label, *args):
- raise RuntimeError("cannot resume states in non-translated versions")
-
-def concretify_argument(hop, index):
- from pypy.objspace.flow import model
-
- v_arg = hop.args_v[index]
- if isinstance(v_arg, model.Variable):
- return v_arg
-
- r_arg = hop.rtyper.bindingrepr(v_arg)
- return hop.inputarg(r_arg, arg=index)
-
-class ResumeStateCreateFnEntry(FrameStackTopReturningFnEntry):
- _about_ = resume_state_create
-
- def compute_result_annotation(self, s_prevstate, s_label, *args_s):
- return FrameStackTopReturningFnEntry.compute_result_annotation(self)
-
- def specialize_call(self, hop):
- from pypy.rpython.lltypesystem import lltype
-
- assert hop.args_s[1].is_constant()
- c_label = hop.inputconst(lltype.Void, hop.args_s[1].const)
-
- v_state = hop.inputarg(hop.r_result, arg=0)
-
- args_v = []
- for i in range(2, len(hop.args_v)):
- args_v.append(concretify_argument(hop, i))
-
- hop.exception_is_here()
- return hop.genop('resume_state_create', [v_state, c_label] + args_v,
- hop.r_result)
-
-def resume_state_invoke(type, state, **kwds):
- raise NotImplementedError("only works in translated versions")
-
-class ResumeStateInvokeFnEntry(ExtRegistryEntry):
- _about_ = resume_state_invoke
-
- def compute_result_annotation(self, s_type, s_state, **kwds):
- from pypy.annotation.bookkeeper import getbookkeeper
- assert s_type.is_constant()
- return getbookkeeper().valueoftype(s_type.const)
-
- def specialize_call(self, hop, **kwds_i):
- from pypy.rpython.lltypesystem import lltype
- v_state = hop.args_v[1]
-
- if 'i_returning' in kwds_i:
- assert len(kwds_i) == 1
- returning_index = kwds_i['i_returning']
- v_returning = concretify_argument(hop, returning_index)
- v_raising = hop.inputconst(lltype.Void, None)
- elif 'i_raising' in kwds_i:
- assert len(kwds_i) == 1
- raising_index = kwds_i['i_raising']
- v_returning = hop.inputconst(lltype.Void, None)
- v_raising = concretify_argument(hop, raising_index)
- else:
- assert not kwds_i
- v_returning = hop.inputconst(lltype.Void, None)
- v_raising = hop.inputconst(lltype.Void, None)
-
- hop.exception_is_here()
- return hop.genop('resume_state_invoke', [v_state, v_returning, v_raising],
- hop.r_result)
-
# ____________________________________________________________
def get_stack_depth_limit():
diff --git a/pypy/translator/stackless/frame.py b/pypy/translator/stackless/frame.py
--- a/pypy/translator/stackless/frame.py
+++ b/pypy/translator/stackless/frame.py
@@ -104,10 +104,8 @@
class RestartInfo(object):
- """A RestartInfo is created (briefly) for each graph that contains
- a resume point.
-
- In addition, a RestartInfo is created for each function that needs
+ """
+ A RestartInfo is created for each function that needs
to do explicit stackless manipulations
(e.g. code.yield_current_frame_to_caller)."""
diff --git a/pypy/translator/stackless/test/test_coroutine_reconstruction.py b/pypy/translator/stackless/test/test_coroutine_reconstruction.py
deleted file mode 100644
--- a/pypy/translator/stackless/test/test_coroutine_reconstruction.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from pypy.rlib import rcoroutine
-from pypy.rlib import rstack
-from pypy.rlib.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
-
-namespace = rcoroutine.make_coroutine_classes(object)
-syncstate = namespace['syncstate']
-AbstractThunk = namespace['AbstractThunk']
-Coroutine = namespace['Coroutine']
-
-class TestCoroutineReconstruction:
-
- def setup_meth(self):
- syncstate.reset()
-
- def test_simple_ish(self):
-
- output = []
- def f(coro, n, x):
- 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)
- output.append(x)
-
- class T(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 = Coroutine.getcurrent()
- sub_coro = Coroutine()
- thunk_f = T(main_coro, 5, 1)
- sub_coro.bind(thunk_f)
- sub_coro.switch()
-
- new_coro = Coroutine()
- new_thunk_f = T(main_coro, 5, 1)
- new_coro.bind(new_thunk_f)
-
- costate = Coroutine._get_default_costate()
- bottom = resume_state_create(None, "yield_current_frame_to_caller_1")
- _bind_frame = resume_state_create(bottom, "coroutine__bind", 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", costate)
-
- new_coro.frame = switch_frame
-
- new_coro.switch()
- return output == [16, 8, 4, 2, 1]
-
- res = llinterp_stackless_function(example)
- assert res == 1
-
diff --git a/pypy/translator/stackless/test/test_resume_point.py b/pypy/translator/stackless/test/test_resume_point.py
deleted file mode 100644
--- a/pypy/translator/stackless/test/test_resume_point.py
+++ /dev/null
@@ -1,457 +0,0 @@
-from pypy.translator.stackless.transform import StacklessTransformer
-from pypy.translator.stackless.test.test_transform import llinterp_stackless_function, rtype_stackless_function, one, run_stackless_function
-from pypy import conftest
-import py
-from pypy.rlib import rstack
-
-def do_backendopt(t):
- from pypy.translator.backendopt import all
- all.backend_optimizations(t)
-
-def transform_stackless_function(fn, callback_for_transform=None):
- def wrapper(argv):
- return fn()
- t = rtype_stackless_function(wrapper)
- if callback_for_transform:
- callback_for_transform(t)
- if conftest.option.view:
- t.view()
- st = StacklessTransformer(t, wrapper, False)
- st.transform_all()
-
-def test_no_call():
- def f(x, y):
- x = x-1
- rstack.resume_point("rp0", x, y)
- r = x+y
- rstack.stack_unwind()
- return r
- def example():
- v1 = f(one(),one()+one())
- state = rstack.resume_state_create(None, "rp0", one(), one()+one()+one())
- v2 = rstack.resume_state_invoke(int, state)
- return v1*10 + v2
-## transform_stackless_function(example)
- res = llinterp_stackless_function(example, assert_unwind=False)
- assert res == 24
-
-def test_bogus_restart_state_create():
- def f(x, y):
- x = x-1
- rstack.resume_point("rp0", x, y)
- return x+y
- def example():
- v1 = f(one(),one()+one())
- state = rstack.resume_state_create(None, "rp0", one())
- return v1
- info = py.test.raises(AssertionError, "transform_stackless_function(example)")
- assert 'rp0' in str(info.value)
-
-
-def test_call():
- def g(x,y):
- return x*y
- def f(x, y):
- z = g(x,y)
- rstack.resume_point("rp1", y, returns=z)
- return z+y
- def example():
- v1 = f(one(),one()+one())
- s = rstack.resume_state_create(None, "rp1", 5*one())
- v2 = rstack.resume_state_invoke(int, s, returning=one()*7)
- return v1*100 + v2
- res = llinterp_stackless_function(example)
- assert res == 412
- res = run_stackless_function(example)
- assert res == 412
-
-def test_returns_with_instance():
- class C:
- def __init__(self, x):
- self.x = x
- def g(x):
- return C(x+1)
- def f(x, y):
- r = g(x)
- rstack.resume_point("rp1", y, returns=r)
- return r.x + y
- def example():
- v1 = f(one(),one()+one())
- s = rstack.resume_state_create(None, "rp1", 5*one())
- v2 = rstack.resume_state_invoke(int, s, returning=C(one()*3))
- return v1*100 + v2
- res = llinterp_stackless_function(example, assert_unwind=False)
- assert res == 408
- res = run_stackless_function(example)
- assert res == 408
-
-def test_call_uncovered():
- def g(x,y):
- return x*y
- def f(x, y):
- z = g(x,y)
- rstack.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)
- msg, = e.value.args
- assert msg.startswith('not covered needed value at resume_point') and 'rp1' in msg
-
-def test_chained_states():
- def g(x, y):
- x += 1
- rstack.resume_point("rp1", x, y)
- return x + y
- def f(x, y, z):
- y += 1
- r = g(x, y)
- rstack.resume_point("rp2", z, returns=r)
- return r + z
- def example():
- v1 = f(one(), 2*one(), 3*one())
- s2 = rstack.resume_state_create(None, "rp2", 2*one())
- s1 = rstack.resume_state_create(s2, "rp1", 4*one(), 5*one())
- return 100*v1 + rstack.resume_state_invoke(int, s1)
- res = llinterp_stackless_function(example)
- assert res == 811
- res = run_stackless_function(example)
- assert res == 811
-
-def test_return_instance():
- class C:
- pass
- def g(x):
- c = C()
- c.x = x + 1
- rstack.resume_point("rp1", c)
- return c
- def f(x, y):
- r = g(x)
- rstack.resume_point("rp2", y, returns=r)
- return r.x + y
- def example():
- v1 = f(one(), 2*one())
- s2 = rstack.resume_state_create(None, "rp2", 2*one())
- c = C()
- c.x = 4*one()
- s1 = rstack.resume_state_create(s2, "rp1", c)
- return v1*100 + rstack.resume_state_invoke(int, s1)
- res = llinterp_stackless_function(example)
- assert res == 406
- res = run_stackless_function(example)
- assert res == 406
-
-def test_really_return_instance():
- class C:
- pass
- def g(x):
- c = C()
- c.x = x + 1
- rstack.resume_point("rp1", c)
- return c
- def example():
- v1 = g(one()).x
- c = C()
- c.x = 4*one()
- s1 = rstack.resume_state_create(None, "rp1", c)
- return v1*100 + rstack.resume_state_invoke(C, s1).x
- res = llinterp_stackless_function(example)
- assert res == 204
- res = run_stackless_function(example)
- assert res == 204
-
-def test_resume_and_raise():
- def g(x):
- rstack.resume_point("rp0", x)
- if x == 0:
- raise KeyError
- return x + 1
- def example():
- v1 = g(one())
- s = rstack.resume_state_create(None, "rp0", one()-1)
- try:
- v2 = rstack.resume_state_invoke(int, s)
- except KeyError:
- v2 = 42
- return v1*100 + v2
- res = llinterp_stackless_function(example)
- assert res == 242
- res = run_stackless_function(example)
- assert res == 242
-
-def test_resume_and_raise_and_catch():
- def g(x):
- rstack.resume_point("rp0", x)
- if x == 0:
- raise KeyError
- return x + 1
- def f(x):
- x = x - 1
- try:
- r = g(x)
- rstack.resume_point("rp1", returns=r)
- except KeyError:
- r = 42
- return r - 1
- def example():
- v1 = f(one()+one())
- s1 = rstack.resume_state_create(None, "rp1")
- s0 = rstack.resume_state_create(s1, "rp0", one()-1)
- v2 = rstack.resume_state_invoke(int, s0)
- return v1*100 + v2
- res = llinterp_stackless_function(example)
- assert res == 141
- res = run_stackless_function(example)
- assert res == 141
-
-def test_invoke_raising():
- def g(x):
- rstack.resume_point("rp0", x)
- return x + 1
- def f(x):
- x = x - 1
- try:
- r = g(x)
- rstack.resume_point("rp1", returns=r)
- except KeyError:
- r = 42
- return r - 1
- def example():
- v1 = f(one()+one())
- s1 = rstack.resume_state_create(None, "rp1")
- s0 = rstack.resume_state_create(s1, "rp0", 0)
- v2 = rstack.resume_state_invoke(int, s0, raising=KeyError())
- return v1*100 + v2
- res = llinterp_stackless_function(example)
- assert res == 141
- res = run_stackless_function(example)
- assert res == 141
-
-
-def test_finally():
- def f(x):
- rstack.resume_point("rp1", x)
- return 1/x
- def in_finally(x):
- rstack.resume_point("rp1.5", x)
- return 2/x
- def g(x):
- r = y = 0
- r += f(x)
- try:
- y = f(x)
- rstack.resume_point("rp0", x, r, returns=y)
- finally:
- r += in_finally(x)
- return r + y
- def example():
- return g(one())
- transform_stackless_function(example)
-
-def test_except():
- py.test.skip("please don't write code like this")
- def f(x):
- rstack.resume_point("rp1", x)
- return 1/x
- def g(x):
- r = y = 0
- r += f(x)
- try:
- y = f(x)
- rstack.resume_point("rp0", x, r, y, returns=y)
- except ZeroDivisionError:
- r += f(x)
- return r + y
- def example():
- return g(one())
- transform_stackless_function(example)
-
-def test_using_pointers():
- from pypy.interpreter.miscutils import FixedStack
- class Arguments:
- def __init__(self, a, b, c, d, e):
- pass
- class W_Root:
- pass
- class FakeFrame:
- def __init__(self, space):
- self.space = space
- self.valuestack = FixedStack()
- self.valuestack.setup(10)
- self.valuestack.push(W_Root())
- class FakeSpace:
- def call_args(self, args, kw):
- return W_Root()
- def str_w(self, ob):
- return 'a string'
- def call_function(f, oparg, w_star=None, w_starstar=None):
- n_arguments = oparg & 0xff
- n_keywords = (oparg>>8) & 0xff
- keywords = None
- if n_keywords:
- keywords = {}
- for i in range(n_keywords):
- w_value = f.valuestack.pop()
- w_key = f.valuestack.pop()
- key = f.space.str_w(w_key)
- keywords[key] = w_value
- arguments = [None] * n_arguments
- for i in range(n_arguments - 1, -1, -1):
- arguments[i] = f.valuestack.pop()
- args = Arguments(f.space, arguments, keywords, w_star, w_starstar)
- w_function = f.valuestack.pop()
- w_result = f.space.call_args(w_function, args)
- rstack.resume_point("call_function", f, returns=w_result)
- f.valuestack.push(w_result)
- def example():
- s = FakeSpace()
- f = FakeFrame(s)
- call_function(f, 100, W_Root(), W_Root())
- return one()
- transform_stackless_function(example, do_backendopt)
-
-def test_always_raising():
- def g(out):
- out.append(3)
- rstack.resume_point('g')
- raise KeyError
-
- def h(out):
- try:
- # g is always raising, good enough to put the resume point
- # before, instead of after!
- rstack.resume_point('h', out)
- g(out)
- except KeyError:
- return 0
- return -1
-
- def example():
- out = []
- x = h(out)
- l = len(out)
- chain = rstack.resume_state_create(None, 'h', out)
- chain = rstack.resume_state_create(chain, 'g')
- x += rstack.resume_state_invoke(int, chain)
- l += len(out)
- return l*100+x
-
- res = llinterp_stackless_function(example)
- assert res == 200
- res = run_stackless_function(example)
- assert res == 200
-
-def test_more_mess():
- from pypy.interpreter.miscutils import Stack
-
- def new_framestack():
- return Stack()
-
- class FakeFrame:
- pass
- class FakeSlpFrame:
- def switch(self):
- rstack.stack_unwind()
- return FakeSlpFrame()
-
- class FakeCoState:
- def update(self, new):
- self.last, self.current = self.current, new
- frame, new.frame = new.frame, None
- return frame
- def do_things_to_do(self):
- self.do_things_to_do()
-
- costate = FakeCoState()
- costate.current = None
-
- class FakeExecutionContext:
- def __init__(self):
- self.space = space
- self.framestack = new_framestack()
-
- def subcontext_new(coobj):
- coobj.framestack = new_framestack()
- subcontext_new = staticmethod(subcontext_new)
-
- def subcontext_enter(self, next):
- self.framestack = next.framestack
-
- def subcontext_leave(self, current):
- current.framestack = self.framestack
-
- class FakeSpace:
- def __init__(self):
- self.ec = None
- def getexecutioncontext(self):
- if self.ec is None:
- self.ec = FakeExecutionContext()
- return self.ec
-
- space = FakeSpace()
-
- class MainCoroutineGetter(object):
- def __init__(self):
- self.costate = None
- def _get_default_costate(self):
- if self.costate is None:
- costate = FakeCoState()
- self.costate = costate
- return costate
- return self.costate
-
- main_coroutine_getter = MainCoroutineGetter()
-
- class FakeCoroutine:
- def __init__(self):
- self.frame = None
- self.costate = costate
- space.getexecutioncontext().subcontext_new(self)
-
- def switch(self):
- if self.frame is None:
- raise RuntimeError
- state = self.costate
- incoming_frame = state.update(self).switch()
- rstack.resume_point("coroutine_switch", self, state, returns=incoming_frame)
- left = state.last
- left.frame = incoming_frame
- left.goodbye()
- self.hello()
- #main_coroutine_getter._get_default_costate().do_things_to_do()
-
- def hello(self):
- pass
-
- def goodbye(self):
- pass
-
- class FakeAppCoroutine(FakeCoroutine):
- def __init__(self):
- FakeCoroutine.__init__(self)
- self.space = space
-
- def hello(self):
- ec = self.space.getexecutioncontext()
- ec.subcontext_enter(self)
-
- def goodbye(self):
- ec = self.space.getexecutioncontext()
- ec.subcontext_leave(self)
-
- def example():
- coro = FakeAppCoroutine()
- othercoro = FakeCoroutine()
- othercoro.frame = FakeSlpFrame()
- if one():
- coro.frame = FakeSlpFrame()
- if one() - one():
- coro.costate = FakeCoState()
- coro.costate.last = coro.costate.current = othercoro
- space.getexecutioncontext().framestack.push(FakeFrame())
- coro.switch()
- return one()
-
- transform_stackless_function(example, do_backendopt)
diff --git a/pypy/translator/stackless/transform.py b/pypy/translator/stackless/transform.py
--- a/pypy/translator/stackless/transform.py
+++ b/pypy/translator/stackless/transform.py
@@ -112,19 +112,6 @@
# abort()
# return retval + x + 1
-class SymbolicRestartNumber(ComputedIntSymbolic):
- def __init__(self, label, value=None):
- ComputedIntSymbolic.__init__(self, self._getvalue)
- self.label = label
- self.value = value
-
- def _getvalue(self):
- # argh, we'd like to assert-fail if value is None here, but we
- # get called too early (during databasing) for this to be
- # valid. so we might return None and rely on the database
- # checking that this only happens before the database is
- # complete.
- return self.value
# the strategy for sharing parts of the resume code:
#
@@ -248,8 +235,7 @@
self.stackless_gc = stackless_gc
def analyze_simple_operation(self, op, graphinfo):
- if op.opname in ('yield_current_frame_to_caller', 'resume_point',
- 'resume_state_invoke', 'resume_state_create', 'stack_frames_depth',
+ if op.opname in ('yield_current_frame_to_caller', 'stack_frames_depth',
'stack_switch', 'stack_unwind', 'stack_capture',
'get_stack_depth_limit', 'set_stack_depth_limit'):
return True
@@ -458,24 +444,11 @@
self.is_finished = False
- # only for sanity checking, but still very very important
- self.explicit_resume_point_data = {}
-
- self.symbolic_restart_numbers = {}
-
- # 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
self.frametyper.ensure_frame_type_for_types(frame_type)
self.register_restart_info(restartinfo)
@@ -589,156 +562,6 @@
# yes
convertblock.exits[0].args[index] = newvar
# end ouch!
-
- def handle_resume_point(self, block, i):
- # in some circumstances we might be able to reuse
- # an already inserted resume point
- op = block.operations[i]
- if i == len(block.operations) - 1:
- link = block.exits[0]
- nextblock = None
- else:
- link = split_block(None, block, i+1)
- i = 0
- nextblock = link.target
-
- label = op.args[0].value
-
- parms = op.args[1:]
- if not isinstance(parms[0], model.Variable):
- assert parms[0].value is None
- parms[0] = None
- args = vars_to_save(block)
- for a in args:
- if a not in parms:
- raise Exception, "not covered needed value at resume_point %r"%(label,)
- 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, varsforcall, saver) = self.frametyper.frame_type_for_vars(parms[1:])
-
- if label in self.explicit_resume_point_data:
- OTHER_TYPE = self.explicit_resume_point_data[label]
- assert FRAME_TYPE == OTHER_TYPE, "inconsistent types for label %r"%(label,)
- else:
- self.explicit_resume_point_data[label] = FRAME_TYPE
-
- self._make_resume_handling(FRAME_TYPE, varsforcall, res, block.exits)
-
- restart_number = len(self.masterarray1) + len(self.resume_blocks) - 1
-
- if label in self.symbolic_restart_numbers:
- symb = self.symbolic_restart_numbers[label]
- assert symb.value is None
- symb.value = restart_number
- else:
- symb = SymbolicRestartNumber(label, restart_number)
- self.symbolic_restart_numbers[label] = symb
-
- return nextblock
-
- def handle_resume_state_create(self, block, i):
- op = block.operations[i]
- llops = LowLevelOpList()
- label = op.args[1].value
- parms = op.args[2:]
- FRAME_TYPE, varsforcall, saver = self.frametyper.frame_type_for_vars(parms)
-
- if label in self.explicit_resume_point_data:
- OTHER_TYPE = self.explicit_resume_point_data[label]
- assert FRAME_TYPE == OTHER_TYPE, "inconsistent types for label %r"%(label,)
- else:
- self.explicit_resume_point_data[label] = FRAME_TYPE
-
- if label in self.symbolic_restart_numbers:
- symb = self.symbolic_restart_numbers[label]
- else:
- symb = SymbolicRestartNumber(label)
- self.symbolic_restart_numbers[label] = symb
-
- # this is rather insane: we create an exception object, pass
- # it to the saving function, then read the thus created state
- # out of and then clear global_state.top
- c_EXC = model.Constant(self.unwind_exception_type.TO, lltype.Void)
- 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:
- if v.concretetype != lltype.Void:
- realvarsforcall.append(gen_cast(llops, storage_type(v.concretetype), v))
-
- llops.genop('direct_call',
- [model.Constant(saver, lltype.typeOf(saver)), v_exc,
- model.Constant(symb, lltype.Signed)] + realvarsforcall,
- resulttype = lltype.Void)
- v_state = varoftype(lltype.Ptr(frame.STATE_HEADER))
- v_state_hdr = llops.genop("getfield",
- [self.ll_global_state, self.c_inst_top_name],
- resulttype=lltype.Ptr(STATE_HEADER))
- v_state = gen_cast(llops, lltype.Ptr(FRAME_TYPE), v_state_hdr)
- llops.genop("setfield",
- [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('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
-
- def handle_resume_state_invoke(self, block):
- op = block.operations[-1]
- assert op.opname == 'resume_state_invoke'
- # some commentary.
- #
- # we don't want to write 155 or so different versions of
- # resume_after_foo that appear to the annotator to return
- # different types. we take advantage of the fact that this
- # function always raises UnwindException and have it (appear
- # to) return Void. then to placate all the other machinery,
- # we pass a constant zero-of-the-appropriate-type along the
- # non-exceptional link (which we know will never be taken).
- # Nota Bene: only mutate a COPY of the non-exceptional link
- # because the non-exceptional link has been stored in
- # self.resume_blocks and we don't want a constant "zero" in
- # there.
- v_state = op.args[0]
- v_returning = op.args[1]
- v_raising = op.args[2]
- llops = LowLevelOpList()
-
- if v_raising.concretetype == lltype.Void:
- erased_type = storage_type(v_returning.concretetype)
- resume_after_ptr = self.resume_afters[erased_type]
- v_param = v_returning
- else:
- assert v_returning.concretetype == lltype.Void
- erased_type = self.exception_type
- resume_after_ptr = self.resume_after_raising_ptr
- v_param = v_raising
-
- if erased_type != v_param.concretetype:
- v_param = gen_cast(llops, erased_type, v_param)
- llops.genop('direct_call', [resume_after_ptr, v_state, v_param],
- resulttype=lltype.Void)
-
- del block.operations[-1]
- block.operations.extend(llops)
-
- noexclink = block.exits[0].copy()
- realrettype = op.result.concretetype
- for i, a in enumerate(noexclink.args):
- if a is op.result:
- noexclink.args[i] = model.Constant(realrettype._defl(), realrettype)
- block.recloseblock(*((noexclink,) + block.exits[1:]))
def insert_unwind_handling(self, block, i):
# for the case where we are resuming to an except:
@@ -821,19 +644,8 @@
op = replace_with_call(self.operation_replacement[op.opname])
stackless_op = True
- if op.opname == 'resume_state_create':
- self.handle_resume_state_create(block, i)
- continue # go back and look at that malloc
-
if (op.opname in ('direct_call', 'indirect_call')
or self.analyzer.analyze(op)):
- if op.opname == 'resume_point':
- block = self.handle_resume_point(block, i)
- if block is None:
- return
- else:
- i = 0
- continue
if not stackless_op and not self.analyzer.analyze(op):
i += 1
@@ -849,9 +661,7 @@
continue
nextblock = self.insert_unwind_handling(block, i)
- if op.opname == 'resume_state_invoke':
- self.handle_resume_state_invoke(block)
-
+
if nextblock is None:
return
More information about the pypy-commit
mailing list