[pypy-commit] pypy ffi-backend: hg merge

arigo noreply at buildbot.pypy.org
Fri Aug 3 13:07:03 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r56557:50c0afab1e32
Date: 2012-08-03 11:05 +0000
http://bitbucket.org/pypy/pypy/changeset/50c0afab1e32/

Log:	hg merge

diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -89,7 +89,6 @@
     "_rawffi": [("objspace.usemodules.struct", True)],
     "cpyext": [("translation.secondaryentrypoints", "cpyext"),
                ("translation.shared", sys.platform == "win32")],
-    "_ffi":    [("translation.jit_ffi", True)],
 }
 
 module_import_dependencies = {
diff --git a/pypy/config/test/test_pypyoption.py b/pypy/config/test/test_pypyoption.py
--- a/pypy/config/test/test_pypyoption.py
+++ b/pypy/config/test/test_pypyoption.py
@@ -72,8 +72,3 @@
         for path in c.getpaths(include_groups=True):
             fn = prefix + "." + path + ".txt"
             yield fn, check_file_exists, fn
-
-def test__ffi_opt():
-    config = get_pypy_config(translating=True)
-    config.objspace.usemodules._ffi = True
-    assert config.translation.jit_ffi
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -122,8 +122,6 @@
     ChoiceOption("jit_profiler", "integrate profiler support into the JIT",
                  ["off", "oprofile"],
                  default="off"),
-    # jit_ffi is automatically turned on by withmod-_ffi (which is enabled by default)
-    BoolOption("jit_ffi", "optimize libffi calls", default=False, cmdline=None),
     BoolOption("check_str_without_nul",
                "Forbid NUL chars in strings in some external function calls",
                default=False, cmdline=None),
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -63,7 +63,8 @@
 
 FLOAT_ARRAY_TP = lltype.Ptr(lltype.Array(lltype.Float, hints={"nolength": True}))
 def maybe_uncast(TP, array):
-    if array._TYPE.TO._hints.get("uncast_on_llgraph"):
+    if array._TYPE.TO.OF != lltype.Float:
+        # array._TYPE.TO._hints.get("uncast_on_llgraph"):
         array = rffi.cast(TP, array)
     return array
 
@@ -802,7 +803,7 @@
         if arraydescr.typeinfo == REF:
             raise NotImplementedError("getarrayitem_raw -> gcref")
         elif arraydescr.typeinfo == INT:
-            return do_getarrayitem_raw_int(array, index)
+            return do_getarrayitem_raw_int(array, index, arraydescr.ofs)
         elif arraydescr.typeinfo == FLOAT:
             return do_getarrayitem_raw_float(array, index)
         else:
@@ -879,7 +880,7 @@
         if arraydescr.typeinfo == REF:
             raise NotImplementedError("setarrayitem_raw <- gcref")
         elif arraydescr.typeinfo == INT:
-            do_setarrayitem_raw_int(array, index, newvalue)
+            do_setarrayitem_raw_int(array, index, newvalue, arraydescr.ofs)
         elif arraydescr.typeinfo == FLOAT:
             do_setarrayitem_raw_float(array, index, newvalue)
         else:
@@ -1448,9 +1449,13 @@
     array = array._obj.container
     return cast_to_int(array.getitem(index))
 
-def do_getarrayitem_raw_int(array, index):
-    array = array.adr.ptr._obj
-    return cast_to_int(array.getitem(index))
+def do_getarrayitem_raw_int(array, index, itemsize):
+    array = array.adr.ptr
+    ITEMTYPE = lltype.typeOf(array).TO.OF
+    TYPE = symbolic.Size2Type[itemsize]
+    if TYPE.OF != ITEMTYPE:
+        array = rffi.cast(lltype.Ptr(TYPE), array)
+    return cast_to_int(array._obj.getitem(index))
 
 def do_getarrayitem_gc_float(array, index):
     array = array._obj.container
@@ -1546,10 +1551,13 @@
     newvalue = cast_from_int(ITEMTYPE, newvalue)
     array.setitem(index, newvalue)
 
-def do_setarrayitem_raw_int(array, index, newvalue):
+def do_setarrayitem_raw_int(array, index, newvalue, itemsize):
     array = array.adr.ptr
     ITEMTYPE = lltype.typeOf(array).TO.OF
-    newvalue = cast_from_int(ITEMTYPE, newvalue)
+    TYPE = symbolic.Size2Type[itemsize]
+    if TYPE.OF != ITEMTYPE:
+        array = rffi.cast(lltype.Ptr(TYPE), array)
+    newvalue = cast_from_int(TYPE.OF, newvalue)
     array._obj.setitem(index, newvalue)
 
 def do_setarrayitem_gc_float(array, index, newvalue):
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -360,21 +360,21 @@
         return self.getdescr(0, token[0], extrainfo=extrainfo,
                              arg_types=''.join(arg_types))
 
-    def calldescrof_dynamic(self, ffi_args, ffi_result, extrainfo, ffi_flags):
+    def 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 arg in ffi_args:
+            for arg in cif_description.atypes:
                 kind = get_ffi_type_kind(self, arg)
                 if kind != history.VOID:
                     arg_types.append(kind)
-            reskind = get_ffi_type_kind(self, ffi_result)
+            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=ffi_flags)
+                             ffi_flags=cif_description.abi)
 
 
     def grab_exc_value(self):
@@ -411,7 +411,7 @@
         return llimpl.do_getarrayitem_gc_int(array, index)
     def bh_getarrayitem_raw_i(self, arraydescr, array, index):
         assert isinstance(arraydescr, Descr)
-        return llimpl.do_getarrayitem_raw_int(array, index)
+        return llimpl.do_getarrayitem_raw_int(array, index, arraydescr.ofs)
     def bh_getarrayitem_gc_r(self, arraydescr, array, index):
         assert isinstance(arraydescr, Descr)
         return llimpl.do_getarrayitem_gc_ptr(array, index)
@@ -507,7 +507,7 @@
 
     def bh_setarrayitem_raw_i(self, arraydescr, array, index, newvalue):
         assert isinstance(arraydescr, Descr)
-        llimpl.do_setarrayitem_raw_int(array, index, newvalue)
+        llimpl.do_setarrayitem_raw_int(array, index, newvalue, arraydescr.ofs)
 
     def bh_setarrayitem_gc_r(self, arraydescr, array, index, newvalue):
         assert isinstance(arraydescr, Descr)
diff --git a/pypy/jit/backend/llsupport/ffisupport.py b/pypy/jit/backend/llsupport/ffisupport.py
--- a/pypy/jit/backend/llsupport/ffisupport.py
+++ b/pypy/jit/backend/llsupport/ffisupport.py
@@ -1,43 +1,81 @@
 from pypy.rlib.rarithmetic import intmask
-from pypy.jit.metainterp import history
-from pypy.rpython.lltypesystem import rffi
+from pypy.rlib.objectmodel import specialize
+from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.jit.backend.llsupport.descr import CallDescr
 
 class UnsupportedKind(Exception):
     pass
 
-def get_call_descr_dynamic(cpu, ffi_args, ffi_result, extrainfo, ffi_flags):
-    """Get a call descr: the types of result and args are represented by
-    rlib.libffi.types.*"""
+def get_call_descr_dynamic(cpu, cif_description, extrainfo):
+    """Get a call descr from the given CIF_DESCRIPTION"""
+    ffi_result = cif_description.rtype
     try:
         reskind = get_ffi_type_kind(cpu, ffi_result)
-        argkinds = [get_ffi_type_kind(cpu, arg) for arg in ffi_args]
+        argkinds = [get_ffi_type_kind(cpu, atype)
+                    for atype in cif_description.atypes]
     except UnsupportedKind:
         return None
-    if reskind == history.VOID:
+    if reskind == 'v':
         result_size = 0
     else:
         result_size = intmask(ffi_result.c_size)
     argkinds = ''.join(argkinds)
     return CallDescr(argkinds, reskind, is_ffi_type_signed(ffi_result),
-                     result_size, extrainfo, ffi_flags=ffi_flags)
+                     result_size, extrainfo, ffi_flags=cif_description.abi)
 
 def get_ffi_type_kind(cpu, ffi_type):
-    from pypy.rlib.libffi import types
+    from pypy.rlib.jit_libffi import types
+    kind = types.getkind(ffi_type)
+    if ((not cpu.supports_floats and kind == 'f') or
+        (not cpu.supports_longlong and kind == 'L') or
+        (not cpu.supports_singlefloats and kind == 'S') or
+        kind == '*'):
+        raise UnsupportedKind("Unsupported kind '%s'" % kind)
+    if kind == 'u':
+        kind = 'i'
+    return kind
+
+def is_ffi_type_signed(ffi_type):
+    from pypy.rlib.jit_libffi import types
+    kind = types.getkind(ffi_type)
+    return kind != 'u'
+
+ at specialize.memo()
+def _get_ffi2descr_dict(cpu):
+    d = {('v', 0): ('v', None)}
+    if cpu.supports_floats:
+        d[('f', 0)] = ('f', cpu.arraydescrof(rffi.CArray(lltype.Float)))
+    if cpu.supports_singlefloats:
+        d[('S', 0)] = cpu.arraydescrof(rffi.CArray(lltype.SingleFloat))
+    for SIGNED_TYPE in [rffi.SIGNEDCHAR,
+                        rffi.SHORT,
+                        rffi.INT,
+                        rffi.LONG,
+                        rffi.LONGLONG]:
+        key = ('i', rffi.sizeof(SIGNED_TYPE))
+        kind = 'i'
+        if key[1] > rffi.sizeof(lltype.Signed):
+            if not cpu.supports_longlong:
+                continue
+            key = ('L', 0)
+            kind = 'f'
+        d[key] = (kind, cpu.arraydescrof(rffi.CArray(SIGNED_TYPE)))
+    for UNSIGNED_TYPE in [rffi.UCHAR,
+                          rffi.USHORT,
+                          rffi.UINT,
+                          rffi.ULONG,
+                          rffi.ULONGLONG]:
+        key = ('u', rffi.sizeof(UNSIGNED_TYPE))
+        if key[1] > rffi.sizeof(lltype.Signed):
+            continue
+        d[key] = ('i', cpu.arraydescrof(rffi.CArray(UNSIGNED_TYPE)))
+    return d
+
+def get_arg_descr(cpu, ffi_type):
+    from pypy.rlib.jit_libffi import types
     kind = types.getkind(ffi_type)
     if kind == 'i' or kind == 'u':
