Commits

wlav committed 3348ef4

make use of the new jit_libffi instead of libffi module; it's still
about 3x slower for now, due to mallocs, and only used on the fast
path (i.e. Reflex backend)

Comments (0)

Files changed (6)

pypy/module/cppyy/capi/cint_capi.py

 
 def c_load_dictionary(name):
     result = _c_load_dictionary(name)
-    if not result:
-        err = rdynload.dlerror()
-        raise rdynload.DLOpenError(err)
-    return libffi.CDLL(name)       # should return handle to already open file
+    # ignore result: libffi.CDLL(name) either returns a handle to the already
+    # open file, or will fail as well and produce a correctly formatted error
+    return libffi.CDLL(name)
 
 
 # CINT-specific pythonizations ===============================================

pypy/module/cppyy/converter.py

 
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rlib.rarithmetic import r_singlefloat
-from pypy.rlib import libffi, clibffi, rfloat
+from pypy.rlib import jit_libffi, rfloat
 
 from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
 from pypy.module._rawffi.array import W_Array
 
 class TypeConverter(object):
     _immutable_ = True
-    libffitype = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+    libffitype = lltype.nullptr(jit_libffi.FFI_TYPE_P.TO)
     uses_local = False
 
     name = ""
     def convert_argument(self, space, w_obj, address, call_local):
         self._is_abstract(space)
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
-    def default_argument_libffi(self, space, argchain):
+    def default_argument_libffi(self, space, address):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 class ArrayTypeConverterMixin(object):
     _mixin_ = True
     _immutable_ = True
+    libffitype = jit_libffi.types.pointer
 
     def __init__(self, space, array_size):
         if array_size <= 0:
 class PtrTypeConverterMixin(object):
     _mixin_ = True
     _immutable_ = True
+    libffitype = jit_libffi.types.pointer
 
     def __init__(self, space, array_size):
         self.size = sys.maxint
         if w_tc is not None and space.str_w(w_tc) != self.typecode:
             msg = "expected %s pointer type, but received %s" % (self.typecode, space.str_w(w_tc))
             raise OperationError(space.w_TypeError, space.wrap(msg))
-        x = rffi.cast(rffi.LONGP, address)
+        x = rffi.cast(rffi.VOIDPP, address)
         try:
-            x[0] = rffi.cast(rffi.LONG, get_rawbuffer(space, w_obj))
+            x[0] = rffi.cast(rffi.VOIDP, get_rawbuffer(space, w_obj))
         except TypeError:
             raise OperationError(space.w_TypeError,
                                  space.wrap("raw buffer interface not supported"))
     _mixin_ = True
     _immutable_ = True
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        argchain.arg(self._unwrap_object(space, w_obj))
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
 
-    def default_argument_libffi(self, space, argchain):
-        argchain.arg(self.default)
+    def default_argument_libffi(self, space, address):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self.default
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = self._get_raw_address(space, w_obj, offset)
     _immutable_ = True
     uses_local = True
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
         assert rffi.sizeof(self.c_type) <= 2*rffi.sizeof(rffi.VOIDP)  # see interp_cppyy.py
         obj = self._unwrap_object(space, w_obj)
         typed_buf = rffi.cast(self.c_ptrtype, call_local)
         typed_buf[0] = obj
-        argchain.arg(call_local)
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = call_local
 
 class IntTypeConverterMixin(NumericTypeConverterMixin):
     _mixin_ = True
 
 class VoidConverter(TypeConverter):
     _immutable_ = True
-    libffitype = libffi.types.void
+    libffitype = jit_libffi.types.void
 
     def __init__(self, space, name):
         self.name = name
         x = rffi.cast(rffi.LONGP, address)
         x[0] = self._unwrap_object(space, w_obj)
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        argchain.arg(self._unwrap_object(space, w_obj))
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.LONGP, address)
+        x[0] = self._unwrap_object(space, w_obj)
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
         x = rffi.cast(rffi.CCHARP, address)
         x[0] = self._unwrap_object(space, w_obj)
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        argchain.arg(self._unwrap_object(space, w_obj))
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        x = rffi.cast(self.c_ptrtype, address)
+        x[0] = self._unwrap_object(space, w_obj)
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
 
 class ConstFloatRefConverter(FloatConverter):
     _immutable_ = True
