[pypy-commit] pypy ffi-backend: Remove this version of libffi.py.
arigo
noreply at buildbot.pypy.org
Thu Aug 2 22:42:01 CEST 2012
Author: Armin Rigo <arigo at 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'.
-
- at 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)
-
- at 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)
-
-
-
More information about the pypy-commit
mailing list