-        return history.INT
-    elif cpu.supports_floats and kind == 'f':
-        return history.FLOAT
-    elif kind == 'v':
-        return history.VOID
-    elif cpu.supports_longlong and (kind == 'I' or kind == 'U'):     # longlong
-        return 'L'
-    elif cpu.supports_singlefloats and kind == 's':    # singlefloat
-        return 'S'
-    raise UnsupportedKind("Unsupported kind '%s'" % kind)
-
-def is_ffi_type_signed(ffi_type):
-    from pypy.rlib.libffi import types
-    kind = types.getkind(ffi_type)
-    return kind != 'u'
+        size = rffi.getintfield(ffi_type, 'c_size')
+    else:
+        size = 0
+    return _get_ffi2descr_dict(cpu)[kind, size]
diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py
--- a/pypy/jit/backend/llsupport/llmodel.py
+++ b/pypy/jit/backend/llsupport/llmodel.py
@@ -280,10 +280,10 @@
     def calldescrof(self, FUNC, ARGS, RESULT, extrainfo):
         return get_call_descr(self.gc_ll_descr, ARGS, RESULT, extrainfo)
 
-    def calldescrof_dynamic(self, ffi_args, ffi_result, extrainfo, ffi_flags):
+    def calldescrof_dynamic(self, cif_description, extrainfo):
         from pypy.jit.backend.llsupport import ffisupport
-        return ffisupport.get_call_descr_dynamic(self, ffi_args, ffi_result,
-                                                 extrainfo, ffi_flags)
+        return ffisupport.get_call_descr_dynamic(self, cif_description,
+                                                 extrainfo)
 
     def get_overflow_error(self):
         ovf_vtable = self.cast_adr_to_int(self._ovf_error_vtable)
diff --git a/pypy/jit/backend/llsupport/test/test_ffisupport.py b/pypy/jit/backend/llsupport/test/test_ffisupport.py
--- a/pypy/jit/backend/llsupport/test/test_ffisupport.py
+++ b/pypy/jit/backend/llsupport/test/test_ffisupport.py
@@ -1,4 +1,5 @@
-from pypy.rlib.libffi import types
+from pypy.rlib.jit_libffi import types, CIF_DESCRIPTION, FFI_TYPE_PP
+from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.jit.codewriter.longlong import is_64_bit
 from pypy.jit.backend.llsupport.descr import *
 from pypy.jit.backend.llsupport.ffisupport import *
@@ -12,11 +13,21 @@
         self.supports_longlong = supports_longlong
         self.supports_singlefloats = supports_singlefloats
 
+def grab(cpu, atypes, rtype):
+    p = lltype.malloc(CIF_DESCRIPTION, len(atypes),
+                      flavor='raw', immortal=True)
+    rffi.setintfield(p, 'abi', 42)
+    p.nargs = len(atypes)
+    p.rtype = rtype
+    p.atypes = lltype.malloc(FFI_TYPE_PP.TO, len(atypes),
+                             flavor='raw', immortal=True)
+    for i in range(len(atypes)):
+        p.atypes[i] = atypes[i]
+    return get_call_descr_dynamic(cpu, p, None)
 
 def test_call_descr_dynamic():
     args = [types.sint, types.pointer]
-    descr = get_call_descr_dynamic(FakeCPU(), args, types.sint, None,
-                                   ffi_flags=42)
+    descr = grab(FakeCPU(), args, types.sint)
     assert isinstance(descr, CallDescr)
     assert descr.result_type == 'i'
     assert descr.result_flag == FLAG_SIGNED
@@ -24,43 +35,39 @@
     assert descr.get_ffi_flags() == 42
 
     args = [types.sint, types.double, types.pointer]
-    descr = get_call_descr_dynamic(FakeCPU(), args, types.void, None, 42)
+    descr = grab(FakeCPU(), args, types.void)
     assert descr is None    # missing floats
-    descr = get_call_descr_dynamic(FakeCPU(supports_floats=True),
-                                   args, types.void, None, ffi_flags=43)
+    descr = grab(FakeCPU(supports_floats=True), args, types.void)
     assert descr.result_type == 'v'
     assert descr.result_flag == FLAG_VOID
     assert descr.arg_classes == 'ifi'
-    assert descr.get_ffi_flags() == 43
+    assert descr.get_ffi_flags() == 42
 
-    descr = get_call_descr_dynamic(FakeCPU(), [], types.sint8, None, 42)
+    descr = grab(FakeCPU(), [], types.sint8)
     assert descr.get_result_size() == 1
     assert descr.result_flag == FLAG_SIGNED
     assert descr.is_result_signed() == True
 
-    descr = get_call_descr_dynamic(FakeCPU(), [], types.uint8, None, 42)
+    descr = grab(FakeCPU(), [], types.uint8)
     assert isinstance(descr, CallDescr)
     assert descr.get_result_size() == 1
     assert descr.result_flag == FLAG_UNSIGNED
     assert descr.is_result_signed() == False
 
     if not is_64_bit or is_emulated_long:
-        descr = get_call_descr_dynamic(FakeCPU(), [], types.slonglong,
-                                       None, 42)
+        descr = grab(FakeCPU(), [], types.slonglong)
         assert descr is None   # missing longlongs
-        descr = get_call_descr_dynamic(FakeCPU(supports_longlong=True),
-                                       [], types.slonglong, None, ffi_flags=43)
+        descr = grab(FakeCPU(supports_longlong=True), [], types.slonglong)
         assert isinstance(descr, CallDescr)
         assert descr.result_flag == FLAG_FLOAT
         assert descr.result_type == 'L'
-        assert descr.get_ffi_flags() == 43
+        assert descr.get_ffi_flags() == 42
     else:
         assert types.slonglong is types.slong
 
-    descr = get_call_descr_dynamic(FakeCPU(), [], types.float, None, 42)
+    descr = grab(FakeCPU(), [], types.float)
     assert descr is None   # missing singlefloats
-    descr = get_call_descr_dynamic(FakeCPU(supports_singlefloats=True),
-                                   [], types.float, None, ffi_flags=44)
+    descr = grab(FakeCPU(supports_singlefloats=True), [], types.float)
     assert descr.result_flag == FLAG_UNSIGNED
     assert descr.result_type == 'S'
-    assert descr.get_ffi_flags() == 44
+    assert descr.get_ffi_flags() == 42
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -998,6 +998,24 @@
             getattr(self.mc, asmop)(arglocs[0], arglocs[1])
         return genop_binary
 
+    def _binaryop_or_lea(asmop, is_add):
+        def genop_binary_or_lea(self, op, arglocs, result_loc):
+            # use a regular ADD or SUB if result_loc is arglocs[0],
+            # and a LEA only if different.
+            if result_loc is arglocs[0]:
+                getattr(self.mc, asmop)(arglocs[0], arglocs[1])
+            else:
+                loc = arglocs[0]
+                argloc = arglocs[1]
+                assert isinstance(loc, RegLoc)
+                assert isinstance(argloc, ImmedLoc)
+                assert isinstance(result_loc, RegLoc)
+                delta = argloc.value
+                if not is_add:    # subtraction
+                    delta = -delta
+                self.mc.LEA_rm(result_loc.value, (loc.value, delta))
+        return genop_binary_or_lea
+
     def _cmpop(cond, rev_cond):
         def genop_cmp(self, op, arglocs, result_loc):
             rl = result_loc.lowest8bits()
@@ -1224,8 +1242,8 @@
 
     genop_int_neg = _unaryop("NEG")
     genop_int_invert = _unaryop("NOT")
-    genop_int_add = _binaryop("ADD", True)
-    genop_int_sub = _binaryop("SUB")
+    genop_int_add = _binaryop_or_lea("ADD", True)
+    genop_int_sub = _binaryop_or_lea("SUB", False)
     genop_int_mul = _binaryop("IMUL", True)
     genop_int_and = _binaryop("AND", True)
     genop_int_or  = _binaryop("OR", True)
@@ -1721,15 +1739,15 @@
                             guard_op.getopname())
 
     def genop_guard_int_add_ovf(self, op, guard_op, guard_token, arglocs, result_loc):
-        self.genop_int_add(op, arglocs, result_loc)
+        self.mc.ADD(arglocs[0], arglocs[1])
         return self._gen_guard_overflow(guard_op, guard_token)
 
     def genop_guard_int_sub_ovf(self, op, guard_op, guard_token, arglocs, result_loc):
-        self.genop_int_sub(op, arglocs, result_loc)
+        self.mc.SUB(arglocs[0], arglocs[1])
         return self._gen_guard_overflow(guard_op, guard_token)
 
     def genop_guard_int_mul_ovf(self, op, guard_op, guard_token, arglocs, result_loc):
-        self.genop_int_mul(op, arglocs, result_loc)
+        self.mc.IMUL(arglocs[0], arglocs[1])
         return self._gen_guard_overflow(guard_op, guard_token)
 
     def genop_guard_guard_false(self, ign_1, guard_op, guard_token, locs, ign_2):
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -23,6 +23,7 @@
      TempBox
 from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE
 from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64, MY_COPY_OF_REGS
+from pypy.jit.backend.x86 import rx86
 from pypy.rlib.rarithmetic import r_longlong
 
 class X86RegisterManager(RegisterManager):
@@ -610,9 +611,31 @@
         loc, argloc = self._consider_binop_part(op)
         self.Perform(op, [loc, argloc], loc)
 