-    libffitype = libffi.types.pointer
+    libffitype = jit_libffi.types.pointer
     typecode = 'F'
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 
 class ConstDoubleRefConverter(ConstRefNumericTypeConverterMixin, DoubleConverter):
     _immutable_ = True
-    libffitype = libffi.types.pointer
+    libffitype = jit_libffi.types.pointer
     typecode = 'D'
 
 
 
 class VoidPtrConverter(TypeConverter):
     _immutable_ = True
+    libffitype = jit_libffi.types.pointer
+
+    def _unwrap_object(self, space, w_obj):
+        try:
+            obj = get_rawbuffer(space, w_obj)
+        except TypeError:
+            obj = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+        return obj
 
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
-        try:
-            x[0] = get_rawbuffer(space, w_obj)
-        except TypeError:
-            x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
         ba[capi.c_function_arg_typeoffset()] = 'o'
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        argchain.arg(get_rawobject(space, w_obj))
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = self._unwrap_object(space, w_obj)
 
 class VoidPtrPtrConverter(TypeConverter):
     _immutable_ = True
 
 class InstancePtrConverter(TypeConverter):
     _immutable_ = True
+    libffitype  = jit_libffi.types.pointer
 
     def __init__(self, space, cppclass):
         from pypy.module.cppyy.interp_cppyy import W_CPPClass
         ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset()] = 'o'
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        argchain.arg(self._unwrap_object(space, w_obj))
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
 class InstanceConverter(InstancePtrConverter):
     _immutable_ = True
 
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible       # TODO: by-value is a jit_libffi special case
+
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
         from pypy.module.cppyy import interp_cppyy
         ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset()] = 'o'
 
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        # TODO: finalize_call not yet called for fast call (see interp_cppyy.py)
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         self._is_abstract(space)
 
 
 class PyObjectConverter(TypeConverter):
     _immutable_ = True
+    libffitype = jit_libffi.types.pointer
 
     def convert_argument(self, space, w_obj, address, call_local):
         if hasattr(space, "fake"):
         ba = rffi.cast(rffi.CCHARP, address)
         ba[capi.c_function_arg_typeoffset()] = 'a'
 
-    def convert_argument_libffi(self, space, w_obj, argchain, call_local):
-        if hasattr(space, "fake"):
+    def convert_argument_libffi(self, space, w_obj, address, call_local):
+        # TODO: free_argument not yet called for fast call (see interp_cppyy.py)
+        from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+        raise FastCallNotPossible
+
+        # proposed implementation:
+        """if hasattr(space, "fake"):
             raise NotImplementedError
         space.getbuiltinmodule("cpyext")
         from pypy.module.cpyext.pyobject import make_ref
         ref = make_ref(space, w_obj)
-        argchain.arg(rffi.cast(rffi.VOIDP, ref))
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, ref)"""
 
     def free_argument(self, space, arg, call_local):
         if hasattr(space, "fake"):
                 self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
         class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
             _immutable_ = True
-            libffitype = libffi.types.pointer
+            libffitype = jit_libffi.types.pointer
         for name in names:
             _converters[name] = BasicConverter
             _converters["const "+name+"&"] = ConstRefConverter
                 self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
         class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
             _immutable_ = True
-            libffitype = libffi.types.pointer
+            libffitype = jit_libffi.types.pointer
             typecode = 'r'
             def convert_argument(self, space, w_obj, address, call_local):
                 x = rffi.cast(self.c_ptrtype, address)
                 self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
         class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
             _immutable_ = True
