Commits

Armin Rigo committed 8ea60af Draft Merge

hg merge ffi-backend: add the "_cffi_backend" module,
and various refactorings to support it in the JIT.

Comments (0)

Files changed (92)

pypy/config/pypyoption.py

      "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array",
      "_bisect", "binascii", "_multiprocessing", '_warnings',
      "_collections", "_multibytecodec", "micronumpy", "_ffi",
-     "_continuation"]
+     "_continuation", "_cffi_backend"]
 ))
 
 translation_modules = default_modules.copy()
     "_rawffi": [("objspace.usemodules.struct", True)],
     "cpyext": [("translation.secondaryentrypoints", "cpyext"),
                ("translation.shared", sys.platform == "win32")],
-    "_ffi":    [("translation.jit_ffi", True)],
 }
 
 module_import_dependencies = {

pypy/config/test/test_pypyoption.py

         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

pypy/config/translationoption.py

     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),

pypy/doc/config/objspace.usemodules._cffi_backend.txt

+Core of CFFI (http://cffi.readthedocs.org)

pypy/interpreter/baseobjspace.py

         w_meth = self.getattr(w_obj, self.wrap(methname))
         return self.call_function(w_meth, *arg_w)
 
+    def raise_key_error(self, w_key):
+        e = self.call_function(self.w_KeyError, w_key)
+        raise OperationError(self.w_KeyError, e)
+
     def lookup(self, w_obj, name):
         w_type = self.type(w_obj)
         w_mro = self.getattr(w_type, self.wrap("__mro__"))

pypy/jit/backend/llgraph/llimpl.py

 from pypy.jit.backend.llgraph import symbolic
 from pypy.jit.codewriter import longlong
 
-from pypy.rlib import libffi, clibffi
 from pypy.rlib.objectmodel import ComputedIntSymbolic, we_are_translated
 from pypy.rlib.rarithmetic import ovfcheck
 from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint
 
 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
 
         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:
     op_getfield_gc_pure = op_getfield_gc
 
     def op_getfield_raw(self, fielddescr, struct):
-        if fielddescr.arg_types == 'dynamic': # abuse of .arg_types
-            return do_getfield_raw_dynamic(struct, fielddescr)
-        elif fielddescr.typeinfo == REF:
+        if fielddescr.typeinfo == REF:
             return do_getfield_raw_ptr(struct, fielddescr.ofs)
         elif fielddescr.typeinfo == INT:
             return do_getfield_raw_int(struct, fielddescr.ofs)
 
     op_getfield_raw_pure = op_getfield_raw
 
+    def op_raw_store(self, arraydescr, addr, offset, value):
+        if arraydescr.typeinfo == REF:
+            raise AssertionError("cannot store GC pointer in raw storage")
+        elif arraydescr.typeinfo == INT:
+            do_raw_store_int(addr, offset, arraydescr.ofs, value)
+        elif arraydescr.typeinfo == FLOAT:
+            do_raw_store_float(addr, offset, value)
+        else:
+            raise NotImplementedError
+
+    def op_raw_load(self, arraydescr, addr, offset):
+        if arraydescr.typeinfo == REF: 
+            raise AssertionError("cannot store GC pointer in raw storage")
+        elif arraydescr.typeinfo == INT:
+            return do_raw_load_int(addr, offset, arraydescr.ofs)
+        elif arraydescr.typeinfo == FLOAT:
+            return do_raw_load_float(addr, offset)
+        else:
+            raise NotImplementedError
+
     def op_new(self, size):
         return do_new(size.ofs)
 
         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:
             raise NotImplementedError
 
     def op_setfield_raw(self, fielddescr, struct, newvalue):
-        if fielddescr.arg_types == 'dynamic': # abuse of .arg_types
-            do_setfield_raw_dynamic(struct, fielddescr, newvalue)
-        elif fielddescr.typeinfo == REF:
+        if fielddescr.typeinfo == REF:
             do_setfield_raw_ptr(struct, fielddescr.ofs, newvalue)
         elif fielddescr.typeinfo == INT:
             do_setfield_raw_int(struct, fielddescr.ofs, newvalue)
     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
     struct = array._obj.container.getitem(index)
     return cast_to_ptr(_getinteriorfield_gc(struct, fieldnum))
 
-def _getinteriorfield_raw(ffitype, array, index, width, ofs):
-    addr = rffi.cast(rffi.VOIDP, array)
-    return libffi.array_getitem(ffitype, width, addr, index, ofs)
-
-def do_getinteriorfield_raw_int(array, index, width, ofs):
-    res = _getinteriorfield_raw(libffi.types.slong, array, index, width, ofs)
-    return res
-
-def do_getinteriorfield_raw_float(array, index, width, ofs):
-    res = _getinteriorfield_raw(libffi.types.double, array, index, width, ofs)
-    return res
-
 def _getfield_raw(struct, fieldnum):
     STRUCT, fieldname = symbolic.TokenToField[fieldnum]
     ptr = cast_from_int(lltype.Ptr(STRUCT), struct)
 def do_getfield_raw_ptr(struct, fieldnum):
     return cast_to_ptr(_getfield_raw(struct, fieldnum))
 
-def do_getfield_raw_dynamic(struct, fielddescr):
-    from pypy.rlib import libffi
-    addr = cast_from_int(rffi.VOIDP, struct)
-    ofs = fielddescr.ofs
-    if fielddescr.is_pointer_field():
-        assert False, 'fixme'
-    elif fielddescr.is_float_field():
-        assert False, 'fixme'
-    else:
-        return libffi._struct_getfield(lltype.Signed, addr, ofs)
+def do_raw_load_int(struct, offset, descrofs):
+    TYPE = symbolic.Size2Type[descrofs]
+    ll_p = rffi.cast(rffi.CCHARP, struct)
+    ll_p = rffi.cast(lltype.Ptr(TYPE), rffi.ptradd(ll_p, offset))
+    value = ll_p[0]
+    return rffi.cast(lltype.Signed, value)
+
+def do_raw_load_float(struct, offset):
+    ll_p = rffi.cast(rffi.CCHARP, struct)
+    ll_p = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE),
+                     rffi.ptradd(ll_p, offset))
+    value = ll_p[0]
+    return value
+
+def do_raw_store_int(struct, offset, descrofs, value):
+    TYPE = symbolic.Size2Type[descrofs]
+    ll_p = rffi.cast(rffi.CCHARP, struct)
+    ll_p = rffi.cast(lltype.Ptr(TYPE), rffi.ptradd(ll_p, offset))
+    ll_p[0] = rffi.cast(TYPE.OF, value)
+
+def do_raw_store_float(struct, offset, value):
+    ll_p = rffi.cast(rffi.CCHARP, struct)
+    ll_p = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE),
+                     rffi.ptradd(ll_p, offset))
+    ll_p[0] = value
 
 def do_new(size):
     TYPE = symbolic.Size2Type[size]
     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):
 do_setinteriorfield_gc_float = new_setinteriorfield_gc(cast_from_floatstorage)
 do_setinteriorfield_gc_ptr = new_setinteriorfield_gc(cast_from_ptr)
 