-    consider_int_add = _consider_binop
+    def _consider_lea(self, op, loc):
+        argloc = self.loc(op.getarg(1))
+        self.rm.possibly_free_var(op.getarg(0))
+        resloc = self.force_allocate_reg(op.result)
+        self.Perform(op, [loc, argloc], resloc)
+
+    def consider_int_add(self, op):
+        loc = self.loc(op.getarg(0))
+        y = op.getarg(1)
+        if (isinstance(loc, RegLoc) and
+            isinstance(y, ConstInt) and rx86.fits_in_32bits(y.value)):
+            self._consider_lea(op, loc)
+        else:
+            self._consider_binop(op)
+
+    def consider_int_sub(self, op):
+        loc = self.loc(op.getarg(0))
+        y = op.getarg(1)
+        if (isinstance(loc, RegLoc) and
+            isinstance(y, ConstInt) and rx86.fits_in_32bits(-y.value)):
+            self._consider_lea(op, loc)
+        else:
+            self._consider_binop(op)
+
     consider_int_mul = _consider_binop
-    consider_int_sub = _consider_binop
     consider_int_and = _consider_binop
     consider_int_or  = _consider_binop
     consider_int_xor = _consider_binop
diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -45,13 +45,7 @@
     OS_UNIEQ_LENGTHOK           = 51   #
     _OS_offset_uni              = OS_UNI_CONCAT - OS_STR_CONCAT
     #
-    OS_LIBFFI_PREPARE           = 60
-    OS_LIBFFI_PUSH_ARG          = 61
     OS_LIBFFI_CALL              = 62
-    OS_LIBFFI_STRUCT_GETFIELD   = 63
-    OS_LIBFFI_STRUCT_SETFIELD   = 64
-    OS_LIBFFI_GETARRAYITEM      = 65
-    OS_LIBFFI_SETARRAYITEM      = 66
     #
     OS_LLONG_INVERT             = 69
     OS_LLONG_ADD                = 70
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -1728,27 +1728,9 @@
     # rlib.libffi
 
     def _handle_libffi_call(self, op, oopspec_name, args):
-        if oopspec_name == 'libffi_prepare_call':
-            oopspecindex = EffectInfo.OS_LIBFFI_PREPARE
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
-        elif oopspec_name.startswith('libffi_push_'):
-            oopspecindex = EffectInfo.OS_LIBFFI_PUSH_ARG
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
-        elif oopspec_name.startswith('libffi_call_'):
+        if oopspec_name == 'libffi_call':
             oopspecindex = EffectInfo.OS_LIBFFI_CALL
             extraeffect = EffectInfo.EF_RANDOM_EFFECTS
-        elif oopspec_name == 'libffi_struct_getfield':
-            oopspecindex = EffectInfo.OS_LIBFFI_STRUCT_GETFIELD
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
-        elif oopspec_name == 'libffi_struct_setfield':
-            oopspecindex = EffectInfo.OS_LIBFFI_STRUCT_SETFIELD
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
-        elif oopspec_name == 'libffi_array_getitem':
-            oopspecindex = EffectInfo.OS_LIBFFI_GETARRAYITEM
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
-        elif oopspec_name == 'libffi_array_setitem':
-            oopspecindex = EffectInfo.OS_LIBFFI_SETARRAYITEM
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
         else:
             assert False, 'unsupported oopspec: %s' % oopspec_name
         return self._handle_oopspec_call(op, args, oopspecindex, extraeffect)
diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -431,31 +431,6 @@
     return llop.uint_mod(lltype.Unsigned, xll, yll)
 
 
-# libffi support
-# --------------
-
-def func(llfunc):
-    from pypy.rlib.libffi import Func
-    return cast_base_ptr_to_instance(Func, llfunc)
-
-def _ll_1_libffi_prepare_call(llfunc):
-    return func(llfunc)._prepare()
-
-def _ll_4_libffi_push_int(llfunc, value, ll_args, i):
-    return func(llfunc)._push_int(value, ll_args, i)
-
-def _ll_4_libffi_push_float(llfunc, value, ll_args, i):
-    return func(llfunc)._push_float(value, ll_args, i)
-
-def _ll_3_libffi_call_int(llfunc, funcsym, ll_args):
-    return func(llfunc)._do_call(funcsym, ll_args, rffi.LONG)
-
-def _ll_3_libffi_call_float(llfunc, funcsym, ll_args):
-    return func(llfunc)._do_call(funcsym, ll_args, rffi.DOUBLE)
-
-def _ll_3_libffi_call_void(llfunc, funcsym, ll_args):
-    return func(llfunc)._do_call(funcsym, ll_args, lltype.Void)
-
 # in the following calls to builtins, the JIT is allowed to look inside:
 inline_calls_to = [
     ('int_floordiv_ovf_zer', [lltype.Signed, lltype.Signed], lltype.Signed),
diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py
--- a/pypy/jit/metainterp/optimizeopt/__init__.py
+++ b/pypy/jit/metainterp/optimizeopt/__init__.py
@@ -5,7 +5,6 @@
 from pypy.jit.metainterp.optimizeopt.heap import OptHeap
 from pypy.jit.metainterp.optimizeopt.vstring import OptString
 from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll
-from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall
 from pypy.jit.metainterp.optimizeopt.simplify import OptSimplify
 from pypy.jit.metainterp.optimizeopt.pure import OptPure
 from pypy.jit.metainterp.optimizeopt.earlyforce import OptEarlyForce
@@ -21,7 +20,6 @@
             ('earlyforce', OptEarlyForce),
             ('pure', OptPure),
             ('heap', OptHeap),
-            ('ffi', None),
             ('unroll', None)]
 # no direct instantiation of unroll
 unroll_all_opts = unrolling_iterable(ALL_OPTS)
@@ -42,11 +40,6 @@
             if opt is not None:
                 o = opt()
                 optimizations.append(o)