-            libffitype = libffi.types.pointer
+            libffitype = jit_libffi.types.pointer
         for name in names:
             _converters[name] = BasicConverter
             _converters["const "+name+"&"] = ConstRefConverter

pypy/module/cppyy/executor.py

 from pypy.interpreter.error import OperationError
 
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.rlib import libffi, clibffi
+from pypy.rlib import jit_libffi
 
 from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
 from pypy.module._rawffi.array import W_Array, W_ArrayInstance
 # exact match for the qualified type.
 
 
-NULL = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+NULL = lltype.nullptr(jit_libffi.FFI_TYPE_P.TO)
 
 class FunctionExecutor(object):
     _immutable_ = True
         raise OperationError(space.w_TypeError,
                              space.wrap('return type not available or supported'))
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 
 class PtrTypeExecutor(FunctionExecutor):
     _immutable_ = True
+    libffitype = jit_libffi.types.pointer
     typecode = 'P'
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
 
 class VoidExecutor(FunctionExecutor):
     _immutable_ = True
-    libffitype = libffi.types.void
+    libffitype = jit_libffi.types.void
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
         capi.c_call_v(cppmethod, cppthis, num_args, args)
         return space.w_None
 
-    def execute_libffi(self, space, libffifunc, argchain):
-        libffifunc.call(argchain, lltype.Void)
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
+        jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
         return space.w_None
 
 
         result = self.c_stubcall(cppmethod, cppthis, num_args, args)
         return self._wrap_object(space, rffi.cast(self.c_type, result))
 
-    def execute_libffi(self, space, libffifunc, argchain):
-        result = libffifunc.call(argchain, self.c_type)
-        return self._wrap_object(space, result)
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
+        data = rffi.ptradd(buffer, cif_descr.exchange_args[1])
+        jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
+        result = rffi.ptradd(buffer, cif_descr.exchange_result)
+        return self._wrap_object(space, rffi.cast(self.c_ptrtype, result)[0])
 
 class NumericRefExecutorMixin(object):
     _mixin_ = True
         result = capi.c_call_r(cppmethod, cppthis, num_args, args)
         return self._wrap_reference(space, rffi.cast(self.c_ptrtype, result))
 
-    def execute_libffi(self, space, libffifunc, argchain):
-        result = libffifunc.call(argchain, self.c_ptrtype)
-        return self._wrap_reference(space, result)
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
+        jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
+        result = rffi.ptradd(buffer, cif_descr.exchange_result)
+        return self._wrap_reference(space,
+            rffi.cast(self.c_ptrtype, rffi.cast(rffi.VOIDPP, result)[0]))
 
 
 class CStringExecutor(FunctionExecutor):
 
 class InstancePtrExecutor(FunctionExecutor):
     _immutable_ = True
-    libffitype = libffi.types.pointer
+    libffitype = jit_libffi.types.pointer
 
     def __init__(self, space, cppclass):
         FunctionExecutor.__init__(self, space, cppclass)
         return interp_cppyy.wrap_cppobject(
             space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
+        jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
+        result = rffi.ptradd(buffer, cif_descr.exchange_result)
         from pypy.module.cppyy import interp_cppyy
-        ptr_result = rffi.cast(capi.C_OBJECT, libffifunc.call(argchain, rffi.VOIDP))
+        ptr_result = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, result)[0])
         return interp_cppyy.wrap_cppobject(
             space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
 
         return interp_cppyy.wrap_cppobject(
             space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
         return interp_cppyy.wrap_cppobject(
             space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=True)
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
         charp_result = capi.c_call_s(cppmethod, cppthis, num_args, args)
         return space.wrap(capi.charp2str_free(charp_result))
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
         lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
         return self.wrap_result(space, lresult)
 
-    def execute_libffi(self, space, libffifunc, argchain):
+    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         if hasattr(space, "fake"):
             raise NotImplementedError
-        lresult = libffifunc.call(argchain, rffi.LONG)
-        return self.wrap_result(space, lresult)
+        jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
+        result = rffi.ptradd(buffer, cif_descr.exchange_result)
+        return self.wrap_result(space, rffi.cast(rffi.LONGP, result)[0])
 
 
 _executors = {}
             c_stubcall  = staticmethod(stub)
         class BasicRefExecutor(ffitypes.typeid(c_type), NumericRefExecutorMixin, FunctionExecutor):
             _immutable_ = True
-            libffitype = libffi.types.pointer
+            libffitype = jit_libffi.types.pointer
         for name in names:
             _executors[name]              = BasicExecutor
             _executors[name+'&']          = BasicRefExecutor

pypy/module/cppyy/ffitypes.py

 
 from pypy.rpython.lltypesystem import rffi
 from pypy.rlib.rarithmetic import r_singlefloat
-from pypy.rlib import libffi, rfloat
+from pypy.rlib import jit_libffi, rfloat
 
 # Mixins to share between converter and executor classes (in converter.py and
 # executor.py, respectively). Basically these mixins allow grouping of the
-# sets of libffi, rffi, and different space unwrapping calls. To get the right
-# mixin, a non-RPython function typeid() is used.
+# sets of jit_libffi, rffi, and different space unwrapping calls. To get the
+# right mixin, a non-RPython function typeid() is used.
 
 
 class BoolTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype  = libffi.types.uchar
+    libffitype  = jit_libffi.types.uchar
     c_type      = rffi.UCHAR
     c_ptrtype   = rffi.UCHARP
 
 class CharTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype  = libffi.types.schar
+    libffitype  = jit_libffi.types.schar
     c_type      = rffi.CHAR
     c_ptrtype   = rffi.CCHARP           # there's no such thing as rffi.CHARP
 
 class ShortTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype  = libffi.types.sshort
+    libffitype  = jit_libffi.types.sshort
     c_type      = rffi.SHORT
     c_ptrtype   = rffi.SHORTP
 
 class UShortTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype  = libffi.types.ushort
+    libffitype  = jit_libffi.types.ushort
     c_type      = rffi.USHORT
     c_ptrtype   = rffi.USHORTP
 
 class IntTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype  = libffi.types.sint
+    libffitype  = jit_libffi.types.sint
     c_type      = rffi.INT
     c_ptrtype   = rffi.INTP
 
 class UIntTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype  = libffi.types.uint
+    libffitype  = jit_libffi.types.uint
     c_type      = rffi.UINT
     c_ptrtype   = rffi.UINTP
 
 class LongTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype = libffi.types.slong
-    c_type     =  rffi.LONG
+    libffitype  = jit_libffi.types.slong
+    c_type      =  rffi.LONG
     c_ptrtype   = rffi.LONGP
 
     def _unwrap_object(self, space, w_obj):
 class ULongTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype = libffi.types.ulong
-    c_type     = rffi.ULONG
-    c_ptrtype  = rffi.ULONGP
+    libffitype  = jit_libffi.types.ulong
+    c_type      = rffi.ULONG
+    c_ptrtype   = rffi.ULONGP
 
     def _unwrap_object(self, space, w_obj):
         return space.uint_w(w_obj)
 class LongLongTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype  = libffi.types.sint64
+    libffitype  = jit_libffi.types.sint64
     c_type      = rffi.LONGLONG
     c_ptrtype   = rffi.LONGLONGP
 
 class ULongLongTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype = libffi.types.uint64
-    c_type     = rffi.ULONGLONG
-    c_ptrtype  = rffi.ULONGLONGP
+    libffitype  = jit_libffi.types.uint64
+    c_type      = rffi.ULONGLONG
+    c_ptrtype   = rffi.ULONGLONGP
 
     def _unwrap_object(self, space, w_obj):
         return space.r_ulonglong_w(w_obj)
 class FloatTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype  = libffi.types.float
+    libffitype  = jit_libffi.types.float
     c_type      = rffi.FLOAT
     c_ptrtype   = rffi.FLOATP
     typecode    = 'f'
 class DoubleTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
-    libffitype  = libffi.types.double
+    libffitype  = jit_libffi.types.double
     c_type      = rffi.DOUBLE
     c_ptrtype   = rffi.DOUBLEP
     typecode    = 'd'

pypy/module/cppyy/interp_cppyy.py

 from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
 from pypy.interpreter.baseobjspace import Wrappable, W_Root
 
-from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rpython.lltypesystem import rffi, lltype, llmemory
 
-from pypy.rlib import libffi, rdynload, rweakref
-from pypy.rlib import jit, debug, objectmodel
+from pypy.rlib import jit, rdynload, rweakref
+from pypy.rlib import jit_libffi, clibffi
+from pypy.rlib.objectmodel import we_are_translated
 
 from pypy.module.cppyy import converter, executor, helper
 
     also takes care of offset casting and recycling of known objects through
     the memory_regulator."""
     _immutable_ = True
-    
+
     def __init__(self, space, containing_scope, method_index, arg_defs, args_required):
         self.space = space
         self.scope = containing_scope
         # the method is actually used.
         self.converters = None
         self.executor = None
-        self._libffifunc = None
+        self.cif_descr = lltype.nullptr(jit_libffi.CIF_DESCRIPTION)
+        self._funcaddr = lltype.nullptr(rffi.VOIDP.TO)
+        self.uses_local = False
 
     def _address_from_local_buffer(self, call_local, idx):
         if not call_local:
 
         # initial setup of converters, executors, and libffi (if available)
         if self.converters is None:
-            self._setup(cppthis)
-
+            try:
+                self._setup(cppthis)
+            except Exception, e:
+                pass
+    
         # some calls, e.g. for ptr-ptr or reference need a local array to store data for
         # the duration of the call
-        if [conv for conv in self.converters if conv.uses_local]:
+        if self.uses_local:
             call_local = lltype.malloc(rffi.VOIDP.TO, 2*len(args_w), flavor='raw')
         else:
             call_local = lltype.nullptr(rffi.VOIDP.TO)
 
         try:
             # attempt to call directly through ffi chain
-            if self._libffifunc:
+            if self._funcaddr:
                 try:
                     return self.do_fast_call(cppthis, args_w, call_local)
                 except FastCallNotPossible:
     @jit.unroll_safe
     def do_fast_call(self, cppthis, args_w, call_local):
         jit.promote(self)
-        argchain = libffi.ArgChain()
-        argchain.arg(cppthis)
-        i = len(self.arg_defs)
-        for i in range(len(args_w)):
-            conv = self.converters[i]
-            w_arg = args_w[i]
-            conv.convert_argument_libffi(self.space, w_arg, argchain, call_local)
-        for j in range(i+1, len(self.arg_defs)):
-            conv = self.converters[j]
-            conv.default_argument_libffi(self.space, argchain)
-        return self.executor.execute_libffi(self.space, self._libffifunc, argchain)
+        if self.cif_descr is None:
+            raise FastCallNotPossible
+        cif_descr = self.cif_descr
+        buffer = lltype.malloc(rffi.CCHARP.TO, cif_descr.exchange_size, flavor='raw')
+        try:
+            # this pointer
+            data = rffi.ptradd(buffer, cif_descr.exchange_args[0])
+            x = rffi.cast(rffi.LONGP, data)       # LONGP needed for test_zjit.py
+            x[0] = rffi.cast(rffi.LONG, cppthis)
+
+            # other arguments and defaults
+            i = len(self.arg_defs) + 1
+            for i in range(len(args_w)):
+                conv = self.converters[i]
+                w_arg = args_w[i]
+                data = rffi.ptradd(buffer, cif_descr.exchange_args[i+1])
+                conv.convert_argument_libffi(self.space, w_arg, data, call_local)
+            for j in range(i+1, len(self.arg_defs)):
+                conv = self.converters[j]
+                data = rffi.ptradd(buffer, cif_descr.exchange_args[j+1])
+                conv.default_argument_libffi(self.space, data)
+
+            w_res = self.executor.execute_libffi(
+                self.space, cif_descr, self._funcaddr, buffer)
+        finally:
+            lltype.free(buffer, flavor='raw')
+        return w_res
 
     def _setup(self, cppthis):
         self.converters = [converter.get_converter(self.space, arg_type, arg_dflt)
                                for arg_type, arg_dflt in self.arg_defs]
         self.executor = executor.get_executor(self.space, capi.c_method_result_type(self.scope, self.index))
 
+        for conv in self.converters:
+            if conv.uses_local:
+                self.uses_local = True
+                break
+
         # Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis
         # has been offset to the matching class. Hence, the libffi pointer is
         # uniquely defined and needs to be setup only once.
         methgetter = capi.c_get_methptr_getter(self.scope, self.index)
         if methgetter and cppthis:      # methods only for now
-            funcptr = methgetter(rffi.cast(capi.C_OBJECT, cppthis))
-            argtypes_libffi = [conv.libffitype for conv in self.converters if conv.libffitype]
-            if (len(argtypes_libffi) == len(self.converters) and
-                    self.executor.libffitype):
-                # add c++ this to the arguments
-                libffifunc = libffi.Func("XXX",
-                                         [libffi.types.pointer] + argtypes_libffi,
-                                         self.executor.libffitype, funcptr)
-                self._libffifunc = libffifunc
+            cif_descr = lltype.nullptr(jit_libffi.CIF_DESCRIPTION)
+            try:
+                funcaddr = methgetter(rffi.cast(capi.C_OBJECT, cppthis))
+                self._funcaddr = rffi.cast(rffi.VOIDP, funcaddr)
+
+                nargs = self.args_expected + 1                   # +1: cppthis
+
+                # memory block for CIF description (note: not tracked as the life
+                # time of methods is normally the duration of the application)
+                size = llmemory.sizeof(jit_libffi.CIF_DESCRIPTION, nargs)
+
+                # allocate the buffer
+                cif_descr = lltype.malloc(jit_libffi.CIF_DESCRIPTION_P.TO,
+                                          llmemory.raw_malloc_usage(size),
+                                          flavor='raw', track_allocation=False)
+
+                # array of 'ffi_type*' values, one per argument
+                size = rffi.sizeof(jit_libffi.FFI_TYPE_P) * nargs
+                atypes = lltype.malloc(rffi.CCHARP.TO, llmemory.raw_malloc_usage(size),
+                                       flavor='raw', track_allocation=False)
+                cif_descr.atypes = rffi.cast(jit_libffi.FFI_TYPE_PP, atypes)
+
+                # argument type specification
+                cif_descr.atypes[0] = jit_libffi.types.pointer   # cppthis
+                for i, conv in enumerate(self.converters):
+                    if not conv.libffitype:
+                        raise FastCallNotPossible
+                    cif_descr.atypes[i+1] = conv.libffitype
+
+                # result type specification
+                cif_descr.rtype = self.executor.libffitype
+
+                # exchange ---
+
+                # first, enough room for an array of 'nargs' pointers
+                exchange_offset = rffi.sizeof(rffi.CCHARP) * nargs
+                exchange_offset = (exchange_offset + 7) & ~7     # alignment
+                cif_descr.exchange_result = exchange_offset
+                cif_descr.exchange_result_libffi = exchange_offset
+
+                # TODO: left this out while testing (see ctypefunc.py)
+                # For results of precisely these types, libffi has a
+                # strange rule that they will be returned as a whole
+                # 'ffi_arg' if they are smaller.  The difference
+                # only matters on big-endian.
+
+                # then enough room for the result, rounded up to sizeof(ffi_arg)
+                exchange_offset += max(rffi.getintfield(cif_descr.rtype, 'c_size'),
+                                       jit_libffi.SIZE_OF_FFI_ARG)
+
+                # loop over args
+                for i in range(nargs):
+                    exchange_offset = (exchange_offset + 7) & ~7 # alignment
+                    cif_descr.exchange_args[i] = exchange_offset
+                    exchange_offset += rffi.getintfield(cif_descr.atypes[i], 'c_size')
+
+                # store the exchange data size
+                cif_descr.exchange_size = exchange_offset
+
+                # --- exchange
+
+                # extra
+                cif_descr.abi = clibffi.FFI_DEFAULT_ABI
+                cif_descr.nargs = self.args_expected + 1         # +1: cppthis
+
+                res = jit_libffi.jit_ffi_prep_cif(cif_descr)
+                if res != clibffi.FFI_OK:
+                    raise FastCallNotPossible
+
+            except Exception, e:
+                if cif_descr:
+                    lltype.free(cif_descr.atypes, flavor='raw', track_allocation=False)
+                    lltype.free(cif_descr, flavor='raw', track_allocation=False)
+                cif_descr = lltype.nullptr(jit_libffi.CIF_DESCRIPTION)
+                self._funcaddr = lltype.nullptr(rffi.VOIDP.TO)
+
+            self.cif_descr = cif_descr
 
     @jit.unroll_safe
     def prepare_arguments(self, args_w, call_local):
     def signature(self):
         return capi.c_method_signature(self.scope, self.index)
 
+    def __del__(self):
+        if self.cif_descr:
+            lltype.free(self.cif_descr.atypes, flavor='raw')
+            lltype.free(self.cif_descr, flavor='raw')
+
     def __repr__(self):
         return "CPPMethod: %s" % self.signature()
 
     def __init__(self, space, containing_scope, functions):
         self.space = space
         self.scope = containing_scope
+        from pypy.rlib import debug
         self.functions = debug.make_sure_not_resized(functions)
 
     def is_static(self):

pypy/module/cppyy/test/test_zjit.py

 # (note that the module is not otherwise used in the test itself)
 import pypy.module.cpyext
 
+# change capi's direct_ptradd to being jit-opaque
+@jit.dont_look_inside
+def _opaque_direct_ptradd(ptr, offset):
+    address = rffi.cast(rffi.CCHARP, ptr)
+    return rffi.cast(capi.C_OBJECT, lltype.direct_ptradd(address, offset))
+capi.direct_ptradd = _opaque_direct_ptradd
+
+# change the runner to use nargs in the loop, rather than rely on atypes
+# bounding, as atypes is actually of unknown size
+from pypy.jit.backend.llgraph import runner
+def _ranged_calldescrof_dynamic(self, cif_description, extrainfo):
+    from pypy.jit.backend.llsupport.ffisupport import get_ffi_type_kind
+    from pypy.jit.backend.llsupport.ffisupport import UnsupportedKind
+    arg_types = []
+    try:
+        for itp in range(cif_description.nargs):
+            arg = cif_description.atypes[itp]
+            kind = get_ffi_type_kind(self, arg)
+            if kind != runner.history.VOID:
+                arg_types.append(kind)
+        reskind = get_ffi_type_kind(self, cif_description.rtype)
+    except UnsupportedKind:
+        return None
+    return self.getdescr(0, reskind, extrainfo=extrainfo,
+                         arg_types=''.join(arg_types),
+                         ffi_flags=cif_description.abi)
+runner.LLtypeCPU.calldescrof_dynamic = _ranged_calldescrof_dynamic
+
 currpath = py.path.local(__file__).dirpath()
 test_dct = str(currpath.join("example01Dict.so"))
 
         FakeType.__init__(self, name)
         self.message = name
 
-@jit.dont_look_inside
-def _opaque_direct_ptradd(ptr, offset):
-    address = rffi.cast(rffi.CCHARP, ptr)
-    return rffi.cast(capi.C_OBJECT, lltype.direct_ptradd(address, offset))
-capi.direct_ptradd = _opaque_direct_ptradd
-
 class FakeUserDelAction(object):
     def __init__(self, space):
         pass