[pypy-svn] r69735 - in pypy/branch/virtual-forcing/pypy: annotation rpython/lltypesystem rpython/lltypesystem/test translator/backendopt translator/backendopt/test translator/stackless
arigo at codespeak.net
arigo at codespeak.net
Sun Nov 29 16:38:50 CET 2009
Author: arigo
Date: Sun Nov 29 16:38:49 2009
New Revision: 69735
Modified:
pypy/branch/virtual-forcing/pypy/annotation/description.py
pypy/branch/virtual-forcing/pypy/rpython/lltypesystem/rffi.py
pypy/branch/virtual-forcing/pypy/rpython/lltypesystem/test/test_rffi.py
pypy/branch/virtual-forcing/pypy/translator/backendopt/canraise.py
pypy/branch/virtual-forcing/pypy/translator/backendopt/graphanalyze.py
pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_canraise.py
pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_writeanalyze.py
pypy/branch/virtual-forcing/pypy/translator/backendopt/writeanalyze.py
pypy/branch/virtual-forcing/pypy/translator/stackless/transform.py
Log:
issue487 testing
(pedronis, arigo)
Fix, mostly for the WriteAnalyzer and the VirtualizableAnalyzer:
record exactly which RPython callback functions a given llexternal
function can invoke, and use this information in the GraphAnalyzer.
Modified: pypy/branch/virtual-forcing/pypy/annotation/description.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/annotation/description.py (original)
+++ pypy/branch/virtual-forcing/pypy/annotation/description.py Sun Nov 29 16:38:49 2009
@@ -202,6 +202,9 @@
graph.name = alt_name
return graph
+ def getgraphs(self):
+ return self._cache.values()
+
def getuniquegraph(self):
if len(self._cache) != 1:
raise NoStandardGraph(self)
Modified: pypy/branch/virtual-forcing/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/rpython/lltypesystem/rffi.py (original)
+++ pypy/branch/virtual-forcing/pypy/rpython/lltypesystem/rffi.py Sun Nov 29 16:38:49 2009
@@ -57,7 +57,7 @@
def llexternal(name, args, result, _callable=None,
compilation_info=ExternalCompilationInfo(),
sandboxsafe=False, threadsafe='auto',
- canraise=False, _nowrapper=False, calling_conv='c',
+ _nowrapper=False, calling_conv='c',
oo_primitive=None, pure_function=False):
"""Build an external function that will invoke the C function 'name'
with the given 'args' types and 'result' type.
@@ -68,6 +68,10 @@
pointing to a read-only null-terminated character of arrays, as usual
for C.
+ The C function can have callbacks, but they must be specified explicitly
+ as constant RPython functions. We don't support yet C functions that
+ invoke callbacks passed otherwise (e.g. set by a previous C call).
+
threadsafe: whether it's ok to release the GIL around the call.
Default is yes, unless sandboxsafe is set, in which case
we consider that the function is really short-running and
@@ -84,12 +88,22 @@
kwds = {}
if oo_primitive:
kwds['oo_primitive'] = oo_primitive
+
+ has_callback = False
+ for ARG in args:
+ if _isfunctype(ARG):
+ has_callback = True
+ if has_callback:
+ kwds['_callbacks'] = callbackholder = CallbackHolder()
+ else:
+ callbackholder = None
+
funcptr = lltype.functionptr(ext_type, name, external='C',
compilation_info=compilation_info,
_callable=_callable,
_safe_not_sandboxed=sandboxsafe,
_debugexc=True, # on top of llinterp
- canraise=canraise,
+ canraise=False,
**kwds)
if isinstance(_callable, ll2ctypes.LL2CtypesCallable):
_callable.funcptr = funcptr
@@ -170,9 +184,11 @@
# XXX pass additional arguments
if invoke_around_handlers:
arg = llhelper(TARGET, _make_wrapper_for(TARGET, arg,
+ callbackholder,
aroundstate))
else:
- arg = llhelper(TARGET, _make_wrapper_for(TARGET, arg))
+ arg = llhelper(TARGET, _make_wrapper_for(TARGET, arg,
+ callbackholder))
else:
SOURCE = lltype.typeOf(arg)
if SOURCE != TARGET:
@@ -202,7 +218,11 @@
return func_with_new_name(wrapper, name)
-def _make_wrapper_for(TP, callable, aroundstate=None):
+class CallbackHolder:
+ def __init__(self):
+ self.callbacks = {}
+
+def _make_wrapper_for(TP, callable, callbackholder, aroundstate=None):
""" Function creating wrappers for callbacks. Note that this is
cheating as we assume constant callbacks and we just memoize wrappers
"""
@@ -213,6 +233,7 @@
else:
errorcode = TP.TO.RESULT._example()
callable_name = getattr(callable, '__name__', '?')
+ callbackholder.callbacks[callable] = True
args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))])
source = py.code.Source(r"""
def wrapper(%s): # no *args - no GIL for mallocing the tuple
Modified: pypy/branch/virtual-forcing/pypy/rpython/lltypesystem/test/test_rffi.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/rpython/lltypesystem/test/test_rffi.py (original)
+++ pypy/branch/virtual-forcing/pypy/rpython/lltypesystem/test/test_rffi.py Sun Nov 29 16:38:49 2009
@@ -387,6 +387,7 @@
fn = self.compile(f, [])
assert fn() == 6
+ assert eating_callback._ptr._obj._callbacks.callbacks == {g: True}
def test_double_callback(self):
eating_callback = self.eating_callback()
@@ -406,6 +407,8 @@
fn = self.compile(f, [int])
assert fn(4) == 4
assert fn(1) == 3
+ assert eating_callback._ptr._obj._callbacks.callbacks == {one: True,
+ two: True}
def test_exception_callback(self):
eating_callback = self.eating_callback()
Modified: pypy/branch/virtual-forcing/pypy/translator/backendopt/canraise.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/backendopt/canraise.py (original)
+++ pypy/branch/virtual-forcing/pypy/translator/backendopt/canraise.py Sun Nov 29 16:38:49 2009
@@ -17,7 +17,7 @@
log.WARNING("Unknown operation: %s" % op.opname)
return True
- def analyze_external_call(self, op):
+ def analyze_external_call(self, op, seen=None):
fnobj = get_funcobj(op.args[0].value)
return getattr(fnobj, 'canraise', True)
Modified: pypy/branch/virtual-forcing/pypy/translator/backendopt/graphanalyze.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/backendopt/graphanalyze.py (original)
+++ pypy/branch/virtual-forcing/pypy/translator/backendopt/graphanalyze.py Sun Nov 29 16:38:49 2009
@@ -1,4 +1,4 @@
-from pypy.translator.simplify import get_graph
+from pypy.translator.simplify import get_graph, get_funcobj
from pypy.rpython.lltypesystem.lloperation import llop, LL_OPERATIONS
from pypy.rpython.lltypesystem import lltype
@@ -38,8 +38,17 @@
def analyze_startblock(self, block, seen=None):
return self.bottom_result()
- def analyze_external_call(self, op):
- return self.top_result()
+ def analyze_external_call(self, op, seen=None):
+ funcobj = get_funcobj(op.args[0].value)
+ result = self.bottom_result()
+ if hasattr(funcobj, '_callbacks'):
+ bk = self.translator.annotator.bookkeeper
+ for function in funcobj._callbacks.callbacks:
+ desc = bk.getdesc(function)
+ for graph in desc.getgraphs():
+ result = self.join_two_results(
+ result, self.analyze_direct_call(graph, seen))
+ return result
def analyze_external_method(self, op, TYPE, meth):
return self.top_result()
@@ -59,7 +68,7 @@
if op.opname == "direct_call":
graph = get_graph(op.args[0], self.translator)
if graph is None:
- return self.analyze_external_call(op)
+ return self.analyze_external_call(op, seen)
return self.analyze_direct_call(graph, seen)
elif op.opname == "indirect_call":
if op.args[-1].value is None:
Modified: pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_canraise.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_canraise.py (original)
+++ pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_canraise.py Sun Nov 29 16:38:49 2009
@@ -189,7 +189,8 @@
result = ra.can_raise(fgraph.startblock.operations[0])
assert not result
- z = llexternal('z', [lltype.Signed], lltype.Signed, canraise=True)
+ z = lltype.functionptr(lltype.FuncType([lltype.Signed], lltype.Signed),
+ 'foobar')
def g(x):
return z(x)
t, ra = self.translate(g, [int])
Modified: pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_writeanalyze.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_writeanalyze.py (original)
+++ pypy/branch/virtual-forcing/pypy/translator/backendopt/test/test_writeanalyze.py Sun Nov 29 16:38:49 2009
@@ -178,6 +178,31 @@
assert name == "length"
assert S1 is S2
+ def test_llexternal_with_callback(self):
+ from pypy.rpython.lltypesystem.rffi import llexternal
+ from pypy.rpython.lltypesystem import lltype
+
+ class Abc:
+ pass
+ abc = Abc()
+
+ FUNC = lltype.FuncType([lltype.Signed], lltype.Signed)
+ z = llexternal('z', [lltype.Ptr(FUNC)], lltype.Signed)
+ def g(n):
+ abc.foobar = n
+ return n + 1
+ def f(x):
+ return z(g)
+ t, wa = self.translate(f, [int])
+ fgraph = graphof(t, f)
+ backend_optimizations(t)
+ assert fgraph.startblock.operations[0].opname == 'direct_call'
+
+ result = wa.analyze(fgraph.startblock.operations[0])
+ assert len(result) == 1
+ (struct, T, name), = result
+ assert struct == "struct"
+ assert name.endswith("foobar")
class TestOOtype(BaseTestCanRaise):
Modified: pypy/branch/virtual-forcing/pypy/translator/backendopt/writeanalyze.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/backendopt/writeanalyze.py (original)
+++ pypy/branch/virtual-forcing/pypy/translator/backendopt/writeanalyze.py Sun Nov 29 16:38:49 2009
@@ -37,9 +37,6 @@
def _array_result(self, TYPE):
return frozenset([("array", TYPE)])
- def analyze_external_call(self, op):
- return self.bottom_result() # an external call cannot change anything
-
def analyze_external_method(self, op, TYPE, meth):
if isinstance(TYPE, ootype.Array):
methname = op.args[0].value
Modified: pypy/branch/virtual-forcing/pypy/translator/stackless/transform.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/translator/stackless/transform.py (original)
+++ pypy/branch/virtual-forcing/pypy/translator/stackless/transform.py Sun Nov 29 16:38:49 2009
@@ -260,7 +260,7 @@
return LL_OPERATIONS[op.opname].canunwindgc
return False
- def analyze_external_call(self, op):
+ def analyze_external_call(self, op, seen=None):
# An external call cannot cause a stack unwind
# Note that this is essential to get good performance in framework GCs
# because there is a pseudo-external call to ROUND_UP_FOR_ALLOCATION
More information about the Pypy-commit
mailing list