-def new_setinteriorfield_raw(cast_func, ffitype):
-    def do_setinteriorfield_raw(array, index, newvalue, width, ofs):
-        addr = rffi.cast(rffi.VOIDP, array)
-        for TYPE, ffitype2 in clibffi.ffitype_map:
-            if ffitype2 is ffitype:
-                newvalue = cast_func(TYPE, newvalue)
-                break
-        return libffi.array_setitem(ffitype, width, addr, index, ofs, newvalue)
-    return do_setinteriorfield_raw
-do_setinteriorfield_raw_int = new_setinteriorfield_raw(cast_from_int, libffi.types.slong)
-do_setinteriorfield_raw_float = new_setinteriorfield_raw(cast_from_floatstorage, libffi.types.double)
-
 def do_setfield_raw_int(struct, fieldnum, newvalue):
     STRUCT, fieldname = symbolic.TokenToField[fieldnum]
     ptr = cast_from_int(lltype.Ptr(STRUCT), struct)
     newvalue = cast_from_ptr(FIELDTYPE, newvalue)
     setattr(ptr, fieldname, newvalue)
 
-def do_setfield_raw_dynamic(struct, fielddescr, newvalue):
-    from pypy.rlib import libffi
-    addr = cast_from_int(rffi.VOIDP, struct)
-    ofs = fielddescr.ofs
-    if fielddescr.is_pointer_field():
-        assert False, 'fixme'
-    elif fielddescr.is_float_field():
-        assert False, 'fixme'
-    else:
-        libffi._struct_setfield(lltype.Signed, addr, ofs, newvalue)
-
 def do_newstr(length):
     x = rstr.mallocstr(length)
     return cast_to_ptr(x)
 setannotation(do_getinteriorfield_gc_int, annmodel.SomeInteger())
 setannotation(do_getinteriorfield_gc_ptr, annmodel.SomePtr(llmemory.GCREF))
 setannotation(do_getinteriorfield_gc_float, s_FloatStorage)
+setannotation(do_raw_load_int, annmodel.SomeInteger())
 setannotation(do_new, annmodel.SomePtr(llmemory.GCREF))
 setannotation(do_new_array, annmodel.SomePtr(llmemory.GCREF))
 setannotation(do_setarrayitem_gc_int, annmodel.s_None)
 setannotation(do_setinteriorfield_gc_int, annmodel.s_None)
 setannotation(do_setinteriorfield_gc_ptr, annmodel.s_None)
 setannotation(do_setinteriorfield_gc_float, annmodel.s_None)
+setannotation(do_raw_store_int, annmodel.s_None)
 setannotation(do_newstr, annmodel.SomePtr(llmemory.GCREF))
 setannotation(do_strsetitem, annmodel.s_None)
 setannotation(do_newunicode, annmodel.SomePtr(llmemory.GCREF))

pypy/jit/backend/llgraph/runner.py

         token = history.getkind(getattr(S, fieldname))
         return self.getdescr(ofs, token[0], name=fieldname)
 
-    def fielddescrof_dynamic(self, offset, fieldsize, is_pointer, is_float, is_signed):
-        if is_pointer:
-            typeinfo = REF
-        elif is_float:
-            typeinfo = FLOAT
-        else:
-            typeinfo = INT
-        # we abuse the arg_types field to distinguish dynamic and static descrs
-        return self.getdescr(offset, typeinfo, arg_types='dynamic', name='<dynamic field>')
-
     def interiorfielddescrof(self, A, fieldname):
         S = A.OF
         width = symbolic.get_size(A)
         token = history.getkind(getattr(S, fieldname))
         return self.getdescr(ofs, token[0], name=fieldname, width=width)
 
-    def interiorfielddescrof_dynamic(self, offset, width, fieldsize,
-        is_pointer, is_float, is_signed):
-
-        if is_pointer:
-            typeinfo = REF
-        elif is_float:
-            typeinfo = FLOAT
-        else:
-            typeinfo = INT
-        # we abuse the arg_types field to distinguish dynamic and static descrs
-        return Descr(offset, typeinfo, arg_types='dynamic', name='<dynamic interior field>', width=width)
-
     def calldescrof(self, FUNC, ARGS, RESULT, extrainfo):
         arg_types = []
         for ARG in ARGS:
         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 _calldescr_dynamic_for_tests(self, atypes, rtype,
+                                     abiname='FFI_DEFAULT_ABI'):
+        from pypy.jit.backend.llsupport import ffisupport
+        return ffisupport.calldescr_dynamic_for_tests(self, atypes, rtype,
+                                                      abiname)
 
     def grab_exc_value(self):
         return llimpl.grab_exc_value()
         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)
         return llimpl.do_setinteriorfield_gc_float(array, index, descr.ofs,
                                                    value)
 
+    def bh_raw_store_i(self, struct, offset, descr, newvalue):
+        assert isinstance(descr, Descr)
+        return llimpl.do_raw_store_int(struct, offset, descr.ofs, newvalue)
+    def bh_raw_store_f(self, struct, offset, descr, newvalue):
+        assert isinstance(descr, Descr)
+        return llimpl.do_raw_store_float(struct, offset, newvalue)
+    def bh_raw_load_i(self, struct, offset, descr):
+        assert isinstance(descr, Descr)
+        return llimpl.do_raw_load_int(struct, offset, descr.ofs)
+    def bh_raw_load_f(self, struct, offset, descr):
+        assert isinstance(descr, Descr)
+        return llimpl.do_raw_load_float(struct, offset)
+
     def bh_new(self, sizedescr):
         assert isinstance(sizedescr, Descr)
         return llimpl.do_new(sizedescr.ofs)
 
     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)

pypy/jit/backend/llgraph/symbolic.py

-import ctypes
 from pypy.rpython.lltypesystem import lltype, rffi, rclass
 
 
-Size2Type = [None]
+Size2Type = [None] * 100
 Type2Size = {}
 
 def get_size(TYPE):
         Type2Size[TYPE] = size
         return size
 
-TokenToField = [None]
+TokenToField = [None] * 100
 FieldToToken = {}
 
 def get_field_token(STRUCT, fieldname):
         FieldToToken[STRUCT, fieldname] = token
         return token
 get_field_token(rclass.OBJECT, 'typeptr')     # force the index 1 for this
-
-def get_array_token(T):
-    # T can be an array or a var-sized structure
-    if isinstance(T, lltype.Struct):
-        assert T._arrayfld is not None, "%r is not variable-sized" % (T,)
-        cstruct = ll2ctypes.get_ctypes_type(T)
-        cfield = getattr(cstruct, T._arrayfld)
-        before_array_part = cfield.offset
-        T = getattr(T, T._arrayfld)
-    else:
-        before_array_part = 0
-    carray = ll2ctypes.get_ctypes_type(T)
-    assert carray.length.size == 4
-    ofs_length = before_array_part + carray.length.offset
-    basesize = before_array_part + carray.items.offset
-    carrayitem = ll2ctypes.get_ctypes_type(T.OF)
-    itemsize = ctypes.sizeof(carrayitem)
-    return basesize, itemsize, ofs_length

pypy/jit/backend/llsupport/descr.py

         cache[(ARRAY, name)] = descr
         return descr
 
