Author: Armin Rigo <ar...@tunes.org> Branch: ffi-backend Changeset: r56544:4f436a389717 Date: 2012-08-02 13:33 +0200 http://bitbucket.org/pypy/pypy/changeset/4f436a389717/
Log: Remove this version of libffi.py. diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py deleted file mode 100644 --- a/pypy/rlib/libffi.py +++ /dev/null @@ -1,434 +0,0 @@ -from __future__ import with_statement - -from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rlib.objectmodel import specialize, enforceargs -from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat, r_longlong -from pypy.rlib import jit -from pypy.rlib import clibffi -from pypy.rlib.clibffi import FUNCFLAG_CDECL, FUNCFLAG_STDCALL, \ - AbstractFuncPtr, push_arg_as_ffiptr, c_ffi_call, FFI_TYPE_STRUCT -from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal -from pypy.rlib.rdynload import DLLHANDLE - -import os - -class types(object): - """ - This namespace contains the primitive types you can use to declare the - signatures of the ffi functions. - - In general, the name of the types are closely related to the ones of the - C-level ffi_type_*: e.g, instead of ffi_type_sint you should use - libffi.types.sint. - - However, you should not rely on a perfect correspondence: in particular, - the exact meaning of ffi_type_{slong,ulong} changes a lot between libffi - versions, so types.slong could be different than ffi_type_slong. - """ - - @classmethod - def _import(cls): - prefix = 'ffi_type_' - for key, value in clibffi.__dict__.iteritems(): - if key.startswith(prefix): - name = key[len(prefix):] - setattr(cls, name, value) - cls.slong = clibffi.cast_type_to_ffitype(rffi.LONG) - cls.ulong = clibffi.cast_type_to_ffitype(rffi.ULONG) - cls.slonglong = clibffi.cast_type_to_ffitype(rffi.LONGLONG) - cls.ulonglong = clibffi.cast_type_to_ffitype(rffi.ULONGLONG) - cls.signed = clibffi.cast_type_to_ffitype(rffi.SIGNED) - cls.wchar_t = clibffi.cast_type_to_ffitype(lltype.UniChar) - del cls._import - - @staticmethod - @jit.elidable - def getkind(ffi_type): - """Returns 'v' for void, 'f' for float, 'i' for signed integer, - and 'u' for unsigned integer. - """ - if ffi_type is types.void: return 'v' - elif ffi_type is types.double: return 'f' - elif ffi_type is types.float: return 's' - elif ffi_type is types.pointer: return 'u' - # - elif ffi_type is types.schar: return 'i' - elif ffi_type is types.uchar: return 'u' - elif ffi_type is types.sshort: return 'i' - elif ffi_type is types.ushort: return 'u' - elif ffi_type is types.sint: return 'i' - elif ffi_type is types.uint: return 'u' - elif ffi_type is types.slong: return 'i' - elif ffi_type is types.ulong: return 'u' - # - elif ffi_type is types.sint8: return 'i' - elif ffi_type is types.uint8: return 'u' - elif ffi_type is types.sint16: return 'i' - elif ffi_type is types.uint16: return 'u' - elif ffi_type is types.sint32: return 'i' - elif ffi_type is types.uint32: return 'u' - ## (note that on 64-bit platforms, types.sint64 is types.slong and the - ## case is caught above) - elif ffi_type is types.sint64: return 'I' - elif ffi_type is types.uint64: return 'U' - # - elif types.is_struct(ffi_type): return 'S' - raise KeyError - - @staticmethod - @jit.elidable - def is_struct(ffi_type): - return intmask(ffi_type.c_type) == FFI_TYPE_STRUCT - -types._import() - -# this was '_fits_into_long', which is not adequate, because long is -# not necessary the type where we compute with. Actually meant is -# the type 'Signed'. - -@specialize.arg(0) -def _fits_into_signed(TYPE): - if isinstance(TYPE, lltype.Ptr): - return True # pointers always fits into Signeds - if not isinstance(TYPE, lltype.Primitive): - return False - if TYPE is lltype.Void or TYPE is rffi.FLOAT or TYPE is rffi.DOUBLE: - return False - sz = rffi.sizeof(TYPE) - return sz <= rffi.sizeof(rffi.SIGNED) - - -# ====================================================================== - -IS_32_BIT = (r_uint.BITS == 32) - -@specialize.memo() -def _check_type(TYPE): - if isinstance(TYPE, lltype.Ptr): - if TYPE.TO._gckind != 'raw': - raise TypeError, "Can only push raw values to C, not 'gc'" - # XXX probably we should recursively check for struct fields here, - # lets just ignore that for now - if isinstance(TYPE.TO, lltype.Array) and 'nolength' not in TYPE.TO._hints: - raise TypeError, "Can only push to C arrays without length info" - - -class ArgChain(object): - first = None - last = None - numargs = 0 - - @specialize.argtype(1) - def arg(self, val): - TYPE = lltype.typeOf(val) - _check_type(TYPE) - if _fits_into_signed(TYPE): - cls = IntArg - val = rffi.cast(rffi.SIGNED, val) - elif TYPE is rffi.DOUBLE: - cls = FloatArg - elif TYPE is rffi.LONGLONG or TYPE is rffi.ULONGLONG: - cls = LongLongArg - val = rffi.cast(rffi.LONGLONG, val) - elif TYPE is rffi.FLOAT: - cls = SingleFloatArg - else: - raise TypeError, 'Unsupported argument type: %s' % TYPE - self._append(cls(val)) - return self - - def arg_raw(self, val): - self._append(RawArg(val)) - - def _append(self, arg): - if self.first is None: - self.first = self.last = arg - else: - self.last.next = arg - self.last = arg - self.numargs += 1 - - -class AbstractArg(object): - next = None - -class IntArg(AbstractArg): - """ An argument holding an integer - """ - - def __init__(self, intval): - self.intval = intval - - def push(self, func, ll_args, i): - func._push_int(self.intval, ll_args, i) - - -class FloatArg(AbstractArg): - """ An argument holding a python float (i.e. a C double) - """ - - def __init__(self, floatval): - self.floatval = floatval - - def push(self, func, ll_args, i): - func._push_float(self.floatval, ll_args, i) - -class RawArg(AbstractArg): - """ An argument holding a raw pointer to put inside ll_args - """ - - def __init__(self, ptrval): - self.ptrval = ptrval - - def push(self, func, ll_args, i): - func._push_raw(self.ptrval, ll_args, i) - -class SingleFloatArg(AbstractArg): - """ An argument representing a C float - """ - - def __init__(self, singlefloatval): - self.singlefloatval = singlefloatval - - def push(self, func, ll_args, i): - func._push_singlefloat(self.singlefloatval, ll_args, i) - - -class LongLongArg(AbstractArg): - """ An argument representing a C long long - """ - - def __init__(self, longlongval): - self.longlongval = longlongval - - def push(self, func, ll_args, i): - func._push_longlong(self.longlongval, ll_args, i) - - -# ====================================================================== - - -class Func(AbstractFuncPtr): - - _immutable_fields_ = ['funcsym'] - argtypes = [] - restype = clibffi.FFI_TYPE_NULL - flags = 0 - funcsym = lltype.nullptr(rffi.VOIDP.TO) - - def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL, - keepalive=None): - AbstractFuncPtr.__init__(self, name, argtypes, restype, flags) - self.keepalive = keepalive - self.funcsym = funcsym - - # ======================================================================== - # PUBLIC INTERFACE - # ======================================================================== - - @jit.unroll_safe - @specialize.arg(2, 3) - def call(self, argchain, RESULT, is_struct=False): - # WARNING! This code is written carefully in a way that the JIT - # optimizer will see a sequence of calls like the following: - # - # libffi_prepare_call - # libffi_push_arg - # libffi_push_arg - # ... - # libffi_call - # - # It is important that there is no other operation in the middle, else - # the optimizer will fail to recognize the pattern and won't turn it - # into a fast CALL. Note that "arg = arg.next" is optimized away, - # assuming that argchain is completely virtual. - self = jit.promote(self) - if argchain.numargs != len(self.argtypes): - raise TypeError, 'Wrong number of arguments: %d expected, got %d' %\ - (len(self.argtypes), argchain.numargs) - ll_args = self._prepare() - i = 0 - arg = argchain.first - while arg: - arg.push(self, ll_args, i) - i += 1 - arg = arg.next - # - if is_struct: - assert types.is_struct(self.restype) - res = self._do_call_raw(self.funcsym, ll_args) - elif _fits_into_signed(RESULT): - assert not types.is_struct(self.restype) - res = self._do_call_int(self.funcsym, ll_args) - elif RESULT is rffi.DOUBLE: - return self._do_call_float(self.funcsym, ll_args) - elif RESULT is rffi.FLOAT: - return self._do_call_singlefloat(self.funcsym, ll_args) - elif RESULT is rffi.LONGLONG or RESULT is rffi.ULONGLONG: - assert IS_32_BIT - res = self._do_call_longlong(self.funcsym, ll_args) - elif RESULT is lltype.Void: - return self._do_call_void(self.funcsym, ll_args) - else: - raise TypeError, 'Unsupported result type: %s' % RESULT - # - return rffi.cast(RESULT, res) - - # END OF THE PUBLIC INTERFACE - # ------------------------------------------------------------------------ - - # JIT friendly interface - # the following methods are supposed to be seen opaquely by the optimizer - - @jit.oopspec('libffi_prepare_call(self)') - def _prepare(self): - ll_args = lltype.malloc(rffi.VOIDPP.TO, len(self.argtypes), flavor='raw') - return ll_args - - - # _push_* and _do_call_* in theory could be automatically specialize()d by - # the annotator. However, specialization doesn't work well with oopspec, - # so we specialize them by hand - - @jit.oopspec('libffi_push_int(self, value, ll_args, i)') - @enforceargs( None, int, None, int) # fix the annotation for tests - def _push_int(self, value, ll_args, i): - self._push_arg(value, ll_args, i) - - @jit.dont_look_inside - def _push_raw(self, value, ll_args, i): - ll_args[i] = value - - @jit.oopspec('libffi_push_float(self, value, ll_args, i)') - @enforceargs( None, float, None, int) # fix the annotation for tests - def _push_float(self, value, ll_args, i): - self._push_arg(value, ll_args, i) - - @jit.oopspec('libffi_push_singlefloat(self, value, ll_args, i)') - @enforceargs(None, r_singlefloat, None, int) # fix the annotation for tests - def _push_singlefloat(self, value, ll_args, i): - self._push_arg(value, ll_args, i) - - @jit.oopspec('libffi_push_longlong(self, value, ll_args, i)') - @enforceargs(None, r_longlong, None, int) # fix the annotation for tests - def _push_longlong(self, value, ll_args, i): - self._push_arg(value, ll_args, i) - - @jit.oopspec('libffi_call_int(self, funcsym, ll_args)') - def _do_call_int(self, funcsym, ll_args): - return self._do_call(funcsym, ll_args, rffi.SIGNED) - - @jit.oopspec('libffi_call_float(self, funcsym, ll_args)') - def _do_call_float(self, funcsym, ll_args): - return self._do_call(funcsym, ll_args, rffi.DOUBLE) - - @jit.oopspec('libffi_call_singlefloat(self, funcsym, ll_args)') - def _do_call_singlefloat(self, funcsym, ll_args): - return self._do_call(funcsym, ll_args, rffi.FLOAT) - - @jit.dont_look_inside - def _do_call_raw(self, funcsym, ll_args): - # same as _do_call_int, but marked as jit.dont_look_inside - return self._do_call(funcsym, ll_args, rffi.SIGNED) - - @jit.oopspec('libffi_call_longlong(self, funcsym, ll_args)') - def _do_call_longlong(self, funcsym, ll_args): - return self._do_call(funcsym, ll_args, rffi.LONGLONG) - - @jit.oopspec('libffi_call_void(self, funcsym, ll_args)') - def _do_call_void(self, funcsym, ll_args): - return self._do_call(funcsym, ll_args, lltype.Void) - - # ------------------------------------------------------------------------ - # private methods - - @specialize.argtype(1) - def _push_arg(self, value, ll_args, i): - # XXX: check the type is not translated? - argtype = self.argtypes[i] - c_size = intmask(argtype.c_size) - ll_buf = lltype.malloc(rffi.CCHARP.TO, c_size, flavor='raw') - push_arg_as_ffiptr(argtype, value, ll_buf) - ll_args[i] = ll_buf - - @specialize.arg(3) - def _do_call(self, funcsym, ll_args, RESULT): - # XXX: check len(args)? - ll_result = lltype.nullptr(rffi.CCHARP.TO) - if self.restype != types.void: - ll_result = lltype.malloc(rffi.CCHARP.TO, - intmask(self.restype.c_size), - flavor='raw') - ffires = c_ffi_call(self.ll_cif, - self.funcsym, - rffi.cast(rffi.VOIDP, ll_result), - rffi.cast(rffi.VOIDPP, ll_args)) - if RESULT is not lltype.Void: - TP = lltype.Ptr(rffi.CArray(RESULT)) - buf = rffi.cast(TP, ll_result) - if types.is_struct(self.restype): - assert RESULT == rffi.SIGNED - # for structs, we directly return the buffer and transfer the - # ownership - res = rffi.cast(RESULT, buf) - else: - res = buf[0] - else: - res = None - self._free_buffers(ll_result, ll_args) - clibffi.check_fficall_result(ffires, self.flags) - return res - - def _free_buffers(self, ll_result, ll_args): - if ll_result: - self._free_buffer_maybe(rffi.cast(rffi.VOIDP, ll_result), self.restype) - for i in range(len(self.argtypes)): - argtype = self.argtypes[i] - self._free_buffer_maybe(ll_args[i], argtype) - lltype.free(ll_args, flavor='raw') - - def _free_buffer_maybe(self, buf, ffitype): - # if it's a struct, the buffer is not freed and the ownership is - # already of the caller (in case of ll_args buffers) or transferred to - # it (in case of ll_result buffer) - if not types.is_struct(ffitype): - lltype.free(buf, flavor='raw') - - -# ====================================================================== - - -# XXX: it partially duplicate the code in clibffi.py -class CDLL(object): - def __init__(self, libname, mode=-1): - """Load the library, or raises DLOpenError.""" - self.lib = rffi.cast(DLLHANDLE, 0) - with rffi.scoped_str2charp(libname) as ll_libname: - self.lib = dlopen(ll_libname, mode) - - def __del__(self): - if self.lib: - dlclose(self.lib) - self.lib = rffi.cast(DLLHANDLE, 0) - - def getpointer(self, name, argtypes, restype, flags=FUNCFLAG_CDECL): - return Func(name, argtypes, restype, dlsym(self.lib, name), - flags=flags, keepalive=self) - - def getpointer_by_ordinal(self, name, argtypes, restype, - flags=FUNCFLAG_CDECL): - return Func('by_ordinal', argtypes, restype, - dlsym_byordinal(self.lib, name), - flags=flags, keepalive=self) - def getaddressindll(self, name): - return dlsym(self.lib, name) - -if os.name == 'nt': - class WinDLL(CDLL): - def getpointer(self, name, argtypes, restype, flags=FUNCFLAG_STDCALL): - return Func(name, argtypes, restype, dlsym(self.lib, name), - flags=flags, keepalive=self) - def getpointer_by_ordinal(self, name, argtypes, restype, - flags=FUNCFLAG_STDCALL): - return Func(name, argtypes, restype, dlsym_byordinal(self.lib, name), - flags=flags, keepalive=self) diff --git a/pypy/rlib/test/test_libffi.py b/pypy/rlib/test/test_libffi.py deleted file mode 100644 --- a/pypy/rlib/test/test_libffi.py +++ /dev/null @@ -1,610 +0,0 @@ -import os - -import py - -from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong -from pypy.rlib.test.test_clibffi import BaseFfiTest, make_struct_ffitype_e -from pypy.rpython.lltypesystem import rffi, lltype -from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED -from pypy.rpython.llinterp import LLException -from pypy.rlib.libffi import (CDLL, ArgChain, types, - IS_32_BIT, array_getitem, array_setitem) -from pypy.rlib.libffi import (struct_getfield_int, struct_setfield_int, - struct_getfield_longlong, struct_setfield_longlong, - struct_getfield_float, struct_setfield_float, - struct_getfield_singlefloat, struct_setfield_singlefloat) - -class TestLibffiMisc(BaseFfiTest): - - CDLL = CDLL - - def test_argchain(self): - chain = ArgChain() - assert chain.numargs == 0 - chain2 = chain.arg(42) - assert chain2 is chain - assert chain.numargs == 1 - intarg = chain.first - assert chain.last is intarg - assert intarg.intval == 42 - chain.arg(123.45) - assert chain.numargs == 2 - assert chain.first is intarg - assert intarg.next is chain.last - floatarg = intarg.next - assert floatarg.floatval == 123.45 - - def test_wrong_args(self): - # so far the test passes but for the wrong reason :-), i.e. because - # .arg() only supports integers and floats - chain = ArgChain() - x = lltype.malloc(lltype.GcStruct('xxx')) - y = lltype.malloc(lltype.GcArray(rffi.SIGNED), 3) - z = lltype.malloc(lltype.Array(rffi.SIGNED), 4, flavor='raw') - py.test.raises(TypeError, "chain.arg(x)") - py.test.raises(TypeError, "chain.arg(y)") - py.test.raises(TypeError, "chain.arg(z)") - lltype.free(z, flavor='raw') - - def test_library_open(self): - lib = self.get_libc() - del lib - assert not ALLOCATED - - def test_library_get_func(self): - lib = self.get_libc() - ptr = lib.getpointer('fopen', [], types.void) - py.test.raises(KeyError, lib.getpointer, 'xxxxxxxxxxxxxxx', [], types.void) - del ptr - del lib - assert not ALLOCATED - - def test_struct_fields(self): - longsize = 4 if IS_32_BIT else 8 - POINT = lltype.Struct('POINT', - ('x', rffi.LONG), - ('y', rffi.SHORT), - ('z', rffi.VOIDP), - ) - y_ofs = longsize - z_ofs = longsize*2 - p = lltype.malloc(POINT, flavor='raw') - p.x = 42 - p.y = rffi.cast(rffi.SHORT, -1) - p.z = rffi.cast(rffi.VOIDP, 0x1234) - addr = rffi.cast(rffi.VOIDP, p) - assert struct_getfield_int(types.slong, addr, 0) == 42 - assert struct_getfield_int(types.sshort, addr, y_ofs) == -1 - assert struct_getfield_int(types.pointer, addr, z_ofs) == 0x1234 - # - struct_setfield_int(types.slong, addr, 0, 43) - struct_setfield_int(types.sshort, addr, y_ofs, 0x1234FFFE) # 0x1234 is masked out - struct_setfield_int(types.pointer, addr, z_ofs, 0x4321) - assert p.x == 43 - assert p.y == -2 - assert rffi.cast(rffi.LONG, p.z) == 0x4321 - # - lltype.free(p, flavor='raw') - - def test_array_fields(self): - POINT = lltype.Struct("POINT", - ("x", lltype.Float), - ("y", lltype.Float), - ) - points = lltype.malloc(rffi.CArray(POINT), 2, flavor="raw") - points[0].x = 1.0 - points[0].y = 2.0 - points[1].x = 3.0 - points[1].y = 4.0 - points = rffi.cast(rffi.CArrayPtr(lltype.Char), points) - assert array_getitem(types.double, 16, points, 0, 0) == 1.0 - assert array_getitem(types.double, 16, points, 0, 8) == 2.0 - assert array_getitem(types.double, 16, points, 1, 0) == 3.0 - assert array_getitem(types.double, 16, points, 1, 8) == 4.0 - # - array_setitem(types.double, 16, points, 0, 0, 10.0) - array_setitem(types.double, 16, points, 0, 8, 20.0) - array_setitem(types.double, 16, points, 1, 0, 30.0) - array_setitem(types.double, 16, points, 1, 8, 40.0) - # - assert array_getitem(types.double, 16, points, 0, 0) == 10.0 - assert array_getitem(types.double, 16, points, 0, 8) == 20.0 - assert array_getitem(types.double, 16, points, 1, 0) == 30.0 - assert array_getitem(types.double, 16, points, 1, 8) == 40.0 - # - lltype.free(points, flavor="raw") - - - def test_struct_fields_longlong(self): - POINT = lltype.Struct('POINT', - ('x', rffi.LONGLONG), - ('y', rffi.ULONGLONG) - ) - y_ofs = 8 - p = lltype.malloc(POINT, flavor='raw') - p.x = r_longlong(123) - p.y = r_ulonglong(456) - addr = rffi.cast(rffi.VOIDP, p) - assert struct_getfield_longlong(types.slonglong, addr, 0) == 123 - assert struct_getfield_longlong(types.ulonglong, addr, y_ofs) == 456 - # - v = rffi.cast(lltype.SignedLongLong, r_ulonglong(9223372036854775808)) - struct_setfield_longlong(types.slonglong, addr, 0, v) - struct_setfield_longlong(types.ulonglong, addr, y_ofs, r_longlong(-1)) - assert p.x == -9223372036854775808 - assert rffi.cast(lltype.UnsignedLongLong, p.y) == 18446744073709551615 - # - lltype.free(p, flavor='raw') - - def test_struct_fields_float(self): - POINT = lltype.Struct('POINT', - ('x', rffi.DOUBLE), - ('y', rffi.DOUBLE) - ) - y_ofs = 8 - p = lltype.malloc(POINT, flavor='raw') - p.x = 123.4 - p.y = 567.8 - addr = rffi.cast(rffi.VOIDP, p) - assert struct_getfield_float(types.double, addr, 0) == 123.4 - assert struct_getfield_float(types.double, addr, y_ofs) == 567.8 - # - struct_setfield_float(types.double, addr, 0, 321.0) - struct_setfield_float(types.double, addr, y_ofs, 876.5) - assert p.x == 321.0 - assert p.y == 876.5 - # - lltype.free(p, flavor='raw') - - def test_struct_fields_singlefloat(self): - POINT = lltype.Struct('POINT', - ('x', rffi.FLOAT), - ('y', rffi.FLOAT) - ) - y_ofs = 4 - p = lltype.malloc(POINT, flavor='raw') - p.x = r_singlefloat(123.4) - p.y = r_singlefloat(567.8) - addr = rffi.cast(rffi.VOIDP, p) - assert struct_getfield_singlefloat(types.double, addr, 0) == r_singlefloat(123.4) - assert struct_getfield_singlefloat(types.double, addr, y_ofs) == r_singlefloat(567.8) - # - struct_setfield_singlefloat(types.double, addr, 0, r_singlefloat(321.0)) - struct_setfield_singlefloat(types.double, addr, y_ofs, r_singlefloat(876.5)) - assert p.x == r_singlefloat(321.0) - assert p.y == r_singlefloat(876.5) - # - lltype.free(p, flavor='raw') - - def test_windll(self): - if os.name != 'nt': - skip('Run only on windows') - from pypy.rlib.libffi import WinDLL - dll = WinDLL('Kernel32.dll') - sleep = dll.getpointer('Sleep',[types.uint], types.void) - chain = ArgChain() - chain.arg(10) - sleep.call(chain, lltype.Void, is_struct=False) - -class TestLibffiCall(BaseFfiTest): - """ - Test various kind of calls through libffi. - - The peculiarity of these tests is that they are run both directly (going - really through libffi) and by jit/metainterp/test/test_fficall.py, which - tests the call when JITted. - - If you need to test a behaviour than it's not affected by JITing (e.g., - typechecking), you should put your test in TestLibffiMisc. - """ - - CDLL = CDLL - - @classmethod - def setup_class(cls): - from pypy.tool.udir import udir - from pypy.translator.tool.cbuild import ExternalCompilationInfo - from pypy.translator.tool.cbuild import STANDARD_DEFINES - from pypy.translator.platform import platform - - BaseFfiTest.setup_class() - # prepare C code as an example, so we can load it and call - # it via rlib.libffi - c_file = udir.ensure("test_libffi", dir=1).join("foolib.c") - # automatically collect the C source from the docstrings of the tests - snippets = [] - exports = [] - for name in dir(cls): - if name.startswith('test_'): - meth = getattr(cls, name) - # the heuristic to determine it it's really C code could be - # improved: so far we just check that there is a '{' :-) - if meth.__doc__ is not None and '{' in meth.__doc__: - snippets.append(meth.__doc__) - import re - for match in re.finditer(" ([A-Za-z_]+)\(", meth.__doc__): - exports.append(match.group(1)) - # - c_file.write(STANDARD_DEFINES + str(py.code.Source('\n'.join(snippets)))) - eci = ExternalCompilationInfo(export_symbols=exports) - cls.libfoo_name = str(platform.compile([c_file], eci, 'x', - standalone=False)) - cls.dll = cls.CDLL(cls.libfoo_name) - - def teardown_class(cls): - if cls.dll: - cls.dll.__del__() - # Why doesn't this call cls.dll.__del__() ? - #del cls.dll - - def get_libfoo(self): - return self.dll - - def call(self, funcspec, args, RESULT, is_struct=False, jitif=[]): - """ - Call the specified function after constructing and ArgChain with the - arguments in ``args``. - - The function is specified with ``funcspec``, which is a tuple of the - form (lib, name, argtypes, restype). - - This method is overridden by metainterp/test/test_fficall.py in - order to do the call in a loop and JIT it. The optional arguments are - used only by that overridden method. - - """ - lib, name, argtypes, restype = funcspec - func = lib.getpointer(name, argtypes, restype) - chain = ArgChain() - for arg in args: - if isinstance(arg, tuple): - methname, arg = arg - meth = getattr(chain, methname) - meth(arg) - else: - chain.arg(arg) - return func.call(chain, RESULT, is_struct=is_struct) - - # ------------------------------------------------------------------------ - - def test_very_simple(self): - """ - int diff_xy(int x, Signed y) - { - return x - y; - } - """ - libfoo = self.get_libfoo() - func = (libfoo, 'diff_xy', [types.sint, types.signed], types.sint) - res = self.call(func, [50, 8], lltype.Signed) - assert res == 42 - - def test_simple(self): - """ - int sum_xy(int x, double y) - { - return (x + (int)y); - } - """ - libfoo = self.get_libfoo() - func = (libfoo, 'sum_xy', [types.sint, types.double], types.sint) - res = self.call(func, [38, 4.2], lltype.Signed, jitif=["floats"]) - assert res == 42 - - def test_float_result(self): - libm = self.get_libm() - func = (libm, 'pow', [types.double, types.double], types.double) - res = self.call(func, [2.0, 3.0], rffi.DOUBLE, jitif=["floats"]) - assert res == 8.0 - - def test_cast_result(self): - """ - unsigned char cast_to_uchar_and_ovf(int x) - { - return 200+(unsigned char)x; - } - """ - libfoo = self.get_libfoo() - func = (libfoo, 'cast_to_uchar_and_ovf', [types.sint], types.uchar) - res = self.call(func, [0], rffi.UCHAR) - assert res == 200 - - def test_cast_argument(self): - """ - int many_args(char a, int b) - { - return a+b; - } - """ - libfoo = self.get_libfoo() - func = (libfoo, 'many_args', [types.uchar, types.sint], types.sint) - res = self.call(func, [chr(20), 22], rffi.SIGNED) - assert res == 42 - - def test_char_args(self): - """ - char sum_args(char a, char b) { - return a + b; - } - """ - libfoo = self.get_libfoo() - func = (libfoo, 'sum_args', [types.schar, types.schar], types.schar) - res = self.call(func, [123, 43], rffi.CHAR) - assert res == chr(166) - - def test_unsigned_short_args(self): - """ - unsigned short sum_xy_us(unsigned short x, unsigned short y) - { - return x+y; - } - """ - libfoo = self.get_libfoo() - func = (libfoo, 'sum_xy_us', [types.ushort, types.ushort], types.ushort) - res = self.call(func, [32000, 8000], rffi.USHORT) - assert res == 40000 - - - def test_pointer_as_argument(self): - """#include <stdlib.h> - Signed inc(Signed* x) - { - Signed oldval; - if (x == NULL) - return -1; - oldval = *x; - *x = oldval+1; - return oldval; - } - """ - libfoo = self.get_libfoo() - func = (libfoo, 'inc', [types.pointer], types.signed) - null = lltype.nullptr(rffi.SIGNEDP.TO) - res = self.call(func, [null], rffi.SIGNED) - assert res == -1 - # - ptr_result = lltype.malloc(rffi.SIGNEDP.TO, 1, flavor='raw') - ptr_result[0] = 41 - res = self.call(func, [ptr_result], rffi.SIGNED) - if self.__class__ is TestLibffiCall: - # the function was called only once - assert res == 41 - assert ptr_result[0] == 42 - lltype.free(ptr_result, flavor='raw') - # the test does not make sense when run with the JIT through - # meta_interp, because the __del__ are not properly called (hence - # we "leak" memory) - del libfoo - assert not ALLOCATED - else: - # the function as been called 9 times - assert res == 50 - assert ptr_result[0] == 51 - lltype.free(ptr_result, flavor='raw') - - def test_return_pointer(self): - """ - struct pair { - Signed a; - Signed b; - }; - - struct pair my_static_pair = {10, 20}; - - Signed* get_pointer_to_b() - { - return &my_static_pair.b; - } - """ - libfoo = self.get_libfoo() - func = (libfoo, 'get_pointer_to_b', [], types.pointer) - res = self.call(func, [], rffi.SIGNEDP) - assert res[0] == 20 - - def test_void_result(self): - """ - int dummy; - void set_dummy(int val) { dummy = val; } - int get_dummy() { return dummy; } - """ - libfoo = self.get_libfoo() - set_dummy = (libfoo, 'set_dummy', [types.sint], types.void) - get_dummy = (libfoo, 'get_dummy', [], types.sint) - # - initval = self.call(get_dummy, [], rffi.SIGNED) - # - res = self.call(set_dummy, [initval+1], lltype.Void) - assert res is None - # - res = self.call(get_dummy, [], rffi.SIGNED) - assert res == initval+1 - - def test_single_float_args(self): - """ - float sum_xy_float(float x, float y) - { - return x+y; - } - """ - from ctypes import c_float # this is used only to compute the expected result - libfoo = self.get_libfoo() - func = (libfoo, 'sum_xy_float', [types.float, types.float], types.float) - x = r_singlefloat(12.34) - y = r_singlefloat(56.78) - res = self.call(func, [x, y], rffi.FLOAT, jitif=["singlefloats"]) - expected = c_float(c_float(12.34).value + c_float(56.78).value).value - assert float(res) == expected - - def test_slonglong_args(self): - """ - long long sum_xy_longlong(long long x, long long y) - { - return x+y; - } - """ - maxint32 = 2147483647 # we cannot really go above maxint on 64 bits - # (and we would not test anything, as there long - # is the same as long long) - libfoo = self.get_libfoo() - func = (libfoo, 'sum_xy_longlong', [types.slonglong, types.slonglong], - types.slonglong) - if IS_32_BIT: - x = r_longlong(maxint32+1) - y = r_longlong(maxint32+2) - else: - x = maxint32+1 - y = maxint32+2 - res = self.call(func, [x, y], rffi.LONGLONG, jitif=["longlong"]) - expected = maxint32*2 + 3 - assert res == expected - - def test_ulonglong_args(self): - """ - unsigned long long sum_xy_ulonglong(unsigned long long x, - unsigned long long y) - { - return x+y; - } - """ - maxint64 = 9223372036854775807 # maxint64+1 does not fit into a - # longlong, but it does into a - # ulonglong - libfoo = self.get_libfoo() - func = (libfoo, 'sum_xy_ulonglong', [types.ulonglong, types.ulonglong], - types.ulonglong) - x = r_ulonglong(maxint64+1) - y = r_ulonglong(2) - res = self.call(func, [x, y], rffi.ULONGLONG, jitif=["longlong"]) - expected = maxint64 + 3 - assert res == expected - - def test_wrong_number_of_arguments(self): - from pypy.rpython.llinterp import LLException - libfoo = self.get_libfoo() - func = (libfoo, 'sum_xy', [types.sint, types.double], types.sint) - - glob = globals() - loc = locals() - def my_raises(s): - try: - exec s in glob, loc - except TypeError: - pass - except LLException, e: - if str(e) != "<LLException 'TypeError'>": - raise - else: - assert False, 'Did not raise' - - my_raises("self.call(func, [38], rffi.SIGNED)") # one less - my_raises("self.call(func, [38, 12.3, 42], rffi.SIGNED)") # one more - - - def test_byval_argument(self): - """ - struct Point { - Signed x; - Signed y; - }; - - Signed sum_point(struct Point p) { - return p.x + p.y; - } - """ - libfoo = CDLL(self.libfoo_name) - ffi_point_struct = make_struct_ffitype_e(0, 0, [types.signed, types.signed]) - ffi_point = ffi_point_struct.ffistruct - sum_point = (libfoo, 'sum_point', [ffi_point], types.signed) - # - ARRAY = rffi.CArray(rffi.SIGNED) - buf = lltype.malloc(ARRAY, 2, flavor='raw') - buf[0] = 30 - buf[1] = 12 - adr = rffi.cast(rffi.VOIDP, buf) - res = self.call(sum_point, [('arg_raw', adr)], rffi.SIGNED, - jitif=["byval"]) - assert res == 42 - # check that we still have the ownership on the buffer - assert buf[0] == 30 - assert buf[1] == 12 - lltype.free(buf, flavor='raw') - lltype.free(ffi_point_struct, flavor='raw') - - def test_byval_result(self): - """ - struct Point make_point(Signed x, Signed y) { - struct Point p; - p.x = x; - p.y = y; - return p; - } - """ - libfoo = CDLL(self.libfoo_name) - ffi_point_struct = make_struct_ffitype_e(0, 0, [types.signed, types.signed]) - ffi_point = ffi_point_struct.ffistruct - - libfoo = CDLL(self.libfoo_name) - make_point = (libfoo, 'make_point', [types.signed, types.signed], ffi_point) - # - PTR = lltype.Ptr(rffi.CArray(rffi.SIGNED)) - p = self.call(make_point, [12, 34], PTR, is_struct=True, - jitif=["byval"]) - assert p[0] == 12 - assert p[1] == 34 - lltype.free(p, flavor='raw') - lltype.free(ffi_point_struct, flavor='raw') - - if os.name == 'nt': - def test_stdcall_simple(self): - """ - int __stdcall std_diff_xy(int x, Signed y) - { - return x - y; - } - """ - libfoo = self.get_libfoo() - func = (libfoo, 'std_diff_xy', [types.sint, types.signed], types.sint) - try: - self.call(func, [50, 8], lltype.Signed) - except ValueError, e: - assert e.message == 'Procedure called with not enough ' + \ - 'arguments (8 bytes missing) or wrong calling convention' - except LLException, e: - #jitted code raises this - assert str(e) == "<LLException 'StackCheckError'>" - else: - assert 0, 'wrong calling convention should have raised' - - def test_by_ordinal(self): - """ - int AAA_first_ordinal_function() - { - return 42; - } - """ - libfoo = self.get_libfoo() - f_by_name = libfoo.getpointer('AAA_first_ordinal_function' ,[], - types.uint) - f_by_ordinal = libfoo.getpointer_by_ordinal(1 ,[], types.uint) - print dir(f_by_name) - assert f_by_name.funcsym == f_by_ordinal.funcsym - - def test_by_ordinal2(self): - """ - int __stdcall BBB_second_ordinal_function() - { - return 24; - } - """ - from pypy.rlib.libffi import WinDLL - dll = WinDLL(self.libfoo_name) - f_by_name = dll.getpointer('BBB_second_ordinal_function' ,[], - types.uint) - f_by_ordinal = dll.getpointer_by_ordinal(2 ,[], types.uint) - print dir(f_by_name) - assert f_by_name.funcsym == f_by_ordinal.funcsym - chain = ArgChain() - assert 24 == f_by_ordinal.call(chain, lltype.Signed, is_struct=False) - - - _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit