jit/metainterp/test/test_fficall.py::TestFfiCall::()::test_guard_not_forced_fails
self = <rpython.jit.metainterp.test.test_fficall.TestFfiCall object at 0x7f52a3f5c790>
def test_guard_not_forced_fails(self):
self._add_libffi_types_to_ll2types_maybe()
FUNC = lltype.FuncType([lltype.Signed], lltype.Signed)
cif_description = get_description([types.slong], types.slong)
cif_description.exchange_args[0] = 16
cif_description.exchange_result = 32
ARRAY = lltype.Ptr(rffi.CArray(lltype.Signed))
@jit.dont_look_inside
def fn(n):
if n >= 50:
exctx.m = exctx.topframeref().n # forces the frame
return n*2
# this function simulates what a real libffi_call does: reading from
# the buffer, calling a function (which can potentially call callbacks
# and force frames) and write back to the buffer
def fake_call_impl_any(cif_description, func_addr, exchange_buffer):
# read the args from the buffer
data_in = rffi.ptradd(exchange_buffer, 16)
n = rffi.cast(ARRAY, data_in)[0]
#
# logic of the function
func_ptr = rffi.cast(lltype.Ptr(FUNC), func_addr)
n = func_ptr(n)
#
# write the result to the buffer
data_out = rffi.ptradd(exchange_buffer, 32)
rffi.cast(ARRAY, data_out)[0] = n
def do_call(n):
func_ptr = llhelper(lltype.Ptr(FUNC), fn)
exbuf = lltype.malloc(rffi.CCHARP.TO, 48, flavor='raw', zero=True)
data_in = rffi.ptradd(exbuf, 16)
rffi.cast(ARRAY, data_in)[0] = n
jit_ffi_call(cif_description, func_ptr, exbuf)
data_out = rffi.ptradd(exbuf, 32)
res = rffi.cast(ARRAY, data_out)[0]
lltype.free(exbuf, flavor='raw')
return res
#
#
class XY:
pass
class ExCtx:
pass
exctx = ExCtx()
myjitdriver = jit.JitDriver(greens = [], reds = ['n'])
def f():
n = 0
while n < 100:
myjitdriver.jit_merge_point(n=n)
xy = XY()
xy.n = n
exctx.topframeref = vref = jit.virtual_ref(xy)
res = do_call(n) # this is equivalent of a cffi call which
# sometimes forces a frame
# when n==50, fn() will force the frame, so guard_not_forced
# fails and we enter blackholing: this test makes sure that
# the result of call_release_gil is kept alive before the
# raw_store, and that the corresponding box is passed
# in the fail_args. Before the fix, the result of
# call_release_gil was simply lost and when guard_not_forced
# failed, and the value of "res" was unpredictable.
# See commit b84ff38f34bd and subsequents.
assert res == n*2
jit.virtual_ref_finish(vref, xy)
exctx.topframeref = jit.vref_None
n += 1
return n
> with FakeFFI(fake_call_impl_any):
jit/metainterp/test/test_fficall.py:322:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <rpython.jit.metainterp.test.test_fficall.FakeFFI object at 0x7f52a3f5ce50>
args = ()
def __enter__(self, *args):
> self.monkey.setattr(jit_libffi, 'jit_ffi_call_impl_any', self.fake_call_impl_any)
E AttributeError: 'generator' object has no attribute 'setattr'
jit/metainterp/test/test_fficall.py:40: AttributeError
builder: rpython-linux-x86-64 build #887
test: jit/metainterp/test/test_fficall/py/TestFfiCall/()/test_guard_not_forced_fails