-            elif name == 'ffi' and config.translation.jit_ffi:
-                # we cannot put the class directly in the unrolling_iterable,
-                # because we do not want it to be seen at all (to avoid to
-                # introduce a dependency on libffi in case we do not need it)
-                optimizations.append(OptFfiCall())
 
     if ('rewrite' not in enable_opts or 'virtualize' not in enable_opts
         or 'heap' not in enable_opts or 'unroll' not in enable_opts
diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py
deleted file mode 100644
--- a/pypy/jit/metainterp/optimizeopt/fficall.py
+++ /dev/null
@@ -1,210 +0,0 @@
-from pypy.jit.codewriter.effectinfo import EffectInfo
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
-from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.rlib import clibffi, libffi
-from pypy.rlib.debug import debug_print
-from pypy.rlib.libffi import Func
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
-from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.rarithmetic import intmask
-
-
-class FuncInfo(object):
-
-    argtypes = None
-    restype = None
-    descr = None
-    prepare_op = None
-
-    def __init__(self, funcval, cpu, prepare_op):
-        self.funcval = funcval
-        self.opargs = []
-        argtypes, restype, flags = self._get_signature(funcval)
-        self.descr = cpu.calldescrof_dynamic(argtypes, restype,
-                                             EffectInfo.MOST_GENERAL,
-                                             ffi_flags=flags)
-        # ^^^ may be None if unsupported
-        self.prepare_op = prepare_op
-        self.delayed_ops = []
-
-    def _get_signature(self, funcval):
-        """
-        given the funcval, return a tuple (argtypes, restype, flags), where
-        the actuall types are libffi.types.*
-
-        The implementation is tricky because we have three possible cases:
-
-        - translated: the easiest case, we can just cast back the pointer to
-          the original Func instance and read .argtypes, .restype and .flags
-
-        - completely untranslated: this is what we get from test_optimizeopt
-          tests. funcval contains a FakeLLObject whose _fake_class is Func,
-          and we can just get .argtypes, .restype and .flags
-
-        - partially translated: this happens when running metainterp tests:
-          funcval contains the low-level equivalent of a Func, and thus we
-          have to fish inst_argtypes and inst_restype by hand.  Note that
-          inst_argtypes is actually a low-level array, but we can use it
-          directly since the only thing we do with it is to read its items
-        """
-
-        llfunc = funcval.box.getref_base()
-        if we_are_translated():
-            func = cast_base_ptr_to_instance(Func, llfunc)
-            return func.argtypes, func.restype, func.flags
-        elif getattr(llfunc, '_fake_class', None) is Func:
-            # untranslated
-            return llfunc.argtypes, llfunc.restype, llfunc.flags
-        else:
-            # partially translated
-            # llfunc contains an opaque pointer to something like the following:
-            # <GcStruct pypy.rlib.libffi.Func { super, inst_argtypes, inst_funcptr,
-            #                                   inst_funcsym, inst_restype }>
-            #
-            # Unfortunately, we cannot use the proper lltype.cast_opaque_ptr,
-            # because we don't have the exact TYPE to cast to.  Instead, we
-            # just fish it manually :-(
-            f = llfunc._obj.container
-            return f.inst_argtypes, f.inst_restype, f.inst_flags
-
-
-class OptFfiCall(Optimization):
-
-    def setup(self):
-        self.funcinfo = None
-        if self.optimizer.loop is not None:
-            self.logops = self.optimizer.loop.logops
-        else:
-            self.logops = None
-
-    def new(self):
-        return OptFfiCall()
-
-    def begin_optimization(self, funcval, op):
-        self.rollback_maybe('begin_optimization', op)
-        self.funcinfo = FuncInfo(funcval, self.optimizer.cpu, op)
-
-    def commit_optimization(self):
-        self.funcinfo = None
-
-    def rollback_maybe(self, msg, op):
-        if self.funcinfo is None:
-            return # nothing to rollback
-        #
-        # we immediately set funcinfo to None to prevent recursion when
-        # calling emit_op
-        if self.logops is not None:
-            debug_print('rollback: ' + msg + ': ', self.logops.repr_of_resop(op))
-        funcinfo = self.funcinfo
-        self.funcinfo = None
-        self.emit_operation(funcinfo.prepare_op)
-        for op in funcinfo.opargs:
-            self.emit_operation(op)
-        for delayed_op in funcinfo.delayed_ops:
-            self.emit_operation(delayed_op)
-
-    def emit_operation(self, op):
-        # we cannot emit any operation during the optimization
-        self.rollback_maybe('invalid op', op)
-        Optimization.emit_operation(self, op)
-
-    def optimize_CALL(self, op):
-        oopspec = self._get_oopspec(op)
-        ops = [op]
-        if oopspec == EffectInfo.OS_LIBFFI_PREPARE:
-            ops = self.do_prepare_call(op)
-        elif oopspec == EffectInfo.OS_LIBFFI_PUSH_ARG:
-            ops = self.do_push_arg(op)
-        elif oopspec == EffectInfo.OS_LIBFFI_CALL:
-            ops = self.do_call(op)
-        #
-        for op in ops:
-            self.emit_operation(op)
-
-    optimize_CALL_MAY_FORCE = optimize_CALL
-
-    def optimize_FORCE_TOKEN(self, op):
-        # The handling of force_token needs a bit of explanation.
-        # The original trace which is getting optimized looks like this:
-        #    i1 = force_token()
-        #    setfield_gc(p0, i1, ...)
-        #    call_may_force(...)
-        #
-        # In theory, fficall should take care of both force_token and
-        # setfield_gc.  However, the lazy setfield optimization in heap.py
-        # delays the setfield_gc, with the effect that fficall.py sees them in
-        # this order:
-        #    i1 = force_token()
-        #    call_may_force(...)
-        #    setfield_gc(p0, i1, ...)
-        #
-        # This means that see the setfield_gc only the call_may_force, when
-        # the optimization has already been done, and thus we need to take
-        # special care just of force_token.
-        #
-        # Finally, the method force_lazy_setfield in heap.py reorders the
-        # call_may_force and the setfield_gc, so the final result we get is
-        # again force_token/setfield_gc/call_may_force.
-        #
-        # However, note that nowadays we also allow to have any setfield_gc
-        # between libffi_prepare and libffi_call, so while the comment above
-        # it's a bit superfluous, it has been left there for future reference.
-        if self.funcinfo is None:
-            self.emit_operation(op)
-        else:
-            self.funcinfo.delayed_ops.append(op)
-
-    optimize_SETFIELD_GC = optimize_FORCE_TOKEN
-
-    def do_prepare_call(self, op):
-        self.rollback_maybe('prepare call', op)
-        funcval = self._get_funcval(op)
-        if not funcval.is_constant():
-            return [op] # cannot optimize
-        self.begin_optimization(funcval, op)
-        return []
-
-    def do_push_arg(self, op):
-        funcval = self._get_funcval(op)
-        if not self.funcinfo or self.funcinfo.funcval is not funcval:
-            return [op] # cannot optimize
-        self.funcinfo.opargs.append(op)
-        return []
-
-    def do_call(self, op):
-        funcval = self._get_funcval(op)
-        funcinfo = self.funcinfo
-        if (not funcinfo or funcinfo.funcval is not funcval or
-            funcinfo.descr is None):
-            return [op] # cannot optimize
-        funcsymval = self.getvalue(op.getarg(2))
-        arglist = [funcsymval.get_key_box()]
-        for push_op in funcinfo.opargs:
-            argval = self.getvalue(push_op.getarg(2))
-            arglist.append(argval.get_key_box())
-        newop = ResOperation(rop.CALL_RELEASE_GIL, arglist, op.result,
-                             descr=funcinfo.descr)
-        self.commit_optimization()
-        ops = []
-        for delayed_op in funcinfo.delayed_ops:
-            ops.append(delayed_op)
-        ops.append(newop)
-        return ops
-
-    def propagate_forward(self, op):
-        if self.logops is not None:
-            debug_print(self.logops.repr_of_resop(op))
-        dispatch_opt(self, op)
-
-    def _get_oopspec(self, op):
-        effectinfo = op.getdescr().get_extra_info()
-        return effectinfo.oopspecindex
-
-    def _get_funcval(self, op):
-        return self.getvalue(op.getarg(1))
-
-dispatch_opt = make_dispatcher_method(OptFfiCall, 'optimize_',
-        default=OptFfiCall.emit_operation)
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py
deleted file mode 100644
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizefficall.py
+++ /dev/null
@@ -1,315 +0,0 @@
-from pypy.rpython.lltypesystem import llmemory
-from pypy.rlib.libffi import Func, types
-from pypy.jit.metainterp.history import AbstractDescr
-from pypy.jit.codewriter.effectinfo import EffectInfo
-from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import BaseTestBasic
-from pypy.jit.metainterp.optimizeopt.test.test_optimizebasic import LLtypeMixin
-
-class MyCallDescr(AbstractDescr):
-    """
-    Fake calldescr to be used inside the tests.
-
-    The particularity is that it provides an __eq__ method, so that it
-    comparses by value by comparing the arg_types and typeinfo fields, so you
-    can check that the signature of a call is really what you want.
-    """
-
-    def __init__(self, arg_types, typeinfo, flags):
-        self.arg_types = arg_types
-        self.typeinfo = typeinfo   # return type
-        self.flags = flags
-
-    def __eq__(self, other):
-        return (self.arg_types == other.arg_types and
-                self.typeinfo == other.typeinfo and
-                self.flags == other.get_ffi_flags())
-
-class FakeLLObject(object):
-
-    def __init__(self, **kwds):
-        self.__dict__.update(kwds)
-        self._TYPE = llmemory.GCREF
-
-    def _identityhash(self):
-        return id(self)
-
-
-class TestFfiCall(BaseTestBasic, LLtypeMixin):
-
-    enable_opts = "intbounds:rewrite:virtualize:string:pure:earlyforce:heap:ffi"
-
-    class namespace:
-        cpu = LLtypeMixin.cpu
-        FUNC = LLtypeMixin.FUNC
-        vable_token_descr = LLtypeMixin.valuedescr
-        valuedescr = LLtypeMixin.valuedescr
-
-        int_float__int_42 = MyCallDescr('if', 'i', 42)
-        int_float__int_43 = MyCallDescr('if', 'i', 43)
-        funcptr = FakeLLObject()
-        func = FakeLLObject(_fake_class=Func,
-                            argtypes=[types.sint, types.double],
-                            restype=types.sint,
-                            flags=42)
-        func2 = FakeLLObject(_fake_class=Func,
-                             argtypes=[types.sint, types.double],
-                             restype=types.sint,
-                             flags=43)
-        #
-        ffi_slong = types.slong
-        dyn_123_field = cpu.fielddescrof_dynamic(offset=123,
-                                                 fieldsize=types.slong.c_size,
-                                                 is_pointer=False,
-                                                 is_float=False,
-                                                 is_signed=True)
-        #
-        def calldescr(cpu, FUNC, oopspecindex, extraeffect=None):
-            if extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
-                f = None   # means "can force all" really
-            else:
-                f = []
-            einfo = EffectInfo(f, f, f, f, oopspecindex=oopspecindex,
-                               extraeffect=extraeffect)
-            return cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, einfo)
-        #
-        libffi_prepare =  calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_PREPARE)
-        libffi_push_arg = calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_PUSH_ARG)
-        libffi_call =     calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_CALL,
-                                    EffectInfo.EF_RANDOM_EFFECTS)
-        libffi_struct_getfield = calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_STRUCT_GETFIELD)
-        libffi_struct_setfield = calldescr(cpu, FUNC, EffectInfo.OS_LIBFFI_STRUCT_SETFIELD)
-    
-    namespace = namespace.__dict__
-
-    # ----------------------------------------------------------------------
-    # this group of tests is the most important, as they represent the "real"
-    # cases you actually get when using rlib.libffi
-    
-    def test_ffi_call_opt(self):
-        ops = """
-        [i0, f1]
-        call(0, ConstPtr(func),                       descr=libffi_prepare)
-        call(0, ConstPtr(func), i0,                   descr=libffi_push_arg)
-        call(0, ConstPtr(func), f1,                   descr=libffi_push_arg)
-        i3 = call_may_force(0, ConstPtr(func), 12345, descr=libffi_call)
-        guard_not_forced() []
-        guard_no_exception() []
-        jump(i3, f1)
-        """
-        expected = """
-        [i0, f1]
-        i3 = call_release_gil(12345, i0, f1, descr=int_float__int_42)
-        guard_not_forced() []
-        guard_no_exception() []
-        jump(i3, f1)
-        """
-        loop = self.optimize_loop(ops, expected)
-
-    def test_ffi_call_nonconst(self):
-        ops = """
-        [i0, f1, p2]
-        call(0, p2,                       descr=libffi_prepare)
-        call(0, p2, i0,                   descr=libffi_push_arg)
-        call(0, p2, f1,                   descr=libffi_push_arg)
-        i3 = call_may_force(0, p2, 12345, descr=libffi_call)
-        guard_not_forced() []
-        guard_no_exception() []
-        jump(i3, f1, p2)
-        """
-        expected = ops
-        loop = self.optimize_loop(ops, expected)
-
-    def test_handle_virtualizables(self):
-        # this test needs an explanation to understand what goes on: see the
-        # comment in optimize_FORCE_TOKEN
-        ops = """
-        [i0, f1, p2]
-        call(0, ConstPtr(func),                       descr=libffi_prepare)
-        call(0, ConstPtr(func), i0,                   descr=libffi_push_arg)
-        call(0, ConstPtr(func), f1,                   descr=libffi_push_arg)
-        i4 = force_token()
-        setfield_gc(p2, i4, descr=vable_token_descr)
-        i3 = call_may_force(0, ConstPtr(func), 12345, descr=libffi_call)
-        guard_not_forced() [p2]
-        guard_no_exception() [p2]
-        jump(i3, f1, p2)
-        """
-        expected = """
-        [i0, f1, p2]
-        i4 = force_token()
-        setfield_gc(p2, i4, descr=vable_token_descr)
-        i3 = call_release_gil(12345, i0, f1, descr=int_float__int_42)
-        guard_not_forced() [p2]
-        guard_no_exception() [p2]
-        jump(i3, f1, p2)
-        """
-        loop = self.optimize_loop(ops, expected)
-
-    # ----------------------------------------------------------------------
-    # in pratice, the situations described in these tests should never happen,
-    # but we still want to ensure correctness
-
-    def test_rollback_if_op_in_between(self):
-        ops = """
-        [i0, f1]
-        call(0, ConstPtr(func),                       descr=libffi_prepare)
-        call(0, ConstPtr(func), i0,                   descr=libffi_push_arg)
-        i1 = int_add(i0, 1)
-        call(0, ConstPtr(func), f1,                   descr=libffi_push_arg)
-        i3 = call_may_force(0, ConstPtr(func), 12345, descr=libffi_call)
-        guard_not_forced() []
-        guard_no_exception() []
-        jump(i3, f1)
-        """
-        expected = ops
-        loop = self.optimize_loop(ops, expected)
-
-    def test_rollback_multiple_calls(self):
-        ops = """
-        [i0, i2, f1]
-        call(0, ConstPtr(func),                        descr=libffi_prepare)
-        call(0, ConstPtr(func),  i0,                   descr=libffi_push_arg)
-        #
-        # this is the culprit!
-        call(0, ConstPtr(func2),                       descr=libffi_prepare)
-        #
-        call(0, ConstPtr(func),  f1,                   descr=libffi_push_arg)
-        i3 = call_may_force(0, ConstPtr(func),  12345, descr=libffi_call)
-        guard_not_forced() []
-        guard_no_exception() []
-        call(0, ConstPtr(func2), i0,                   descr=libffi_push_arg)
-        call(0, ConstPtr(func2), f1,                   descr=libffi_push_arg)
-        i4 = call_may_force(0, ConstPtr(func2), 67890, descr=libffi_call)
-        guard_not_forced() []
-        guard_no_exception() []
-        jump(i3, i4, f1)
-        """
-        expected = ops
-        loop = self.optimize_loop(ops, expected)
-
-    def test_rollback_multiple_prepare(self):
-        ops = """
-        [i0, i2, f1]
-        call(0, ConstPtr(func),                        descr=libffi_prepare)
-        #
-        # this is the culprit!
-        call(0, ConstPtr(func2),                       descr=libffi_prepare)
-        #
-        call(0, ConstPtr(func),  i0,                   descr=libffi_push_arg)
-        call(0, ConstPtr(func),  f1,                   descr=libffi_push_arg)
-        i3 = call_may_force(0, ConstPtr(func),  12345, descr=libffi_call)
-        guard_not_forced() []
-        guard_no_exception() []
-        call(0, ConstPtr(func2), i0,                   descr=libffi_push_arg)
-        call(0, ConstPtr(func2), f1,                   descr=libffi_push_arg)
-        i4 = call_may_force(0, ConstPtr(func2), 67890, descr=libffi_call)
-        guard_not_forced() []
-        guard_no_exception() []
-        jump(i3, i4, f1)
-        """
-        expected = ops
-        loop = self.optimize_loop(ops, expected)
-
-    def test_optimize_nested_call(self):
-        ops = """
-        [i0, i2, f1]
-        call(0, ConstPtr(func),                        descr=libffi_prepare)
-        #
-        # this "nested" call is nicely optimized
-        call(0, ConstPtr(func2),                       descr=libffi_prepare)
-        call(0, ConstPtr(func2), i0,                   descr=libffi_push_arg)
-        call(0, ConstPtr(func2), f1,                   descr=libffi_push_arg)
-        i4 = call_may_force(0, ConstPtr(func2), 67890, descr=libffi_call)
-        guard_not_forced() []
-        guard_no_exception() []
-        #
-        call(0, ConstPtr(func),  i0,                   descr=libffi_push_arg)
-        call(0, ConstPtr(func),  f1,                   descr=libffi_push_arg)
-        i3 = call_may_force(0, ConstPtr(func),  12345, descr=libffi_call)
-        guard_not_forced() []
-        guard_no_exception() []
-        jump(i3, i4, f1)
-        """
-        expected = """
-        [i0, i2, f1]
-        call(0, ConstPtr(func),                        descr=libffi_prepare)
-        #
-        # this "nested" call is nicely optimized
-        i4 = call_release_gil(67890, i0, f1, descr=int_float__int_43)
-        guard_not_forced() []
-        guard_no_exception() []
-        #
-        call(0, ConstPtr(func),  i0,                   descr=libffi_push_arg)
-        call(0, ConstPtr(func),  f1,                   descr=libffi_push_arg)
-        i3 = call_may_force(0, ConstPtr(func),  12345, descr=libffi_call)
-        guard_not_forced() []
-        guard_no_exception() []
-        jump(i3, i4, f1)
-        """
-        loop = self.optimize_loop(ops, expected)
-
-    def test_rollback_force_token(self):
-        ops = """
-        [i0, f1, p2]
-        call(0, ConstPtr(func),                       descr=libffi_prepare)
-        call(0, ConstPtr(func), i0,                   descr=libffi_push_arg)
-        call(0, ConstPtr(func), f1,                   descr=libffi_push_arg)
-        i4 = force_token()
-        i5 = int_add(i0, 1) # culprit!
-        setfield_gc(p2, i4, descr=vable_token_descr)
-        i3 = call_may_force(0, ConstPtr(func), 12345, descr=libffi_call)
-        guard_not_forced() [p2]
-        guard_no_exception() [p2]
-        jump(i3, f1, p2)
-        """
-        expected = ops
-        loop = self.optimize_loop(ops, expected)
-
-    def test_allow_setfields_in_between(self):
-        ops = """
-        [i0, f1, p2]
-        call(0, ConstPtr(func),                       descr=libffi_prepare)
-        call(0, ConstPtr(func), i0,                   descr=libffi_push_arg)
-        call(0, ConstPtr(func), f1,                   descr=libffi_push_arg)
-        setfield_gc(p2, i0,                           descr=valuedescr)
-        i3 = call_may_force(0, ConstPtr(func), 12345, descr=libffi_call)
-        guard_not_forced() []
-        guard_no_exception() []
-        jump(i3, f1, p2)
-        """
-        expected = """
-        [i0, f1, p2]
-        setfield_gc(p2, i0, descr=valuedescr)
-        i3 = call_release_gil(12345, i0, f1, descr=int_float__int_42)
-        guard_not_forced() []
-        guard_no_exception() []
-        jump(i3, f1, p2)
-        """
-        loop = self.optimize_loop(ops, expected)
-
-    def test_ffi_struct_fields(self):
-        ops = """
-        [i0]
-        i1 = call(0, ConstClass(ffi_slong), i0, 123, descr=libffi_struct_getfield)
-        i2 = int_add(i1, 1)
-        call(0, ConstClass(ffi_slong), i0, 123, i2, descr=libffi_struct_setfield)
-        jump(i1)
-        """
-        expected = """
-        [i0]
-        i1 = getfield_raw(i0, descr=dyn_123_field)
-        i2 = int_add(i1, 1)
-        setfield_raw(i0, i2, descr=dyn_123_field)
-        jump(i1)
-        """
-        loop = self.optimize_loop(ops, expected)
-
-    def test_ffi_struct_fields_nonconst(self):
-        ops = """
-        [i0, i1]
-        i2 = call(0, ConstClass(ffi_slong), i0, i1,  descr=libffi_struct_getfield)
-        i3 = call(0, i1                   , i0, 123, descr=libffi_struct_getfield)
-        jump(i1)
-        """
-        expected = ops
-        loop = self.optimize_loop(ops, expected)
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -41,14 +41,6 @@
     #
     chain, _ = build_opt_chain(metainterp_sd, "aaa:bbb")
     check(chain, ["OptSimplify"])
-    #
-    chain, _ = build_opt_chain(metainterp_sd, "ffi")
-    check(chain, ["OptFfiCall", "OptSimplify"])
-    #
-    metainterp_sd.config = get_pypy_config(translating=True)
-    assert not metainterp_sd.config.translation.jit_ffi
-    chain, _ = build_opt_chain(metainterp_sd, "ffi")
-    check(chain, ["OptSimplify"])
 
 
 # ____________________________________________________________
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_util.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py
@@ -346,7 +346,6 @@
         self.options = Fake()
         self.globaldata = Fake()
         self.config = get_pypy_config(translating=True)
-        self.config.translation.jit_ffi = True
 
     class logger_noopt:
         @classmethod
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -1390,6 +1390,8 @@
             if vablebox is not None:
                 self.metainterp.history.record(rop.KEEPALIVE, [vablebox], None)
             self.metainterp.handle_possible_exception()
+            if effectinfo.oopspecindex == effectinfo.OS_LIBFFI_CALL:
+                self.metainterp.direct_libffi_call()
             return resbox
         else:
             effect = effectinfo.extraeffect
@@ -2533,6 +2535,85 @@
         else:
             return None
 
+    def direct_libffi_call(self):
+        """Generate a direct call to C code, patching the CALL_MAY_FORCE
+        to jit_ffi_call() that occurred just now.
+        """
+        from pypy.rpython.lltypesystem import llmemory
+        from pypy.rlib.jit_libffi import CIF_DESCRIPTION_P
+        from pypy.jit.backend.llsupport.ffisupport import get_arg_descr
+        #
+        num_extra_guards = 0
+        while True:
+            op = self.history.operations[-1-num_extra_guards]
+            if op.getopnum() == rop.CALL_MAY_FORCE:
+                break
+            assert op.is_guard()
+            num_extra_guards += 1
+        #
+        box_cif_description = op.getarg(1)
+        if not isinstance(box_cif_description, ConstInt):
+            return
+        cif_description = box_cif_description.getint()
+        cif_description = llmemory.cast_int_to_adr(cif_description)
+        cif_description = llmemory.cast_adr_to_ptr(cif_description,
+                                                   CIF_DESCRIPTION_P)
+        calldescr = self.cpu.calldescrof_dynamic(cif_description,
+                                                 op.getdescr().extrainfo)
+        if calldescr is None:
+            return
+        #
+        extra_guards = []
+        for i in range(num_extra_guards):
+            extra_guards.append(self.history.operations.pop())
+        extra_guards.reverse()
+        #
+        box_exchange_buffer = op.getarg(3)
+        self.history.operations.pop()
+        arg_boxes = []
+        for i in range(cif_description.nargs):
+            kind, descr = get_arg_descr(self.cpu, cif_description.atypes[i])
+            if kind == 'i':
+                box_arg = history.BoxInt()
+            elif kind == 'f':
+                box_arg = history.BoxFloat()
+            else:
+                assert kind == 'v'
+                continue
+            ofs = cif_description.exchange_args[i]
+            box_argpos = history.BoxInt()
+            self.history.record(rop.INT_ADD,
+                                [box_exchange_buffer, ConstInt(ofs)],
+                                box_argpos)
+            self.history.record(rop.GETARRAYITEM_RAW,
+                                [box_argpos, ConstInt(0)],
+                                box_arg, descr)
+            arg_boxes.append(box_arg)
+        #
+        kind, descr = get_arg_descr(self.cpu, cif_description.rtype)
+        if kind == 'i':
+            box_result = history.BoxInt()
+        elif kind == 'f':
+            box_result = history.BoxFloat()
+        else:
+            assert kind == 'v'
+            box_result = None
+        self.history.record(rop.CALL_RELEASE_GIL,
+                            [op.getarg(2)] + arg_boxes,
+                            box_result, calldescr)
+        #
+        self.history.operations.extend(extra_guards)
+        #
+        if box_result is not None:
+            ofs = cif_description.exchange_result
+            box_resultpos = history.BoxInt()
+            self.history.record(rop.INT_ADD,
+                                [box_exchange_buffer, ConstInt(ofs)],
+                                box_resultpos)
+            self.history.record(rop.SETARRAYITEM_RAW,
+                                [box_resultpos, ConstInt(0), box_result],
+                                None, descr)
+
 # ____________________________________________________________
 
 class ChangeFrame(JitException):
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -3797,6 +3797,7 @@
         assert res == 3
 
     def test_float_bytes(self):