-def compute_flag(is_pointer, is_float, is_signed):
-    if is_pointer:
-        assert not is_float
-        return FLAG_POINTER
-    elif is_float:
-        return FLAG_FLOAT
-    elif is_signed:
-        return FLAG_SIGNED
-    else:
-        return FLAG_UNSIGNED
-
-def get_dynamic_field_descr(offset, fieldsize, is_pointer, is_float, is_signed):
-    flag = compute_flag(is_pointer, is_float, is_signed)
-    return FieldDescr('dynamic', offset, fieldsize, flag)
-
-def get_dynamic_interiorfield_descr(gc_ll_descr, offset, width, fieldsize,
-                                    is_pointer, is_float, is_signed):
-    arraydescr = ArrayDescr(0, width, None, FLAG_STRUCT)
-    flag = compute_flag(is_pointer, is_float, is_signed)
-    fielddescr = FieldDescr('dynamic', offset, fieldsize, flag)
-    return InteriorFieldDescr(arraydescr, fielddescr)
-
-
 # ____________________________________________________________
 # CallDescrs
 

pypy/jit/backend/llsupport/ffisupport.py

 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, cif_description.atypes[i])
+                    for i in range(cif_description.nargs)]
     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'
+
+@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)] = ('i', 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)
+        size = rffi.getintfield(ffi_type, 'c_size')
+    else:
+        size = 0
+    return _get_ffi2descr_dict(cpu)[kind, size]
 
-def is_ffi_type_signed(ffi_type):
-    from pypy.rlib.libffi import types
-    kind = types.getkind(ffi_type)
-    return kind != 'u'
+def calldescr_dynamic_for_tests(cpu, atypes, rtype, abiname='FFI_DEFAULT_ABI'):
+    from pypy.rlib import clibffi
+    from pypy.rlib.jit_libffi import CIF_DESCRIPTION, FFI_TYPE_PP
+    from pypy.jit.codewriter.effectinfo import EffectInfo
+    #
+    p = lltype.malloc(CIF_DESCRIPTION, len(atypes),
+                      flavor='raw', immortal=True)
+    p.abi = getattr(clibffi, abiname)
+    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 cpu.calldescrof_dynamic(p, EffectInfo.MOST_GENERAL)

pypy/jit/backend/llsupport/llmodel.py

 from pypy.jit.backend.llsupport.symbolic import WORD, unroll_basic_sizes
 from pypy.jit.backend.llsupport.descr import (
     get_size_descr, get_field_descr, get_array_descr,
-    get_call_descr, get_interiorfield_descr, get_dynamic_interiorfield_descr,
-    FieldDescr, ArrayDescr, CallDescr, InteriorFieldDescr, get_dynamic_field_descr)
+    get_call_descr, get_interiorfield_descr,
+    FieldDescr, ArrayDescr, CallDescr, InteriorFieldDescr)
 from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager
 
 
     def fielddescrof(self, STRUCT, fieldname):
         return get_field_descr(self.gc_ll_descr, STRUCT, fieldname)
 
-    def fielddescrof_dynamic(self, offset, fieldsize, is_pointer, is_float, is_signed):
-        return get_dynamic_field_descr(offset, fieldsize, is_pointer, is_float, is_signed)
-
     def unpack_fielddescr(self, fielddescr):
         assert isinstance(fielddescr, FieldDescr)
         return fielddescr.offset
     def interiorfielddescrof(self, A, fieldname):
         return get_interiorfield_descr(self.gc_ll_descr, A, fieldname)
 
-    def interiorfielddescrof_dynamic(self, offset, width, fieldsize,
-                                     is_pointer, is_float, is_signed):
-        return get_dynamic_interiorfield_descr(self.gc_ll_descr,
-                                               offset, width, fieldsize,
-                                               is_pointer, is_float, is_signed)
-
     def unpack_arraydescr(self, arraydescr):
         assert isinstance(arraydescr, ArrayDescr)
         return arraydescr.basesize
     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 _calldescr_dynamic_for_tests(self, atypes, rtype,
+                                     abiname='FFI_DEFAULT_ABI'):
+        from pypy.jit.backend.llsupport import ffisupport
+        return ffisupport.calldescr_dynamic_for_tests(self, atypes, rtype,
+                                                      abiname)
 
     def get_overflow_error(self):
         ovf_vtable = self.cast_adr_to_int(self._ovf_error_vtable)
     bh_setfield_raw_r = _base_do_setfield_r
     bh_setfield_raw_f = _base_do_setfield_f
 
+    def bh_raw_store_i(self, addr, offset, descr, newvalue):
+        ofs, size, sign = self.unpack_arraydescr_size(descr)
+        items = addr + offset
+        for TYPE, _, itemsize in unroll_basic_sizes:
+            if size == itemsize:
+                items = rffi.cast(rffi.CArrayPtr(TYPE), items)
+                items[0] = rffi.cast(TYPE, newvalue)
+                break
+
+    def bh_raw_store_f(self, addr, offset, descr, newvalue):
+        items = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), addr + offset)
+        items[0] = newvalue
+
+    def bh_raw_load_i(self, addr, offset, descr):
+        ofs, size, sign = self.unpack_arraydescr_size(descr)
+        items = addr + offset
+        for TYPE, _, itemsize in unroll_basic_sizes:
+            if size == itemsize:
+                items = rffi.cast(rffi.CArrayPtr(TYPE), items)
+                return rffi.cast(lltype.Signed, items[0])
+        assert False # unreachable code
+
+    def bh_raw_load_f(self, addr, offset, descr):
+        items = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), addr + offset)
+        return items[0]
+
     def bh_new(self, sizedescr):
         return self.gc_ll_descr.gc_malloc(sizedescr)
 

pypy/jit/backend/llsupport/test/test_ffisupport.py

-from pypy.rlib.libffi import types
+from pypy.rlib.jit_libffi import types, CIF_DESCRIPTION, FFI_TYPE_PP
+from pypy.rlib.clibffi import FFI_DEFAULT_ABI
+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 *
         self.supports_floats = supports_floats
         self.supports_longlong = supports_longlong
         self.supports_singlefloats = supports_singlefloats
-
+    def calldescrof_dynamic(self, cif_descr, effectinfo):
+        return get_call_descr_dynamic(self, cif_descr, effectinfo)
 
 def test_call_descr_dynamic():
     args = [types.sint, types.pointer]
-    descr = get_call_descr_dynamic(FakeCPU(), args, types.sint, None,
-                                   ffi_flags=42)
+    descr = calldescr_dynamic_for_tests(FakeCPU(), args, types.sint)
     assert isinstance(descr, CallDescr)
     assert descr.result_type == 'i'
     assert descr.result_flag == FLAG_SIGNED
     assert descr.arg_classes == 'ii'
-    assert descr.get_ffi_flags() == 42
+    assert descr.get_ffi_flags() == FFI_DEFAULT_ABI
 
     args = [types.sint, types.double, types.pointer]