+        from pypy.rlib.rfloat import isnan
         def f(n):
             ll = float2longlong(n)
             return longlong2float(ll)
@@ -3804,7 +3805,7 @@
         for x in [2.5, float("nan"), -2.5, float("inf")]:
             # There are tests elsewhere to verify the correctness of this.
             res = self.interp_operations(f, [x])
-            assert res == x or math.isnan(x) and math.isnan(res)
+            assert res == x or isnan(x) and isnan(res)
 
 
 class TestLLtype(BaseLLtypeTests, LLJitMixin):
diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py
--- a/pypy/jit/metainterp/test/test_fficall.py
+++ b/pypy/jit/metainterp/test/test_fficall.py
@@ -1,210 +1,106 @@
-from __future__ import with_statement
 import py
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.jit.metainterp.test.support import LLJitMixin
+from pypy.rlib import jit
+from pypy.rlib.jit_libffi import types, CIF_DESCRIPTION, FFI_TYPE_PP
+from pypy.rlib.unroll import unrolling_iterable
 
-from pypy.jit.metainterp.test.support import LLJitMixin
-from pypy.rlib.jit import JitDriver, promote, dont_look_inside
-from pypy.rlib.libffi import (ArgChain, IS_32_BIT, array_getitem, array_setitem,
-    types, struct_setfield_int, struct_getfield_int)
-from pypy.rlib.objectmodel import specialize
-from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong
-from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall
-from pypy.rlib.unroll import unrolling_iterable
-from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.tool.sourcetools import func_with_new_name
 
+def get_description(atypes, rtype):
+    p = lltype.malloc(CIF_DESCRIPTION, len(atypes),
+                      flavor='raw', immortal=True)
+    rffi.setintfield(p, 'abi', 42)
+    p.nargs = len(atypes)
+    p.rtype = rtype
+    p.atypes = lltype.malloc(FFI_TYPE_PP.TO, len(atypes),
+                             flavor='raw', immortal=True)
+    for i in range(len(atypes)):
+        p.atypes[i] = atypes[i]
+    return p
 
-class FfiCallTests(_TestLibffiCall):
-    # ===> ../../../rlib/test/test_libffi.py
 
-    def call(self, funcspec, args, RESULT, is_struct=False, jitif=[]):
-        """
-        Call the function specified by funcspec in a loop, and let the jit to
-        see and optimize it.
-        """
-        #
-        lib, name, argtypes, restype = funcspec
-        method_and_args = []
-        for argval in args:
-            if isinstance(argval, tuple):
-                method_name, argval = argval
+class FfiCallTests(object):
+
+    def _run(self, atypes, rtype, avalues, rvalue):
+        cif_description = get_description(atypes, rtype)
+
+        def verify(*args):
+            assert args == tuple(avalues)
+            return rvalue
+        FUNC = lltype.FuncType([lltype.typeOf(avalue) for avalue in avalues],
+                               lltype.typeOf(rvalue))
+        func = lltype.functionptr(FUNC, 'verify', _callable=verify)
+        func_addr = rffi.cast(rffi.VOIDP, func)
+
+        for i in range(len(avalues)):
+            cif_description.exchange_args[i] = (i+1) * 16
+        cif_description.exchange_result = (len(avalues)+1) * 16
+
+        unroll_avalues = unrolling_iterable(avalues)
+
+        @jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)")
+        def fake_call(cif_description, func_addr, exchange_buffer):
+            ofs = 16
+            for avalue in unroll_avalues:
+                TYPE = rffi.CArray(lltype.typeOf(avalue))
+                data = rffi.ptradd(exchange_buffer, ofs)
+                assert rffi.cast(lltype.Ptr(TYPE), data)[0] == avalue
+                ofs += 16
+            if rvalue is not None:
+                write_rvalue = rvalue
             else:
-                method_name = 'arg'
-            method_and_args.append((method_name, argval))
-        method_and_args = unrolling_iterable(method_and_args)
-        #
-        reds = ['n', 'res', 'func']
-        if (RESULT is rffi.DOUBLE or
-            IS_32_BIT and RESULT in [rffi.LONGLONG, rffi.ULONGLONG]):
-            reds = ['n', 'func', 'res'] # 'double' floats must be *after* refs
-        driver = JitDriver(reds=reds, greens=[])
-        init_result = rffi.cast(RESULT, 0)
-        #
-        def g(func):
-            # a different function, which is marked as "dont_look_inside"
-            # in case it uses an unsupported argument
-            argchain = ArgChain()
-            # this loop is unrolled
-            for method_name, argval in method_and_args:
-                getattr(argchain, method_name)(argval)
-            return func.call(argchain, RESULT, is_struct=is_struct)
-        #
-        def f(n):
-            func = lib.getpointer(name, argtypes, restype)
-            res = init_result
-            while n < 10:
-                driver.jit_merge_point(n=n, res=res, func=func)
-                promote(func)
-                res = g(func)
-                n += 1
+                write_rvalue = 12923  # ignored
+            TYPE = rffi.CArray(lltype.typeOf(write_rvalue))
+            data = rffi.ptradd(exchange_buffer, ofs)
+            rffi.cast(lltype.Ptr(TYPE), data)[0] = write_rvalue
+
+        def f():
+            exbuf = lltype.malloc(rffi.CCHARP.TO, (len(avalues)+2) * 16,
+                                  flavor='raw', zero=True)
+            ofs = 16
+            for avalue in unroll_avalues:
+                TYPE = rffi.CArray(lltype.typeOf(avalue))
+                data = rffi.ptradd(exbuf, ofs)
+                rffi.cast(lltype.Ptr(TYPE), data)[0] = avalue
+                ofs += 16
+
+            fake_call(cif_description, func_addr, exbuf)
+
+            if rvalue is None:
+                res = 654321
+            else:
+                TYPE = rffi.CArray(lltype.typeOf(rvalue))
+                data = rffi.ptradd(exbuf, ofs)
+                res = rffi.cast(lltype.Ptr(TYPE), data)[0]
+            lltype.free(exbuf, flavor='raw')
             return res
-        #
-        res = self.meta_interp(f, [0], backendopt=True,
-                               supports_floats       = self.supports_all,
-                               supports_longlong     = self.supports_all,
-                               supports_singlefloats = self.supports_all)
-        d = {'floats': self.supports_all,
-             'longlong': self.supports_all or not IS_32_BIT,
-             'singlefloats': self.supports_all,
-             'byval': False}
-        supported = all(d[check] for check in jitif)
-        if supported:
-            self.check_resops(
-                call_release_gil=2,   # a CALL_RELEASE_GIL, and no other CALLs
-                call=0,
-                call_may_force=0,
-                guard_no_exception=2,
-                guard_not_forced=2,
-                int_add=2,
-                int_lt=2,
-                guard_true=2,
-                jump=1)
-        else:
-            self.check_resops(
-                call_release_gil=0,   # no CALL_RELEASE_GIL
-                int_add=2,
-                int_lt=2,
-                guard_true=2,
-                jump=1)
-        return res
 
-    def test_byval_result(self):
-        _TestLibffiCall.test_byval_result(self)
-    test_byval_result.__doc__ = _TestLibffiCall.test_byval_result.__doc__
-    test_byval_result.dont_track_allocations = True
+        res = f()
+        assert res == rvalue or (res, rvalue) == (654321, None)
+        res = self.interp_operations(f, [])
+        assert res == rvalue or (res, rvalue) == (654321, None)
+        self.check_operations_history(call_may_force=0,
+                                      call_release_gil=1)
 
-class FfiLookupTests(object):
-    def test_array_fields(self):
-        myjitdriver = JitDriver(
-            greens = [],
-            reds = ["n", "i", "points", "result_point"],
-        )
+    def test_simple_call(self):
+        self._run([types.signed] * 2, types.signed, [456, 789], -42)
 
-        POINT = lltype.Struct("POINT",
-            ("x", lltype.Signed),
-            ("y", lltype.Signed),
-        )
-        def f(points, result_point, n):
-            i = 0
-            while i < n:
-                myjitdriver.jit_merge_point(i=i, points=points, n=n,
-                                            result_point=result_point)
-                x = array_getitem(
-                    types.slong, rffi.sizeof(lltype.Signed) * 2, points, i, 0
-                )
-                y = array_getitem(
-                    types.slong, rffi.sizeof(lltype.Signed) * 2, points, i, rffi.sizeof(lltype.Signed)
-                )
+    def test_many_arguments(self):
+        for i in [0, 6, 20]:
+            self._run([types.signed] * i, types.signed,
+                      [-123456*j for j in range(i)],
+                      -42434445)
 
-                cur_x = array_getitem(
-                    types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, 0
-                )
-                cur_y = array_getitem(
-                    types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, rffi.sizeof(lltype.Signed)
-                )
+    def test_simple_call_float(self):
+        self._run([types.double] * 2, types.double, [45.6, 78.9], -4.2)
 
-                array_setitem(
-                    types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, 0, cur_x + x
-                )
-                array_setitem(
-                    types.slong, rffi.sizeof(lltype.Signed) * 2, result_point, 0, rffi.sizeof(lltype.Signed), cur_y + y
-                )
-                i += 1
+    def test_returns_none(self):
+        self._run([types.signed] * 2, types.void, [456, 789], None)
 
-        def main(n):
-            with lltype.scoped_alloc(rffi.CArray(POINT), n) as points:
-                with lltype.scoped_alloc(rffi.CArray(POINT), 1) as result_point:
-                    for i in xrange(n):
-                        points[i].x = i * 2
-                        points[i].y = i * 2 + 1
-                    points = rffi.cast(rffi.CArrayPtr(lltype.Char), points)
-                    result_point[0].x = 0
-                    result_point[0].y = 0
-                    result_point = rffi.cast(rffi.CArrayPtr(lltype.Char), result_point)
-                    f(points, result_point, n)
-                    result_point = rffi.cast(rffi.CArrayPtr(POINT), result_point)
-                    return result_point[0].x * result_point[0].y
-
-        assert self.meta_interp(main, [10]) == main(10) == 9000
-        self.check_resops({'jump': 1, 'int_lt': 2, 'setinteriorfield_raw': 4,
-                           'getinteriorfield_raw': 8, 'int_add': 6, 'guard_true': 2})
-
-    def _test_getitem_type(self, TYPE, ffitype, COMPUTE_TYPE):
-        reds = ["n", "i", "s", "data"]
-        if COMPUTE_TYPE is lltype.Float:
-            # Move the float var to the back.
-            reds.remove("s")
-            reds.append("s")
-        myjitdriver = JitDriver(
-            greens = [],
-            reds = reds,
-        )
-        def f(data, n):
-            i = 0
-            s = rffi.cast(COMPUTE_TYPE, 0)
-            while i < n:
-                myjitdriver.jit_merge_point(n=n, i=i, s=s, data=data)
-                s += rffi.cast(COMPUTE_TYPE, array_getitem(ffitype, rffi.sizeof(TYPE), data, 0, 0))
-                i += 1
-            return s
-        def main(n):
-            with lltype.scoped_alloc(rffi.CArray(TYPE), 1) as data:
-                data[0] = rffi.cast(TYPE, 200)
-                return f(data, n)
-        assert self.meta_interp(main, [10]) == 2000
-
-    def test_array_getitem_uint8(self):
-        self._test_getitem_type(rffi.UCHAR, types.uchar, lltype.Signed)
-        self.check_resops({'jump': 1, 'int_lt': 2, 'getinteriorfield_raw': 2,
-                           'guard_true': 2, 'int_add': 4})
-
-    def test_array_getitem_float(self):
-        self._test_getitem_type(rffi.FLOAT, types.float, lltype.Float)
+    def test_returns_signedchar(self):
+        self._run([types.signed], types.sint8, [456],
+                  rffi.cast(rffi.SIGNEDCHAR, -42))
 
 
 class TestFfiCall(FfiCallTests, LLJitMixin):
-    supports_all = False
-
-class TestFfiCallSupportAll(FfiCallTests, LLJitMixin):
-    supports_all = True     # supports_{floats,longlong,singlefloats}
-
-    def test_struct_getfield(self):
-        myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'addr'])
-
-        def f(n):
-            i = 0
-            addr = lltype.malloc(rffi.VOIDP.TO, 10, flavor='raw')
-            while i < n:
-                myjitdriver.jit_merge_point(n=n, i=i, addr=addr)
-                struct_setfield_int(types.slong, addr, 0, 1)
-                i += struct_getfield_int(types.slong, addr, 0)
-            lltype.free(addr, flavor='raw')
-            return i
-        assert self.meta_interp(f, [20]) == f(20)
-        self.check_resops(
-            setfield_raw=2,
-            getfield_raw=2,
-            call=0)
-
-
-class TestFfiLookup(FfiLookupTests, LLJitMixin):
     pass
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -79,10 +79,6 @@
         translator.config.translation.list_comprehension_operations = True
     except ConfigError:
         pass
-    try:
-        translator.config.translation.jit_ffi = True
-    except ConfigError:
-        pass
     warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds)
     for jd in warmrunnerdesc.jitdrivers_sd:
         jd.warmstate.set_param_threshold(3)          # for tests
diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -5,7 +5,10 @@
 import sys
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-from pypy.rlib import jit, clibffi
+from pypy.rlib import jit, clibffi, jit_libffi
+from pypy.rlib.jit_libffi import CIF_DESCRIPTION, CIF_DESCRIPTION_P
+from pypy.rlib.jit_libffi import FFI_TYPE, FFI_TYPE_P, FFI_TYPE_PP
+from pypy.rlib.jit_libffi import SIZE_OF_FFI_ARG
 from pypy.rlib.objectmodel import we_are_translated, instantiate
 from pypy.rlib.objectmodel import keepalive_until_here
 
@@ -120,42 +123,24 @@
         mustfree_max_plus_1 = 0
         buffer = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
         try:
-            buffer_array = rffi.cast(rffi.VOIDPP, buffer)
             for i in range(len(args_w)):
                 data = rffi.ptradd(buffer, cif_descr.exchange_args[i])
-                buffer_array[i] = data
                 w_obj = args_w[i]
                 argtype = self.fargs[i]
                 if argtype.convert_argument_from_object(data, w_obj):
                     # argtype is a pointer type, and w_obj a list/tuple/str
                     mustfree_max_plus_1 = i + 1
-            resultdata = rffi.ptradd(buffer, cif_descr.exchange_result)
 
             ec = cerrno.get_errno_container(space)
             cerrno.restore_errno_from(ec)
-            clibffi.c_ffi_call(cif_descr.cif,
-                               rffi.cast(rffi.VOIDP, funcaddr),
-                               rffi.cast(rffi.VOIDP, resultdata),
-                               buffer_array)
+            jit_libffi.jit_ffi_call(cif_descr,
+                                    rffi.cast(rffi.VOIDP, funcaddr),
+                                    buffer)
             e = cerrno.get_real_errno()
             cerrno.save_errno_into(ec, e)
 
-            if self.ctitem.is_primitive_integer:
-                if BIG_ENDIAN:
-                    # 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.
-                    if self.ctitem.size < SIZE_OF_FFI_ARG:
-                        diff = SIZE_OF_FFI_ARG - self.ctitem.size
-                        resultdata = rffi.ptradd(resultdata, diff)
-                w_res = self.ctitem.convert_to_object(resultdata)
-            elif isinstance(self.ctitem, W_CTypeVoid):
-                w_res = space.w_None
-            elif isinstance(self.ctitem, W_CTypeStructOrUnion):
-                w_res = self.ctitem.copy_and_convert_to_object(resultdata)
-            else:
-                w_res = self.ctitem.convert_to_object(resultdata)
+            resultdata = rffi.ptradd(buffer, cif_descr.exchange_result)
+            w_res = self.ctitem.copy_and_convert_to_object(resultdata)
         finally:
             for i in range(mustfree_max_plus_1):
                 argtype = self.fargs[i]
@@ -180,46 +165,11 @@
 
 # ____________________________________________________________
 
-# The "cif" is a block of raw memory describing how to do a call via libffi.
-# It starts with a block of memory of type FFI_CIF, which is used by libffi
-# itself.  Following it, we find _cffi_backend-specific information:
-#
-#  - 'exchange_size': an integer that tells how big a buffer we must
-#    allocate for the call; this buffer should start with an array of
-#    pointers to the actual argument values.
-#
-#  - 'exchange_result': the offset in that buffer for the result of the call.
-#
-#  - 'exchange_args[nargs]': the offset in that buffer for each argument.
-#
-# Following this, we have other data structures for libffi (with direct
-# pointers from the FFI_CIF to these data structures):
-#
-#  - the argument types, as an array of 'ffi_type *'.
-#
-#  - optionally, the result's and the arguments' ffi type data
-#    (this is used only for 'struct' ffi types; in other cases the
-#    'ffi_type *' just points to static data like 'ffi_type_sint32').
 
-FFI_CIF = clibffi.FFI_CIFP.TO
-FFI_TYPE = clibffi.FFI_TYPE_P.TO
-FFI_TYPE_P = clibffi.FFI_TYPE_P
-FFI_TYPE_PP = clibffi.FFI_TYPE_PP
-SIZE_OF_FFI_ARG = rffi.sizeof(clibffi.ffi_arg)
+W_CTypeFunc.cif_descr = lltype.nullptr(CIF_DESCRIPTION)     # default value
+
 BIG_ENDIAN = sys.byteorder == 'big'
 