-    descr = get_call_descr_dynamic(FakeCPU(), args, types.void, None, 42)
+    descr = calldescr_dynamic_for_tests(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 = calldescr_dynamic_for_tests(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() == FFI_DEFAULT_ABI
 
-    descr = get_call_descr_dynamic(FakeCPU(), [], types.sint8, None, 42)
+    descr = calldescr_dynamic_for_tests(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 = calldescr_dynamic_for_tests(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 = calldescr_dynamic_for_tests(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 = calldescr_dynamic_for_tests(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() == FFI_DEFAULT_ABI
     else:
         assert types.slonglong is types.slong
 
-    descr = get_call_descr_dynamic(FakeCPU(), [], types.float, None, 42)
+    descr = calldescr_dynamic_for_tests(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 = calldescr_dynamic_for_tests(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() == FFI_DEFAULT_ABI

pypy/jit/backend/model.py

     def interiorfielddescrof(self, A, fieldname):
         raise NotImplementedError
 
-    def interiorfielddescrof_dynamic(self, offset, width, fieldsize, is_pointer,
-        is_float, is_signed):
-        raise NotImplementedError
-
     def arraydescrof(self, A):
         raise NotImplementedError
 

pypy/jit/backend/test/calling_convention_test.py

         return ConstInt(heaptracker.adr2int(addr))
 
     def test_call_aligned_with_spilled_values(self):
-        from pypy.rlib.libffi import types
         cpu = self.cpu
         if not cpu.supports_floats:
             py.test.skip('requires floats')
             assert abs(x - expected_result) < 0.0001
 
     def test_call_aligned_with_imm_values(self):
-        from pypy.rlib.libffi import types
         cpu = self.cpu
         if not cpu.supports_floats:
             py.test.skip('requires floats')
             assert abs(res.getfloat() - result) < 0.0001
 
     def test_call_aligned_with_args_on_the_stack(self):
-        from pypy.rlib.libffi import types
         cpu = self.cpu
         if not cpu.supports_floats:
             py.test.skip('requires floats')
             assert abs(res.getfloat() - result) < 0.0001
 
     def test_call_alignment_call_assembler(self):
-        from pypy.rlib.libffi import types
         cpu = self.cpu
         if not cpu.supports_floats:
             py.test.skip('requires floats')
             py.test.skip('requires floats and singlefloats')
 
         import random
-        from pypy.rlib.libffi import types
         from pypy.rlib.rarithmetic import r_singlefloat
 
         def func(*args):

pypy/jit/backend/test/runner_test.py

             assert longlong.getrealfloat(x) == 3.5 - 42
 
     def test_call(self):
-        from pypy.rlib.libffi import types, FUNCFLAG_CDECL
+        from pypy.rlib.jit_libffi import types
 
         def func_int(a, b):
             return a + b
                                          'int', descr=calldescr)
             assert res.value == 2 * num
             # then, try it with the dynamic calldescr
-            dyn_calldescr = cpu.calldescrof_dynamic([ffi_type, ffi_type], ffi_type,
-                                                    EffectInfo.MOST_GENERAL,
-                                                    ffi_flags=FUNCFLAG_CDECL)
+            dyn_calldescr = cpu._calldescr_dynamic_for_tests(
+                [ffi_type, ffi_type], ffi_type)
             res = self.execute_operation(rop.CALL,
                                          [funcbox, BoxInt(num), BoxInt(num)],
                                          'int', descr=dyn_calldescr)
         assert s.x == chr(190)
         assert s.y == chr(150)
 
-    def test_fielddescrof_dynamic(self):
-        S = lltype.Struct('S',
-                          ('x', lltype.Signed),
-                          ('y', lltype.Signed),
-                          )
-        longsize = rffi.sizeof(lltype.Signed)
-        y_ofs = longsize
-        s = lltype.malloc(S, flavor='raw')
-        sa = llmemory.cast_ptr_to_adr(s)
-        s_box = BoxInt(heaptracker.adr2int(sa))
-        #
-        field = self.cpu.fielddescrof(S, 'y')
-        field_dyn = self.cpu.fielddescrof_dynamic(offset=y_ofs,
-                                                  fieldsize=longsize,
-                                                  is_pointer=False,
-                                                  is_float=False,
-                                                  is_signed=True)
-        assert field.is_pointer_field() == field_dyn.is_pointer_field()
-        assert field.is_float_field()   == field_dyn.is_float_field()
-        if 'llgraph' not in str(self.cpu):
-            assert field.is_field_signed()  == field_dyn.is_field_signed()
-
-        #
-        for get_op, set_op in ((rop.GETFIELD_RAW, rop.SETFIELD_RAW),
-                               (rop.GETFIELD_RAW_PURE, rop.SETFIELD_RAW)):
-            for descr in (field, field_dyn):
-                self.execute_operation(set_op, [s_box, BoxInt(32)], 'void',
-                                       descr=descr)
-                res = self.execute_operation(get_op, [s_box], 'int', descr=descr)
-                assert res.getint()  == 32
-
-        lltype.free(s, flavor='raw')
-
     def test_new_with_vtable(self):
         cpu = self.cpu
         t_box, T_box = self.alloc_instance(self.T)
         cpu = self.cpu
         func_adr = llmemory.cast_ptr_to_adr(c_tolower.funcsym)
         funcbox = ConstInt(heaptracker.adr2int(func_adr))
-        calldescr = cpu.calldescrof_dynamic([types.uchar], types.sint,
-                                            EffectInfo.MOST_GENERAL,
-                                            ffi_flags=FUNCFLAG_CDECL)
+        calldescr = cpu._calldescr_dynamic_for_tests([types.uchar], types.sint)
         i1 = BoxInt()
         i2 = BoxInt()
         tok = BoxInt()
         cpu = self.cpu
         func_adr = llmemory.cast_ptr_to_adr(c_qsort.funcsym)
         funcbox = ConstInt(heaptracker.adr2int(func_adr))
-        calldescr = cpu.calldescrof_dynamic([types.pointer, types_size_t,
-                                             types_size_t, types.pointer],
-                                            types.void,
-                                            EffectInfo.MOST_GENERAL,
-                                            ffi_flags=clibffi.FUNCFLAG_CDECL)
+        calldescr = cpu._calldescr_dynamic_for_tests(
+            [types.pointer, types_size_t, types_size_t, types.pointer],
+            types.void)
         i0 = BoxInt()
         i1 = BoxInt()
         i2 = BoxInt()
         cpu = self.cpu
         func_adr = llmemory.cast_ptr_to_adr(c_GetCurrentDir.funcsym)
         funcbox = ConstInt(heaptracker.adr2int(func_adr))
-        calldescr = cpu.calldescrof_dynamic([types.ulong, types.pointer],
-                                            types.ulong,
-                                            EffectInfo.MOST_GENERAL,
-                                            ffi_flags=FUNCFLAG_STDCALL)
+        calldescr = cpu._calldescr_dynamic_for_tests(
+            [types.ulong, types.pointer],
+            types.ulong,
+            abiname='FFI_STDCALL')
         i1 = BoxInt()
         i2 = BoxInt()
         faildescr = BasicFailDescr(1)
         fail = self.cpu.execute_token(looptoken2, -9)
         assert fail.identifier == 42
 
+    def test_raw_load_int(self):
+        from pypy.rlib import rawstorage
+        for T in [rffi.UCHAR, rffi.SIGNEDCHAR,
+                  rffi.USHORT, rffi.SHORT,
+                  rffi.UINT, rffi.INT,
+                  rffi.ULONG, rffi.LONG]:
+            ops = """
+            [i0, i1]
+            i2 = raw_load(i0, i1, descr=arraydescr)
+            finish(i2)
+            """
+            arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
+            p = rawstorage.alloc_raw_storage(31)
+            for i in range(31):
+                p[i] = '\xDD'
+            value = rffi.cast(T, 0x4243444546474849)
+            rawstorage.raw_storage_setitem(p, 16, value)
+            loop = parse(ops, self.cpu, namespace=locals())
+            looptoken = JitCellToken()
+            self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+            self.cpu.execute_token(looptoken,
+                                   rffi.cast(lltype.Signed, p), 16)
+            result = self.cpu.get_latest_value_int(0)
+            assert result == rffi.cast(lltype.Signed, value)
+            rawstorage.free_raw_storage(p)
+
+    def test_raw_load_float(self):
+        if not self.cpu.supports_floats:
+            py.test.skip("requires floats")
+        from pypy.rlib import rawstorage
+        for T in [rffi.DOUBLE]:
+            ops = """
+            [i0, i1]
+            f2 = raw_load(i0, i1, descr=arraydescr)
+            finish(f2)
+            """
+            arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
+            p = rawstorage.alloc_raw_storage(31)
+            for i in range(31):
+                p[i] = '\xDD'
+            value = rffi.cast(T, 1.12e20)
+            rawstorage.raw_storage_setitem(p, 16, value)
+            loop = parse(ops, self.cpu, namespace=locals())
+            looptoken = JitCellToken()
+            self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+            self.cpu.execute_token(looptoken,
+                                   rffi.cast(lltype.Signed, p), 16)
+            result = self.cpu.get_latest_value_float(0)
+            result = longlong.getrealfloat(result)
+            assert result == rffi.cast(lltype.Float, value)
+            rawstorage.free_raw_storage(p)
+
+    def test_raw_store_int(self):
+        from pypy.rlib import rawstorage
+        for T in [rffi.UCHAR, rffi.SIGNEDCHAR,
+                  rffi.USHORT, rffi.SHORT,
+                  rffi.UINT, rffi.INT,
+                  rffi.ULONG, rffi.LONG]:
+            ops = """
+            [i0, i1, i2]
+            raw_store(i0, i1, i2, descr=arraydescr)
+            finish()
+            """
+            arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
+            p = rawstorage.alloc_raw_storage(31)
+            for i in range(31):
+                p[i] = '\xDD'
+            value = 0x4243444546474849 & sys.maxint
+            loop = parse(ops, self.cpu, namespace=locals())
+            looptoken = JitCellToken()
+            self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+            self.cpu.execute_token(looptoken,
+                                   rffi.cast(lltype.Signed, p), 16, value)
+            result = rawstorage.raw_storage_getitem(T, p, 16)
+            assert result == rffi.cast(T, value)
+            rawstorage.free_raw_storage(p)
+
+    def test_raw_store_float(self):
+        if not self.cpu.supports_floats:
+            py.test.skip("requires floats")
+        from pypy.rlib import rawstorage
+        for T in [rffi.DOUBLE]:
+            ops = """
+            [i0, i1, f2]
+            raw_store(i0, i1, f2, descr=arraydescr)
+            finish()
+            """
+            arraydescr = self.cpu.arraydescrof(rffi.CArray(T))
+            p = rawstorage.alloc_raw_storage(31)
+            for i in range(31):
+                p[i] = '\xDD'
+            value = 1.23e20
+            loop = parse(ops, self.cpu, namespace=locals())
+            looptoken = JitCellToken()
+            self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+            self.cpu.execute_token(looptoken,
+                                   rffi.cast(lltype.Signed, p), 16,
+                                   longlong.getfloatstorage(value))
+            result = rawstorage.raw_storage_getitem(T, p, 16)
+            assert result == rffi.cast(T, value)
+            rawstorage.free_raw_storage(p)
 
 class OOtypeBackendTest(BaseBackendTest):
 

pypy/jit/backend/x86/assembler.py

 
     genop_getarrayitem_gc_pure = genop_getarrayitem_gc
     genop_getarrayitem_raw = genop_getarrayitem_gc
+    genop_getarrayitem_raw_pure = genop_getarrayitem_gc
+
+    def genop_raw_load(self, op, arglocs, resloc):
+        base_loc, ofs_loc, size_loc, ofs, sign_loc = arglocs
+        assert isinstance(ofs, ImmedLoc)
+        src_addr = addr_add(base_loc, ofs_loc, ofs.value, 0)
+        self.load_from_mem(resloc, src_addr, size_loc, sign_loc)
 
     def _get_interiorfield_addr(self, temp_loc, index_loc, itemsize_loc,
                                 base_loc, ofs_loc):
                                                 ofs_loc)
         self.load_from_mem(resloc, src_addr, fieldsize_loc, sign_loc)
 
-    genop_getinteriorfield_raw = genop_getinteriorfield_gc
-
-
     def genop_discard_setfield_gc(self, op, arglocs):
         base_loc, ofs_loc, size_loc, value_loc = arglocs
         assert isinstance(size_loc, ImmedLoc)
         dest_addr = AddressLoc(base_loc, ofs_loc, scale, baseofs.value)
         self.save_into_mem(dest_addr, value_loc, size_loc)
 
+    def genop_discard_raw_store(self, op, arglocs):
+        base_loc, ofs_loc, value_loc, size_loc, baseofs = arglocs
+        assert isinstance(baseofs, ImmedLoc)
+        dest_addr = AddressLoc(base_loc, ofs_loc, 0, baseofs.value)
+        self.save_into_mem(dest_addr, value_loc, size_loc)
+
     def genop_discard_strsetitem(self, op, arglocs):
         base_loc, ofs_loc, val_loc = arglocs
         basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,

pypy/jit/backend/x86/regalloc.py

                                  imm(itemsize), imm(ofs)])
 
     consider_setarrayitem_raw = consider_setarrayitem_gc
+    consider_raw_store = consider_setarrayitem_gc
 
     def consider_getfield_gc(self, op):
         ofs_loc, size_loc, sign = self._unpack_fielddescr(op.getdescr())
 
     consider_getarrayitem_raw = consider_getarrayitem_gc
     consider_getarrayitem_gc_pure = consider_getarrayitem_gc
+    consider_getarrayitem_raw_pure = consider_getarrayitem_gc
+    consider_raw_load = consider_getarrayitem_gc
 
     def consider_getinteriorfield_gc(self, op):
         t = self._unpack_interiorfielddescr(op.getdescr())
         self.Perform(op, [base_loc, ofs, itemsize, fieldsize,
                           index_loc, temp_loc, sign_loc], result_loc)
 
-    consider_getinteriorfield_raw = consider_getinteriorfield_gc
-
     def consider_int_is_true(self, op, guard_op):
         # doesn't need arg to be in a register
         argloc = self.loc(op.getarg(0))

pypy/jit/backend/x86/test/test_fficall.py

 from pypy.jit.metainterp.test import test_fficall
 from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
 
-class TestFfiLookups(Jit386Mixin, test_fficall.FfiLookupTests):
+class TestFfiCall(Jit386Mixin, test_fficall.FfiCallTests):
     # for the individual tests see
     # ====> ../../../metainterp/test/test_fficall.py
-    supports_all = True
+    pass

pypy/jit/backend/x86/test/test_rawmem.py

+
+from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
+from pypy.jit.metainterp.test.test_rawmem import RawMemTests
+
+
+class TestRawMem(Jit386Mixin, RawMemTests):
+    # for the individual tests see
+    # ====> ../../../metainterp/test/test_rawmem.py
+    pass

pypy/jit/backend/x86/test/test_runner.py

                 mc.RET16_i(40)
             rawstart = mc.materialize(cpu.asmmemmgr, [])
             #
-            calldescr = cpu.calldescrof_dynamic([types.slong] * 10,
-                                                types.slong,
-                                                EffectInfo.MOST_GENERAL,
-                                                ffi_flags=-1)
+            calldescr = cpu._calldescr_dynamic_for_tests([types.slong] * 10,
+                                                         types.slong)
             calldescr.get_call_conv = lambda: ffi      # <==== hack
             # ^^^ we patch get_call_conv() so that the test also makes sense
             #     on Linux, because clibffi.get_call_conv() would always

pypy/jit/codewriter/call.py

 
 class CallControl(object):
     virtualref_info = None     # optionally set from outside
+    has_libffi_call = False    # default value
 
     def __init__(self, cpu=None, jitdrivers_sd=[]):
         assert isinstance(jitdrivers_sd, list)   # debugging

pypy/jit/codewriter/effectinfo.py

     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
     OS_LLONG_U_TO_FLOAT         = 94
     #
     OS_MATH_SQRT                = 100
+    #
+    OS_RAW_MALLOC_VARSIZE       = 110
+    OS_RAW_FREE                 = 111
 
     # for debugging:
-    _OS_CANRAISE = set([OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL])
+    _OS_CANRAISE = set([OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL,
+                        OS_RAW_MALLOC_VARSIZE])
 
     def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays,
                 write_descrs_fields, write_descrs_arrays,

pypy/jit/codewriter/jtransform.py

 from pypy.objspace.flow.model import SpaceOperation, Variable, Constant, c_last_exception
 from pypy.rlib import objectmodel
 from pypy.rlib.jit import _we_are_jitted
+from pypy.rlib.rgc import lltype_is_gc
 from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass, rffi
 from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY
 from pypy.translator.simplify import get_funcobj
         if op.args[0] in self.vable_array_vars:
             self.vable_array_vars[op.result]= self.vable_array_vars[op.args[0]]
 
+    def rewrite_op_cast_ptr_to_adr(self, op):
+        if lltype_is_gc(op.args[0].concretetype):
+            raise Exception("cast_ptr_to_adr for GC types unsupported")
+
     def rewrite_op_cast_pointer(self, op):
         newop = self.rewrite_op_same_as(op)
         assert newop is None
                 return [None, # hack, do the right renaming from op.args[0] to op.result
                         SpaceOperation("record_known_class", [op.args[0], const_vtable], None)]
 
+    def rewrite_op_raw_malloc_usage(self, op):
+        pass
+
     def rewrite_op_jit_record_known_class(self, op):
         return SpaceOperation("record_known_class", [op.args[0], op.args[1]], None)
 
             name += '_add_memory_pressure'
         if not track_allocation:
             name += '_no_track_allocation'
-        return self._do_builtin_call(op, name, args,
-                                     extra = (TYPE,),
-                                     extrakey = TYPE)
+        op1 = self.prepare_builtin_call(op, name, args, (TYPE,), TYPE)
+        if name == 'raw_malloc_varsize':
+            return self._handle_oopspec_call(op1, args,
+                                             EffectInfo.OS_RAW_MALLOC_VARSIZE,
+                                             EffectInfo.EF_CAN_RAISE)
+        return self.rewrite_op_direct_call(op1)
 
     def rewrite_op_malloc_varsize(self, op):
         if op.args[1].value['flavor'] == 'raw':
         name = 'raw_free'
         if not track_allocation:
             name += '_no_track_allocation'
-        return self._do_builtin_call(op, name, [op.args[0]],
-                                     extra = (STRUCT,), extrakey = STRUCT)
+        op1 = self.prepare_builtin_call(op, name, [op.args[0]], (STRUCT,),
+                                        STRUCT)
+        if name == 'raw_free':
+            return self._handle_oopspec_call(op1, [op.args[0]],
+                                             EffectInfo.OS_RAW_FREE,
+                                             EffectInfo.EF_CANNOT_RAISE)
+        return self.rewrite_op_direct_call(op1)
 
     def rewrite_op_getarrayitem(self, op):
         ARRAY = op.args[0].concretetype.TO
                                    [v_base, arrayfielddescr, arraydescr,
                                     op.args[1]], op.result)]
         # normal case follows
+        pure = ''
+        immut = ARRAY._immutable_field(None)
+        if immut:
+            pure = '_pure'
         arraydescr = self.cpu.arraydescrof(ARRAY)
         kind = getkind(op.result.concretetype)
-        return SpaceOperation('getarrayitem_%s_%s' % (ARRAY._gckind, kind[0]),
+        return SpaceOperation('getarrayitem_%s_%s%s' % (ARRAY._gckind,
+                                                        kind[0], pure),
                               [op.args[0], arraydescr, op.args[1]],
                               op.result)
 
                               [v_inst, descr, v_value],
                               None)
 
+    def rewrite_op_getsubstruct(self, op):
+        STRUCT = op.args[0].concretetype.TO
+        argname = getattr(STRUCT, '_gckind', 'gc')
+        if argname != 'raw':
+            raise Exception("%r: only supported for gckind=raw" % (op,))
+        ofs = llmemory.offsetof(STRUCT, op.args[1].value)
+        return SpaceOperation('int_add',
+                              [op.args[0], Constant(ofs, lltype.Signed)],
+                              op.result)
+
     def is_typeptr_getset(self, op):
         return (op.args[1].value == 'typeptr' and
                 op.args[0].concretetype.TO._hints.get('typeptr'))
             return SpaceOperation('setinteriorfield_gc_%s' % kind, args,
                                   op.result)
 
+    def rewrite_op_raw_store(self, op):
+        T = op.args[2].concretetype
+        kind = getkind(T)[0]
+        assert kind != 'r'
+        descr = self.cpu.arraydescrof(rffi.CArray(T))
+        return SpaceOperation('raw_store_%s' % kind,
+                              [op.args[0], op.args[1], descr, op.args[2]],
+                              None)
+
+    def rewrite_op_raw_load(self, op):
+        T = op.result.concretetype
+        kind = getkind(T)[0]
+        assert kind != 'r'
+        descr = self.cpu.arraydescrof(rffi.CArray(T))
+        return SpaceOperation('raw_load_%s' % kind,
+                              [op.args[0], op.args[1], descr], op.result)
+
     def _rewrite_equality(self, op, opname):
         arg0, arg1 = op.args
         if isinstance(arg0, Constant) and not arg0.value:
             return self._rewrite_symmetric(op)
 
     def _is_gc(self, v):
-        return getattr(getattr(v.concretetype, "TO", None), "_gckind", "?") == 'gc'
+        return lltype_is_gc(v.concretetype)
 
     def _is_rclass_instance(self, v):
         return lltype._castdepth(v.concretetype.TO, rclass.OBJECT) >= 0
                        ('uint_or', 'int_or'),
                        ('uint_lshift', 'int_lshift'),
                        ('uint_xor', 'int_xor'),
+
+                       ('adr_add', 'int_add'),
                        ]:
         assert _old not in locals()
         exec py.code.Source('''
                                                      'check_neg_index')
         extra = getkind(op.result.concretetype)[0]
         if pure:
-            extra = 'pure_' + extra
+            extra += '_pure'
         op = SpaceOperation('getarrayitem_gc_%s' % extra,
                             [args[0], arraydescr, v_index], op.result)
         return extraop + [op]
     # 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
+            self.callcontrol.has_libffi_call = True
         else:
             assert False, 'unsupported oopspec: %s' % oopspec_name
         return self._handle_oopspec_call(op, args, oopspecindex, extraeffect)

pypy/jit/codewriter/support.py

     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),

pypy/jit/codewriter/test/test_jtransform.py

             INT = lltype.Signed
             UNICHAR = lltype.UniChar
             FLOAT = lltype.Float
+            ARRAYPTR = rffi.CArrayPtr(lltype.Signed)
             argtypes = {
              EI.OS_MATH_SQRT:  ([FLOAT], FLOAT),
              EI.OS_STR2UNICODE:([PSTR], PUNICODE),
              EI.OS_UNIEQ_NONNULL_CHAR:   ([PUNICODE, UNICHAR], INT),
              EI.OS_UNIEQ_CHECKNULL_CHAR: ([PUNICODE, UNICHAR], INT),
              EI.OS_UNIEQ_LENGTHOK:       ([PUNICODE, PUNICODE], INT),
+             EI.OS_RAW_MALLOC_VARSIZE:   ([INT], ARRAYPTR),
+             EI.OS_RAW_FREE:             ([ARRAYPTR], lltype.Void),
             }
             argtypes = argtypes[oopspecindex]
             assert argtypes[0] == [v.concretetype for v in op.args[1:]]
             assert argtypes[1] == op.result.concretetype
             if oopspecindex == EI.OS_STR2UNICODE:
                 assert extraeffect == EI.EF_ELIDABLE_CAN_RAISE
+            elif oopspecindex == EI.OS_RAW_MALLOC_VARSIZE:
+                assert extraeffect == EI.EF_CAN_RAISE
+            elif oopspecindex == EI.OS_RAW_FREE:
+                assert extraeffect == EI.EF_CANNOT_RAISE
             else:
                 assert extraeffect == EI.EF_ELIDABLE_CANNOT_RAISE
         return 'calldescr-%d' % oopspecindex
+
     def calldescr_canraise(self, calldescr):
+        EI = effectinfo.EffectInfo
+        if calldescr == 'calldescr-%d' % EI.OS_RAW_MALLOC_VARSIZE:
+            return True
         return False
 
 
     flags = Constant({'flavor': 'raw'}, lltype.Void)
     op = SpaceOperation('malloc_varsize', [Constant(S, lltype.Void), flags,
                                            v1], v)
-    tr = Transformer(FakeCPU(), FakeResidualCallControl())
+    tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
     op0, op1 = tr.rewrite_operation(op)
     assert op0.opname == 'residual_call_ir_i'
     assert op0.args[0].value == 'raw_malloc_varsize' # pseudo-function as a str
+    assert (op0.args[1] == 'calldescr-%d' %
+            effectinfo.EffectInfo.OS_RAW_MALLOC_VARSIZE)
+
     assert op1.opname == '-live-'
     assert op1.args == []
 
     assert op1.args == []
 
 def test_raw_free():
-    S = lltype.Struct('dummy', ('x', lltype.Signed))
-    for flag in [True, False]:
-        flags = Constant({'flavor': 'raw', 'track_allocation': flag},
-                         lltype.Void)
-        op = SpaceOperation('free', [varoftype(lltype.Ptr(S)), flags],
-                            varoftype(lltype.Void))
-        tr = Transformer(FakeCPU(), FakeResidualCallControl())
-        op0, op1 = tr.rewrite_operation(op)
-        assert op0.opname == 'residual_call_ir_v'
-        if flag:
-            pseudo_op_name = 'raw_free'
-        else:
-            pseudo_op_name = 'raw_free_no_track_allocation'
-        assert op0.args[0].value == pseudo_op_name   # pseudo-function as a str
-        assert op1.opname == '-live-'
+    S = rffi.CArray(lltype.Signed)
+    flags = Constant({'flavor': 'raw', 'track_allocation': True},
+                     lltype.Void)
+    op = SpaceOperation('free', [varoftype(lltype.Ptr(S)), flags],
+                        varoftype(lltype.Void))
+    tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+    op0 = tr.rewrite_operation(op)
+    assert op0.opname == 'residual_call_ir_v'
+    assert op0.args[0].value == 'raw_free'
+    assert op0.args[1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_RAW_FREE
+
+def test_raw_free_no_track_allocation():
+    S = rffi.CArray(lltype.Signed)
+    flags = Constant({'flavor': 'raw', 'track_allocation': False},
+                     lltype.Void)
+    op = SpaceOperation('free', [varoftype(lltype.Ptr(S)), flags],
+                        varoftype(lltype.Void))
+    tr = Transformer(FakeCPU(), FakeResidualCallControl())
+    op0, op1 = tr.rewrite_operation(op)
+    assert op0.opname == 'residual_call_ir_v'
+    assert op0.args[0].value == 'raw_free_no_track_allocation'
+    assert op1.opname == '-live-'
 
 def test_rename_on_links():
     v1 = Variable()
     assert block.exits[0].target is block2
     assert block.exits[0].args == [v1]
 
+def test_cast_ptr_to_adr():
+    t = Transformer(FakeCPU(), None)
+    v = varoftype(lltype.Ptr(lltype.Array()))
+    v2 = varoftype(llmemory.Address)
+    op1 = t.rewrite_operation(SpaceOperation('cast_ptr_to_adr', [v], v2))
+    assert op1 is None
+
 def test_int_eq():
     v1 = varoftype(lltype.Signed)
     v2 = varoftype(lltype.Signed)
     op1 = Transformer(FakeCPU()).rewrite_operation(op)
     assert not op1
 
+def test_raw_store():
+    v_storage = varoftype(llmemory.Address)
+    v_index = varoftype(lltype.Signed)
+    v_item = varoftype(lltype.Signed) # for example
+    op = SpaceOperation('raw_store', [v_storage, v_index, v_item], None)
+    op1 = Transformer(FakeCPU()).rewrite_operation(op)
+    assert op1.opname == 'raw_store_i'
+    assert op1.args[0] == v_storage
+    assert op1.args[1] == v_index
+    assert op1.args[2] == ('arraydescr', rffi.CArray(lltype.Signed))
+    assert op1.args[3] == v_item
+
+def test_raw_load():
+    v_storage = varoftype(llmemory.Address)
+    v_index = varoftype(lltype.Signed)
+    v_res = varoftype(lltype.Signed) # for example
+    op = SpaceOperation('raw_load', [v_storage, v_index], v_res)
+    op1 = Transformer(FakeCPU()).rewrite_operation(op)
+    assert op1.opname == 'raw_load_i'
+    assert op1.args[0] == v_storage
+    assert op1.args[1] == v_index
+    assert op1.args[2] == ('arraydescr', rffi.CArray(lltype.Signed))
+    assert op1.result == v_res
+
 def test_promote_1():
     v1 = varoftype(lltype.Signed)
     v2 = varoftype(lltype.Signed)

pypy/jit/codewriter/test/test_list.py

     builtin_test('list.getitem_foldable/NONNEG',
                  [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
                  lltype.Signed, """
-                     getarrayitem_gc_pure_i %r0, <ArrayDescr>, %i0 -> %i1
+                     getarrayitem_gc_i_pure %r0, <ArrayDescr>, %i0 -> %i1
                  """)
     builtin_test('list.getitem_foldable/NEG',
                  [varoftype(FIXEDLIST), varoftype(lltype.Signed)],
                  lltype.Signed, """
                      -live-
                      check_neg_index %r0, <ArrayDescr>, %i0 -> %i1
-                     getarrayitem_gc_pure_i %r0, <ArrayDescr>, %i1 -> %i2
+                     getarrayitem_gc_i_pure %r0, <ArrayDescr>, %i1 -> %i2
                  """)
 
 def test_fixed_setitem():

pypy/jit/metainterp/blackhole.py

     def bhimpl_getarrayitem_gc_f(cpu, array, arraydescr, index):
         return cpu.bh_getarrayitem_gc_f(arraydescr, array, index)
 
-    bhimpl_getarrayitem_gc_pure_i = bhimpl_getarrayitem_gc_i
-    bhimpl_getarrayitem_gc_pure_r = bhimpl_getarrayitem_gc_r
-    bhimpl_getarrayitem_gc_pure_f = bhimpl_getarrayitem_gc_f
+    bhimpl_getarrayitem_gc_i_pure = bhimpl_getarrayitem_gc_i
+    bhimpl_getarrayitem_gc_r_pure = bhimpl_getarrayitem_gc_r
+    bhimpl_getarrayitem_gc_f_pure = bhimpl_getarrayitem_gc_f
 
     @arguments("cpu", "i", "d", "i", returns="i")
     def bhimpl_getarrayitem_raw_i(cpu, array, arraydescr, index):
     def bhimpl_getarrayitem_raw_f(cpu, array, arraydescr, index):
         return cpu.bh_getarrayitem_raw_f(arraydescr, array, index)
 
+    bhimpl_getarrayitem_raw_i_pure = bhimpl_getarrayitem_raw_i
+    bhimpl_getarrayitem_raw_f_pure = bhimpl_getarrayitem_raw_f
+
     @arguments("cpu", "r", "d", "i", "i")
     def bhimpl_setarrayitem_gc_i(cpu, array, arraydescr, index, newvalue):
         cpu.bh_setarrayitem_gc_i(arraydescr, array, index, newvalue)
     def bhimpl_setfield_raw_f(cpu, struct, fielddescr, newvalue):
         cpu.bh_setfield_raw_f(struct, fielddescr, newvalue)
 
+    @arguments("cpu", "i", "i", "d", "i")
+    def bhimpl_raw_store_i(cpu, addr, offset, arraydescr, newvalue):
+        cpu.bh_raw_store_i(addr, offset, arraydescr, newvalue)
+    @arguments("cpu", "i", "i", "d", "f")
+    def bhimpl_raw_store_f(cpu, addr, offset, arraydescr, newvalue):
+        cpu.bh_raw_store_f(addr, offset, arraydescr, newvalue)
+
+    @arguments("cpu", "i", "i", "d", returns="i")
+    def bhimpl_raw_load_i(cpu, addr, offset, arraydescr):
+        return cpu.bh_raw_load_i(addr, offset, arraydescr)
+    @arguments("cpu", "i", "i", "d", returns="f")
+    def bhimpl_raw_load_f(cpu, addr, offset, arraydescr):
+        return cpu.bh_raw_load_f(addr, offset, arraydescr)
+
     @arguments("r", "d", "d")
     def bhimpl_record_quasiimmut_field(struct, fielddescr, mutatefielddescr):
         pass

pypy/jit/metainterp/executor.py

     else:
         cpu.bh_setfield_raw_i(struct, fielddescr, itembox.getint())
 
+def do_raw_store(cpu, _, addrbox, offsetbox, valuebox, arraydescr):
+    addr = addrbox.getint()
+    offset = offsetbox.getint()
+    if arraydescr.is_array_of_pointers():
+        raise AssertionError("cannot store GC pointers in raw store")
+    elif arraydescr.is_array_of_floats():
+        cpu.bh_raw_store_f(addr, offset, arraydescr,valuebox.getfloatstorage())
+    else:
+        cpu.bh_raw_store_i(addr, offset, arraydescr, valuebox.getint())
+
+def do_raw_load(cpu, _, addrbox, offsetbox, arraydescr):
+    addr = addrbox.getint()
+    offset = offsetbox.getint()
+    if arraydescr.is_array_of_pointers():
+        raise AssertionError("cannot store GC pointers in raw store")
+    elif arraydescr.is_array_of_floats():
+        return BoxFloat(cpu.bh_raw_load_f(addr, offset, arraydescr))
+    else:
+        return BoxInt(cpu.bh_raw_load_i(addr, offset, arraydescr))
+
 def exec_new_with_vtable(cpu, clsbox):
     from pypy.jit.codewriter import heaptracker
     vtable = clsbox.getint()
                          rop.DEBUG_MERGE_POINT,
                          rop.JIT_DEBUG,
                          rop.SETARRAYITEM_RAW,
-                         rop.GETINTERIORFIELD_RAW,
                          rop.SETINTERIORFIELD_RAW,
                          rop.CALL_RELEASE_GIL,
                          rop.QUASIIMMUT_FIELD,

pypy/jit/metainterp/history.py

         # XXX fix this for oo...
         if (TYPE != llmemory.Address and
             rffi.sizeof(TYPE) > rffi.sizeof(lltype.Signed)):
-            if supports_longlong:
+            if supports_longlong and TYPE is not lltype.LongFloat:
                 assert rffi.sizeof(TYPE) == 8
                 return 'float'
             raise NotImplementedError("type %s is too large" % TYPE)

pypy/jit/metainterp/optimizeopt/__init__.py

 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
             ('earlyforce', OptEarlyForce),
             ('pure', OptPure),
             ('heap', OptHeap),
-            ('ffi', None),
             ('unroll', None)]
 # no direct instantiation of unroll
 unroll_all_opts = unrolling_iterable(ALL_OPTS)
             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

pypy/jit/metainterp/optimizeopt/fficall.py

-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)
-        elif (oopspec == EffectInfo.OS_LIBFFI_STRUCT_GETFIELD or
-              oopspec == EffectInfo.OS_LIBFFI_STRUCT_SETFIELD):
-            ops = self.do_struct_getsetfield(op, oopspec)
-        elif (oopspec == EffectInfo.OS_LIBFFI_GETARRAYITEM or
-            oopspec == EffectInfo.OS_LIBFFI_SETARRAYITEM):
-            ops = self.do_getsetarrayitem(op, oopspec)
-        #
-        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, ...)
-        #