-CIF_DESCRIPTION = lltype.Struct(
-    'CIF_DESCRIPTION',
-    ('cif', FFI_CIF),
-    ('exchange_size', lltype.Signed),
-    ('exchange_result', lltype.Signed),
-    ('exchange_args', lltype.Array(lltype.Signed,
-                          hints={'nolength': True, 'immutable': True})),
-    hints={'immutable': True})
-
-CIF_DESCRIPTION_P = lltype.Ptr(CIF_DESCRIPTION)
-W_CTypeFunc.cif_descr = lltype.nullptr(CIF_DESCRIPTION)     # default value
-
 
 # ----------
 # We attach to the classes small methods that return a 'ffi_type'
@@ -351,6 +301,16 @@
 
 
     def fb_build(self):
+        # Build a CIF_DESCRIPTION.  Actually this computes the size and
+        # allocates a larger amount of data.  It starts with a
+        # CIF_DESCRIPTION and continues with data needed for the CIF:
+        #
+        #  - the argument types, as an array of 'ffi_type *'.
+        #
+        #  - optionally, the result's and the arguments' ffi type data
+        #    (this is used only for 'struct' ffi types; in other cases the
+        #    'ffi_type *' just points to static data like 'ffi_type_sint32').
+        #
         nargs = len(self.fargs)
 
         # start with a cif_description (cif and exchange_* fields)
@@ -380,13 +340,23 @@
         exchange_offset = rffi.sizeof(rffi.CCHARP) * nargs
         exchange_offset = self.align_arg(exchange_offset)
         cif_descr.exchange_result = exchange_offset
+        cif_descr.exchange_result_libffi = exchange_offset
 
-        # then enough room for the result --- which means at least
-        # sizeof(ffi_arg), according to the ffi docs
+        if BIG_ENDIAN and self.fresult.is_primitive_integer:
+            # 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.
+            if self.fresult.size < SIZE_OF_FFI_ARG:
+                diff = SIZE_OF_FFI_ARG - self.fresult.size
+                cif_descr.exchange_result += diff
+
+        # then enough room for the result, rounded up to sizeof(ffi_arg)
         exchange_offset += max(rffi.getintfield(self.rtype, 'c_size'),
                                SIZE_OF_FFI_ARG)
 
         # loop over args
+        cif_descr.exchange_nb_args = len(self.fargs)
         for i, farg in enumerate(self.fargs):
             if isinstance(farg, W_CTypePointer):
                 exchange_offset += 1   # for the "must free" flag
diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py
--- a/pypy/module/_cffi_backend/ctypeobj.py
+++ b/pypy/module/_cffi_backend/ctypeobj.py
@@ -162,6 +162,9 @@
                               "cdata '%s' has no attribute '%s'",
                               self.name, attr)
 
+    def copy_and_convert_to_object(self, cdata):
+        return self.convert_to_object(cdata)
+
 
 W_CType.typedef = TypeDef(
     'CTypeDescr',
diff --git a/pypy/module/_cffi_backend/ctypevoid.py b/pypy/module/_cffi_backend/ctypevoid.py
--- a/pypy/module/_cffi_backend/ctypevoid.py
+++ b/pypy/module/_cffi_backend/ctypevoid.py
@@ -11,3 +11,6 @@
 
     def __init__(self, space):
         W_CType.__init__(self, space, -1, "void", len("void"))
+
+    def copy_and_convert_to_object(self, cdata):
+        return self.space.w_None
diff --git a/pypy/rlib/clibffi.py b/pypy/rlib/clibffi.py
--- a/pypy/rlib/clibffi.py
+++ b/pypy/rlib/clibffi.py
@@ -202,7 +202,7 @@
 
 FFI_TYPE_P.TO.become(cConfig.ffi_type)
 size_t = cConfig.size_t
-ffi_abi = cConfig.ffi_abi
+FFI_ABI = cConfig.ffi_abi
 ffi_arg = cConfig.ffi_arg
 
 for name in type_names:
@@ -333,7 +333,7 @@
 
 VOIDPP = rffi.CArrayPtr(rffi.VOIDP)
 
-c_ffi_prep_cif = external('ffi_prep_cif', [FFI_CIFP, ffi_abi, rffi.UINT,
+c_ffi_prep_cif = external('ffi_prep_cif', [FFI_CIFP, FFI_ABI, rffi.UINT,
                                            FFI_TYPE_P, FFI_TYPE_PP], rffi.INT)
 if _MSVC:
     c_ffi_call_return_type = rffi.INT
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -402,7 +402,7 @@
     """Inconsistency in the JIT hints."""
 
 ENABLE_ALL_OPTS = (
-    'intbounds:rewrite:virtualize:string:earlyforce:pure:heap:ffi:unroll')
+    'intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll')
 
 PARAMETER_DOCS = {
     'threshold': 'number of times a loop has to run for it to become hot',
diff --git a/pypy/rlib/jit_libffi.py b/pypy/rlib/jit_libffi.py
new file mode 100644
--- /dev/null
+++ b/pypy/rlib/jit_libffi.py
@@ -0,0 +1,125 @@
+import sys
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib import clibffi, jit
+
+
+FFI_CIF = clibffi.FFI_CIFP.TO
+FFI_TYPE = clibffi.FFI_TYPE_P.TO
+FFI_TYPE_P = clibffi.FFI_TYPE_P
+FFI_TYPE_PP = clibffi.FFI_TYPE_PP
+FFI_ABI = clibffi.FFI_ABI
+SIZE_OF_FFI_ARG = rffi.sizeof(clibffi.ffi_arg)
+
+# "cif_description" is a block of raw memory describing how to do the call.
+# It starts with a block of memory of type FFI_CIF, which is used by libffi
+# itself.  Following it, we find jit_libffi-specific information:
+#
+#  - 'exchange_size': an integer that tells how big a buffer we must
+#    allocate for the call; this buffer should have enough room at the
+#    beginning for an array of pointers to the actual argument values,
+#    which is initialized internally by jit_ffi_call().
+#
+#  - 'exchange_result': the offset in that buffer for the result of the call.
+#
+#  - 'exchange_result_libffi': the actual offset passed to ffi_call().
+#    Differs on big-endian machines if the result is an integer type smaller
+#    than SIZE_OF_FFI_ARG (blame libffi).
+#
+#  - 'exchange_args[nargs]': the offset in that buffer for each argument.
+
+CIF_DESCRIPTION = lltype.Struct(
+    'CIF_DESCRIPTION',
+    ('cif', FFI_CIF),
+    ('abi', FFI_ABI),
+    ('nargs', lltype.Signed),
+    ('rtype', FFI_TYPE_P),
+    ('atypes', FFI_TYPE_PP),
+    ('exchange_size', lltype.Signed),
+    ('exchange_result', lltype.Signed),
+    ('exchange_result_libffi', lltype.Signed),
+    ('exchange_args', lltype.Array(lltype.Signed,
+                          hints={'nolength': True, 'immutable': True})),
+    hints={'immutable': True})
+
+CIF_DESCRIPTION_P = lltype.Ptr(CIF_DESCRIPTION)
+
+
+ at jit.oopspec("libffi_call(cif_description, func_addr, exchange_buffer)")
+def jit_ffi_call(cif_description, func_addr, exchange_buffer):
+    """Wrapper around ffi_call().  Must receive a CIF_DESCRIPTION_P that
+    describes the layout of the 'exchange_buffer'.
+    """
+    buffer_array = rffi.cast(rffi.VOIDPP, exchange_buffer)
+    for i in range(cif_description.nargs):
+        data = rffi.ptradd(exchange_buffer, cif_description.exchange_args[i])
+        buffer_array[i] = data
+    resultdata = rffi.ptradd(exchange_buffer,
+                             cif_description.exchange_result_libffi)
+    clibffi.c_ffi_call(cif_description.cif, func_addr,
+                       rffi.cast(rffi.VOIDP, resultdata),
+                       buffer_array)
+
+# ____________________________________________________________
+
+class types(object):
+    """
+    This namespace contains the mapping the JIT needs from ffi types to
+    a less strict "kind" character.
+    """
+
+    @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,
+        'u' for unsigned integer, 'S' for singlefloat, 'L' for long long
+        integer (signed or unsigned), or '*' for struct.
+        """
+        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 'i'
+        #
+        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 'L'
+        elif ffi_type is types.uint64:  return 'L'
+        #
+        elif types.is_struct(ffi_type): return '*'
+        raise KeyError
+
+    @staticmethod
+    @jit.elidable
+    def is_struct(ffi_type):
+        return intmask(ffi_type.c_type) == FFI_TYPE_STRUCT
+
+types._import()
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)
-
-
-        
diff --git a/pypy/rpython/lltypesystem/llmemory.py b/pypy/rpython/lltypesystem/llmemory.py
--- a/pypy/rpython/lltypesystem/llmemory.py
+++ b/pypy/rpython/lltypesystem/llmemory.py
@@ -541,8 +541,12 @@
     def __nonzero__(self):
         return bool(self.adr)
     def __add__(self, ofs):
+        if (isinstance(ofs, int) and
+                getattr(self.adr.ptr._TYPE.TO, 'OF', None) == lltype.Char):
+            return AddressAsInt(self.adr + ItemOffset(lltype.Char, ofs))
         if isinstance(ofs, FieldOffset) and ofs.TYPE is self.adr.ptr._TYPE.TO:
-            return AddressAsInt(cast_ptr_to_adr(self.adr.ptr.b))
+            fieldadr = getattr(self.adr.ptr, ofs.fieldname)
+            return AddressAsInt(cast_ptr_to_adr(fieldadr))
         return NotImplemented
     def __repr__(self):
         try:


More information about the pypy-commit mailing list