[pypy-commit] pypy stm-jit: hg merge default

arigo noreply at buildbot.pypy.org
Thu Aug 30 17:29:53 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: stm-jit
Changeset: r56950:451f9581de35
Date: 2012-08-29 17:31 +0200
http://bitbucket.org/pypy/pypy/changeset/451f9581de35/

Log:	hg merge default

diff too long, truncating to 10000 out of 13873 lines

diff --git a/lib_pypy/_ctypes/__init__.py b/lib_pypy/_ctypes/__init__.py
--- a/lib_pypy/_ctypes/__init__.py
+++ b/lib_pypy/_ctypes/__init__.py
@@ -19,6 +19,10 @@
     from _rawffi import FormatError
     from _rawffi import check_HRESULT as _check_HRESULT
 
+    try: from __pypy__ import builtinify
+    except ImportError: builtinify = lambda f: f
+
+    @builtinify
     def CopyComPointer(src, dst):
         from ctypes import c_void_p, cast
         if src:
@@ -28,6 +32,8 @@
         dst[0] = cast(src, c_void_p).value
         return 0
 
+    del builtinify
+
     LoadLibrary = dlopen
 
 from _rawffi import FUNCFLAG_STDCALL, FUNCFLAG_CDECL, FUNCFLAG_PYTHONAPI
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -3,6 +3,9 @@
 import _ffi
 import sys
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
 keepalive_key = str # XXX fix this when provided with test
 
 def ensure_objects(where):
@@ -59,7 +62,8 @@
         'resbuffer' is a _rawffi array of length 1 containing the value,
         and this returns a general Python object that corresponds.
         """
-        res = self.__new__(self)
+        res = object.__new__(self)
+        res.__class__ = self
         res.__dict__['_buffer'] = resbuffer
         res.__dict__['_base'] = base
         res.__dict__['_index'] = index
@@ -144,6 +148,7 @@
     _b_base_ = property(_get_b_base)
     _b_needsfree_ = False
 
+ at builtinify
 def sizeof(tp):
     if not isinstance(tp, _CDataMeta):
         if isinstance(tp, _CData):
@@ -153,6 +158,7 @@
                 type(tp).__name__,))
     return tp._sizeofinstances()
 
+ at builtinify
 def alignment(tp):
     if not isinstance(tp, _CDataMeta):
         if isinstance(tp, _CData):
@@ -162,6 +168,7 @@
                 type(tp).__name__,))
     return tp._alignmentofinstances()
 
+ at builtinify
 def byref(cdata):
     # "pointer" is imported at the end of this module to avoid circular
     # imports
@@ -175,6 +182,7 @@
     instance._buffer = self._ffiarray.fromaddress(address, lgt)
     return instance
 
+ at builtinify
 def addressof(tp):
     return tp._buffer.buffer
 
diff --git a/lib_pypy/_ctypes/dll.py b/lib_pypy/_ctypes/dll.py
--- a/lib_pypy/_ctypes/dll.py
+++ b/lib_pypy/_ctypes/dll.py
@@ -1,5 +1,9 @@
 import _rawffi
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
+ at builtinify
 def dlopen(name, mode):
     # XXX mode is ignored
     return _rawffi.CDLL(name)
diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -10,6 +10,8 @@
 import traceback
 import warnings
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
 
 # XXX this file needs huge refactoring I fear
 
@@ -34,6 +36,7 @@
     from _ctypes import COMError
     return COMError(errcode, None, None)
 
+ at builtinify
 def call_function(func, args):
     "Only for debugging so far: So that we can call CFunction instances"
     funcptr = CFuncPtr(func)
diff --git a/lib_pypy/_ctypes/pointer.py b/lib_pypy/_ctypes/pointer.py
--- a/lib_pypy/_ctypes/pointer.py
+++ b/lib_pypy/_ctypes/pointer.py
@@ -7,6 +7,9 @@
 from _ctypes.array import Array, array_get_slice_params, array_slice_getitem,\
      array_slice_setitem
 
+try: from __pypy__ import builtinify
+except ImportError: builtinify = lambda f: f
+
 # This cache maps types to pointers to them.
 _pointer_type_cache = {}
 
@@ -154,6 +157,7 @@
 
     return result
 
+ at builtinify
 def POINTER(cls):
     try:
         return _pointer_type_cache[cls]
@@ -173,6 +177,7 @@
         _pointer_type_cache[cls] = klass
     return klass
 
+ at builtinify
 def pointer(inst):
     return POINTER(type(inst))(inst)
 
diff --git a/lib_pypy/_marshal.py b/lib_pypy/_marshal.py
--- a/lib_pypy/_marshal.py
+++ b/lib_pypy/_marshal.py
@@ -430,6 +430,7 @@
 def _read(self, n):
     pos = self.bufpos
     newpos = pos + n
+    if newpos > len(self.bufstr): raise EOFError
     ret = self.bufstr[pos : newpos]
     self.bufpos = newpos
     return ret
diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py
--- a/lib_pypy/greenlet.py
+++ b/lib_pypy/greenlet.py
@@ -77,8 +77,6 @@
         try:
             unbound_method = getattr(_continulet, methodname)
             args = unbound_method(current, *args, to=target)
-        except GreenletExit, e:
-            args = (e,)
         finally:
             _tls.current = current
         #
@@ -132,6 +130,8 @@
     _tls.current = greenlet
     try:
         res = greenlet.run(*args)
+    except GreenletExit, e:
+        res = e
     finally:
         _continuation.permute(greenlet, greenlet.parent)
     return (res,)
diff --git a/lib_pypy/pypy_test/test_marshal_extra.py b/lib_pypy/pypy_test/test_marshal_extra.py
--- a/lib_pypy/pypy_test/test_marshal_extra.py
+++ b/lib_pypy/pypy_test/test_marshal_extra.py
@@ -142,4 +142,6 @@
         f2.close()
     assert obj == case
 
-
+def test_load_truncated_string():
+    s = '(\x02\x00\x00\x00i\x03\x00\x00\x00sB\xf9\x00\x00\nabcd'
+    py.test.raises(EOFError, marshal.loads, s)
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -450,6 +450,12 @@
                     attrs.update(self.basedesc.all_enforced_attrs)
                 self.all_enforced_attrs = attrs
 
+            if (self.is_builtin_exception_class() and
+                self.all_enforced_attrs is None):
+                from pypy.annotation import classdef
+                if self.pyobj not in classdef.FORCE_ATTRIBUTES_INTO_CLASSES:
+                    self.all_enforced_attrs = []    # no attribute allowed
+
     def add_source_attribute(self, name, value, mixin=False):
         if isinstance(value, types.FunctionType):
             # for debugging
diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py
--- a/pypy/annotation/test/test_annrpython.py
+++ b/pypy/annotation/test/test_annrpython.py
@@ -3829,7 +3829,7 @@
 
             def next(self):
                 return 1
-        
+
         def fn():
             s = 0
             for x in A():
@@ -3841,6 +3841,24 @@
         assert len(a.translator.graphs) == 3 # fn, __iter__, next
         assert isinstance(s, annmodel.SomeInteger)
 
+    def test_next_function(self):
+        def fn(n):
+            x = [0, 1, n]
+            i = iter(x)
+            return next(i) + next(i)
+
+        a = self.RPythonAnnotator()
+        s = a.build_types(fn, [int])
+        assert isinstance(s, annmodel.SomeInteger)
+
+    def test_no_attr_on_common_exception_classes(self):
+        for cls in [ValueError, Exception]:
+            def fn():
+                e = cls()
+                e.foo = "bar"
+            a = self.RPythonAnnotator()
+            py.test.raises(Exception, a.build_types, fn, [])
+
 def g(n):
     return [0,1,2,n]
 
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -34,7 +34,7 @@
      "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array",
      "_bisect", "binascii", "_multiprocessing", '_warnings',
      "_collections", "_multibytecodec", "micronumpy", "_ffi",
-     "_continuation"]
+     "_continuation", "_cffi_backend"]
 ))
 
 translation_modules = default_modules.copy()
@@ -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
@@ -131,8 +131,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/conftest.py b/pypy/conftest.py
--- a/pypy/conftest.py
+++ b/pypy/conftest.py
@@ -19,6 +19,17 @@
 #
 option = None
 
+
+def braindead_deindent(self):
+    """monkeypatch that wont end up doing stupid in the python tokenizer"""
+    text = '\n'.join(self.lines)
+    short = py.std.textwrap.dedent(text)
+    newsource = py.code.Source()
+    newsource.lines[:] = short.splitlines()
+    return newsource
+
+py.code.Source.deindent = braindead_deindent
+
 def pytest_report_header():
     return "pytest-%s from %s" %(pytest.__version__, pytest.__file__)
 
@@ -186,6 +197,9 @@
     def delslice(self, obj, *args):
         obj.__delslice__(*args)
 
+    def is_w(self, obj1, obj2):
+        return obj1 is obj2
+
 def translation_test_so_skip_if_appdirect():
     if option.runappdirect:
         py.test.skip("translation test, skipped for appdirect")
diff --git a/pypy/doc/config/objspace.usemodules._cffi_backend.txt b/pypy/doc/config/objspace.usemodules._cffi_backend.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/objspace.usemodules._cffi_backend.txt
@@ -0,0 +1,1 @@
+Core of CFFI (http://cffi.readthedocs.org)
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -23,6 +23,12 @@
 .. branch: improve-rbigint
 Introduce __int128 on systems where it's supported and improve the speed of
 rlib/rbigint.py greatly.
+.. branch: translation-cleanup
+Start to clean up a bit the flow object space.
+.. branch: ffi-backend
+Support CFFI.  http://morepypy.blogspot.ch/2012/08/cffi-release-03.html
+.. branch: speedup-unpackiterable
+
 
 .. "uninteresting" branches that we should just ignore for the whatsnew:
 .. branch: slightly-shorter-c
diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst
--- a/pypy/doc/windows.rst
+++ b/pypy/doc/windows.rst
@@ -135,6 +135,10 @@
 the name of a valid gcc-derivative compiler, i.e. x86_64-w64-mingw32-gcc for the 64 bit
 compiler creating a 64 bit target.
 
+You probably want to set the CPATH, LIBRARY_PATH, and PATH environment variable to
+the header files, lib or dlls, and dlls respectively of the locally installed packages 
+if they are not in the mingw directory heirarchy. 
+
 libffi for the mingw compiler
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -175,7 +179,7 @@
 Since hacking on Pypy means running tests, you will need a way to specify
 the mingw compiler when hacking (as opposed to translating). As of
 March 2012, --cc is not a valid option for pytest.py. However if you set an
-environment variable CC it will allow you to choose a compiler.
+environment variable CC to the compliter exe, testing will use it.
 
 .. _'mingw32 build': http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Automated%20Builds
 .. _`mingw64 build`: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Automated%20Builds
diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -301,10 +301,7 @@
         if num_kwds:
             # kwds_mapping maps target indexes in the scope (minus input_argcount)
             # to positions in the keywords_w list
-            cnt = (co_argcount - input_argcount)
-            if cnt < 0:
-                cnt = 0
-            kwds_mapping = [0] * cnt
+            kwds_mapping = [0] * (co_argcount - input_argcount)
             # initialize manually, for the JIT :-(
             for i in range(len(kwds_mapping)):
                 kwds_mapping[i] = -1
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -20,6 +20,9 @@
 
 UINT_MAX_32_BITS = r_uint(4294967295)
 
+unpackiterable_driver = jit.JitDriver(name = 'unpackiterable',
+                                      greens = ['tp'],
+                                      reds = ['items', 'w_iterator'])
 
 class W_Root(object):
     """This is the abstract root class of all wrapped objects that live
@@ -224,6 +227,23 @@
     def __spacebind__(self, space):
         return self
 
+class W_InterpIterable(W_Root):
+    def __init__(self, space, w_iterable):
+        self.w_iter = space.iter(w_iterable)
+        self.space = space
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        space = self.space
+        try:
+            return space.next(self.w_iter)
+        except OperationError, e:
+            if not e.match(space, space.w_StopIteration):
+                raise
+            raise StopIteration
+
 class InternalSpaceCache(Cache):
     """A generic cache for an object space.  Arbitrary information can
     be attached to the space by defining a function or class 'f' which
@@ -835,6 +855,9 @@
                                                       expected_length)
             return lst_w[:]     # make the resulting list resizable
 
+    def iteriterable(self, w_iterable):
+        return W_InterpIterable(self, w_iterable)
+
     @jit.dont_look_inside
     def _unpackiterable_unknown_length(self, w_iterator, w_iterable):
         # Unpack a variable-size list of unknown length.
@@ -855,7 +878,11 @@
             except MemoryError:
                 items = [] # it might have lied
         #
+        tp = self.type(w_iterator)
         while True:
+            unpackiterable_driver.jit_merge_point(tp=tp,
+                                                  w_iterator=w_iterator,
+                                                  items=items)
             try:
                 w_item = self.next(w_iterator)
             except OperationError, e:
@@ -1037,6 +1064,10 @@
         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__"))
diff --git a/pypy/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py
--- a/pypy/interpreter/test/test_function.py
+++ b/pypy/interpreter/test/test_function.py
@@ -16,6 +16,7 @@
         assert f.func_defaults == None
         assert f.func_dict == {}
         assert type(f.func_globals) == dict
+        assert f.func_globals is f.__globals__
         assert f.func_closure is None
         assert f.func_doc == None
         assert f.func_name == 'f'
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -37,7 +37,7 @@
         assert __total_ordering__ in (None, 'auto'), "Unknown value for __total_ordering"
         if __total_ordering__ == 'auto':
             self.auto_total_ordering()
-    
+
     def add_entries(self, **rawdict):
         # xxx fix the names of the methods to match what app-level expects
         for key, value in rawdict.items():
@@ -228,7 +228,7 @@
 
     def add(Proto):
         for key, value in Proto.__dict__.items():
-            if (not key.startswith('__') and not key.startswith('_mixin_') 
+            if (not key.startswith('__') and not key.startswith('_mixin_')
                     or key == '__del__'):
                 if hasattr(value, "func_name"):
                     value = func_with_new_name(value, value.func_name)
@@ -315,10 +315,10 @@
         class Proto(object):
             def getdict(self, space):
                 return self.w__dict__
-            
+
             def setdict(self, space, w_dict):
                 self.w__dict__ = check_new_dictionary(space, w_dict)
-            
+
             def user_setup(self, space, w_subtype):
                 self.w__dict__ = space.newdict(
                     instance=True)
@@ -383,7 +383,7 @@
             return %(name)s(%(args)s, %(extra)s)
         """
         miniglobals[cls_name] = cls
-    
+
     name = func.__name__
     extra = ', '.join(extraargs)
     from pypy.interpreter import pycode
@@ -503,7 +503,7 @@
                 space, '__delattr__',
                 self.reqcls, Arguments(space, [w_obj,
                                                space.wrap(self.name)]))
-    
+
     def descr_get_objclass(space, property):
         return property.objclass_getter(space)
 
@@ -521,7 +521,7 @@
             return space.w_None
         else:
             return w_value
-    
+
     return GetSetProperty(fget, cls=cls, doc=doc)
 
 GetSetProperty.typedef = TypeDef(
@@ -543,7 +543,7 @@
         self.index = index
         self.name = name
         self.w_cls = w_cls
-    
+
     def typecheck(self, space, w_obj):
         if not space.is_true(space.isinstance(w_obj, self.w_cls)):
             raise operationerrfmt(space.w_TypeError,
@@ -552,7 +552,7 @@
                                   self.name,
                                   self.w_cls.name,
                                   space.type(w_obj).getname(space))
-    
+
     def descr_member_get(self, space, w_obj, w_w_cls=None):
         """member.__get__(obj[, type]) -> value
         Read the slot 'member' of the given 'obj'."""
@@ -565,13 +565,13 @@
                 raise OperationError(space.w_AttributeError,
                                      space.wrap(self.name)) # XXX better message
             return w_result
-    
+
     def descr_member_set(self, space, w_obj, w_value):
         """member.__set__(obj, value)
         Write into the slot 'member' of the given 'obj'."""
         self.typecheck(space, w_obj)
         w_obj.setslotvalue(self.index, w_value)
-    
+
     def descr_member_del(self, space, w_obj):
         """member.__delete__(obj)
         Delete the value of the slot 'member' from the given 'obj'."""
@@ -803,15 +803,16 @@
     func_dict = getset_func_dict,
     func_defaults = getset_func_defaults,
     func_globals = interp_attrproperty_w('w_func_globals', cls=Function),
-    func_closure = GetSetProperty( Function.fget_func_closure ),
+    func_closure = GetSetProperty(Function.fget_func_closure),
     __code__ = getset_func_code,
     __doc__ = getset_func_doc,
     __name__ = getset_func_name,
     __dict__ = getset_func_dict,
     __defaults__ = getset_func_defaults,
+    __globals__ = interp_attrproperty_w('w_func_globals', cls=Function),
     __module__ = getset___module__,
     __weakref__ = make_weakref_descr(Function),
-    )
+)
 Function.typedef.acceptable_as_base_class = False
 
 Method.typedef = TypeDef(
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
@@ -21,7 +21,6 @@
 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
@@ -64,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
 
@@ -803,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:
@@ -824,9 +824,7 @@
     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)
@@ -837,6 +835,26 @@
 
     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)
 
@@ -862,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:
@@ -922,9 +940,7 @@
             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)
@@ -1433,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
@@ -1479,18 +1499,6 @@
     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)
@@ -1505,16 +1513,31 @@
 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]
@@ -1533,10 +1556,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):
@@ -1581,18 +1607,6 @@
 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)
@@ -1614,17 +1628,6 @@
     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)
@@ -1923,6 +1926,7 @@
 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)
@@ -1939,6 +1943,7 @@
 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))
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
@@ -339,16 +339,6 @@
         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)
@@ -356,18 +346,6 @@
         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:
@@ -382,22 +360,27 @@
         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()
@@ -433,7 +416,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)
@@ -487,6 +470,19 @@
         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)
@@ -516,7 +512,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/llgraph/symbolic.py b/pypy/jit/backend/llgraph/symbolic.py
--- a/pypy/jit/backend/llgraph/symbolic.py
+++ b/pypy/jit/backend/llgraph/symbolic.py
@@ -1,8 +1,7 @@
-import ctypes
 from pypy.rpython.lltypesystem import lltype, rffi, rclass
 
 
-Size2Type = [None]
+Size2Type = [None] * 100
 Type2Size = {}
 
 def get_size(TYPE):
@@ -14,7 +13,7 @@
         Type2Size[TYPE] = size
         return size
 
-TokenToField = [None]
+TokenToField = [None] * 100
 FieldToToken = {}
 
 def get_field_token(STRUCT, fieldname):
@@ -26,21 +25,3 @@
         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
diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py
--- a/pypy/jit/backend/llsupport/descr.py
+++ b/pypy/jit/backend/llsupport/descr.py
@@ -237,29 +237,6 @@
         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
 
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,97 @@
 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 == '*' 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)] = ('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)
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
@@ -10,8 +10,8 @@
 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
 
 
@@ -245,9 +245,6 @@
     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
@@ -267,12 +264,6 @@
     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
@@ -289,10 +280,16 @@
     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)
@@ -735,6 +732,32 @@
     bh_setfield_raw_i = _base_do_setfield_i
     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)
 
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,6 @@
-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 *
@@ -11,56 +13,55 @@
         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
diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py
--- a/pypy/jit/backend/model.py
+++ b/pypy/jit/backend/model.py
@@ -208,10 +208,6 @@
     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
 
diff --git a/pypy/jit/backend/test/calling_convention_test.py b/pypy/jit/backend/test/calling_convention_test.py
--- a/pypy/jit/backend/test/calling_convention_test.py
+++ b/pypy/jit/backend/test/calling_convention_test.py
@@ -59,7 +59,6 @@
         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')
@@ -118,7 +117,6 @@
             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')
@@ -161,7 +159,6 @@
             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')
@@ -204,7 +201,6 @@
             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')
@@ -303,7 +299,6 @@
             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):
@@ -315,9 +310,9 @@
         F = lltype.Float
         S = lltype.SingleFloat
         I = lltype.Signed
-        floats = [random.random() - 0.5 for i in range(8)]
-        singlefloats = [r_singlefloat(random.random() - 0.5) for i in range(8)]
-        ints = [random.randrange(-99, 99) for i in range(8)]
+        floats = [random.random() - 0.5 for i in range(20)]
+        singlefloats = [r_singlefloat(random.random() - 0.5) for i in range(20)]
+        ints = [random.randrange(-99, 99) for i in range(20)]
         for repeat in range(100):
             args = []
             argvalues = []
@@ -325,20 +320,23 @@
             local_floats = list(floats)
             local_singlefloats = list(singlefloats)
             local_ints = list(ints)
-            for i in range(8):
-                case = random.randrange(0, 3)
-                if case == 0:
+            for i in range(random.randrange(4, 20)):
+                case = random.randrange(0, 6)
+                if case & 1: boxme = BoxInt
+                else:        boxme = ConstInt
+                if case < 2:
                     args.append(F)
-                    arg = local_floats.pop()
-                    argslist.append(boxfloat(arg))
-                elif case == 1:
+                    arg = arg1 = local_floats.pop()
+                    if case & 1: boxme = boxfloat
+                    else:        boxme = constfloat
+                elif case < 4:
                     args.append(S)
                     arg = local_singlefloats.pop()
-                    argslist.append(BoxInt(longlong.singlefloat2int(arg)))
+                    arg1 = longlong.singlefloat2int(arg)
                 else:
                     args.append(I)
-                    arg = local_ints.pop()
-                    argslist.append(BoxInt(arg))
+                    arg = arg1 = local_ints.pop()
+                argslist.append(boxme(arg1))
                 argvalues.append(arg)
             FUNC = self.FuncType(args, F)
             FPTR = self.Ptr(FUNC)
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -515,7 +515,7 @@
             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
@@ -543,9 +543,8 @@
                                          '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)
@@ -1733,39 +1732,6 @@
         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)
@@ -2200,9 +2166,7 @@
         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()
@@ -2255,11 +2219,9 @@
         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()
@@ -2308,10 +2270,10 @@
         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)
@@ -2565,13 +2527,14 @@
         assert str.chars[4] == '/'
 
     def test_sorting_of_fields(self):
-        S = self.S
+        S = lltype.GcStruct('S', ('parent', rclass.OBJECT),
+                                  ('value', lltype.Signed),
+                                  ('chr1', lltype.Char),
+                                  ('chr2', lltype.Char))
+        chr1 = self.cpu.fielddescrof(S, 'chr1').sort_key()
         value = self.cpu.fielddescrof(S, 'value').sort_key()
-        chr1 = self.cpu.fielddescrof(S, 'chr1').sort_key()
         chr2 = self.cpu.fielddescrof(S, 'chr2').sort_key()
-        assert (sorted([chr2, chr1, value]) ==
-                [value, chr1, chr2])
-        assert len(dict.fromkeys([value, chr1, chr2]).keys()) == 3
+        assert len(set([value, chr1, chr2])) == 3
 
     def test_guards_nongc(self):
         x = lltype.malloc(lltype.Struct('x'), flavor='raw')
@@ -3206,6 +3169,20 @@
         res = self.cpu.get_latest_value_int(0)
         assert res == -10
 
+    def test_int_force_ge_zero(self):
+        ops = """
+        [i0]
+        i1 = int_force_ge_zero(i0)    # but forced to be in a register
+        finish(i1, descr=1)
+        """
+        loop = parse(ops, self.cpu, namespace=locals())
+        descr = loop.operations[-1].getdescr()
+        looptoken = JitCellToken()
+        self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+        for inp, outp in [(2,2), (-3, 0)]:
+            self.cpu.execute_token(looptoken, inp)
+            assert outp == self.cpu.get_latest_value_int(0)
+
     def test_compile_asmlen(self):
         from pypy.jit.backend.llsupport.llmodel import AbstractLLCPU
         if not isinstance(self.cpu, AbstractLLCPU):
@@ -3340,6 +3317,107 @@
         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):
 
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
@@ -127,9 +127,13 @@
         self._build_stack_check_slowpath()
         if gc_ll_descr.gcrootmap:
             self._build_release_gil(gc_ll_descr.gcrootmap)
-        debug_start('jit-backend-counts')
-        self.set_debug(have_debug_prints())
-        debug_stop('jit-backend-counts')
+        if not self._debug:
+            # if self._debug is already set it means that someone called
+            # set_debug by hand before initializing the assembler. Leave it
+            # as it is
+            debug_start('jit-backend-counts')
+            self.set_debug(have_debug_prints())
+            debug_stop('jit-backend-counts')
 
     def setup(self, looptoken):
         assert self.memcpy_addr != 0, "setup_once() not called?"
@@ -1178,11 +1182,13 @@
                     xmm_dst_locs.append(unused_xmm.pop())
                 else:
                     pass_on_stack.append(loc)
-            elif (argtypes is not None and argtypes[i-start] == 'S' and
-                  len(unused_xmm) > 0):
+            elif argtypes is not None and argtypes[i-start] == 'S':
                 # Singlefloat argument
-                if singlefloats is None: singlefloats = []
-                singlefloats.append((loc, unused_xmm.pop()))
+                if len(unused_xmm) > 0:
+                    if singlefloats is None: singlefloats = []
+                    singlefloats.append((loc, unused_xmm.pop()))
+                else:
+                    pass_on_stack.append(loc)
             else:
                 if len(unused_gpr) > 0:
                     src_locs.append(loc)
@@ -1216,6 +1222,9 @@
         # Load the singlefloat arguments from main regs or stack to xmm regs
         if singlefloats is not None:
             for src, dst in singlefloats:
+                if isinstance(src, ImmedLoc):
+                    self.mc.MOV(X86_64_SCRATCH_REG, src)
+                    src = X86_64_SCRATCH_REG
                 self.mc.MOVD(dst, src)
         # Finally remap the arguments in the main regs
         # If x is a register and is in dst_locs, then oups, it needs to
@@ -1407,7 +1416,7 @@
     def genop_int_force_ge_zero(self, op, arglocs, resloc):
         self.mc.TEST(arglocs[0], arglocs[0])
         self.mov(imm0, resloc)
-        self.mc.CMOVNS(arglocs[0], resloc)
+        self.mc.CMOVNS(resloc, arglocs[0])
 
     def genop_int_mod(self, op, arglocs, resloc):
         if IS_X86_32:
@@ -1579,6 +1588,13 @@
 
     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):
@@ -1605,9 +1621,6 @@
                                                 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)
@@ -1632,6 +1645,12 @@
         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,
@@ -2717,13 +2736,13 @@
     return AddressLoc(reg_or_imm1, reg_or_imm2, scale, offset)
 
 def addr_add_const(reg_or_imm1, offset):
-    return AddressLoc(reg_or_imm1, ImmedLoc(0), 0, offset)
+    return AddressLoc(reg_or_imm1, imm0, 0, offset)
 
 def mem(loc, offset):
-    return AddressLoc(loc, ImmedLoc(0), 0, offset)
+    return AddressLoc(loc, imm0, 0, offset)
 
 def heap(addr):
-    return AddressLoc(ImmedLoc(addr), ImmedLoc(0), 0, 0)
+    return AddressLoc(ImmedLoc(addr), imm0, 0, 0)
 
 def not_implemented(msg):
     os.write(2, '[x86/asm] %s\n' % msg)
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
@@ -1133,6 +1133,7 @@
                                  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())
@@ -1166,6 +1167,8 @@
 
     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())
@@ -1197,8 +1200,6 @@
         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))
diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py
--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -530,7 +530,7 @@
     NOT_r = insn(rex_w, '\xF7', register(1), '\xD0')
     NOT_b = insn(rex_w, '\xF7', orbyte(2<<3), stack_bp(1))
 
-    CMOVNS_rr = insn(rex_w, '\x0F\x49', register(2, 8), register(1), '\xC0')
+    CMOVNS_rr = insn(rex_w, '\x0F\x49', register(1, 8), register(2), '\xC0')
 
     # ------------------------------ Misc stuff ------------------------------
 
diff --git a/pypy/jit/backend/x86/test/test_fficall.py b/pypy/jit/backend/x86/test/test_fficall.py
--- a/pypy/jit/backend/x86/test/test_fficall.py
+++ b/pypy/jit/backend/x86/test/test_fficall.py
@@ -2,7 +2,7 @@
 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
diff --git a/pypy/jit/backend/x86/test/test_rawmem.py b/pypy/jit/backend/x86/test/test_rawmem.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/backend/x86/test/test_rawmem.py
@@ -0,0 +1,9 @@
+
+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
diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py
--- a/pypy/jit/backend/x86/test/test_runner.py
+++ b/pypy/jit/backend/x86/test/test_runner.py
@@ -458,10 +458,8 @@
                 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
diff --git a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py
--- a/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py
+++ b/pypy/jit/backend/x86/test/test_rx86_32_auto_encoding.py
@@ -317,9 +317,7 @@
                 # CALL_j is actually relative, so tricky to test
                 (instrname == 'CALL' and argmodes == 'j') or
                 # SET_ir must be tested manually
-                (instrname == 'SET' and argmodes == 'ir') or
-                # asm gets CMOVNS args the wrong way
-                (instrname.startswith('CMOV'))
+                (instrname == 'SET' and argmodes == 'ir')
         )
 
 
diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py
--- a/pypy/jit/backend/x86/test/test_ztranslation.py
+++ b/pypy/jit/backend/x86/test/test_ztranslation.py
@@ -187,7 +187,8 @@
             return len(ll_times)
 
         res = self.meta_interp(main, [])
-        assert res == 1
+        assert res == 3
+        # one for loop, one for entry point and one for the prologue
 
 class TestTranslationRemoveTypePtrX86(CCompiledMixin):
     CPUClass = getcpuclass()
diff --git a/pypy/jit/backend/x86/tool/test/test_viewcode.py b/pypy/jit/backend/x86/tool/test/test_viewcode.py
--- a/pypy/jit/backend/x86/tool/test/test_viewcode.py
+++ b/pypy/jit/backend/x86/tool/test/test_viewcode.py
@@ -1,5 +1,10 @@
 from cStringIO import StringIO
 from pypy.jit.backend.x86.tool.viewcode import format_code_dump_with_labels
+from pypy.jit.backend.x86.tool.viewcode import find_objdump
+import os
+import py
+import tempfile
+from pypy.tool.udir import udir
 
 def test_format_code_dump_with_labels():
     lines = StringIO("""
@@ -53,3 +58,16 @@
     lines = format_code_dump_with_labels(0xAA00, lines, label_list=None)
     out = ''.join(lines)
     assert out.strip() == input
+
+def test_find_objdump():
+    old = os.environ['PATH']
+    os.environ['PATH'] = ''
+    py.test.raises(find_objdump)
+
+    #
+    path = udir.join('objdump')
+    print >>path, 'hello world'
+    os.environ['PATH'] = path.dirname
+    assert find_objdump() == 'objdump'
+    #
+    os.environ['PATH'] = old
diff --git a/pypy/jit/backend/x86/tool/viewcode.py b/pypy/jit/backend/x86/tool/viewcode.py
--- a/pypy/jit/backend/x86/tool/viewcode.py
+++ b/pypy/jit/backend/x86/tool/viewcode.py
@@ -8,9 +8,9 @@
     ./viewcode.py log               # also includes a pygame viewer
 """
 
-import autopath
 import new
 import operator
+import os
 import py
 import re
 import sys
@@ -36,6 +36,17 @@
 if sys.platform == "win32":
     pass   # lots more in Psyco
 
+def find_objdump():
+    exe = ('objdump', 'gobjdump')
+    path = os.environ['PATH'].split(os.pathsep)
+    for e in exe:
+        for p in path:
+            path_to = os.path.join(p, e)
+            if not os.path.exists(path_to):
+                continue
+            return e
+    raise AssertionError('(g)objdump was not found in PATH')
+
 def machine_code_dump(data, originaddr, backend_name, label_list=None):
     objdump_backend_option = {
         'x86': 'i386',
@@ -43,7 +54,8 @@
         'x86_64': 'x86-64',
         'i386': 'i386',
     }
-    objdump = ('objdump -M %(backend)s -b binary -m i386 '
+    cmd = find_objdump()
+    objdump = ('%(command)s -M %(backend)s -b binary -m i386 '
                '--disassembler-options=intel-mnemonics '
                '--adjust-vma=%(origin)d -D %(file)s')
     #
@@ -51,6 +63,7 @@
     f.write(data)
     f.close()
     p = subprocess.Popen(objdump % {
+        'command': cmd,
         'file': tmpfile,
         'origin': originaddr,
         'backend': objdump_backend_option[backend_name],
diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py
--- a/pypy/jit/codewriter/call.py
+++ b/pypy/jit/codewriter/call.py
@@ -16,6 +16,7 @@
 
 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
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
@@ -81,9 +75,13 @@
     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,
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
@@ -11,6 +11,7 @@
 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
@@ -208,6 +209,10 @@
         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
@@ -223,6 +228,9 @@
                 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)
 
@@ -520,9 +528,12 @@
             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':
@@ -550,8 +561,13 @@
         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
@@ -566,9 +582,14 @@
                                    [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)
 
@@ -691,6 +712,16 @@
                               [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'))
@@ -840,6 +871,23 @@
             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:
@@ -850,7 +898,7 @@
             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
@@ -1228,6 +1276,8 @@
                        ('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('''
@@ -1469,7 +1519,7 @@
                                                      '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]
@@ -1678,27 +1728,10 @@
     # 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)
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/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py
--- a/pypy/jit/codewriter/test/test_jtransform.py
+++ b/pypy/jit/codewriter/test/test_jtransform.py
@@ -123,6 +123,7 @@
             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),
@@ -139,16 +140,26 @@
              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
 
 
@@ -547,10 +558,13 @@
     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 == []
 
@@ -591,21 +605,28 @@
     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()
@@ -621,6 +642,13 @@
     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)
@@ -830,6 +858,30 @@
     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)
diff --git a/pypy/jit/codewriter/test/test_list.py b/pypy/jit/codewriter/test/test_list.py
--- a/pypy/jit/codewriter/test/test_list.py
+++ b/pypy/jit/codewriter/test/test_list.py
@@ -129,14 +129,14 @@
     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():
diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -1129,9 +1129,9 @@
     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):
@@ -1140,6 +1140,9 @@
     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)
@@ -1274,6 +1277,20 @@
     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
diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py
--- a/pypy/jit/metainterp/executor.py
+++ b/pypy/jit/metainterp/executor.py
@@ -180,6 +180,26 @@
     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()
@@ -277,19 +297,6 @@
 
 
 def _make_execute_list():
-    if 0:     # enable this to trace calls to do_xxx
-        def wrap(fn):
-            def myfn(*args):
-                print '<<<', fn.__name__
-                try:
-                    return fn(*args)
-                finally:
-                    print fn.__name__, '>>>'
-            return myfn
-    else:
-        def wrap(fn):
-            return fn
-    #
     execute_by_num_args = {}
     for key, value in rop.__dict__.items():
         if not key.startswith('_'):
@@ -343,7 +350,6 @@
                          rop.DEBUG_MERGE_POINT,
                          rop.JIT_DEBUG,
                          rop.SETARRAYITEM_RAW,
-                         rop.GETINTERIORFIELD_RAW,
                          rop.SETINTERIORFIELD_RAW,
                          rop.CALL_RELEASE_GIL,
                          rop.QUASIIMMUT_FIELD,
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -39,7 +39,7 @@
         # 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)
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,307 +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)
-        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, ...)
-        #
-        # 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 do_struct_getsetfield(self, op, oopspec):
-        ffitypeval = self.getvalue(op.getarg(1))
-        addrval = self.getvalue(op.getarg(2))
-        offsetval = self.getvalue(op.getarg(3))
-        if not ffitypeval.is_constant() or not offsetval.is_constant():
-            return [op]
-        #
-        ffitypeaddr = ffitypeval.box.getaddr()
-        ffitype = llmemory.cast_adr_to_ptr(ffitypeaddr, clibffi.FFI_TYPE_P)
-        offset = offsetval.box.getint()
-        descr = self._get_field_descr(ffitype, offset)
-        #
-        arglist = [addrval.force_box(self.optimizer)]
-        if oopspec == EffectInfo.OS_LIBFFI_STRUCT_GETFIELD:
-            opnum = rop.GETFIELD_RAW
-        else:
-            opnum = rop.SETFIELD_RAW
-            newval = self.getvalue(op.getarg(4))
-            arglist.append(newval.force_box(self.optimizer))
-        #
-        newop = ResOperation(opnum, arglist, op.result, descr=descr)
-        return [newop]
-
-    def _get_field_descr(self, ffitype, offset):
-        kind = libffi.types.getkind(ffitype)
-        is_pointer = is_float = is_signed = False
-        if ffitype is libffi.types.pointer:
-            is_pointer = True
-        elif kind == 'i':
-            is_signed = True
-        elif kind == 'f' or kind == 'I' or kind == 'U':
-            # longlongs are treated as floats, see e.g. llsupport/descr.py:getDescrClass
-            is_float = True
-        else:
-            assert False, "unsupported ffitype or kind"
-        #
-        fieldsize = intmask(ffitype.c_size)
-        return self.optimizer.cpu.fielddescrof_dynamic(offset, fieldsize,
-                                                       is_pointer, is_float, is_signed)
-    
-    def do_getsetarrayitem(self, op, oopspec):
-        ffitypeval = self.getvalue(op.getarg(1))
-        widthval = self.getvalue(op.getarg(2))
-        offsetval = self.getvalue(op.getarg(5))
-        if not ffitypeval.is_constant() or not widthval.is_constant() or not offsetval.is_constant():
-            return [op]
-
-        ffitypeaddr = ffitypeval.box.getaddr()
-        ffitype = llmemory.cast_adr_to_ptr(ffitypeaddr, clibffi.FFI_TYPE_P)
-        offset = offsetval.box.getint()
-        width = widthval.box.getint()
-        descr = self._get_interior_descr(ffitype, width, offset)
-
-        arglist = [
-            self.getvalue(op.getarg(3)).force_box(self.optimizer),
-            self.getvalue(op.getarg(4)).force_box(self.optimizer),
-        ]
-        if oopspec == EffectInfo.OS_LIBFFI_GETARRAYITEM:
-            opnum = rop.GETINTERIORFIELD_RAW
-        elif oopspec == EffectInfo.OS_LIBFFI_SETARRAYITEM:
-            opnum = rop.SETINTERIORFIELD_RAW
-            arglist.append(self.getvalue(op.getarg(6)).force_box(self.optimizer))
-        else:
-            assert False
-        return [
-            ResOperation(opnum, arglist, op.result, descr=descr),
-        ]
-
-    def _get_interior_descr(self, ffitype, width, offset):
-        kind = libffi.types.getkind(ffitype)
-        is_pointer = is_float = is_signed = False
-        if ffitype is libffi.types.pointer:
-            is_pointer = True
-        elif kind == 'i':
-            is_signed = True
-        elif kind == 'f' or kind == 'I' or kind == 'U':
-            # longlongs are treated as floats, see
-            # e.g. llsupport/descr.py:getDescrClass
-            is_float = True
-        elif kind == 'u' or kind == 's':
-            # they're all False
-            pass
-        else:
-            raise NotImplementedError("unsupported ffitype or kind: %s" % kind)
-        #
-        fieldsize = rffi.getintfield(ffitype, 'c_size')
-        return self.optimizer.cpu.interiorfielddescrof_dynamic(
-            offset, width, fieldsize, is_pointer, is_float, is_signed
-        )
-
-
-    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/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -255,6 +255,7 @@
             opnum == rop.SETARRAYITEM_GC or      # handled specially
             opnum == rop.SETARRAYITEM_RAW or     # no effect on GC struct
             opnum == rop.SETINTERIORFIELD_RAW or # no effect on GC struct
+            opnum == rop.RAW_STORE or            # no effect on GC struct
             opnum == rop.STRSETITEM or           # no effect on GC struct/array
             opnum == rop.UNICODESETITEM or       # no effect on GC struct/array
             opnum == rop.DEBUG_MERGE_POINT or    # no effect whatsoever
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
@@ -451,12 +451,27 @@
     opimpl_getarrayitem_raw_f = _opimpl_getarrayitem_raw_any
 
     @arguments("box", "descr", "box")
+    def _opimpl_getarrayitem_raw_pure_any(self, arraybox,arraydescr, indexbox):
+        return self.execute_with_descr(rop.GETARRAYITEM_RAW_PURE,
+                                       arraydescr, arraybox, indexbox)
+
+    opimpl_getarrayitem_raw_i_pure = _opimpl_getarrayitem_raw_pure_any
+    opimpl_getarrayitem_raw_f_pure = _opimpl_getarrayitem_raw_pure_any
+
+    @arguments("box", "descr", "box")
     def _opimpl_getarrayitem_gc_pure_any(self, arraybox, arraydescr, indexbox):
+        if isinstance(arraybox, ConstPtr) and isinstance(indexbox, ConstInt):
+            # if the arguments are directly constants, bypass the heapcache
+            # completely
+            resbox = executor.execute(self.metainterp.cpu, self.metainterp,
+                                      rop.GETARRAYITEM_GC_PURE, arraydescr,
+                                      arraybox, indexbox)
+            return resbox.constbox()
         return self._do_getarrayitem_gc_any(rop.GETARRAYITEM_GC_PURE, arraybox, arraydescr, indexbox)
 
-    opimpl_getarrayitem_gc_pure_i = _opimpl_getarrayitem_gc_pure_any
-    opimpl_getarrayitem_gc_pure_r = _opimpl_getarrayitem_gc_pure_any
-    opimpl_getarrayitem_gc_pure_f = _opimpl_getarrayitem_gc_pure_any
+    opimpl_getarrayitem_gc_i_pure = _opimpl_getarrayitem_gc_pure_any
+    opimpl_getarrayitem_gc_r_pure = _opimpl_getarrayitem_gc_pure_any
+    opimpl_getarrayitem_gc_f_pure = _opimpl_getarrayitem_gc_pure_any
 
     @arguments("box", "descr", "box", "box")
     def _opimpl_setarrayitem_gc_any(self, arraybox, arraydescr,
@@ -563,6 +578,11 @@
 
     @arguments("box", "descr")
     def _opimpl_getfield_gc_pure_any(self, box, fielddescr):
+        if isinstance(box, ConstPtr):
+            # if 'box' is directly a ConstPtr, bypass the heapcache completely
+            resbox = executor.execute(self.metainterp.cpu, self.metainterp,
+                                      rop.GETFIELD_GC_PURE, fielddescr, box)
+            return resbox.constbox()
         return self._opimpl_getfield_gc_any_pureornot(
                 rop.GETFIELD_GC_PURE, box, fielddescr)
     opimpl_getfield_gc_i_pure = _opimpl_getfield_gc_pure_any
@@ -647,6 +667,20 @@
     opimpl_setfield_raw_r = _opimpl_setfield_raw_any
     opimpl_setfield_raw_f = _opimpl_setfield_raw_any
 
+    @arguments("box", "box", "descr", "box")
+    def _opimpl_raw_store(self, addrbox, offsetbox, arraydescr, valuebox):
+        self.execute_with_descr(rop.RAW_STORE, arraydescr,
+                                addrbox, offsetbox, valuebox)
+    opimpl_raw_store_i = _opimpl_raw_store
+    opimpl_raw_store_f = _opimpl_raw_store
+
+    @arguments("box", "box", "descr")
+    def _opimpl_raw_load(self, addrbox, offsetbox, arraydescr):
+        return self.execute_with_descr(rop.RAW_LOAD, arraydescr,
+                                       addrbox, offsetbox)
+    opimpl_raw_load_i = _opimpl_raw_load
+    opimpl_raw_load_f = _opimpl_raw_load
+
     @arguments("box", "descr", "descr", "orgpc")
     def opimpl_record_quasiimmut_field(self, box, fielddescr,
                                        mutatefielddescr, orgpc):
@@ -1368,6 +1402,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
@@ -1462,6 +1498,7 @@
         self.jitdrivers_sd = codewriter.callcontrol.jitdrivers_sd
         self.virtualref_info = codewriter.callcontrol.virtualref_info
         self.callinfocollection = codewriter.callcontrol.callinfocollection
+        self.has_libffi_call = codewriter.callcontrol.has_libffi_call
         #
         # store this information for fastpath of call_assembler
         # (only the paths that can actually be taken)
@@ -2511,6 +2548,89 @@
         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.
+        """
+        # an 'assert' that constant-folds away the rest of this function
+        # if the codewriter didn't produce any OS_LIBFFI_CALL at all.
+        assert self.staticdata.has_libffi_call
+        #
+        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)
+        extrainfo = op.getdescr().get_extra_info()
+        calldescr = self.cpu.calldescrof_dynamic(cif_description, 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/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -456,6 +456,7 @@
     'GETFIELD_GC_PURE/1d',
     'GETFIELD_RAW_PURE/1d',
     'GETARRAYITEM_GC_PURE/2d',
+    'GETARRAYITEM_RAW_PURE/2d',
     'UNICODELEN/1',
     'UNICODEGETITEM/2',
     #
@@ -468,7 +469,7 @@
     'GETARRAYITEM_GC/2d',
     'GETARRAYITEM_RAW/2d',
     'GETINTERIORFIELD_GC/2d',
-    'GETINTERIORFIELD_RAW/2d',
+    'RAW_LOAD/2d',
     'GETFIELD_GC/1d',
     'GETFIELD_RAW/1d',
     '_MALLOC_FIRST',
@@ -487,7 +488,8 @@
     'SETARRAYITEM_GC/3d',
     'SETARRAYITEM_RAW/3d',
     'SETINTERIORFIELD_GC/3d',
-    'SETINTERIORFIELD_RAW/3d',
+    'SETINTERIORFIELD_RAW/3d',    # only used by llsupport/rewrite.py
+    'RAW_STORE/3d',
     'SETFIELD_GC/2d',
     'SETFIELD_RAW/2d',
     'STRSETITEM/3',
diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py
--- a/pypy/jit/metainterp/test/support.py
+++ b/pypy/jit/metainterp/test/support.py
@@ -42,6 +42,9 @@
         trace_limit = sys.maxint
         enable_opts = ALL_OPTS_DICT
 
+    if kwds.pop('disable_optimizations', False):
+        FakeWarmRunnerState.enable_opts = {}
+
     func._jit_unroll_safe_ = True
     rtyper = support.annotate(func, values, type_system=type_system,
                               translationoptions=translationoptions)
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)
+    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/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py
--- a/pypy/jit/metainterp/test/test_immutable.py
+++ b/pypy/jit/metainterp/test/test_immutable.py
@@ -89,6 +89,92 @@
                             int_add=3)
 
 
+    def test_raw_field_and_array(self):
+        from pypy.rpython.lltypesystem import lltype
+        X = lltype.Struct('X',
+            ('a', lltype.Signed),
+            ('b', lltype.Array(lltype.Signed,
+                               hints={'nolength': True, 'immutable': True})),
+            hints={'immutable': True})
+
+        x = lltype.malloc(X, 4, flavor='raw', immortal=True)
+        x.a = 6
+        x.b[2] = 7
+        xlist = [x, lltype.nullptr(X)]
+        def g(num):
+            if num < 0:
+                num = 0
+            return num
+        g._dont_inline_ = True
+        def f(num):
+            num = g(num)
+            x = xlist[num]
+            return x.a * x.b[2]
+        #
+        res = self.interp_operations(f, [0], disable_optimizations=True)
+        assert res == 42
+        self.check_operations_history(getfield_raw_pure=1,
+                                      getarrayitem_raw_pure=1,
+                                      int_mul=1)
+        #
+        # second try, in which we get num=0 constant-folded through f()
+        res = self.interp_operations(f, [-1], disable_optimizations=True)
+        assert res == 42
+        self.check_operations_history(getfield_raw_pure=0,
+                                      getarrayitem_raw_pure=0,
+                                      int_mul=0)
+
+    def test_read_on_promoted(self):
+        # this test used to fail because the n = f.n was staying alive
+        # in a box (not a const, as it was read before promote), and
+        # thus the second f.n was returning the same box, although it
+        # could now return a const.
+        class Foo(object):
+            _immutable_fields_ = ['n']
+            def __init__(self, n):
+                self.n = n
+        f1 = Foo(42); f2 = Foo(43)
+        @jit.dont_look_inside
+        def some(m):
+            return [f1, f2][m]
+        @jit.dont_look_inside
+        def do_stuff_with(n):
+            print n
+        def main(m):
+            f = some(m)
+            n = f.n
+            f = jit.hint(f, promote=True)
+            res = f.n * 6
+            do_stuff_with(n)
+            return res
+        res = self.interp_operations(main, [1])
+        assert res == 43 * 6
+        self.check_operations_history(int_mul=0)   # constant-folded
+
+    def test_read_on_promoted_array(self):
+        class Foo(object):
+            _immutable_fields_ = ['lst[*]']
+            def __init__(self, lst):
+                self.lst = lst
+        f1 = Foo([42]); f2 = Foo([43])
+        @jit.dont_look_inside
+        def some(m):
+            return [f1, f2][m]
+        @jit.dont_look_inside
+        def do_stuff_with(n):
+            print n
+        def main(m):
+            f = some(m)
+            n = f.lst[0]
+            f = jit.hint(f, promote=True)
+            res = f.lst[0] * 6
+            do_stuff_with(n)
+            return res
+        res = self.interp_operations(main, [1])
+        assert res == 43 * 6
+        self.check_operations_history(int_mul=0)   # constant-folded
+
+
 class TestLLtypeImmutableFieldsTests(ImmutableFieldsTests, LLJitMixin):
     pass
 
diff --git a/pypy/jit/metainterp/test/test_rawmem.py b/pypy/jit/metainterp/test/test_rawmem.py
--- a/pypy/jit/metainterp/test/test_rawmem.py
+++ b/pypy/jit/metainterp/test/test_rawmem.py
@@ -1,8 +1,9 @@
 from pypy.jit.metainterp.test.support import LLJitMixin
 from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.rawstorage import (alloc_raw_storage, raw_storage_setitem,
+                                  free_raw_storage, raw_storage_getitem)
 
-
-class TestJITRawMem(LLJitMixin):
+class RawMemTests(object):
     def test_cast_void_ptr(self):
         TP = lltype.Array(lltype.Float, hints={"nolength": True})
         VOID_TP = lltype.Array(lltype.Void, hints={"nolength": True, "uncast_on_llgraph": True})
@@ -18,7 +19,7 @@
             s += rffi.cast(lltype.Ptr(TP), a.storage)[0]
             lltype.free(x, flavor="raw")
             return s
-        res = self.interp_operations(f, [10])
+        self.interp_operations(f, [10])
 
     def test_fixed_size_malloc(self):
         TIMEVAL = lltype.Struct('dummy', ('tv_sec', rffi.LONG), ('tv_usec', rffi.LONG))
@@ -30,3 +31,32 @@
         assert res == 42
         self.check_operations_history({'call': 2, 'guard_no_exception': 1,
                                        'finish': 1})
+
+    def test_raw_storage_int(self):
+        def f():
+            p = alloc_raw_storage(15)
+            raw_storage_setitem(p, 3, 24)
+            res = raw_storage_getitem(lltype.Signed, p, 3)
+            free_raw_storage(p)
+            return res
+        res = self.interp_operations(f, [])
+        assert res == 24
+        self.check_operations_history({'call': 2, 'guard_no_exception': 1,
+                                       'raw_store': 1, 'raw_load': 1,
+                                       'finish': 1})
+
+    def test_raw_storage_float(self):
+        def f():
+            p = alloc_raw_storage(15)
+            raw_storage_setitem(p, 3, 2.4e15)
+            res = raw_storage_getitem(lltype.Float, p, 3)
+            free_raw_storage(p)
+            return res
+        res = self.interp_operations(f, [])
+        assert res == 2.4e15
+        self.check_operations_history({'call': 2, 'guard_no_exception': 1,
+                                       'raw_store': 1, 'raw_load': 1,
+                                       'finish': 1})
+
+class TestRawMem(RawMemTests, LLJitMixin):
+    pass
diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py
--- a/pypy/jit/metainterp/test/test_warmspot.py
+++ b/pypy/jit/metainterp/test/test_warmspot.py
@@ -260,6 +260,33 @@
                     pass   # other case
         self.meta_interp(f1, [18])
 
+    def test_bug_constant_int(self):
+        py.test.skip("crashes because a is a constant")
+        from pypy.rpython.lltypesystem import lltype, rffi
+        mydriver = JitDriver(greens=['a'], reds=['m'])
+        def f1(m, a):
+            while m > 0:
+                mydriver.jit_merge_point(a=a, m=m)
+                m = m - 1
+        def entry(m):
+            f1(m, 42)
+        self.meta_interp(entry, [18])
+
+    def test_bug_constant_instance(self):
+        py.test.skip("crashes because a is a constant")
+        from pypy.rpython.lltypesystem import lltype, rffi
+        mydriver = JitDriver(greens=['a'], reds=['m'])
+        class A(object):
+            pass
+        a1 = A()
+        def f1(m, a):
+            while m > 0:
+                mydriver.jit_merge_point(a=a, m=m)
+                m = m - 1
+        def entry(m):
+            f1(m, a1)
+        self.meta_interp(entry, [18])
+
     def test_bug_constant_rawptrs(self):
         py.test.skip("crashes because a is a constant")
         from pypy.rpython.lltypesystem import lltype, rffi
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
@@ -14,6 +14,7 @@
 from pypy.rlib.debug import fatalerror
 from pypy.rlib.rstackovf import StackOverflow
 from pypy.translator.simplify import get_functype
+from pypy.translator.backendopt import removenoops
 from pypy.translator.unsimplify import call_final_function
 
 from pypy.jit.metainterp import history, pyjitpl, gc, memmgr
@@ -79,10 +80,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
@@ -264,6 +261,10 @@
         graph = copygraph(graph)
         [jmpp] = find_jit_merge_points([graph])
         graph.startblock = support.split_before_jit_merge_point(*jmpp)
+        # XXX this is incredibly obscure, but this is sometiems necessary
+        #     so we don't explode in checkgraph. for reasons unknown this
+        #     is not contanied within simplify_graph
+        removenoops.remove_same_as(graph)
         # a crash in the following checkgraph() means that you forgot
         # to list some variable in greens=[] or reds=[] in JitDriver,
         # or that a jit_merge_point() takes a constant as an argument.
diff --git a/pypy/module/__pypy__/interp_time.py b/pypy/module/__pypy__/interp_time.py
--- a/pypy/module/__pypy__/interp_time.py
+++ b/pypy/module/__pypy__/interp_time.py
@@ -1,5 +1,5 @@
 from __future__ import with_statement
-import os
+import sys
 
 from pypy.interpreter.error import exception_from_errno
 from pypy.interpreter.gateway import unwrap_spec
@@ -7,10 +7,11 @@
 from pypy.rpython.tool import rffi_platform
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
-if os.name == 'nt':
+if sys.platform == 'linux2':
+    libraries = ["rt"]
+else:
     libraries = []
-else:
-    libraries = ["rt"]
+
 
 class CConfig:
     _compilation_info_ = ExternalCompilationInfo(
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -0,0 +1,42 @@
+from pypy.interpreter.mixedmodule import MixedModule
+
+class Module(MixedModule):
+
+    appleveldefs = {
+        }
+    interpleveldefs = {
+        '__version__': 'space.wrap("0.3")',
+
+        'nonstandard_integer_types': 'misc.nonstandard_integer_types',
+
+        'load_library': 'libraryobj.load_library',
+
+        'new_primitive_type': 'newtype.new_primitive_type',
+        'new_pointer_type': 'newtype.new_pointer_type',
+        'new_array_type': 'newtype.new_array_type',
+        'new_struct_type': 'newtype.new_struct_type',
+        'new_union_type': 'newtype.new_union_type',
+        'complete_struct_or_union': 'newtype.complete_struct_or_union',
+        'new_void_type': 'newtype.new_void_type',
+        'new_enum_type': 'newtype.new_enum_type',
+        'new_function_type': 'newtype.new_function_type',
+
+        'newp': 'func.newp',
+        'cast': 'func.cast',
+        'callback': 'func.callback',
+        'alignof': 'func.alignof',
+        'sizeof': 'func.sizeof',
+        'typeof': 'func.typeof',
+        'offsetof': 'func.offsetof',
+        '_getfields': 'func._getfields',
+        'getcname': 'func.getcname',
+
+        'string': 'func.string',
+        'buffer': 'cbuffer.buffer',
+
+        'get_errno': 'cerrno.get_errno',
+        'set_errno': 'cerrno.set_errno',
+
+        'FFI_DEFAULT_ABI': 'ctypefunc._get_abi(space, "FFI_DEFAULT_ABI")',
+        'FFI_CDECL': 'ctypefunc._get_abi(space,"FFI_DEFAULT_ABI")',#win32 name
+        }
diff --git a/pypy/module/_cffi_backend/cbuffer.py b/pypy/module/_cffi_backend/cbuffer.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/cbuffer.py
@@ -0,0 +1,55 @@
+from pypy.interpreter.error import operationerrfmt
+from pypy.interpreter.buffer import RWBuffer
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.rpython.lltypesystem import rffi
+from pypy.module._cffi_backend import cdataobj, ctypeptr, ctypearray
+
+
+class LLBuffer(RWBuffer):
+    _immutable_ = True
+
+    def __init__(self, raw_cdata, size):
+        self.raw_cdata = raw_cdata
+        self.size = size
+
+    def getlength(self):
+        return self.size
+
+    def getitem(self, index):
+        return self.raw_cdata[index]
+
+    def setitem(self, index, char):
+        self.raw_cdata[index] = char
+
+    def get_raw_address(self):
+        return self.raw_cdata
+
+    def getslice(self, start, stop, step, size):
+        if step == 1:
+            return rffi.charpsize2str(rffi.ptradd(self.raw_cdata, start), size)
+        return RWBuffer.getslice(self, start, stop, step, size)
+
+    def setslice(self, start, string):
+        raw_cdata = rffi.ptradd(self.raw_cdata, start)
+        for i in range(len(string)):
+            raw_cdata[i] = string[i]
+
+
+ at unwrap_spec(cdata=cdataobj.W_CData, size=int)
+def buffer(space, cdata, size=-1):
+    ctype = cdata.ctype
+    if isinstance(ctype, ctypeptr.W_CTypePointer):
+        if size < 0:
+            size = ctype.ctitem.size
+    elif isinstance(ctype, ctypearray.W_CTypeArray):
+        if size < 0:
+            size = cdata._sizeof()
+    else:
+        raise operationerrfmt(space.w_TypeError,
+                              "expected a pointer or array cdata, got '%s'",
+                              ctype.name)
+    if size < 0:
+        raise operationerrfmt(space.w_TypeError,
+                              "don't know the size pointed to by '%s'",
+                              ctype.name)
+    return space.wrap(LLBuffer(cdata._cdata, size))
diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/ccallback.py
@@ -0,0 +1,200 @@
+"""
+Callbacks.
+"""
+import os
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+from pypy.rlib.objectmodel import compute_unique_id, keepalive_until_here
+from pypy.rlib import clibffi, rweakref, rgc
+from pypy.rlib.rarithmetic import r_ulonglong
+
+from pypy.module._cffi_backend.cdataobj import W_CData
+from pypy.module._cffi_backend.ctypefunc import SIZE_OF_FFI_ARG, BIG_ENDIAN
+from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned
+from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid
+from pypy.module._cffi_backend import cerrno, misc
+
+# ____________________________________________________________
+
+
+class W_CDataCallback(W_CData):
+    #_immutable_fields_ = ...
+    ll_error = lltype.nullptr(rffi.CCHARP.TO)
+
+    def __init__(self, space, ctype, w_callable, w_error):
+        raw_closure = rffi.cast(rffi.CCHARP, clibffi.closureHeap.alloc())
+        W_CData.__init__(self, space, raw_closure, ctype)
+        #
+        if not space.is_true(space.callable(w_callable)):
+            raise operationerrfmt(space.w_TypeError,
+                                  "expected a callable object, not %s",
+                                  space.type(w_callable).getname(space))
+        self.w_callable = w_callable
+        self.w_error = w_error
+        #
+        fresult = self.getfunctype().ctitem
+        size = fresult.size
+        if size > 0:
+            if fresult.is_primitive_integer and size < SIZE_OF_FFI_ARG:
+                size = SIZE_OF_FFI_ARG
+            self.ll_error = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw',
+                                          zero=True)
+        if not space.is_w(w_error, space.w_None):
+            convert_from_object_fficallback(fresult, self.ll_error, w_error)
+        #
+        self.unique_id = compute_unique_id(self)
+        global_callback_mapping.set(self.unique_id, self)
+        #
+        cif_descr = self.getfunctype().cif_descr
+        if not cif_descr:
+            raise OperationError(space.w_NotImplementedError,
+                                 space.wrap("callbacks with '...'"))
+        res = clibffi.c_ffi_prep_closure(self.get_closure(), cif_descr.cif,
+                                         invoke_callback,
+                                         rffi.cast(rffi.VOIDP, self.unique_id))
+        if rffi.cast(lltype.Signed, res) != clibffi.FFI_OK:
+            raise OperationError(space.w_SystemError,
+                space.wrap("libffi failed to build this callback"))
+
+    def get_closure(self):
+        return rffi.cast(clibffi.FFI_CLOSUREP, self._cdata)
+
+    #@rgc.must_be_light_finalizer
+    def __del__(self):
+        clibffi.closureHeap.free(self.get_closure())
+        if self.ll_error:
+            lltype.free(self.ll_error, flavor='raw')
+
+    def _repr_extra(self):
+        space = self.space
+        return 'calling ' + space.str_w(space.repr(self.w_callable))
+
+    def getfunctype(self):
+        ctype = self.ctype
+        if not isinstance(ctype, W_CTypeFunc):
+            space = self.space
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("expected a function ctype"))
+        return ctype
+
+    def invoke(self, ll_args, ll_res):
+        space = self.space
+        ctype = self.getfunctype()
+        args_w = []
+        for i, farg in enumerate(ctype.fargs):
+            ll_arg = rffi.cast(rffi.CCHARP, ll_args[i])
+            args_w.append(farg.convert_to_object(ll_arg))
+        fresult = ctype.ctitem
+        #
+        w_res = space.call(self.w_callable, space.newtuple(args_w))
+        #
+        convert_from_object_fficallback(fresult, ll_res, w_res)
+
+    def print_error(self, operr):
+        space = self.space
+        operr.write_unraisable(space, "cffi callback", self.w_callable)
+
+    def write_error_return_value(self, ll_res):
+        fresult = self.getfunctype().ctitem
+        if fresult.size > 0:
+            misc._raw_memcopy(self.ll_error, ll_res, fresult.size)
+            keepalive_until_here(self)
+
+
+global_callback_mapping = rweakref.RWeakValueDictionary(int, W_CDataCallback)
+
+
+def convert_from_object_fficallback(fresult, ll_res, w_res):
+    space = fresult.space
+    small_result = fresult.size < SIZE_OF_FFI_ARG
+    if small_result and isinstance(fresult, W_CTypeVoid):
+        if not space.is_w(w_res, space.w_None):
+            raise OperationError(space.w_TypeError,
+                    space.wrap("callback with the return type 'void'"
+                               " must return None"))
+        return
+    #
+    if small_result and fresult.is_primitive_integer:
+        # work work work around a libffi irregularity: for integer return
+        # types we have to fill at least a complete 'ffi_arg'-sized result
+        # buffer.
+        if type(fresult) is W_CTypePrimitiveSigned:
+            # It's probably fine to always zero-extend, but you never
+            # know: maybe some code somewhere expects a negative
+            # 'short' result to be returned into EAX as a 32-bit
+            # negative number.  Better safe than sorry.  This code
+            # is about that case.  Let's ignore this for enums.
+            #
+            # do a first conversion only to detect overflows.  This
+            # conversion produces stuff that is otherwise ignored.
+            fresult.convert_from_object(ll_res, w_res)
+            #
+            # manual inlining and tweaking of
+            # W_CTypePrimitiveSigned.convert_from_object() in order
+            # to write a whole 'ffi_arg'.
+            value = misc.as_long_long(space, w_res)
+            value = r_ulonglong(value)
+            misc.write_raw_integer_data(ll_res, value, SIZE_OF_FFI_ARG)
+            return
+        else:
+            # zero extension: fill the '*result' with zeros, and (on big-
+            # endian machines) correct the 'result' pointer to write to
+            misc._raw_memclear(ll_res, SIZE_OF_FFI_ARG)
+            if BIG_ENDIAN:
+                diff = SIZE_OF_FFI_ARG - fresult.size
+                ll_res = rffi.ptradd(ll_res, diff)
+    #
+    fresult.convert_from_object(ll_res, w_res)
+
+
+# ____________________________________________________________
+
+STDERR = 2
+
+def invoke_callback(ffi_cif, ll_res, ll_args, ll_userdata):
+    """ Callback specification.
+    ffi_cif - something ffi specific, don't care
+    ll_args - rffi.VOIDPP - pointer to array of pointers to args
+    ll_restype - rffi.VOIDP - pointer to result
+    ll_userdata - a special structure which holds necessary information
+                  (what the real callback is for example), casted to VOIDP
+    """
+    e = cerrno.get_real_errno()
+    ll_res = rffi.cast(rffi.CCHARP, ll_res)
+    unique_id = rffi.cast(lltype.Signed, ll_userdata)
+    callback = global_callback_mapping.get(unique_id)
+    if callback is None:
+        # oups!
+        try:
+            os.write(STDERR, "SystemError: invoking a callback "
+                             "that was already freed\n")
+        except OSError:
+            pass
+        # In this case, we don't even know how big ll_res is.  Let's assume
+        # it is just a 'ffi_arg', and store 0 there.
+        misc._raw_memclear(ll_res, SIZE_OF_FFI_ARG)
+        return
+    #
+    ec = None
+    try:
+        ec = cerrno.get_errno_container(callback.space)
+        cerrno.save_errno_into(ec, e)
+        try:
+            callback.invoke(ll_args, ll_res)
+        except OperationError, e:
+            # got an app-level exception
+            callback.print_error(e)
+            callback.write_error_return_value(ll_res)
+        #
+    except Exception, e:
+        # oups! last-level attempt to recover.
+        try:
+            os.write(STDERR, "SystemError: callback raised ")
+            os.write(STDERR, str(e))
+            os.write(STDERR, "\n")
+        except OSError:
+            pass
+        callback.write_error_return_value(ll_res)
+    if ec is not None:
+        cerrno.restore_errno_from(ec)
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -0,0 +1,309 @@
+import operator
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef, make_weakref_descr
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib import objectmodel, rgc
+from pypy.tool.sourcetools import func_with_new_name
+
+from pypy.module._cffi_backend import misc
+
+
+class W_CData(Wrappable):
+    _attrs_ = ['space', '_cdata', 'ctype', '_lifeline_']
+    _immutable_fields_ = ['_cdata', 'ctype']
+    _cdata = lltype.nullptr(rffi.CCHARP.TO)
+
+    def __init__(self, space, cdata, ctype):
+        from pypy.module._cffi_backend import ctypeprim
+        assert lltype.typeOf(cdata) == rffi.CCHARP
+        assert isinstance(ctype, ctypeprim.W_CType)
+        self.space = space
+        self._cdata = cdata    # don't forget keepalive_until_here!
+        self.ctype = ctype
+
+    def _repr_extra(self):
+        extra = self.ctype.extra_repr(self._cdata)
+        keepalive_until_here(self)
+        return extra
+
+    def _repr_extra_owning(self):
+        from pypy.module._cffi_backend.ctypeptr import W_CTypePointer
+        ctype = self.ctype
+        if isinstance(ctype, W_CTypePointer):
+            num_bytes = ctype.ctitem.size
+        else:
+            num_bytes = self._sizeof()
+        return 'owning %d bytes' % num_bytes
+
+    def repr(self):
+        extra2 = self._repr_extra()
+        extra1 = ''
+        if not isinstance(self, W_CDataNewOwning):
+            # it's slightly confusing to get "<cdata 'struct foo' 0x...>"
+            # because the struct foo is not owned.  Trying to make it
+            # clearer, write in this case "<cdata 'struct foo &' 0x...>".
+            from pypy.module._cffi_backend import ctypestruct
+            if isinstance(self.ctype, ctypestruct.W_CTypeStructOrUnion):
+                extra1 = ' &'
+        return self.space.wrap("<cdata '%s%s' %s>" % (
+            self.ctype.name, extra1, extra2))
+
+    def nonzero(self):
+        return self.space.wrap(bool(self._cdata))
+
+    def int(self):
+        w_result = self.ctype.int(self._cdata)
+        keepalive_until_here(self)
+        return w_result
+
+    def long(self):
+        w_result = self.int()
+        space = self.space
+        if space.is_w(space.type(w_result), space.w_int):
+            w_result = space.newlong(space.int_w(w_result))
+        return w_result
+
+    def float(self):
+        w_result = self.ctype.float(self._cdata)
+        keepalive_until_here(self)
+        return w_result
+
+    def len(self):
+        from pypy.module._cffi_backend import ctypearray
+        space = self.space
+        if isinstance(self.ctype, ctypearray.W_CTypeArray):
+            return space.wrap(self.get_array_length())
+        raise operationerrfmt(space.w_TypeError,
+                              "cdata of type '%s' has no len()",
+                              self.ctype.name)
+
+    def _make_comparison(name):
+        op = getattr(operator, name)
+        requires_ordering = name not in ('eq', 'ne')
+        #
+        def _cmp(self, w_other):
+            from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitive
+            space = self.space
+            cdata1 = self._cdata
+            other = space.interpclass_w(w_other)
+            if isinstance(other, W_CData):
+                cdata2 = other._cdata
+            else:
+                return space.w_NotImplemented
+
+            if requires_ordering:
+                if (isinstance(self.ctype, W_CTypePrimitive) or
+                    isinstance(other.ctype, W_CTypePrimitive)):
+                    raise OperationError(space.w_TypeError,
+                        space.wrap("cannot do comparison on a primitive cdata"))
+                cdata1 = rffi.cast(lltype.Unsigned, cdata1)
+                cdata2 = rffi.cast(lltype.Unsigned, cdata2)
+            return space.newbool(op(cdata1, cdata2))
+        #
+        return func_with_new_name(_cmp, name)
+
+    lt = _make_comparison('lt')
+    le = _make_comparison('le')
+    eq = _make_comparison('eq')
+    ne = _make_comparison('ne')
+    gt = _make_comparison('gt')
+    ge = _make_comparison('ge')
+
+    def hash(self):
+        h = (objectmodel.compute_identity_hash(self.ctype) ^
+             rffi.cast(lltype.Signed, self._cdata))
+        return self.space.wrap(h)
+
+    def getitem(self, w_index):
+        space = self.space
+        i = space.getindex_w(w_index, space.w_IndexError)
+        ctype = self.ctype._check_subscript_index(self, i)
+        w_o = self._do_getitem(ctype, i)
+        keepalive_until_here(self)
+        return w_o
+
+    def _do_getitem(self, ctype, i):
+        ctitem = ctype.ctitem
+        return ctitem.convert_to_object(
+            rffi.ptradd(self._cdata, i * ctitem.size))
+
+    def setitem(self, w_index, w_value):
+        space = self.space
+        i = space.getindex_w(w_index, space.w_IndexError)
+        ctype = self.ctype._check_subscript_index(self, i)
+        ctitem = ctype.ctitem
+        ctitem.convert_from_object(
+            rffi.ptradd(self._cdata, i * ctitem.size),
+            w_value)
+        keepalive_until_here(self)
+
+    def _add_or_sub(self, w_other, sign):
+        space = self.space
+        i = sign * space.getindex_w(w_other, space.w_OverflowError)
+        return self.ctype.add(self._cdata, i)
+
+    def add(self, w_other):
+        return self._add_or_sub(w_other, +1)
+
+    def sub(self, w_other):
+        space = self.space
+        ob = space.interpclass_w(w_other)
+        if isinstance(ob, W_CData):
+            from pypy.module._cffi_backend import ctypeptr, ctypearray
+            ct = ob.ctype
+            if isinstance(ct, ctypearray.W_CTypeArray):
+                ct = ct.ctptr
+            #
+            if (ct is not self.ctype or
+                   not isinstance(ct, ctypeptr.W_CTypePointer) or
+                   ct.ctitem.size <= 0):
+                raise operationerrfmt(space.w_TypeError,
+                    "cannot subtract cdata '%s' and cdata '%s'",
+                    self.ctype.name, ct.name)
+            #
+            diff = (rffi.cast(lltype.Signed, self._cdata) -
+                    rffi.cast(lltype.Signed, ob._cdata)) // ct.ctitem.size
+            return space.wrap(diff)
+        #
+        return self._add_or_sub(w_other, -1)
+
+    def getcfield(self, w_attr):
+        return self.ctype.getcfield(self.space.str_w(w_attr))
+
+    def getattr(self, w_attr):
+        w_res = self.getcfield(w_attr).read(self._cdata)
+        keepalive_until_here(self)
+        return w_res
+
+    def setattr(self, w_attr, w_value):
+        self.getcfield(w_attr).write(self._cdata, w_value)
+        keepalive_until_here(self)
+
+    def call(self, args_w):
+        w_result = self.ctype.call(self._cdata, args_w)
+        keepalive_until_here(self)
+        return w_result
+
+    def iter(self):
+        return self.ctype.iter(self)
+
+    def write_raw_integer_data(self, source):
+        misc.write_raw_integer_data(self._cdata, source, self.ctype.size)
+        keepalive_until_here(self)
+
+    def write_raw_float_data(self, source):
+        misc.write_raw_float_data(self._cdata, source, self.ctype.size)
+        keepalive_until_here(self)
+
+    def convert_to_object(self):
+        w_obj = self.ctype.convert_to_object(self._cdata)
+        keepalive_until_here(self)
+        return w_obj
+
+    def get_array_length(self):
+        from pypy.module._cffi_backend import ctypearray
+        ctype = self.ctype
+        assert isinstance(ctype, ctypearray.W_CTypeArray)
+        length = ctype.length
+        assert length >= 0
+        return length
+
+    def _sizeof(self):
+        return self.ctype.size
+
+
+class W_CDataMem(W_CData):
+    """This is the base class used for cdata objects that own and free
+    their memory.  Used directly by the results of cffi.cast('int', x)
+    or other primitive explicitly-casted types.  It is further subclassed
+    by W_CDataNewOwning."""
+    _attrs_ = []
+
+    def __init__(self, space, size, ctype):
+        cdata = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw', zero=True)
+        W_CData.__init__(self, space, cdata, ctype)
+
+    @rgc.must_be_light_finalizer
+    def __del__(self):
+        lltype.free(self._cdata, flavor='raw')
+
+
+class W_CDataNewOwning(W_CDataMem):
+    """This is the class used for the cata objects created by newp()."""
+    _attrs_ = []
+
+    def _repr_extra(self):
+        return self._repr_extra_owning()
+
+
+class W_CDataNewOwningLength(W_CDataNewOwning):
+    """Subclass with an explicit length, for allocated instances of
+    the C type 'foo[]'."""
+    _attrs_ = ['length']
+    _immutable_fields_ = ['length']
+
+    def __init__(self, space, size, ctype, length):
+        W_CDataNewOwning.__init__(self, space, size, ctype)
+        self.length = length
+
+    def _sizeof(self):
+        from pypy.module._cffi_backend import ctypearray
+        ctype = self.ctype
+        assert isinstance(ctype, ctypearray.W_CTypeArray)
+        return self.length * ctype.ctitem.size
+
+    def get_array_length(self):
+        return self.length
+
+
+class W_CDataPtrToStructOrUnion(W_CData):
+    """This subclass is used for the pointer returned by new('struct foo').
+    It has a strong reference to a W_CDataNewOwning that really owns the
+    struct, which is the object returned by the app-level expression 'p[0]'.
+    But it is not itself owning any memory, although its repr says so;
+    it is merely a co-owner."""
+    _attrs_ = ['structobj']
+    _immutable_fields_ = ['structobj']
+
+    def __init__(self, space, cdata, ctype, structobj):
+        W_CData.__init__(self, space, cdata, ctype)
+        self.structobj = structobj
+
+    def _repr_extra(self):
+        return self._repr_extra_owning()
+
+    def _do_getitem(self, ctype, i):
+        assert i == 0
+        return self.structobj
+
+
+W_CData.typedef = TypeDef(
+    'CData',
+    __module__ = '_cffi_backend',
+    __repr__ = interp2app(W_CData.repr),
+    __nonzero__ = interp2app(W_CData.nonzero),
+    __int__ = interp2app(W_CData.int),
+    __long__ = interp2app(W_CData.long),
+    __float__ = interp2app(W_CData.float),
+    __len__ = interp2app(W_CData.len),
+    __lt__ = interp2app(W_CData.lt),
+    __le__ = interp2app(W_CData.le),
+    __eq__ = interp2app(W_CData.eq),
+    __ne__ = interp2app(W_CData.ne),
+    __gt__ = interp2app(W_CData.gt),
+    __ge__ = interp2app(W_CData.ge),
+    __hash__ = interp2app(W_CData.hash),
+    __getitem__ = interp2app(W_CData.getitem),
+    __setitem__ = interp2app(W_CData.setitem),
+    __add__ = interp2app(W_CData.add),
+    __sub__ = interp2app(W_CData.sub),
+    __getattr__ = interp2app(W_CData.getattr),
+    __setattr__ = interp2app(W_CData.setattr),
+    __call__ = interp2app(W_CData.call),
+    __iter__ = interp2app(W_CData.iter),
+    __weakref__ = make_weakref_descr(W_CData),
+    )
+W_CData.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/cerrno.py b/pypy/module/_cffi_backend/cerrno.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/cerrno.py
@@ -0,0 +1,29 @@
+from pypy.rlib import rposix
+from pypy.interpreter.executioncontext import ExecutionContext
+from pypy.interpreter.gateway import unwrap_spec
+
+
+ExecutionContext._cffi_saved_errno = 0
+
+
+def get_errno_container(space):
+    return space.getexecutioncontext()
+
+get_real_errno = rposix.get_errno
+
+
+def restore_errno_from(ec):
+    rposix.set_errno(ec._cffi_saved_errno)
+
+def save_errno_into(ec, errno):
+    ec._cffi_saved_errno = errno
+
+
+def get_errno(space):
+    ec = get_errno_container(space)
+    return space.wrap(ec._cffi_saved_errno)
+
+ at unwrap_spec(errno=int)
+def set_errno(space, errno):
+    ec = get_errno_container(space)
+    ec._cffi_saved_errno = errno
diff --git a/pypy/module/_cffi_backend/ctypearray.py b/pypy/module/_cffi_backend/ctypearray.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/ctypearray.py
@@ -0,0 +1,128 @@
+"""
+Arrays.
+"""
+
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.typedef import TypeDef
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib.rarithmetic import ovfcheck
+
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveChar
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveUniChar
+from pypy.module._cffi_backend.ctypeptr import W_CTypePtrOrArray
+from pypy.module._cffi_backend import cdataobj
+
+
+class W_CTypeArray(W_CTypePtrOrArray):
+    _attrs_            = ['ctptr']
+    _immutable_fields_ = ['ctptr']
+
+    def __init__(self, space, ctptr, length, arraysize, extra):
+        W_CTypePtrOrArray.__init__(self, space, arraysize, extra, 0,
+                                   ctptr.ctitem)
+        self.length = length
+        self.ctptr = ctptr
+
+    def _alignof(self):
+        return self.ctitem.alignof()
+
+    def newp(self, w_init):
+        space = self.space
+        datasize = self.size
+        #
+        if datasize < 0:
+            if (space.isinstance_w(w_init, space.w_list) or
+                space.isinstance_w(w_init, space.w_tuple)):
+                length = space.int_w(space.len(w_init))
+            elif space.isinstance_w(w_init, space.w_basestring):
+                # from a string, we add the null terminator
+                length = space.int_w(space.len(w_init)) + 1
+            else:
+                length = space.getindex_w(w_init, space.w_OverflowError)
+                if length < 0:
+                    raise OperationError(space.w_ValueError,
+                                         space.wrap("negative array length"))
+                w_init = space.w_None
+            #
+            try:
+                datasize = ovfcheck(length * self.ctitem.size)
+            except OverflowError:
+                raise OperationError(space.w_OverflowError,
+                    space.wrap("array size would overflow a ssize_t"))
+            #
+            cdata = cdataobj.W_CDataNewOwningLength(space, datasize,
+                                                    self, length)
+        #
+        else:
+            cdata = cdataobj.W_CDataNewOwning(space, datasize, self)
+        #
+        if not space.is_w(w_init, space.w_None):
+            self.convert_from_object(cdata._cdata, w_init)
+            keepalive_until_here(cdata)
+        return cdata
+
+    def _check_subscript_index(self, w_cdata, i):
+        space = self.space
+        if i < 0:
+            raise OperationError(space.w_IndexError,
+                                 space.wrap("negative index not supported"))
+        if i >= w_cdata.get_array_length():
+            raise operationerrfmt(space.w_IndexError,
+                "index too large for cdata '%s' (expected %d < %d)",
+                self.name, i, w_cdata.get_array_length())
+        return self
+
+    def convert_from_object(self, cdata, w_ob):
+        self.convert_array_from_object(cdata, w_ob)
+
+    def convert_to_object(self, cdata):
+        if self.length < 0:
+            # we can't return a <cdata 'int[]'> here, because we don't
+            # know the length to give it.  As a compromize, returns
+            # <cdata 'int *'> in this case.
+            self = self.ctptr
+        #
+        return cdataobj.W_CData(self.space, cdata, self)
+
+    def add(self, cdata, i):
+        p = rffi.ptradd(cdata, i * self.ctitem.size)
+        return cdataobj.W_CData(self.space, p, self.ctptr)
+
+    def iter(self, cdata):
+        return W_CDataIter(self.space, self.ctitem, cdata)
+
+    def get_vararg_type(self):
+        return self.ctptr
+
+
+class W_CDataIter(Wrappable):
+    _immutable_fields_ = ['ctitem', 'cdata', '_stop']    # but not '_next'
+
+    def __init__(self, space, ctitem, cdata):
+        self.space = space
+        self.ctitem = ctitem
+        self.cdata = cdata
+        length = cdata.get_array_length()
+        self._next = cdata._cdata
+        self._stop = rffi.ptradd(cdata._cdata, length * ctitem.size)
+
+    def iter_w(self):
+        return self.space.wrap(self)
+
+    def next_w(self):
+        result = self._next
+        if result == self._stop:
+            raise OperationError(self.space.w_StopIteration, self.space.w_None)
+        self._next = rffi.ptradd(result, self.ctitem.size)
+        return self.ctitem.convert_to_object(result)
+
+W_CDataIter.typedef = TypeDef(
+    'CDataIter',
+    __module__ = '_cffi_backend',
+    __iter__ = interp2app(W_CDataIter.iter_w),
+    next = interp2app(W_CDataIter.next_w),
+    )
+W_CDataIter.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/ctypeenum.py b/pypy/module/_cffi_backend/ctypeenum.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/ctypeenum.py
@@ -0,0 +1,88 @@
+"""
+Enums.
+"""
+
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib.rarithmetic import intmask, r_ulonglong
+from pypy.rlib.objectmodel import keepalive_until_here
+
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned
+from pypy.module._cffi_backend import misc
+
+
+class W_CTypeEnum(W_CTypePrimitiveSigned):
+    _attrs_            = ['enumerators2values', 'enumvalues2erators']
+    _immutable_fields_ = ['enumerators2values', 'enumvalues2erators']
+
+    def __init__(self, space, name, enumerators, enumvalues):
+        from pypy.module._cffi_backend.newtype import alignment
+        name = "enum " + name
+        size = rffi.sizeof(rffi.INT)
+        align = alignment(rffi.INT)
+        W_CTypePrimitiveSigned.__init__(self, space, size,
+                                        name, len(name), align)
+        self.enumerators2values = {}   # str -> int
+        self.enumvalues2erators = {}   # int -> str
+        for i in range(len(enumerators)-1, -1, -1):
+            self.enumerators2values[enumerators[i]] = enumvalues[i]
+            self.enumvalues2erators[enumvalues[i]] = enumerators[i]
+
+    def _getfields(self):
+        space = self.space
+        lst = []
+        for enumerator in self.enumerators2values:
+            enumvalue = self.enumerators2values[enumerator]
+            lst.append(space.newtuple([space.wrap(enumvalue),
+                                       space.wrap(enumerator)]))
+        w_lst = space.newlist(lst)
+        space.call_method(w_lst, 'sort')
+        return w_lst
+
+    def string(self, cdataobj, maxlen):
+        w_result = self.convert_to_object(cdataobj._cdata)
+        keepalive_until_here(cdataobj)
+        return w_result
+
+    def convert_to_object(self, cdata):
+        value = intmask(misc.read_raw_signed_data(cdata, self.size))
+        try:
+            enumerator = self.enumvalues2erators[value]
+        except KeyError:
+            enumerator = '#%d' % (value,)
+        return self.space.wrap(enumerator)
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        try:
+            return W_CTypePrimitiveSigned.convert_from_object(self, cdata,
+                                                              w_ob)
+        except OperationError, e:
+            if not e.match(space, space.w_TypeError):
+                raise
+        if space.isinstance_w(w_ob, space.w_str):
+            value = self.convert_enum_string_to_int(space.str_w(w_ob))
+            value = r_ulonglong(value)
+            misc.write_raw_integer_data(cdata, value, self.size)
+        else:
+            raise self._convert_error("str or int", w_ob)
+
+    def cast_str(self, w_ob):
+        space = self.space
+        return self.convert_enum_string_to_int(space.str_w(w_ob))
+
+    def convert_enum_string_to_int(self, s):
+        space = self.space
+        if s.startswith('#'):
+            try:
+                return int(s[1:])     # xxx is it RPython?
+            except ValueError:
+                raise OperationError(space.w_ValueError,
+                                     space.wrap("invalid literal after '#'"))
+        else:
+            try:
+                return self.enumerators2values[s]
+            except KeyError:
+                raise operationerrfmt(space.w_ValueError,
+                                      "'%s' is not an enumerator for %s",
+                                      s, self.name)
diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -0,0 +1,422 @@
+"""
+Function pointers.
+"""
+
+import sys
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+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
+
+from pypy.module._cffi_backend.ctypeobj import W_CType
+from pypy.module._cffi_backend.ctypeptr import W_CTypePtrBase, W_CTypePointer
+from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid
+from pypy.module._cffi_backend.ctypestruct import W_CTypeStruct
+from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveUnsigned
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveCharOrUniChar
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveFloat
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveLongDouble
+from pypy.module._cffi_backend import ctypearray, cdataobj, cerrno
+
+
+class W_CTypeFunc(W_CTypePtrBase):
+    _attrs_            = ['fargs', 'ellipsis', 'cif_descr']
+    _immutable_fields_ = ['fargs[*]', 'ellipsis', 'cif_descr']
+
+    def __init__(self, space, fargs, fresult, ellipsis):
+        extra = self._compute_extra_text(fargs, fresult, ellipsis)
+        size = rffi.sizeof(rffi.VOIDP)
+        W_CTypePtrBase.__init__(self, space, size, extra, 2, fresult,
+                                could_cast_anything=False)
+        self.fargs = fargs
+        self.ellipsis = bool(ellipsis)
+        # fresult is stored in self.ctitem
+
+        if not ellipsis:
+            # Functions with '...' varargs are stored without a cif_descr
+            # at all.  The cif is computed on every call from the actual
+            # types passed in.  For all other functions, the cif_descr
+            # is computed here.
+            CifDescrBuilder(fargs, fresult).rawallocate(self)
+
+    def new_ctypefunc_completing_argtypes(self, args_w):
+        space = self.space
+        nargs_declared = len(self.fargs)
+        fvarargs = [None] * len(args_w)
+        fvarargs[:nargs_declared] = self.fargs
+        for i in range(nargs_declared, len(args_w)):
+            w_obj = args_w[i]
+            if isinstance(w_obj, cdataobj.W_CData):
+                ct = w_obj.ctype.get_vararg_type()
+            else:
+                raise operationerrfmt(space.w_TypeError,
+                             "argument %d passed in the variadic part "
+                             "needs to be a cdata object (got %s)",
+                             i + 1, space.type(w_obj).getname(space))
+            fvarargs[i] = ct
+        ctypefunc = instantiate(W_CTypeFunc)
+        ctypefunc.space = space
+        ctypefunc.fargs = fvarargs
+        ctypefunc.ctitem = self.ctitem
+        CifDescrBuilder(fvarargs, self.ctitem).rawallocate(ctypefunc)
+        return ctypefunc
+
+    def __del__(self):
+        if self.cif_descr:
+            lltype.free(self.cif_descr, flavor='raw')
+
+    def _compute_extra_text(self, fargs, fresult, ellipsis):
+        argnames = ['(*)(']
+        for i, farg in enumerate(fargs):
+            if i > 0:
+                argnames.append(', ')
+            argnames.append(farg.name)
+        if ellipsis:
+            if len(fargs) > 0:
+                argnames.append(', ')
+            argnames.append('...')
+        argnames.append(')')
+        return ''.join(argnames)
+
+
+    def call(self, funcaddr, args_w):
+        if self.cif_descr:
+            # regular case: this function does not take '...' arguments
+            self = jit.promote(self)
+            nargs_declared = len(self.fargs)
+            if len(args_w) != nargs_declared:
+                space = self.space
+                raise operationerrfmt(space.w_TypeError,
+                                      "'%s' expects %d arguments, got %d",
+                                      self.name, nargs_declared, len(args_w))
+            return self._call(funcaddr, args_w)
+        else:
+            # call of a variadic function
+            return self.call_varargs(funcaddr, args_w)
+
+    @jit.dont_look_inside
+    def call_varargs(self, funcaddr, args_w):
+        nargs_declared = len(self.fargs)
+        if len(args_w) < nargs_declared:
+            space = self.space
+            raise operationerrfmt(space.w_TypeError,
+                                  "'%s' expects at least %d arguments, got %d",
+                                  self.name, nargs_declared, len(args_w))
+        completed = self.new_ctypefunc_completing_argtypes(args_w)
+        return completed._call(funcaddr, args_w)
+
+    # The following is the core of function calls.  It is @unroll_safe,
+    # which means that the JIT is free to unroll the argument handling.
+    # But in case the function takes variable arguments, we don't unroll
+    # this (yet) for better safety: this is handled by @dont_look_inside
+    # in call_varargs.
+    @jit.unroll_safe
+    def _call(self, funcaddr, args_w):
+        space = self.space
+        cif_descr = self.cif_descr
+        size = cif_descr.exchange_size
+        mustfree_max_plus_1 = 0
+        buffer = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
+        try:
+            for i in range(len(args_w)):
+                data = rffi.ptradd(buffer, cif_descr.exchange_args[i])
+                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
+
+            ec = cerrno.get_errno_container(space)
+            cerrno.restore_errno_from(ec)
+            jit_libffi.jit_ffi_call(cif_descr,
+                                    rffi.cast(rffi.VOIDP, funcaddr),
+                                    buffer)
+            e = cerrno.get_real_errno()
+            cerrno.save_errno_into(ec, e)
+
+            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]
+                if isinstance(argtype, W_CTypePointer):
+                    data = rffi.ptradd(buffer, cif_descr.exchange_args[i])
+                    if get_mustfree_flag(data):
+                        raw_string = rffi.cast(rffi.CCHARPP, data)[0]
+                        lltype.free(raw_string, flavor='raw')
+            lltype.free(buffer, flavor='raw')
+        return w_res
+
+def get_mustfree_flag(data):
+    return ord(rffi.ptradd(data, -1)[0])
+
+def set_mustfree_flag(data, flag):
+    rffi.ptradd(data, -1)[0] = chr(flag)
+
+def _get_abi(space, name):
+    abi = getattr(clibffi, name)
+    assert isinstance(abi, int)
+    return space.wrap(abi)
+
+# ____________________________________________________________
+
+
+W_CTypeFunc.cif_descr = lltype.nullptr(CIF_DESCRIPTION)     # default value
+
+BIG_ENDIAN = sys.byteorder == 'big'
+
+
+# ----------
+# We attach to the classes small methods that return a 'ffi_type'
+def _missing_ffi_type(self, cifbuilder):
+    space = self.space
+    if self.size < 0:
+        raise operationerrfmt(space.w_TypeError,
+                              "ctype '%s' has incomplete type",
+                              self.name)
+    raise operationerrfmt(space.w_NotImplementedError,
+                          "ctype '%s' (size %d) not supported as argument"
+                          " or return value",
+                          self.name, self.size)
+
+def _struct_ffi_type(self, cifbuilder):
+    if self.size >= 0:
+        return cifbuilder.fb_struct_ffi_type(self)
+    return _missing_ffi_type(self, cifbuilder)
+
+def _primsigned_ffi_type(self, cifbuilder):
+    size = self.size
+    if   size == 1: return clibffi.ffi_type_sint8
+    elif size == 2: return clibffi.ffi_type_sint16
+    elif size == 4: return clibffi.ffi_type_sint32
+    elif size == 8: return clibffi.ffi_type_sint64
+    return _missing_ffi_type(self, cifbuilder)
+
+def _primunsigned_ffi_type(self, cifbuilder):
+    size = self.size
+    if   size == 1: return clibffi.ffi_type_uint8
+    elif size == 2: return clibffi.ffi_type_uint16
+    elif size == 4: return clibffi.ffi_type_uint32
+    elif size == 8: return clibffi.ffi_type_uint64
+    return _missing_ffi_type(self, cifbuilder)
+
+def _primfloat_ffi_type(self, cifbuilder):
+    size = self.size
+    if   size == 4: return clibffi.ffi_type_float
+    elif size == 8: return clibffi.ffi_type_double
+    return _missing_ffi_type(self, cifbuilder)
+
+def _primlongdouble_ffi_type(self, cifbuilder):
+    return clibffi.ffi_type_longdouble
+
+def _ptr_ffi_type(self, cifbuilder):
+    return clibffi.ffi_type_pointer
+
+def _void_ffi_type(self, cifbuilder):
+    return clibffi.ffi_type_void
+
+W_CType._get_ffi_type                       = _missing_ffi_type
+W_CTypeStruct._get_ffi_type                 = _struct_ffi_type
+W_CTypePrimitiveSigned._get_ffi_type        = _primsigned_ffi_type
+W_CTypePrimitiveCharOrUniChar._get_ffi_type = _primunsigned_ffi_type
+W_CTypePrimitiveUnsigned._get_ffi_type      = _primunsigned_ffi_type
+W_CTypePrimitiveFloat._get_ffi_type         = _primfloat_ffi_type
+W_CTypePrimitiveLongDouble._get_ffi_type    = _primlongdouble_ffi_type
+W_CTypePtrBase._get_ffi_type                = _ptr_ffi_type
+#W_CTypeVoid._get_ffi_type                  = _void_ffi_type -- special-cased
+# ----------
+
+
+class CifDescrBuilder(object):
+    rawmem = lltype.nullptr(rffi.CCHARP.TO)
+
+    def __init__(self, fargs, fresult):
+        self.fargs = fargs
+        self.fresult = fresult
+
+    def fb_alloc(self, size):
+        size = llmemory.raw_malloc_usage(size)
+        if not self.bufferp:
+            self.nb_bytes += size
+            return lltype.nullptr(rffi.CCHARP.TO)
+        else:
+            result = self.bufferp
+            self.bufferp = rffi.ptradd(result, size)
+            return result
+
+
+    def fb_fill_type(self, ctype, is_result_type):
+        if is_result_type and isinstance(ctype, W_CTypeVoid):
+            return clibffi.ffi_type_void
+        return ctype._get_ffi_type(self)
+
+    def fb_struct_ffi_type(self, ctype):
+        # We can't pass a struct that was completed by verify().
+        # Issue: assume verify() is given "struct { long b; ...; }".
+        # Then it will complete it in the same way whether it is actually
+        # "struct { long a, b; }" or "struct { double a; long b; }".
+        # But on 64-bit UNIX, these two structs are passed by value
+        # differently: e.g. on x86-64, "b" ends up in register "rsi" in
+        # the first case and "rdi" in the second case.
+        #
+        # Another reason for 'custom_field_pos' would be anonymous
+        # nested structures: we lost the information about having it
+        # here, so better safe (and forbid it) than sorry (and maybe
+        # crash).
+        space = self.space
+        if ctype.custom_field_pos:
+            raise OperationError(space.w_TypeError,
+                                 space.wrap(
+               "cannot pass as an argument a struct that was completed "
+               "with verify() (see pypy/module/_cffi_backend/ctypefunc.py "
+               "for details)"))
+
+        # allocate an array of (n + 1) ffi_types
+        n = len(ctype.fields_list)
+        elements = self.fb_alloc(rffi.sizeof(FFI_TYPE_P) * (n + 1))
+        elements = rffi.cast(FFI_TYPE_PP, elements)
+
+        # fill it with the ffi types of the fields
+        for i, cf in enumerate(ctype.fields_list):
+            if cf.is_bitfield():
+                raise OperationError(space.w_NotImplementedError,
+                    space.wrap("cannot pass as argument a struct "
+                               "with bit fields"))
+            ffi_subtype = self.fb_fill_type(cf.ctype, False)
+            if elements:
+                elements[i] = ffi_subtype
+
+        # zero-terminate the array
+        if elements:
+            elements[n] = lltype.nullptr(FFI_TYPE_P.TO)
+
+        # allocate and fill an ffi_type for the struct itself
+        ffistruct = self.fb_alloc(rffi.sizeof(FFI_TYPE))
+        ffistruct = rffi.cast(FFI_TYPE_P, ffistruct)
+        if ffistruct:
+            rffi.setintfield(ffistruct, 'c_size', ctype.size)
+            rffi.setintfield(ffistruct, 'c_alignment', ctype.alignof())
+            rffi.setintfield(ffistruct, 'c_type', clibffi.FFI_TYPE_STRUCT)
+            ffistruct.c_elements = elements
+
+        return ffistruct
+
+
+    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)
+        self.fb_alloc(llmemory.sizeof(CIF_DESCRIPTION, nargs))
+
+        # next comes an array of 'ffi_type*', one per argument
+        atypes = self.fb_alloc(rffi.sizeof(FFI_TYPE_P) * nargs)
+        self.atypes = rffi.cast(FFI_TYPE_PP, atypes)
+
+        # next comes the result type data
+        self.rtype = self.fb_fill_type(self.fresult, True)
+
+        # next comes each argument's type data
+        for i, farg in enumerate(self.fargs):
+            atype = self.fb_fill_type(farg, False)
+            if self.atypes:
+                self.atypes[i] = atype
+
+
+    def align_arg(self, n):
+        return (n + 7) & ~7
+
+    def fb_build_exchange(self, cif_descr):
+        nargs = len(self.fargs)
+
+        # first, enough room for an array of 'nargs' pointers
+        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
+
+        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
+        for i, farg in enumerate(self.fargs):
+            if isinstance(farg, W_CTypePointer):
+                exchange_offset += 1   # for the "must free" flag
+            exchange_offset = self.align_arg(exchange_offset)
+            cif_descr.exchange_args[i] = exchange_offset
+            exchange_offset += rffi.getintfield(self.atypes[i], 'c_size')
+
+        # store the exchange data size
+        cif_descr.exchange_size = exchange_offset
+
+    def fb_extra_fields(self, cif_descr):
+        cif_descr.abi = clibffi.FFI_DEFAULT_ABI    # XXX
+        cif_descr.nargs = len(self.fargs)
+        cif_descr.rtype = self.rtype
+        cif_descr.atypes = self.atypes
+
+    @jit.dont_look_inside
+    def rawallocate(self, ctypefunc):
+        space = ctypefunc.space
+        self.space = space
+
+        # compute the total size needed in the CIF_DESCRIPTION buffer
+        self.nb_bytes = 0
+        self.bufferp = lltype.nullptr(rffi.CCHARP.TO)
+        self.fb_build()
+
+        # allocate the buffer
+        if we_are_translated():
+            rawmem = lltype.malloc(rffi.CCHARP.TO, self.nb_bytes,
+                                   flavor='raw')
+            rawmem = rffi.cast(CIF_DESCRIPTION_P, rawmem)
+        else:
+            # gross overestimation of the length below, but too bad
+            rawmem = lltype.malloc(CIF_DESCRIPTION_P.TO, self.nb_bytes,
+                                   flavor='raw')
+
+        # the buffer is automatically managed from the W_CTypeFunc instance
+        ctypefunc.cif_descr = rawmem
+
+        # call again fb_build() to really build the libffi data structures
+        self.bufferp = rffi.cast(rffi.CCHARP, rawmem)
+        self.fb_build()
+        assert self.bufferp == rffi.ptradd(rffi.cast(rffi.CCHARP, rawmem),
+                                           self.nb_bytes)
+
+        # fill in the 'exchange_*' fields
+        self.fb_build_exchange(rawmem)
+
+        # fill in the extra fields
+        self.fb_extra_fields(rawmem)
+
+        # call libffi's ffi_prep_cif() function
+        res = jit_libffi.jit_ffi_prep_cif(rawmem)
+        if res != clibffi.FFI_OK:
+            raise OperationError(space.w_SystemError,
+                space.wrap("libffi failed to build this function type"))
diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/ctypeobj.py
@@ -0,0 +1,175 @@
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.typedef import TypeDef
+from pypy.interpreter.typedef import make_weakref_descr
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+from pypy.rlib.objectmodel import we_are_translated
+
+from pypy.module._cffi_backend import cdataobj
+
+
+class W_CType(Wrappable):
+    _attrs_   = ['space', 'size',  'name', 'name_position', '_lifeline_']
+    _immutable_fields_ = ['size?', 'name', 'name_position']
+    # note that 'size' is not strictly immutable, because it can change
+    # from -1 to the real value in the W_CTypeStruct subclass.
+
+    cast_anything = False
+    is_primitive_integer = False
+
+    def __init__(self, space, size, name, name_position):
+        self.space = space
+        self.size = size     # size of instances, or -1 if unknown
+        self.name = name     # the name of the C type as a string
+        self.name_position = name_position
+        # 'name_position' is the index in 'name' where it must be extended,
+        # e.g. with a '*' or a variable name.
+
+    def repr(self):
+        space = self.space
+        return space.wrap("<ctype '%s'>" % (self.name,))
+
+    def extra_repr(self, cdata):
+        if cdata:
+            return '0x%x' % rffi.cast(lltype.Unsigned, cdata)
+        else:
+            return 'NULL'
+
+    def is_char_ptr_or_array(self):
+        return False
+
+    def is_unichar_ptr_or_array(self):
+        return False
+
+    def newp(self, w_init):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "expected a pointer or array ctype, got '%s'",
+                              self.name)
+
+    def cast(self, w_ob):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "cannot cast to '%s'", self.name)
+
+    def int(self, cdata):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "int() not supported on cdata '%s'", self.name)
+
+    def float(self, cdata):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "float() not supported on cdata '%s'", self.name)
+
+    def convert_to_object(self, cdata):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "cannot return a cdata '%s'", self.name)
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "cannot initialize cdata '%s'", self.name)
+
+    def convert_argument_from_object(self, cdata, w_ob):
+        self.convert_from_object(cdata, w_ob)
+        return False
+
+    def _convert_error(self, expected, w_got):
+        space = self.space
+        ob = space.interpclass_w(w_got)
+        if isinstance(ob, cdataobj.W_CData):
+            return operationerrfmt(space.w_TypeError,
+                                   "initializer for ctype '%s' must be a %s, "
+                                   "not cdata '%s'", self.name, expected,
+                                   ob.ctype.name)
+        else:
+            return operationerrfmt(space.w_TypeError,
+                                   "initializer for ctype '%s' must be a %s, "
+                                   "not %s", self.name, expected,
+                                   space.type(w_got).getname(space))
+
+    def _check_subscript_index(self, w_cdata, i):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "cdata of type '%s' cannot be indexed",
+                              self.name)
+
+    def string(self, cdataobj, maxlen):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "string(): unexpected cdata '%s' argument",
+                              self.name)
+
+    def add(self, cdata, i):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "cannot add a cdata '%s' and a number",
+                              self.name)
+
+    def insert_name(self, extra, extra_position):
+        name = '%s%s%s' % (self.name[:self.name_position],
+                           extra,
+                           self.name[self.name_position:])
+        name_position = self.name_position + extra_position
+        return name, name_position
+
+    def alignof(self):
+        align = self._alignof()
+        if not we_are_translated():
+            # obscure hack when untranslated, maybe, approximate, don't use
+            if isinstance(align, llmemory.FieldOffset):
+                align = rffi.sizeof(align.TYPE.y)
+        else:
+            # a different hack when translated, to avoid seeing constants
+            # of a symbolic integer type
+            align = llmemory.raw_malloc_usage(align)
+        return align
+
+    def _alignof(self):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "ctype '%s' is of unknown alignment",
+                              self.name)
+
+    def offsetof(self, fieldname):
+        space = self.space
+        raise OperationError(space.w_TypeError,
+                             space.wrap("not a struct or union ctype"))
+
+    def _getfields(self):
+        return None
+
+    def call(self, funcaddr, args_w):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "cdata '%s' is not callable", self.name)
+
+    def iter(self, cdata):
+        space = self.space
+        raise operationerrfmt(space.w_TypeError,
+                              "cdata '%s' does not support iteration",
+                              self.name)
+
+    def get_vararg_type(self):
+        return self
+
+    def getcfield(self, attr):
+        space = self.space
+        raise operationerrfmt(space.w_AttributeError,
+                              "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',
+    __module__ = '_cffi_backend',
+    __repr__ = interp2app(W_CType.repr),
+    __weakref__ = make_weakref_descr(W_CType),
+    )
+W_CType.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -0,0 +1,332 @@
+"""
+Primitives.
+"""
+
+from pypy.interpreter.error import operationerrfmt
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.rarithmetic import r_ulonglong
+from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib import jit
+
+from pypy.module._cffi_backend.ctypeobj import W_CType
+from pypy.module._cffi_backend import cdataobj, misc
+
+
+class W_CTypePrimitive(W_CType):
+    _attrs_            = ['align']
+    _immutable_fields_ = ['align']
+
+    def __init__(self, space, size, name, name_position, align):
+        W_CType.__init__(self, space, size, name, name_position)
+        self.align = align
+
+    def extra_repr(self, cdata):
+        w_ob = self.convert_to_object(cdata)
+        return self.space.str_w(self.space.repr(w_ob))
+
+    def _alignof(self):
+        return self.align
+
+    def cast_str(self, w_ob):
+        space = self.space
+        s = space.str_w(w_ob)
+        if len(s) != 1:
+            raise operationerrfmt(space.w_TypeError,
+                              "cannot cast string of length %d to ctype '%s'",
+                                  len(s), self.name)
+        return ord(s[0])
+
+    def cast_unicode(self, w_ob):
+        space = self.space
+        s = space.unicode_w(w_ob)
+        if len(s) != 1:
+            raise operationerrfmt(space.w_TypeError,
+                      "cannot cast unicode string of length %d to ctype '%s'",
+                                  len(s), self.name)
+        return ord(s[0])
+
+    def cast(self, w_ob):
+        from pypy.module._cffi_backend import ctypeptr
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+               isinstance(ob.ctype, ctypeptr.W_CTypePtrOrArray)):
+            value = rffi.cast(lltype.Signed, ob._cdata)
+            value = r_ulonglong(value)
+        elif space.isinstance_w(w_ob, space.w_str):
+            value = self.cast_str(w_ob)
+            value = r_ulonglong(value)
+        elif space.isinstance_w(w_ob, space.w_unicode):
+            value = self.cast_unicode(w_ob)
+            value = r_ulonglong(value)
+        else:
+            value = misc.as_unsigned_long_long(space, w_ob, strict=False)
+        w_cdata = cdataobj.W_CDataMem(space, self.size, self)
+        w_cdata.write_raw_integer_data(value)
+        return w_cdata
+
+    def _overflow(self, w_ob):
+        space = self.space
+        s = space.str_w(space.str(w_ob))
+        raise operationerrfmt(space.w_OverflowError,
+                              "integer %s does not fit '%s'", s, self.name)
+
+    def string(self, cdataobj, maxlen):
+        if self.size == 1:
+            s = cdataobj._cdata[0]
+            keepalive_until_here(cdataobj)
+            return self.space.wrap(s)
+        return W_CType.string(self, cdataobj, maxlen)
+
+
+class W_CTypePrimitiveCharOrUniChar(W_CTypePrimitive):
+    _attrs_ = []
+    is_primitive_integer = True
+
+    def get_vararg_type(self):
+        from pypy.module._cffi_backend import newtype
+        return newtype.new_primitive_type(self.space, "int")
+
+
+class W_CTypePrimitiveChar(W_CTypePrimitiveCharOrUniChar):
+    _attrs_ = []
+    cast_anything = True
+
+    def int(self, cdata):
+        return self.space.wrap(ord(cdata[0]))
+
+    def convert_to_object(self, cdata):
+        return self.space.wrap(cdata[0])
+
+    def _convert_to_char(self, w_ob):
+        space = self.space
+        if space.isinstance_w(w_ob, space.w_str):
+            s = space.str_w(w_ob)
+            if len(s) == 1:
+                return s[0]
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+               isinstance(ob.ctype, W_CTypePrimitiveChar)):
+            return ob._cdata[0]
+        raise self._convert_error("string of length 1", w_ob)
+
+    def convert_from_object(self, cdata, w_ob):
+        value = self._convert_to_char(w_ob)
+        cdata[0] = value
+
+
+class W_CTypePrimitiveUniChar(W_CTypePrimitiveCharOrUniChar):
+    _attrs_ = []
+
+    def int(self, cdata):
+        unichardata = rffi.cast(rffi.CWCHARP, cdata)
+        return self.space.wrap(ord(unichardata[0]))
+
+    def convert_to_object(self, cdata):
+        unichardata = rffi.cast(rffi.CWCHARP, cdata)
+        s = rffi.wcharpsize2unicode(unichardata, 1)
+        return self.space.wrap(s)
+
+    def string(self, cdataobj, maxlen):
+        w_res = self.convert_to_object(cdataobj._cdata)
+        keepalive_until_here(cdataobj)
+        return w_res
+
+    def _convert_to_unichar(self, w_ob):
+        space = self.space
+        if space.isinstance_w(w_ob, space.w_unicode):
+            s = space.unicode_w(w_ob)
+            if len(s) == 1:
+                return s[0]
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+               isinstance(ob.ctype, W_CTypePrimitiveUniChar)):
+            return rffi.cast(rffi.CWCHARP, ob._cdata)[0]
+        raise self._convert_error("unicode string of length 1", w_ob)
+
+    def convert_from_object(self, cdata, w_ob):
+        value = self._convert_to_unichar(w_ob)
+        rffi.cast(rffi.CWCHARP, cdata)[0] = value
+
+
+class W_CTypePrimitiveSigned(W_CTypePrimitive):
+    _attrs_            = ['value_fits_long', 'vmin', 'vrangemax']
+    _immutable_fields_ = ['value_fits_long', 'vmin', 'vrangemax']
+    is_primitive_integer = True
+
+    def __init__(self, *args):
+        W_CTypePrimitive.__init__(self, *args)
+        self.value_fits_long = self.size <= rffi.sizeof(lltype.Signed)
+        if self.size < rffi.sizeof(lltype.SignedLongLong):
+            sh = self.size * 8
+            self.vmin = r_ulonglong(-1) << (sh - 1)
+            self.vrangemax = (r_ulonglong(1) << sh) - 1
+
+    def int(self, cdata):
+        if self.value_fits_long:
+            # this case is to handle enums, but also serves as a slight
+            # performance improvement for some other primitive types
+            value = misc.read_raw_long_data(cdata, self.size)
+            return self.space.wrap(value)
+        else:
+            return self.convert_to_object(cdata)
+
+    def convert_to_object(self, cdata):
+        if self.value_fits_long:
+            value = misc.read_raw_long_data(cdata, self.size)
+            return self.space.wrap(value)
+        else:
+            value = misc.read_raw_signed_data(cdata, self.size)
+            return self.space.wrap(value)    # r_longlong => on 32-bit, 'long'
+
+    def convert_from_object(self, cdata, w_ob):
+        value = misc.as_long_long(self.space, w_ob)
+        if self.size < rffi.sizeof(lltype.SignedLongLong):
+            if r_ulonglong(value) - self.vmin > self.vrangemax:
+                self._overflow(w_ob)
+        value = r_ulonglong(value)
+        misc.write_raw_integer_data(cdata, value, self.size)
+
+    def get_vararg_type(self):
+        if self.size < rffi.sizeof(rffi.INT):
+            from pypy.module._cffi_backend import newtype
+            return newtype.new_primitive_type(self.space, "int")
+        return self
+
+
+class W_CTypePrimitiveUnsigned(W_CTypePrimitive):
+    _attrs_            = ['value_fits_long', 'vrangemax']
+    _immutable_fields_ = ['value_fits_long', 'vrangemax']
+    is_primitive_integer = True
+
+    def __init__(self, *args):
+        W_CTypePrimitive.__init__(self, *args)
+        self.value_fits_long = self.size < rffi.sizeof(lltype.Signed)
+        if self.size < rffi.sizeof(lltype.SignedLongLong):
+            sh = self.size * 8
+            self.vrangemax = (r_ulonglong(1) << sh) - 1
+
+    def int(self, cdata):
+        return self.convert_to_object(cdata)
+
+    def convert_from_object(self, cdata, w_ob):
+        value = misc.as_unsigned_long_long(self.space, w_ob, strict=True)
+        if self.size < rffi.sizeof(lltype.SignedLongLong):
+            if value > self.vrangemax:
+                self._overflow(w_ob)
+        misc.write_raw_integer_data(cdata, value, self.size)
+
+    def convert_to_object(self, cdata):
+        if self.value_fits_long:
+            value = misc.read_raw_ulong_data(cdata, self.size)
+            return self.space.wrap(value)
+        else:
+            value = misc.read_raw_unsigned_data(cdata, self.size)
+            return self.space.wrap(value)    # r_ulonglong => 'long' object
+
+    def get_vararg_type(self):
+        if self.size < rffi.sizeof(rffi.INT):
+            from pypy.module._cffi_backend import newtype
+            return newtype.new_primitive_type(self.space, "int")
+        return self
+
+
+class W_CTypePrimitiveFloat(W_CTypePrimitive):
+    _attrs_ = []
+
+    def cast(self, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if isinstance(ob, cdataobj.W_CData):
+            if not isinstance(ob.ctype, W_CTypePrimitive):
+                raise operationerrfmt(space.w_TypeError,
+                                      "cannot cast ctype '%s' to ctype '%s'",
+                                      ob.ctype.name, self.name)
+            w_ob = ob.convert_to_object()
+        #
+        if space.isinstance_w(w_ob, space.w_str):
+            value = self.cast_str(w_ob)
+        elif space.isinstance_w(w_ob, space.w_unicode):
+            value = self.cast_unicode(w_ob)
+        else:
+            value = space.float_w(w_ob)
+        w_cdata = cdataobj.W_CDataMem(space, self.size, self)
+        if not isinstance(self, W_CTypePrimitiveLongDouble):
+            w_cdata.write_raw_float_data(value)
+        else:
+            self._to_longdouble_and_write(value, w_cdata._cdata)
+            keepalive_until_here(w_cdata)
+        return w_cdata
+
+    def int(self, cdata):
+        w_value = self.float(cdata)
+        return self.space.int(w_value)
+
+    def float(self, cdata):
+        return self.convert_to_object(cdata)
+
+    def convert_to_object(self, cdata):
+        value = misc.read_raw_float_data(cdata, self.size)
+        return self.space.wrap(value)
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        value = space.float_w(space.float(w_ob))
+        misc.write_raw_float_data(cdata, value, self.size)
+
+
+class W_CTypePrimitiveLongDouble(W_CTypePrimitiveFloat):
+    _attrs_ = []
+
+    @jit.dont_look_inside
+    def extra_repr(self, cdata):
+        lvalue = misc.read_raw_longdouble_data(cdata)
+        return misc.longdouble2str(lvalue)
+
+    def cast(self, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+                isinstance(ob.ctype, W_CTypePrimitiveLongDouble)):
+            w_cdata = self.convert_to_object(ob._cdata)
+            keepalive_until_here(ob)
+            return w_cdata
+        else:
+            return W_CTypePrimitiveFloat.cast(self, w_ob)
+
+    @jit.dont_look_inside
+    def _to_longdouble_and_write(self, value, cdata):
+        lvalue = rffi.cast(rffi.LONGDOUBLE, value)
+        misc.write_raw_longdouble_data(cdata, lvalue)
+
+    @jit.dont_look_inside
+    def _read_from_longdouble(self, cdata):
+        lvalue = misc.read_raw_longdouble_data(cdata)
+        value = rffi.cast(lltype.Float, lvalue)
+        return value
+
+    @jit.dont_look_inside
+    def _copy_longdouble(self, cdatasrc, cdatadst):
+        lvalue = misc.read_raw_longdouble_data(cdatasrc)
+        misc.write_raw_longdouble_data(cdatadst, lvalue)
+
+    def float(self, cdata):
+        value = self._read_from_longdouble(cdata)
+        return self.space.wrap(value)
+
+    def convert_to_object(self, cdata):
+        w_cdata = cdataobj.W_CDataMem(self.space, self.size, self)
+        self._copy_longdouble(cdata, w_cdata._cdata)
+        keepalive_until_here(w_cdata)
+        return w_cdata
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+                isinstance(ob.ctype, W_CTypePrimitiveLongDouble)):
+            self._copy_longdouble(ob._cdata, cdata)
+            keepalive_until_here(ob)
+        else:
+            value = space.float_w(space.float(w_ob))
+            self._to_longdouble_and_write(value, cdata)
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -0,0 +1,291 @@
+"""
+Pointers.
+"""
+
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib.rarithmetic import ovfcheck
+
+from pypy.module._cffi_backend.ctypeobj import W_CType
+from pypy.module._cffi_backend import cdataobj, misc, ctypeprim
+
+
+class W_CTypePtrOrArray(W_CType):
+    _attrs_            = ['ctitem', 'can_cast_anything', 'is_struct_ptr',
+                          'length']
+    _immutable_fields_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr',
+                          'length']
+    length = -1
+
+    def __init__(self, space, size, extra, extra_position, ctitem,
+                 could_cast_anything=True):
+        from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
+        name, name_position = ctitem.insert_name(extra, extra_position)
+        W_CType.__init__(self, space, size, name, name_position)
+        # this is the "underlying type":
+        #  - for pointers, it is the pointed-to type
+        #  - for arrays, it is the array item type
+        #  - for functions, it is the return type
+        self.ctitem = ctitem
+        self.can_cast_anything = could_cast_anything and ctitem.cast_anything
+        self.is_struct_ptr = isinstance(ctitem, W_CTypeStructOrUnion)
+
+    def is_char_ptr_or_array(self):
+        return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar)
+
+    def is_unichar_ptr_or_array(self):
+        return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar)
+
+    def is_char_or_unichar_ptr_or_array(self):
+        return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveCharOrUniChar)
+
+    def cast(self, w_ob):
+        # cast to a pointer, to a funcptr, or to an array.
+        # Note that casting to an array is an extension to the C language,
+        # which seems to be necessary in order to sanely get a
+        # <cdata 'int[3]'> at some address.
+        if self.size < 0:
+            return W_CType.cast(self, w_ob)
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if (isinstance(ob, cdataobj.W_CData) and
+                isinstance(ob.ctype, W_CTypePtrOrArray)):
+            value = ob._cdata
+        else:
+            value = misc.as_unsigned_long_long(space, w_ob, strict=False)
+            value = rffi.cast(rffi.CCHARP, value)
+        return cdataobj.W_CData(space, value, self)
+
+    def convert_array_from_object(self, cdata, w_ob):
+        space = self.space
+        if (space.isinstance_w(w_ob, space.w_list) or
+            space.isinstance_w(w_ob, space.w_tuple)):
+            lst_w = space.listview(w_ob)
+            if self.length >= 0 and len(lst_w) > self.length:
+                raise operationerrfmt(space.w_IndexError,
+                    "too many initializers for '%s' (got %d)",
+                                      self.name, len(lst_w))
+            ctitem = self.ctitem
+            for i in range(len(lst_w)):
+                ctitem.convert_from_object(cdata, lst_w[i])
+                cdata = rffi.ptradd(cdata, ctitem.size)
+        elif isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar):
+            try:
+                s = space.str_w(w_ob)
+            except OperationError, e:
+                if not e.match(space, space.w_TypeError):
+                    raise
+                raise self._convert_error("str or list or tuple", w_ob)
+            n = len(s)
+            if self.length >= 0 and n > self.length:
+                raise operationerrfmt(space.w_IndexError,
+                                      "initializer string is too long for '%s'"
+                                      " (got %d characters)",
+                                      self.name, n)
+            for i in range(n):
+                cdata[i] = s[i]
+            if n != self.length:
+                cdata[n] = '\x00'
+        elif isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar):
+            try:
+                s = space.unicode_w(w_ob)
+            except OperationError, e:
+                if not e.match(space, space.w_TypeError):
+                    raise
+                raise self._convert_error("unicode or list or tuple", w_ob)
+            n = len(s)
+            if self.length >= 0 and n > self.length:
+                raise operationerrfmt(space.w_IndexError,
+                              "initializer unicode string is too long for '%s'"
+                                      " (got %d characters)",
+                                      self.name, n)
+            unichardata = rffi.cast(rffi.CWCHARP, cdata)
+            for i in range(n):
+                unichardata[i] = s[i]
+            if n != self.length:
+                unichardata[n] = u'\x00'
+        else:
+            raise self._convert_error("list or tuple", w_ob)
+
+    def string(self, cdataobj, maxlen):
+        space = self.space
+        if isinstance(self.ctitem, ctypeprim.W_CTypePrimitive):
+            cdata = cdataobj._cdata
+            if not cdata:
+                raise operationerrfmt(space.w_RuntimeError,
+                                      "cannot use string() on %s",
+                                      space.str_w(cdataobj.repr()))
+            #
+            from pypy.module._cffi_backend import ctypearray
+            length = maxlen
+            if length < 0 and isinstance(self, ctypearray.W_CTypeArray):
+                length = cdataobj.get_array_length()
+            #
+            # pointer to a primitive type of size 1: builds and returns a str
+            if self.ctitem.size == rffi.sizeof(lltype.Char):
+                if length < 0:
+                    s = rffi.charp2str(cdata)
+                else:
+                    s = rffi.charp2strn(cdata, length)
+                keepalive_until_here(cdataobj)
+                return space.wrap(s)
+            #
+            # pointer to a wchar_t: builds and returns a unicode
+            if self.is_unichar_ptr_or_array():
+                cdata = rffi.cast(rffi.CWCHARP, cdata)
+                if length < 0:
+                    u = rffi.wcharp2unicode(cdata)
+                else:
+                    u = rffi.wcharp2unicoden(cdata, length)
+                keepalive_until_here(cdataobj)
+                return space.wrap(u)
+        #
+        return W_CType.string(self, cdataobj, maxlen)
+
+
+class W_CTypePtrBase(W_CTypePtrOrArray):
+    # base class for both pointers and pointers-to-functions
+    _attrs_ = []
+
+    def convert_to_object(self, cdata):
+        ptrdata = rffi.cast(rffi.CCHARPP, cdata)[0]
+        return cdataobj.W_CData(self.space, ptrdata, self)
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if not isinstance(ob, cdataobj.W_CData):
+            raise self._convert_error("compatible pointer", w_ob)
+        other = ob.ctype
+        if not isinstance(other, W_CTypePtrBase):
+            from pypy.module._cffi_backend import ctypearray
+            if isinstance(other, ctypearray.W_CTypeArray):
+                other = other.ctptr
+            else:
+                raise self._convert_error("compatible pointer", w_ob)
+        if self is not other:
+            if not (self.can_cast_anything or other.can_cast_anything):
+                raise self._convert_error("compatible pointer", w_ob)
+
+        rffi.cast(rffi.CCHARPP, cdata)[0] = ob._cdata
+
+    def _alignof(self):
+        from pypy.module._cffi_backend import newtype
+        return newtype.alignment_of_pointer
+
+
+class W_CTypePointer(W_CTypePtrBase):
+    _attrs_ = []
+
+    def __init__(self, space, ctitem):
+        from pypy.module._cffi_backend import ctypearray
+        size = rffi.sizeof(rffi.VOIDP)
+        if isinstance(ctitem, ctypearray.W_CTypeArray):
+            extra = "(*)"    # obscure case: see test_array_add
+        else:
+            extra = " *"
+        W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem)
+
+    def newp(self, w_init):
+        space = self.space
+        ctitem = self.ctitem
+        datasize = ctitem.size
+        if datasize < 0:
+            raise operationerrfmt(space.w_TypeError,
+                "cannot instantiate ctype '%s' of unknown size",
+                                  self.name)
+        if self.is_struct_ptr:
+            # 'newp' on a struct-or-union pointer: in this case, we return
+            # a W_CDataPtrToStruct object which has a strong reference
+            # to a W_CDataNewOwning that really contains the structure.
+            cdatastruct = cdataobj.W_CDataNewOwning(space, datasize, ctitem)
+            cdata = cdataobj.W_CDataPtrToStructOrUnion(space,
+                                                       cdatastruct._cdata,
+                                                       self, cdatastruct)
+        else:
+            if self.is_char_or_unichar_ptr_or_array():
+                datasize *= 2       # forcefully add a null character
+            cdata = cdataobj.W_CDataNewOwning(space, datasize, self)
+        #
+        if not space.is_w(w_init, space.w_None):
+            ctitem.convert_from_object(cdata._cdata, w_init)
+            keepalive_until_here(cdata)
+        return cdata
+
+    def _check_subscript_index(self, w_cdata, i):
+        if (isinstance(w_cdata, cdataobj.W_CDataNewOwning) or
+            isinstance(w_cdata, cdataobj.W_CDataPtrToStructOrUnion)):
+            if i != 0:
+                space = self.space
+                raise operationerrfmt(space.w_IndexError,
+                                      "cdata '%s' can only be indexed by 0",
+                                      self.name)
+        return self
+
+    def add(self, cdata, i):
+        space = self.space
+        ctitem = self.ctitem
+        if ctitem.size < 0:
+            raise operationerrfmt(space.w_TypeError,
+                                  "ctype '%s' points to items of unknown size",
+                                  self.name)
+        p = rffi.ptradd(cdata, i * self.ctitem.size)
+        return cdataobj.W_CData(space, p, self)
+
+    def _prepare_pointer_call_argument(self, w_init):
+        space = self.space
+        if (space.isinstance_w(w_init, space.w_list) or
+            space.isinstance_w(w_init, space.w_tuple)):
+            length = space.int_w(space.len(w_init))
+        elif space.isinstance_w(w_init, space.w_basestring):
+            # from a string, we add the null terminator
+            length = space.int_w(space.len(w_init)) + 1
+        else:
+            return lltype.nullptr(rffi.CCHARP.TO)
+        if self.ctitem.size <= 0:
+            return lltype.nullptr(rffi.CCHARP.TO)
+        try:
+            datasize = ovfcheck(length * self.ctitem.size)
+        except OverflowError:
+            raise OperationError(space.w_OverflowError,
+                space.wrap("array size would overflow a ssize_t"))
+        result = lltype.malloc(rffi.CCHARP.TO, datasize,
+                               flavor='raw', zero=True)
+        try:
+            self.convert_array_from_object(result, w_init)
+        except Exception:
+            lltype.free(result, flavor='raw')
+            raise
+        return result
+
+    def convert_argument_from_object(self, cdata, w_ob):
+        from pypy.module._cffi_backend.ctypefunc import set_mustfree_flag
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if isinstance(ob, cdataobj.W_CData):
+            buffer = lltype.nullptr(rffi.CCHARP.TO)
+        else:
+            buffer = self._prepare_pointer_call_argument(w_ob)
+        #
+        if buffer:
+            rffi.cast(rffi.CCHARPP, cdata)[0] = buffer
+            set_mustfree_flag(cdata, True)
+            return True
+        else:
+            set_mustfree_flag(cdata, False)
+            try:
+                self.convert_from_object(cdata, w_ob)
+            except OperationError:
+                if (self.is_struct_ptr and isinstance(ob, cdataobj.W_CData)
+                    and ob.ctype is self.ctitem):
+                    # special case to make the life of verifier.py easier:
+                    # if the formal argument type is 'struct foo *' but
+                    # we pass a 'struct foo', then get a pointer to it
+                    rffi.cast(rffi.CCHARPP, cdata)[0] = ob._cdata
+                else:
+                    raise
+            return False
+
+    def getcfield(self, attr):
+        return self.ctitem.getcfield(attr)
diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -0,0 +1,251 @@
+"""
+Struct and unions.
+"""
+
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.rpython.lltypesystem import rffi
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.typedef import TypeDef, interp_attrproperty
+from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib.rarithmetic import r_ulonglong, r_longlong, intmask
+from pypy.rlib import jit
+
+from pypy.module._cffi_backend.ctypeobj import W_CType
+from pypy.module._cffi_backend import cdataobj, ctypeprim, misc
+
+
+class W_CTypeStructOrUnion(W_CType):
+    _immutable_fields_ = ['alignment?', 'fields_list?', 'fields_dict?',
+                          'custom_field_pos?']
+    # fields added by complete_struct_or_union():
+    alignment = -1
+    fields_list = None
+    fields_dict = None
+    custom_field_pos = False
+
+    def __init__(self, space, name):
+        name = '%s %s' % (self.kind, name)
+        W_CType.__init__(self, space, -1, name, len(name))
+
+    def check_complete(self):
+        if self.fields_dict is None:
+            space = self.space
+            raise operationerrfmt(space.w_TypeError,
+                                  "'%s' is not completed yet", self.name)
+
+    def _alignof(self):
+        self.check_complete()
+        return self.alignment
+
+    def _getfields(self):
+        if self.size < 0:
+            return None
+        space = self.space
+        result = [None] * len(self.fields_list)
+        for fname, field in self.fields_dict.iteritems():
+            i = self.fields_list.index(field)
+            result[i] = space.newtuple([space.wrap(fname),
+                                        space.wrap(field)])
+        return space.newlist(result)
+
+    def convert_to_object(self, cdata):
+        space = self.space
+        self.check_complete()
+        return cdataobj.W_CData(space, cdata, self)
+
+    def copy_and_convert_to_object(self, cdata):
+        space = self.space
+        self.check_complete()
+        ob = cdataobj.W_CDataNewOwning(space, self.size, self)
+        misc._raw_memcopy(cdata, ob._cdata, self.size)
+        keepalive_until_here(ob)
+        return ob
+
+    def offsetof(self, fieldname):
+        self.check_complete()
+        try:
+            cfield = self.fields_dict[fieldname]
+        except KeyError:
+            space = self.space
+            raise OperationError(space.w_KeyError, space.wrap(fieldname))
+        return cfield.offset
+
+    def _copy_from_same(self, cdata, w_ob):
+        space = self.space
+        ob = space.interpclass_w(w_ob)
+        if isinstance(ob, cdataobj.W_CData):
+            if ob.ctype is self and self.size >= 0:
+                misc._raw_memcopy(ob._cdata, cdata, self.size)
+                keepalive_until_here(ob)
+                return True
+        return False
+
+    def _check_only_one_argument_for_union(self, w_ob):
+        pass
+
+    def convert_from_object(self, cdata, w_ob):
+        space = self.space
+        if self._copy_from_same(cdata, w_ob):
+            return
+
+        self._check_only_one_argument_for_union(w_ob)
+
+        if (space.isinstance_w(w_ob, space.w_list) or
+            space.isinstance_w(w_ob, space.w_tuple)):
+            lst_w = space.listview(w_ob)
+            if len(lst_w) > len(self.fields_list):
+                raise operationerrfmt(space.w_ValueError,
+                        "too many initializers for '%s' (got %d)",
+                                      self.name, len(lst_w))
+            for i in range(len(lst_w)):
+                self.fields_list[i].write(cdata, lst_w[i])
+
+        elif space.isinstance_w(w_ob, space.w_dict):
+            lst_w = space.fixedview(w_ob)
+            for i in range(len(lst_w)):
+                w_key = lst_w[i]
+                key = space.str_w(w_key)
+                try:
+                    cf = self.fields_dict[key]
+                except KeyError:
+                    space.raise_key_error(w_key)
+                    assert 0
+                cf.write(cdata, space.getitem(w_ob, w_key))
+
+        else:
+            raise self._convert_error("list or tuple or dict or struct-cdata",
+                                      w_ob)
+
+    @jit.elidable
+    def _getcfield_const(self, attr):
+        return self.fields_dict[attr]
+
+    def getcfield(self, attr):
+        if self.fields_dict is not None:
+            self = jit.promote(self)
+            attr = jit.promote_string(attr)
+            try:
+                return self._getcfield_const(attr)
+            except KeyError:
+                pass
+        return W_CType.getcfield(self, attr)
+
+
+class W_CTypeStruct(W_CTypeStructOrUnion):
+    kind = "struct"
+
+class W_CTypeUnion(W_CTypeStructOrUnion):
+    kind = "union"
+
+    def _check_only_one_argument_for_union(self, w_ob):
+        space = self.space
+        n = space.int_w(space.len(w_ob))
+        if n > 1:
+            raise operationerrfmt(space.w_ValueError,
+                                  "initializer for '%s': %d items given, but "
+                                  "only one supported (use a dict if needed)",
+                                  self.name, n)
+
+
+class W_CField(Wrappable):
+    _immutable_ = True
+
+    BS_REGULAR     = -1
+    BS_EMPTY_ARRAY = -2
+
+    def __init__(self, ctype, offset, bitshift, bitsize):
+        self.ctype = ctype
+        self.offset = offset
+        self.bitshift = bitshift # >= 0: bitshift; or BS_REGULAR/BS_EMPTY_ARRAY
+        self.bitsize = bitsize
+
+    def is_bitfield(self):
+        return self.bitshift >= 0
+
+    def make_shifted(self, offset):
+        return W_CField(self.ctype, offset + self.offset,
+                        self.bitshift, self.bitsize)
+
+    def read(self, cdata):
+        cdata = rffi.ptradd(cdata, self.offset)
+        if self.bitshift == self.BS_REGULAR:
+            return self.ctype.convert_to_object(cdata)
+        elif self.bitshift == self.BS_EMPTY_ARRAY:
+            from pypy.module._cffi_backend import ctypearray
+            ctype = self.ctype
+            assert isinstance(ctype, ctypearray.W_CTypeArray)
+            return cdataobj.W_CData(ctype.space, cdata, ctype.ctptr)
+        else:
+            return self.convert_bitfield_to_object(cdata)
+
+    def write(self, cdata, w_ob):
+        cdata = rffi.ptradd(cdata, self.offset)
+        if self.is_bitfield():
+            self.convert_bitfield_from_object(cdata, w_ob)
+        else:
+            self.ctype.convert_from_object(cdata, w_ob)
+
+    def convert_bitfield_to_object(self, cdata):
+        ctype = self.ctype
+        space = ctype.space
+        #
+        if isinstance(ctype, ctypeprim.W_CTypePrimitiveSigned):
+            value = r_ulonglong(misc.read_raw_signed_data(cdata, ctype.size))
+            valuemask = (r_ulonglong(1) << self.bitsize) - 1
+            shiftforsign = r_ulonglong(1) << (self.bitsize - 1)
+            value = ((value >> self.bitshift) + shiftforsign) & valuemask
+            result = r_longlong(value) - r_longlong(shiftforsign)
+            if ctype.value_fits_long:
+                return space.wrap(intmask(result))
+            else:
+                return space.wrap(result)
+        #
+        if isinstance(ctype, ctypeprim.W_CTypePrimitiveUnsigned):
+            value_fits_long = ctype.value_fits_long
+        elif isinstance(ctype, ctypeprim.W_CTypePrimitiveCharOrUniChar):
+            value_fits_long = True
+        else:
+            raise NotImplementedError
+        #
+        value = misc.read_raw_unsigned_data(cdata, ctype.size)
+        valuemask = (r_ulonglong(1) << self.bitsize) - 1
+        value = (value >> self.bitshift) & valuemask
+        if value_fits_long:
+            return space.wrap(intmask(value))
+        else:
+            return space.wrap(value)
+
+    def convert_bitfield_from_object(self, cdata, w_ob):
+        ctype = self.ctype
+        space = ctype.space
+        #
+        value = misc.as_long_long(space, w_ob)
+        if isinstance(ctype, ctypeprim.W_CTypePrimitiveSigned):
+            fmin = -(r_longlong(1) << (self.bitsize-1))
+            fmax = (r_longlong(1) << (self.bitsize-1)) - 1
+            if fmax == 0:
+                fmax = 1      # special case to let "int x:1" receive "1"
+        else:
+            fmin = r_longlong(0)
+            fmax = r_longlong((r_ulonglong(1) << self.bitsize) - 1)
+        if value < fmin or value > fmax:
+            raise operationerrfmt(space.w_OverflowError,
+                                  "value %d outside the range allowed by the "
+                                  "bit field width: %d <= x <= %d",
+                                  value, fmin, fmax)
+        rawmask = ((r_ulonglong(1) << self.bitsize) - 1) << self.bitshift
+        rawvalue = r_ulonglong(value) << self.bitshift
+        rawfielddata = misc.read_raw_unsigned_data(cdata, ctype.size)
+        rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask)
+        misc.write_raw_integer_data(cdata, rawfielddata, ctype.size)
+
+
+W_CField.typedef = TypeDef(
+    'CField',
+    __module__ = '_cffi_backend',
+    type = interp_attrproperty('ctype', W_CField),
+    offset = interp_attrproperty('offset', W_CField),
+    bitshift = interp_attrproperty('bitshift', W_CField),
+    bitsize = interp_attrproperty('bitsize', W_CField),
+    )
+W_CField.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/ctypevoid.py b/pypy/module/_cffi_backend/ctypevoid.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/ctypevoid.py
@@ -0,0 +1,16 @@
+"""
+Void.
+"""
+
+from pypy.module._cffi_backend.ctypeobj import W_CType
+
+
+class W_CTypeVoid(W_CType):
+    _attrs_ = []
+    cast_anything = True
+
+    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/module/_cffi_backend/func.py b/pypy/module/_cffi_backend/func.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/func.py
@@ -0,0 +1,77 @@
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.rpython.lltypesystem import lltype, rffi
+
+from pypy.module._cffi_backend import ctypeobj, cdataobj
+
+
+# ____________________________________________________________
+
+ at unwrap_spec(ctype=ctypeobj.W_CType)
+def newp(space, ctype, w_init=None):
+    return ctype.newp(w_init)
+
+# ____________________________________________________________
+
+ at unwrap_spec(ctype=ctypeobj.W_CType)
+def cast(space, ctype, w_ob):
+    return ctype.cast(w_ob)
+
+# ____________________________________________________________
+
+ at unwrap_spec(ctype=ctypeobj.W_CType)
+def callback(space, ctype, w_callable, w_error=None):
+    from pypy.module._cffi_backend.ccallback import W_CDataCallback
+    return W_CDataCallback(space, ctype, w_callable, w_error)
+
+# ____________________________________________________________
+
+ at unwrap_spec(cdata=cdataobj.W_CData)
+def typeof(space, cdata):
+    return cdata.ctype
+
+# ____________________________________________________________
+
+def sizeof(space, w_obj):
+    ob = space.interpclass_w(w_obj)
+    if isinstance(ob, cdataobj.W_CData):
+        size = ob._sizeof()
+    elif isinstance(ob, ctypeobj.W_CType):
+        size = ob.size
+        if size < 0:
+            raise operationerrfmt(space.w_ValueError,
+                                  "ctype '%s' is of unknown size",
+                                  ob.name)
+    else:
+        raise OperationError(space.w_TypeError,
+                            space.wrap("expected a 'cdata' or 'ctype' object"))
+    return space.wrap(size)
+
+ at unwrap_spec(ctype=ctypeobj.W_CType)
+def alignof(space, ctype):
+    align = ctype.alignof()
+    return space.wrap(align)
+
+ at unwrap_spec(ctype=ctypeobj.W_CType, fieldname=str)
+def offsetof(space, ctype, fieldname):
+    ofs = ctype.offsetof(fieldname)
+    return space.wrap(ofs)
+
+ at unwrap_spec(ctype=ctypeobj.W_CType)
+def _getfields(space, ctype):
+    return ctype._getfields()
+
+# ____________________________________________________________
+
+ at unwrap_spec(ctype=ctypeobj.W_CType, replace_with=str)
+def getcname(space, ctype, replace_with):
+    p = ctype.name_position
+    s = '%s%s%s' % (ctype.name[:p], replace_with, ctype.name[p:])
+    return space.wrap(s)
+
+# ____________________________________________________________
+
+ at unwrap_spec(cdata=cdataobj.W_CData, maxlen=int)
+def string(space, cdata, maxlen=-1):
+    return cdata.ctype.string(cdata, maxlen)
diff --git a/pypy/module/_cffi_backend/libraryobj.py b/pypy/module/_cffi_backend/libraryobj.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/libraryobj.py
@@ -0,0 +1,106 @@
+from __future__ import with_statement
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.rdynload import DLLHANDLE, dlopen, dlsym, dlclose, DLOpenError
+from pypy.rlib.rdynload import RTLD_GLOBAL
+
+from pypy.module._cffi_backend.cdataobj import W_CData
+from pypy.module._cffi_backend.ctypeobj import W_CType
+
+
+class W_Library(Wrappable):
+    _immutable_ = True
+    handle = rffi.cast(DLLHANDLE, 0)
+
+    def __init__(self, space, filename, is_global):
+        self.space = space
+        if is_global and RTLD_GLOBAL is not None:
+            mode = RTLD_GLOBAL
+        else:
+            mode = -1     # default value, corresponds to RTLD_LOCAL
+        with rffi.scoped_str2charp(filename) as ll_libname:
+            if filename is None:
+                filename = "<None>"
+            try:
+                self.handle = dlopen(ll_libname, mode)
+            except DLOpenError, e:
+                raise operationerrfmt(space.w_OSError,
+                                      "cannot load '%s': %s",
+                                      filename, e.msg)
+        self.name = filename
+
+    def __del__(self):
+        h = self.handle
+        if h != rffi.cast(DLLHANDLE, 0):
+            self.handle = rffi.cast(DLLHANDLE, 0)
+            dlclose(h)
+
+    def repr(self):
+        space = self.space
+        return space.wrap("<clibrary '%s'>" % self.name)
+
+    @unwrap_spec(ctype=W_CType, name=str)
+    def load_function(self, ctype, name):
+        from pypy.module._cffi_backend import ctypefunc, ctypeptr, ctypevoid
+        space = self.space
+        #
+        ok = False
+        if isinstance(ctype, ctypefunc.W_CTypeFunc):
+            ok = True
+        if (isinstance(ctype, ctypeptr.W_CTypePointer) and
+            isinstance(ctype.ctitem, ctypevoid.W_CTypeVoid)):
+            ok = True
+        if not ok:
+            raise operationerrfmt(space.w_TypeError,
+                                  "function cdata expected, got '%s'",
+                                  ctype.name)
+        #
+        try:
+            cdata = dlsym(self.handle, name)
+        except KeyError:
+            raise operationerrfmt(space.w_KeyError,
+                                  "function '%s' not found in library '%s'",
+                                  name, self.name)
+        return W_CData(space, rffi.cast(rffi.CCHARP, cdata), ctype)
+
+    @unwrap_spec(ctype=W_CType, name=str)
+    def read_variable(self, ctype, name):
+        space = self.space
+        try:
+            cdata = dlsym(self.handle, name)
+        except KeyError:
+            raise operationerrfmt(space.w_KeyError,
+                                  "variable '%s' not found in library '%s'",
+                                  name, self.name)
+        return ctype.convert_to_object(rffi.cast(rffi.CCHARP, cdata))
+
+    @unwrap_spec(ctype=W_CType, name=str)
+    def write_variable(self, ctype, name, w_value):
+        space = self.space
+        try:
+            cdata = dlsym(self.handle, name)
+        except KeyError:
+            raise operationerrfmt(space.w_KeyError,
+                                  "variable '%s' not found in library '%s'",
+                                  name, self.name)
+        ctype.convert_from_object(rffi.cast(rffi.CCHARP, cdata), w_value)
+
+
+W_Library.typedef = TypeDef(
+    'Library',
+    __module__ = '_cffi_backend',
+    __repr__ = interp2app(W_Library.repr),
+    load_function = interp2app(W_Library.load_function),
+    read_variable = interp2app(W_Library.read_variable),
+    write_variable = interp2app(W_Library.write_variable),
+    )
+W_Library.acceptable_as_base_class = False
+
+
+ at unwrap_spec(filename="str_or_None", is_global=int)
+def load_library(space, filename, is_global=0):
+    lib = W_Library(space, filename, is_global)
+    return space.wrap(lib)
diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/misc.py
@@ -0,0 +1,202 @@
+from __future__ import with_statement
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+from pypy.rlib.rarithmetic import r_ulonglong
+from pypy.rlib.unroll import unrolling_iterable
+from pypy.rlib import jit
+
+# ____________________________________________________________
+
+_prim_signed_types = unrolling_iterable([
+    (rffi.SIGNEDCHAR, rffi.SIGNEDCHARP),
+    (rffi.SHORT, rffi.SHORTP),
+    (rffi.INT, rffi.INTP),
+    (rffi.LONG, rffi.LONGP),
+    (rffi.LONGLONG, rffi.LONGLONGP)])
+
+_prim_unsigned_types = unrolling_iterable([
+    (rffi.UCHAR, rffi.UCHARP),
+    (rffi.USHORT, rffi.USHORTP),
+    (rffi.UINT, rffi.UINTP),
+    (rffi.ULONG, rffi.ULONGP),
+    (rffi.ULONGLONG, rffi.ULONGLONGP)])
+
+_prim_float_types = unrolling_iterable([
+    (rffi.FLOAT, rffi.FLOATP),
+    (rffi.DOUBLE, rffi.DOUBLEP)])
+
+def read_raw_signed_data(target, size):
+    for TP, TPP in _prim_signed_types:
+        if size == rffi.sizeof(TP):
+            return rffi.cast(lltype.SignedLongLong, rffi.cast(TPP, target)[0])
+    raise NotImplementedError("bad integer size")
+
+def read_raw_long_data(target, size):
+    for TP, TPP in _prim_signed_types:
+        if size == rffi.sizeof(TP):
+            assert rffi.sizeof(TP) <= rffi.sizeof(lltype.Signed)
+            return rffi.cast(lltype.Signed, rffi.cast(TPP, target)[0])
+    raise NotImplementedError("bad integer size")
+
+def read_raw_unsigned_data(target, size):
+    for TP, TPP in _prim_unsigned_types:
+        if size == rffi.sizeof(TP):
+            return rffi.cast(lltype.UnsignedLongLong, rffi.cast(TPP,target)[0])
+    raise NotImplementedError("bad integer size")
+
+def read_raw_ulong_data(target, size):
+    for TP, TPP in _prim_unsigned_types:
+        if size == rffi.sizeof(TP):
+            assert rffi.sizeof(TP) < rffi.sizeof(lltype.Signed)
+            return rffi.cast(lltype.Signed, rffi.cast(TPP,target)[0])
+    raise NotImplementedError("bad integer size")
+
+def read_raw_float_data(target, size):
+    for TP, TPP in _prim_float_types:
+        if size == rffi.sizeof(TP):
+            return rffi.cast(lltype.Float, rffi.cast(TPP, target)[0])
+    raise NotImplementedError("bad float size")
+
+def read_raw_longdouble_data(target):
+    return rffi.cast(rffi.LONGDOUBLEP, target)[0]
+
+def write_raw_integer_data(target, source, size):
+    for TP, TPP in _prim_unsigned_types:
+        if size == rffi.sizeof(TP):
+            rffi.cast(TPP, target)[0] = rffi.cast(TP, source)
+            return
+    raise NotImplementedError("bad integer size")
+
+def write_raw_float_data(target, source, size):
+    for TP, TPP in _prim_float_types:
+        if size == rffi.sizeof(TP):
+            rffi.cast(TPP, target)[0] = rffi.cast(TP, source)
+            return
+    raise NotImplementedError("bad float size")
+
+def write_raw_longdouble_data(target, source):
+    rffi.cast(rffi.LONGDOUBLEP, target)[0] = source
+
+# ____________________________________________________________
+
+sprintf_longdouble = rffi.llexternal(
+    "sprintf", [rffi.CCHARP, rffi.CCHARP, rffi.LONGDOUBLE], lltype.Void,
+    _nowrapper=True, sandboxsafe=True)
+
+FORMAT_LONGDOUBLE = rffi.str2charp("%LE")
+
+def longdouble2str(lvalue):
+    with lltype.scoped_alloc(rffi.CCHARP.TO, 128) as p:    # big enough
+        sprintf_longdouble(p, FORMAT_LONGDOUBLE, lvalue)
+        return rffi.charp2str(p)
+
+# ____________________________________________________________
+
+
+UNSIGNED = 0x1000
+
+TYPES = [
+    ("int8_t",        1),
+    ("uint8_t",       1 | UNSIGNED),
+    ("int16_t",       2),
+    ("uint16_t",      2 | UNSIGNED),
+    ("int32_t",       4),
+    ("uint32_t",      4 | UNSIGNED),
+    ("int64_t",       8),
+    ("uint64_t",      8 | UNSIGNED),
+
+    ("intptr_t",      rffi.sizeof(rffi.INTPTR_T)),
+    ("uintptr_t",     rffi.sizeof(rffi.UINTPTR_T) | UNSIGNED),
+    ("ptrdiff_t",     rffi.sizeof(rffi.INTPTR_T)),   # XXX can it be different?
+    ("size_t",        rffi.sizeof(rffi.SIZE_T) | UNSIGNED),
+    ("ssize_t",       rffi.sizeof(rffi.SSIZE_T)),
+]
+
+
+def nonstandard_integer_types(space):
+    w_d = space.newdict()
+    for name, size in TYPES:
+        space.setitem(w_d, space.wrap(name), space.wrap(size))
+    return w_d
+
+# ____________________________________________________________
+
+def as_long_long(space, w_ob):
+    # (possibly) convert and cast a Python object to a long long.
+    # This version accepts a Python int too, and does convertions from
+    # other types of objects.  It refuses floats.
+    if space.is_w(space.type(w_ob), space.w_int):   # shortcut
+        return space.int_w(w_ob)
+    try:
+        bigint = space.bigint_w(w_ob)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+        if space.isinstance_w(w_ob, space.w_float):
+            raise
+        bigint = space.bigint_w(space.int(w_ob))
+    try:
+        return bigint.tolonglong()
+    except OverflowError:
+        raise OperationError(space.w_OverflowError, space.wrap(ovf_msg))
+
+def as_unsigned_long_long(space, w_ob, strict):
+    # (possibly) convert and cast a Python object to an unsigned long long.
+    # This accepts a Python int too, and does convertions from other types of
+    # objects.  If 'strict', complains with OverflowError; if 'not strict',
+    # mask the result and round floats.
+    if space.is_w(space.type(w_ob), space.w_int):   # shortcut
+        value = space.int_w(w_ob)
+        if strict and value < 0:
+            raise OperationError(space.w_OverflowError, space.wrap(neg_msg))
+        return r_ulonglong(value)
+    try:
+        bigint = space.bigint_w(w_ob)
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+        if strict and space.isinstance_w(w_ob, space.w_float):
+            raise
+        bigint = space.bigint_w(space.int(w_ob))
+    if strict:
+        try:
+            return bigint.toulonglong()
+        except ValueError:
+            raise OperationError(space.w_OverflowError, space.wrap(neg_msg))
+        except OverflowError:
+            raise OperationError(space.w_OverflowError, space.wrap(ovf_msg))
+    else:
+        return bigint.ulonglongmask()
+
+neg_msg = "can't convert negative number to unsigned"
+ovf_msg = "long too big to convert"
+
+# ____________________________________________________________
+
+def _raw_memcopy(source, dest, size):
+    if jit.isconstant(size):
+        # for the JIT: first handle the case where 'size' is known to be
+        # a constant equal to 1, 2, 4, 8
+        for TP, TPP in _prim_unsigned_types:
+            if size == rffi.sizeof(TP):
+                rffi.cast(TPP, dest)[0] = rffi.cast(TPP, source)[0]
+                return
+    _raw_memcopy_opaque(source, dest, size)
+
+ at jit.dont_look_inside
+def _raw_memcopy_opaque(source, dest, size):
+    # push push push at the llmemory interface (with hacks that are all
+    # removed after translation)
+    zero = llmemory.itemoffsetof(rffi.CCHARP.TO, 0)
+    llmemory.raw_memcopy(
+        llmemory.cast_ptr_to_adr(source) + zero,
+        llmemory.cast_ptr_to_adr(dest) + zero,
+        size * llmemory.sizeof(lltype.Char))
+
+def _raw_memclear(dest, size):
+    # for now, only supports the cases of size = 1, 2, 4, 8
+    for TP, TPP in _prim_unsigned_types:
+        if size == rffi.sizeof(TP):
+            rffi.cast(TPP, dest)[0] = rffi.cast(TP, 0)
+            return
+    raise NotImplementedError("bad clear size")
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -0,0 +1,275 @@
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.rarithmetic import ovfcheck
+from pypy.rlib.objectmodel import specialize
+
+from pypy.module._cffi_backend import ctypeobj, ctypeprim, ctypeptr, ctypearray
+from pypy.module._cffi_backend import ctypestruct, ctypevoid, ctypeenum
+
+
+ at specialize.memo()
+def alignment(TYPE):
+    S = lltype.Struct('aligncheck', ('x', lltype.Char), ('y', TYPE))
+    return rffi.offsetof(S, 'y')
+
+alignment_of_pointer = alignment(rffi.CCHARP)
+
+# ____________________________________________________________
+
+
+PRIMITIVE_TYPES = {}
+
+def eptype(name, TYPE, ctypecls):
+    PRIMITIVE_TYPES[name] = ctypecls, rffi.sizeof(TYPE), alignment(TYPE)
+
+eptype("char",        lltype.Char,     ctypeprim.W_CTypePrimitiveChar)
+eptype("wchar_t",     lltype.UniChar,  ctypeprim.W_CTypePrimitiveUniChar)
+eptype("signed char", rffi.SIGNEDCHAR, ctypeprim.W_CTypePrimitiveSigned)
+eptype("short",       rffi.SHORT,      ctypeprim.W_CTypePrimitiveSigned)
+eptype("int",         rffi.INT,        ctypeprim.W_CTypePrimitiveSigned)
+eptype("long",        rffi.LONG,       ctypeprim.W_CTypePrimitiveSigned)
+eptype("long long",   rffi.LONGLONG,   ctypeprim.W_CTypePrimitiveSigned)
+eptype("unsigned char",      rffi.UCHAR,    ctypeprim.W_CTypePrimitiveUnsigned)
+eptype("unsigned short",     rffi.SHORT,    ctypeprim.W_CTypePrimitiveUnsigned)
+eptype("unsigned int",       rffi.INT,      ctypeprim.W_CTypePrimitiveUnsigned)
+eptype("unsigned long",      rffi.LONG,     ctypeprim.W_CTypePrimitiveUnsigned)
+eptype("unsigned long long", rffi.LONGLONG, ctypeprim.W_CTypePrimitiveUnsigned)
+eptype("float",  rffi.FLOAT,  ctypeprim.W_CTypePrimitiveFloat)
+eptype("double", rffi.DOUBLE, ctypeprim.W_CTypePrimitiveFloat)
+eptype("long double", rffi.LONGDOUBLE, ctypeprim.W_CTypePrimitiveLongDouble)
+
+ at unwrap_spec(name=str)
+def new_primitive_type(space, name):
+    try:
+        ctypecls, size, align = PRIMITIVE_TYPES[name]
+    except KeyError:
+        raise OperationError(space.w_KeyError, space.wrap(name))
+    ctype = ctypecls(space, size, name, len(name), align)
+    return ctype
+
+# ____________________________________________________________
+
+ at unwrap_spec(ctype=ctypeobj.W_CType)
+def new_pointer_type(space, ctype):
+    ctypepointer = ctypeptr.W_CTypePointer(space, ctype)
+    return ctypepointer
+
+# ____________________________________________________________
+
+ at unwrap_spec(ctptr=ctypeobj.W_CType)
+def new_array_type(space, ctptr, w_length):
+    if not isinstance(ctptr, ctypeptr.W_CTypePointer):
+        raise OperationError(space.w_TypeError,
+                             space.wrap("first arg must be a pointer ctype"))
+    ctitem = ctptr.ctitem
+    if ctitem.size < 0:
+        raise operationerrfmt(space.w_ValueError,
+                              "array item of unknown size: '%s'",
+                              ctitem.name)
+    if space.is_w(w_length, space.w_None):
+        length = -1
+        arraysize = -1
+        extra = '[]'
+    else:
+        length = space.getindex_w(w_length, space.w_OverflowError)
+        if length < 0:
+            raise OperationError(space.w_ValueError,
+                                 space.wrap("negative array length"))
+        try:
+            arraysize = ovfcheck(length * ctitem.size)
+        except OverflowError:
+            raise OperationError(space.w_OverflowError,
+                space.wrap("array size would overflow a ssize_t"))
+        extra = '[%d]' % length
+    #
+    ctype = ctypearray.W_CTypeArray(space, ctptr, length, arraysize, extra)
+    return ctype
+
+# ____________________________________________________________
+
+ at unwrap_spec(name=str)
+def new_struct_type(space, name):
+    return ctypestruct.W_CTypeStruct(space, name)
+
+ at unwrap_spec(name=str)
+def new_union_type(space, name):
+    return ctypestruct.W_CTypeUnion(space, name)
+
+ at unwrap_spec(ctype=ctypeobj.W_CType, totalsize=int, totalalignment=int)
+def complete_struct_or_union(space, ctype, w_fields, w_ignored=None,
+                             totalsize=-1, totalalignment=-1):
+    if (not isinstance(ctype, ctypestruct.W_CTypeStructOrUnion)
+            or ctype.size >= 0):
+        raise OperationError(space.w_TypeError,
+                             space.wrap("first arg must be a non-initialized"
+                                        " struct or union ctype"))
+
+    is_union = isinstance(ctype, ctypestruct.W_CTypeUnion)
+    maxsize = 1
+    alignment = 1
+    offset = 0
+    fields_w = space.listview(w_fields)
+    fields_list = []
+    fields_dict = {}
+    prev_bit_position = 0
+    custom_field_pos = False
+
+    for w_field in fields_w:
+        field_w = space.fixedview(w_field)
+        if not (2 <= len(field_w) <= 4):
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("bad field descr"))
+        fname = space.str_w(field_w[0])
+        ftype = space.interp_w(ctypeobj.W_CType, field_w[1])
+        fbitsize = -1
+        foffset = -1
+        if len(field_w) > 2: fbitsize = space.int_w(field_w[2])
+        if len(field_w) > 3: foffset = space.int_w(field_w[3])
+        #
+        if fname in fields_dict:
+            raise operationerrfmt(space.w_KeyError,
+                                  "duplicate field name '%s'", fname)
+        #
+        if ftype.size < 0:
+            raise operationerrfmt(space.w_TypeError,
+                    "field '%s.%s' has ctype '%s' of unknown size",
+                                  ctype.name, fname, ftype.name)
+        #
+        falign = ftype.alignof()
+        if alignment < falign:
+            alignment = falign
+        #
+        if foffset < 0:
+            # align this field to its own 'falign' by inserting padding
+            offset = (offset + falign - 1) & ~(falign-1)
+        else:
+            # a forced field position: ignore the offset just computed,
+            # except to know if we must set 'custom_field_pos'
+            custom_field_pos |= (offset != foffset)
+            offset = foffset
+        #
+        if fbitsize < 0 or (
+                fbitsize == 8 * ftype.size and not
+                isinstance(ftype, ctypeprim.W_CTypePrimitiveCharOrUniChar)):
+            fbitsize = -1
+            if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length==0:
+                bitshift = ctypestruct.W_CField.BS_EMPTY_ARRAY
+            else:
+                bitshift = ctypestruct.W_CField.BS_REGULAR
+            prev_bit_position = 0
+        else:
+            if (not (isinstance(ftype, ctypeprim.W_CTypePrimitiveSigned) or
+                     isinstance(ftype, ctypeprim.W_CTypePrimitiveUnsigned) or
+                     isinstance(ftype, ctypeprim.W_CTypePrimitiveChar)) or
+                fbitsize == 0 or
+                fbitsize > 8 * ftype.size):
+                raise operationerrfmt(space.w_TypeError,
+                                      "invalid bit field '%s'", fname)
+            if prev_bit_position > 0:
+                prev_field = fields_list[-1]
+                assert prev_field.bitshift >= 0
+                if prev_field.ctype.size != ftype.size:
+                    raise OperationError(space.w_NotImplementedError,
+                        space.wrap("consecutive bit fields should be "
+                                   "declared with a same-sized type"))
+                if prev_bit_position + fbitsize > 8 * ftype.size:
+                    prev_bit_position = 0
+                else:
+                    # we can share the same field as 'prev_field'
+                    offset = prev_field.offset
+            bitshift = prev_bit_position
+            if not is_union:
+                prev_bit_position += fbitsize
+        #
+        if (len(fname) == 0 and
+            isinstance(ftype, ctypestruct.W_CTypeStructOrUnion)):
+            # a nested anonymous struct or union
+            srcfield2names = {}
+            for name, srcfld in ftype.fields_dict.items():
+                srcfield2names[srcfld] = name
+            for srcfld in ftype.fields_list:
+                fld = srcfld.make_shifted(offset)
+                fields_list.append(fld)
+                try:
+                    fields_dict[srcfield2names[srcfld]] = fld
+                except KeyError:
+                    pass
+            # always forbid such structures from being passed by value
+            custom_field_pos = True
+        else:
+            # a regular field
+            fld = ctypestruct.W_CField(ftype, offset, bitshift, fbitsize)
+            fields_list.append(fld)
+            fields_dict[fname] = fld
+        #
+        if maxsize < ftype.size:
+            maxsize = ftype.size
+        if not is_union:
+            offset += ftype.size
+
+    if is_union:
+        assert offset == 0
+        offset = maxsize
+    offset = (offset + alignment - 1) & ~(alignment-1)
+
+    # Like C, if the size of this structure would be zero, we compute it
+    # as 1 instead.  But for ctypes support, we allow the manually-
+    # specified totalsize to be zero in this case.
+    if totalsize < 0:
+        totalsize = offset or 1
+    elif totalsize < offset:
+        raise operationerrfmt(space.w_TypeError,
+                     "%s cannot be of size %d: there are fields at least "
+                     "up to %d", ctype.name, totalsize, offset)
+    if totalalignment < 0:
+        totalalignment = alignment
+
+    ctype.size = totalsize
+    ctype.alignment = totalalignment
+    ctype.fields_list = fields_list
+    ctype.fields_dict = fields_dict
+    ctype.custom_field_pos = custom_field_pos
+
+# ____________________________________________________________
+
+def new_void_type(space):
+    ctype = ctypevoid.W_CTypeVoid(space)
+    return ctype
+
+# ____________________________________________________________
+
+ at unwrap_spec(name=str)
+def new_enum_type(space, name, w_enumerators, w_enumvalues):
+    enumerators_w = space.fixedview(w_enumerators)
+    enumvalues_w  = space.fixedview(w_enumvalues)
+    if len(enumerators_w) != len(enumvalues_w):
+        raise OperationError(space.w_ValueError,
+                             space.wrap("tuple args must have the same size"))
+    enumerators = [space.str_w(w) for w in enumerators_w]
+    enumvalues  = [space.int_w(w) for w in enumvalues_w]
+    ctype = ctypeenum.W_CTypeEnum(space, name, enumerators, enumvalues)
+    return ctype
+
+# ____________________________________________________________
+
+ at unwrap_spec(fresult=ctypeobj.W_CType, ellipsis=int)
+def new_function_type(space, w_fargs, fresult, ellipsis=0):
+    from pypy.module._cffi_backend import ctypefunc
+    fargs = []
+    for w_farg in space.fixedview(w_fargs):
+        farg = space.interpclass_w(w_farg)
+        if not isinstance(farg, ctypeobj.W_CType):
+            raise OperationError(space.w_TypeError,
+                space.wrap("first arg must be a tuple of ctype objects"))
+        if isinstance(farg, ctypearray.W_CTypeArray):
+            farg = farg.ctptr
+        fargs.append(farg)
+    #
+    if ((fresult.size < 0 and not isinstance(fresult, ctypevoid.W_CTypeVoid))
+            or isinstance(fresult, ctypearray.W_CTypeArray)):
+        raise operationerrfmt(space.w_TypeError,
+                              "invalid result type: '%s'", fresult.name)
+    #
+    fct = ctypefunc.W_CTypeFunc(space, fargs, fresult, ellipsis)
+    return fct
diff --git a/pypy/module/_cffi_backend/test/__init__.py b/pypy/module/_cffi_backend/test/__init__.py
new file mode 100644
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -0,0 +1,2055 @@
+# ____________________________________________________________
+
+import sys
+if sys.version_info < (3,):
+    type_or_class = "type"
+    mandatory_b_prefix = ''
+    mandatory_u_prefix = 'u'
+    readbuf = str
+    bufchar = lambda x: x
+    bytechr = chr
+    class U(object):
+        def __add__(self, other):
+            return eval('u'+repr(other).replace(r'\\u', r'\u')
+                                       .replace(r'\\U', r'\U'))
+    u = U()
+else:
+    type_or_class = "class"
+    long = int
+    unicode = str
+    unichr = chr
+    mandatory_b_prefix = 'b'
+    mandatory_u_prefix = ''
+    readbuf = lambda buf: buf.tobytes()
+    bufchar = ord
+    bytechr = lambda n: bytes([n])
+    u = ""
+
+def size_of_int():
+    BInt = new_primitive_type("int")
+    return sizeof(BInt)
+
+def size_of_long():
+    BLong = new_primitive_type("long")
+    return sizeof(BLong)
+
+def size_of_ptr():
+    BInt = new_primitive_type("int")
+    BPtr = new_pointer_type(BInt)
+    return sizeof(BPtr)
+
+
+def find_and_load_library(name, is_global=0):
+    import ctypes.util
+    if name is None:
+        path = None
+    else:
+        path = ctypes.util.find_library(name)
+    return load_library(path, is_global)
+
+def test_load_library():
+    x = find_and_load_library('c')
+    assert repr(x).startswith("<clibrary '")
+    x = find_and_load_library('c', 1)
+    assert repr(x).startswith("<clibrary '")
+
+def test_nonstandard_integer_types():
+    d = nonstandard_integer_types()
+    assert type(d) is dict
+    assert 'char' not in d
+    assert d['size_t'] in (0x1004, 0x1008)
+    assert d['size_t'] == d['ssize_t'] + 0x1000
+
+def test_new_primitive_type():
+    py.test.raises(KeyError, new_primitive_type, "foo")
+    p = new_primitive_type("signed char")
+    assert repr(p) == "<ctype 'signed char'>"
+
+def test_cast_to_signed_char():
+    p = new_primitive_type("signed char")
+    x = cast(p, -65 + 17*256)
+    assert repr(x) == "<cdata 'signed char' -65>"
+    assert repr(type(x)) == "<%s '_cffi_backend.CData'>" % type_or_class
+    assert int(x) == -65
+    x = cast(p, -66 + (1<<199)*256)
+    assert repr(x) == "<cdata 'signed char' -66>"
+    assert int(x) == -66
+    assert (x == cast(p, -66)) is False
+    assert (x != cast(p, -66)) is True
+    q = new_primitive_type("short")
+    assert (x == cast(q, -66)) is False
+    assert (x != cast(q, -66)) is True
+
+def test_sizeof_type():
+    py.test.raises(TypeError, sizeof, 42.5)
+    p = new_primitive_type("short")
+    assert sizeof(p) == 2
+
+def test_integer_types():
+    for name in ['signed char', 'short', 'int', 'long', 'long long']:
+        p = new_primitive_type(name)
+        size = sizeof(p)
+        min = -(1 << (8*size-1))
+        max = (1 << (8*size-1)) - 1
+        assert int(cast(p, min)) == min
+        assert int(cast(p, max)) == max
+        assert int(cast(p, min - 1)) == max
+        assert int(cast(p, max + 1)) == min
+        py.test.raises(TypeError, cast, p, None)
+        assert long(cast(p, min - 1)) == max
+        assert int(cast(p, b'\x08')) == 8
+        assert int(cast(p, u+'\x08')) == 8
+    for name in ['char', 'short', 'int', 'long', 'long long']:
+        p = new_primitive_type('unsigned ' + name)
+        size = sizeof(p)
+        max = (1 << (8*size)) - 1
+        assert int(cast(p, 0)) == 0
+        assert int(cast(p, max)) == max
+        assert int(cast(p, -1)) == max
+        assert int(cast(p, max + 1)) == 0
+        assert long(cast(p, -1)) == max
+        assert int(cast(p, b'\xFE')) == 254
+        assert int(cast(p, u+'\xFE')) == 254
+
+def test_no_float_on_int_types():
+    p = new_primitive_type('long')
+    py.test.raises(TypeError, float, cast(p, 42))
+    py.test.raises(TypeError, complex, cast(p, 42))
+
+def test_float_types():
+    INF = 1E200 * 1E200
+    for name in ["float", "double"]:
+        p = new_primitive_type(name)
+        assert bool(cast(p, 0))
+        assert bool(cast(p, INF))
+        assert bool(cast(p, -INF))
+        assert int(cast(p, -150)) == -150
+        assert int(cast(p, 61.91)) == 61
+        assert long(cast(p, 61.91)) == 61
+        assert type(int(cast(p, 61.91))) is int
+        assert type(int(cast(p, 1E22))) is long
+        assert type(long(cast(p, 61.91))) is long
+        assert type(long(cast(p, 1E22))) is long
+        py.test.raises(OverflowError, int, cast(p, INF))
+        py.test.raises(OverflowError, int, cast(p, -INF))
+        assert float(cast(p, 1.25)) == 1.25
+        assert float(cast(p, INF)) == INF
+        assert float(cast(p, -INF)) == -INF
+        if name == "float":
+            assert float(cast(p, 1.1)) != 1.1     # rounding error
+            assert float(cast(p, 1E200)) == INF   # limited range
+
+        assert cast(p, -1.1) != cast(p, -1.1)
+        assert repr(float(cast(p, -0.0))) == '-0.0'
+        assert float(cast(p, b'\x09')) == 9.0
+        assert float(cast(p, u+'\x09')) == 9.0
+        assert float(cast(p, True)) == 1.0
+        py.test.raises(TypeError, cast, p, None)
+
+def test_complex_types():
+    py.test.skip("later")
+    INF = 1E200 * 1E200
+    for name in ["float", "double"]:
+        p = new_primitive_type("_Complex " + name)
+        assert bool(cast(p, 0))
+        assert bool(cast(p, INF))
+        assert bool(cast(p, -INF))
+        assert bool(cast(p, 0j))
+        assert bool(cast(p, INF*1j))
+        assert bool(cast(p, -INF*1j))
+        py.test.raises(TypeError, int, cast(p, -150))
+        py.test.raises(TypeError, long, cast(p, -150))
+        py.test.raises(TypeError, float, cast(p, -150))
+        assert complex(cast(p, 1.25)) == 1.25
+        assert complex(cast(p, 1.25j)) == 1.25j
+        assert float(cast(p, INF*1j)) == INF*1j
+        assert float(cast(p, -INF)) == -INF
+        if name == "float":
+            assert complex(cast(p, 1.1j)) != 1.1j         # rounding error
+            assert complex(cast(p, 1E200+3j)) == INF+3j   # limited range
+            assert complex(cast(p, 3+1E200j)) == 3+INF*1j # limited range
+
+        assert cast(p, -1.1j) != cast(p, -1.1j)
+        assert repr(complex(cast(p, -0.0)).real) == '-0.0'
+        assert repr(complex(cast(p, -0j))) == '-0j'
+        assert complex(cast(p, '\x09')) == 9.0
+        assert complex(cast(p, True)) == 1.0
+        py.test.raises(TypeError, cast, p, None)
+        #
+        py.test.raises(cast, new_primitive_type(name), 1+2j)
+    py.test.raises(cast, new_primitive_type("int"), 1+2j)
+
+def test_character_type():
+    p = new_primitive_type("char")
+    assert bool(cast(p, '\x00'))
+    assert cast(p, '\x00') != cast(p, -17*256)
+    assert int(cast(p, 'A')) == 65
+    assert long(cast(p, 'A')) == 65
+    assert type(int(cast(p, 'A'))) is int
+    assert type(long(cast(p, 'A'))) is long
+    assert str(cast(p, 'A')) == repr(cast(p, 'A'))
+    assert repr(cast(p, 'A')) == "<cdata 'char' %s'A'>" % mandatory_b_prefix
+    assert repr(cast(p, 255)) == r"<cdata 'char' %s'\xff'>" % mandatory_b_prefix
+    assert repr(cast(p, 0)) == r"<cdata 'char' %s'\x00'>" % mandatory_b_prefix
+
+def test_pointer_type():
+    p = new_primitive_type("int")
+    assert repr(p) == "<ctype 'int'>"
+    p = new_pointer_type(p)
+    assert repr(p) == "<ctype 'int *'>"
+    p = new_pointer_type(p)
+    assert repr(p) == "<ctype 'int * *'>"
+    p = new_pointer_type(p)
+    assert repr(p) == "<ctype 'int * * *'>"
+
+def test_pointer_to_int():
+    BInt = new_primitive_type("int")
+    py.test.raises(TypeError, newp, BInt)
+    py.test.raises(TypeError, newp, BInt, None)
+    BPtr = new_pointer_type(BInt)
+    p = newp(BPtr)
+    assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
+    p = newp(BPtr, None)
+    assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
+    p = newp(BPtr, 5000)
+    assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
+    q = cast(BPtr, p)
+    assert repr(q).startswith("<cdata 'int *' 0x")
+    assert p == q
+    assert hash(p) == hash(q)
+
+def test_pointer_bool():
+    BInt = new_primitive_type("int")
+    BPtr = new_pointer_type(BInt)
+    p = cast(BPtr, 0)
+    assert bool(p) is False
+    p = cast(BPtr, 42)
+    assert bool(p) is True
+
+def test_pointer_to_pointer():
+    BInt = new_primitive_type("int")
+    BPtr = new_pointer_type(BInt)
+    BPtrPtr = new_pointer_type(BPtr)
+    p = newp(BPtrPtr, None)
+    assert repr(p) == "<cdata 'int * *' owning %d bytes>" % size_of_ptr()
+
+def test_reading_pointer_to_int():
+    BInt = new_primitive_type("int")
+    BPtr = new_pointer_type(BInt)
+    p = newp(BPtr, None)
+    assert p[0] == 0
+    p = newp(BPtr, 5000)
+    assert p[0] == 5000
+    py.test.raises(IndexError, "p[1]")
+    py.test.raises(IndexError, "p[-1]")
+
+def test_reading_pointer_to_float():
+    BFloat = new_primitive_type("float")
+    py.test.raises(TypeError, newp, BFloat, None)
+    BPtr = new_pointer_type(BFloat)
+    p = newp(BPtr, None)
+    assert p[0] == 0.0 and type(p[0]) is float
+    p = newp(BPtr, 1.25)
+    assert p[0] == 1.25 and type(p[0]) is float
+    p = newp(BPtr, 1.1)
+    assert p[0] != 1.1 and abs(p[0] - 1.1) < 1E-5   # rounding errors
+
+def test_cast_float_to_int():
+    for type in ["int", "unsigned int", "long", "unsigned long",
+                 "long long", "unsigned long long"]:
+        p = new_primitive_type(type)
+        assert int(cast(p, 4.2)) == 4
+        py.test.raises(TypeError, newp, new_pointer_type(p), 4.2)
+
+def test_newp_integer_types():
+    for name in ['signed char', 'short', 'int', 'long', 'long long']:
+        p = new_primitive_type(name)
+        pp = new_pointer_type(p)
+        size = sizeof(p)
+        min = -(1 << (8*size-1))
+        max = (1 << (8*size-1)) - 1
+        assert newp(pp, min)[0] == min
+        assert newp(pp, max)[0] == max
+        py.test.raises(OverflowError, newp, pp, min - 1)
+        py.test.raises(OverflowError, newp, pp, max + 1)
+    for name in ['char', 'short', 'int', 'long', 'long long']:
+        p = new_primitive_type('unsigned ' + name)
+        pp = new_pointer_type(p)
+        size = sizeof(p)
+        max = (1 << (8*size)) - 1
+        assert newp(pp, 0)[0] == 0
+        assert newp(pp, max)[0] == max
+        py.test.raises(OverflowError, newp, pp, -1)
+        py.test.raises(OverflowError, newp, pp, max + 1)
+
+def test_reading_pointer_to_char():
+    BChar = new_primitive_type("char")
+    py.test.raises(TypeError, newp, BChar, None)
+    BPtr = new_pointer_type(BChar)
+    p = newp(BPtr, None)
+    assert p[0] == b'\x00'
+    p = newp(BPtr, b'A')
+    assert p[0] == b'A'
+    py.test.raises(TypeError, newp, BPtr, 65)
+    py.test.raises(TypeError, newp, BPtr, b"foo")
+    py.test.raises(TypeError, newp, BPtr, u+"foo")
+    c = cast(BChar, b'A')
+    assert str(c) == repr(c)
+    assert int(c) == ord(b'A')
+    py.test.raises(TypeError, cast, BChar, b'foo')
+    py.test.raises(TypeError, cast, BChar, u+'foo')
+
+def test_reading_pointer_to_pointer():
+    BVoidP = new_pointer_type(new_void_type())
+    BCharP = new_pointer_type(new_primitive_type("char"))
+    BInt = new_primitive_type("int")
+    BIntPtr = new_pointer_type(BInt)
+    BIntPtrPtr = new_pointer_type(BIntPtr)
+    q = newp(BIntPtr, 42)
+    assert q[0] == 42
+    p = newp(BIntPtrPtr, None)
+    assert p[0] is not None
+    assert p[0] == cast(BVoidP, 0)
+    assert p[0] == cast(BCharP, 0)
+    assert p[0] != None
+    assert repr(p[0]) == "<cdata 'int *' NULL>"
+    p[0] = q
+    assert p[0] != cast(BVoidP, 0)
+    assert p[0] != cast(BCharP, 0)
+    assert p[0][0] == 42
+    q[0] += 1
+    assert p[0][0] == 43
+    p = newp(BIntPtrPtr, q)
+    assert p[0][0] == 43
+
+def test_load_standard_library():
+    if sys.platform == "win32":
+        py.test.raises(OSError, find_and_load_library, None)
+        return
+    x = find_and_load_library(None)
+    BVoidP = new_pointer_type(new_void_type())
+    assert x.load_function(BVoidP, 'strcpy')
+    py.test.raises(KeyError, x.load_function,
+                   BVoidP, 'xxx_this_function_does_not_exist')
+
+def test_hash_differences():
+    BChar = new_primitive_type("char")
+    BInt = new_primitive_type("int")
+    BFloat = new_primitive_type("float")
+    for i in range(1, 20):
+        if (hash(cast(BChar, chr(i))) !=
+            hash(cast(BInt, i))):
+            break
+    else:
+        raise AssertionError("hashes are equal")
+    for i in range(1, 20):
+        if hash(cast(BFloat, i)) != hash(float(i)):
+            break
+    else:
+        raise AssertionError("hashes are equal")
+
+def test_no_len_on_nonarray():
+    p = new_primitive_type("int")
+    py.test.raises(TypeError, len, cast(p, 42))
+
+def test_cmp_none():
+    p = new_primitive_type("int")
+    x = cast(p, 42)
+    assert (x == None) is False
+    assert (x != None) is True
+    assert (x == ["hello"]) is False
+    assert (x != ["hello"]) is True
+
+def test_invalid_indexing():
+    p = new_primitive_type("int")
+    x = cast(p, 42)
+    py.test.raises(TypeError, "p[0]")
+
+def test_default_str():
+    BChar = new_primitive_type("char")
+    x = cast(BChar, 42)
+    assert str(x) == repr(x)
+    BInt = new_primitive_type("int")
+    x = cast(BInt, 42)
+    assert str(x) == repr(x)
+    BArray = new_array_type(new_pointer_type(BInt), 10)
+    x = newp(BArray, None)
+    assert str(x) == repr(x)
+
+def test_default_unicode():
+    BInt = new_primitive_type("int")
+    x = cast(BInt, 42)
+    assert unicode(x) == unicode(repr(x))
+    BArray = new_array_type(new_pointer_type(BInt), 10)
+    x = newp(BArray, None)
+    assert unicode(x) == unicode(repr(x))
+
+def test_cast_from_cdataint():
+    BInt = new_primitive_type("int")
+    x = cast(BInt, 0)
+    y = cast(new_pointer_type(BInt), x)
+    assert bool(y) is False
+    #
+    x = cast(BInt, 42)
+    y = cast(BInt, x)
+    assert int(y) == 42
+    y = cast(new_primitive_type("char"), x)
+    assert int(y) == 42
+    y = cast(new_primitive_type("float"), x)
+    assert float(y) == 42.0
+    #
+    z = cast(BInt, 42.5)
+    assert int(z) == 42
+    z = cast(BInt, y)
+    assert int(z) == 42
+
+def test_array_type():
+    p = new_primitive_type("int")
+    assert repr(p) == "<ctype 'int'>"
+    #
+    py.test.raises(TypeError, new_array_type, new_pointer_type(p), "foo")
+    py.test.raises(ValueError, new_array_type, new_pointer_type(p), -42)
+    #
+    p1 = new_array_type(new_pointer_type(p), None)
+    assert repr(p1) == "<ctype 'int[]'>"
+    py.test.raises(ValueError, new_array_type, new_pointer_type(p1), 42)
+    #
+    p1 = new_array_type(new_pointer_type(p), 42)
+    p2 = new_array_type(new_pointer_type(p1), 25)
+    assert repr(p2) == "<ctype 'int[25][42]'>"
+    p2 = new_array_type(new_pointer_type(p1), None)
+    assert repr(p2) == "<ctype 'int[][42]'>"
+    #
+    py.test.raises(OverflowError,
+                   new_array_type, new_pointer_type(p), sys.maxsize+1)
+    py.test.raises(OverflowError,
+                   new_array_type, new_pointer_type(p), sys.maxsize // 3)
+
+def test_array_instance():
+    LENGTH = 1423
+    p = new_primitive_type("int")
+    p1 = new_array_type(new_pointer_type(p), LENGTH)
+    a = newp(p1, None)
+    assert repr(a) == "<cdata 'int[%d]' owning %d bytes>" % (
+        LENGTH, LENGTH * size_of_int())
+    assert len(a) == LENGTH
+    for i in range(LENGTH):
+        assert a[i] == 0
+    py.test.raises(IndexError, "a[LENGTH]")
+    py.test.raises(IndexError, "a[-1]")
+    for i in range(LENGTH):
+        a[i] = i * i + 1
+    for i in range(LENGTH):
+        assert a[i] == i * i + 1
+    e = py.test.raises(IndexError, "a[LENGTH+100] = 500")
+    assert ('(expected %d < %d)' % (LENGTH+100, LENGTH)) in str(e.value)
+    py.test.raises(TypeError, int, a)
+
+def test_array_of_unknown_length_instance():
+    p = new_primitive_type("int")
+    p1 = new_array_type(new_pointer_type(p), None)
+    py.test.raises(TypeError, newp, p1, None)
+    py.test.raises(ValueError, newp, p1, -42)
+    a = newp(p1, 42)
+    assert len(a) == 42
+    for i in range(42):
+        a[i] -= i
+    for i in range(42):
+        assert a[i] == -i
+    py.test.raises(IndexError, "a[42]")
+    py.test.raises(IndexError, "a[-1]")
+    py.test.raises(IndexError, "a[42] = 123")
+    py.test.raises(IndexError, "a[-1] = 456")
+
+def test_array_of_unknown_length_instance_with_initializer():
+    p = new_primitive_type("int")
+    p1 = new_array_type(new_pointer_type(p), None)
+    a = newp(p1, list(range(42)))
+    assert len(a) == 42
+    a = newp(p1, tuple(range(142)))
+    assert len(a) == 142
+
+def test_array_initializer():
+    p = new_primitive_type("int")
+    p1 = new_array_type(new_pointer_type(p), None)
+    a = newp(p1, list(range(100, 142)))
+    for i in range(42):
+        assert a[i] == 100 + i
+    #
+    p2 = new_array_type(new_pointer_type(p), 43)
+    a = newp(p2, tuple(range(100, 142)))
+    for i in range(42):
+        assert a[i] == 100 + i
+    assert a[42] == 0      # extra uninitialized item
+
+def test_array_add():
+    p = new_primitive_type("int")
+    p1 = new_array_type(new_pointer_type(p), 5)    # int[5]
+    p2 = new_array_type(new_pointer_type(p1), 3)   # int[3][5]
+    a = newp(p2, [list(range(n, n+5)) for n in [100, 200, 300]])
+    assert repr(a) == "<cdata 'int[3][5]' owning %d bytes>" % (
+        3*5*size_of_int(),)
+    assert repr(a + 0).startswith("<cdata 'int(*)[5]' 0x")
+    assert repr(a[0]).startswith("<cdata 'int[5]' 0x")
+    assert repr((a + 0)[0]).startswith("<cdata 'int[5]' 0x")
+    assert repr(a[0] + 0).startswith("<cdata 'int *' 0x")
+    assert type(a[0][0]) is int
+    assert type((a[0] + 0)[0]) is int
+
+def test_array_sub():
+    BInt = new_primitive_type("int")
+    BArray = new_array_type(new_pointer_type(BInt), 5)   # int[5]
+    a = newp(BArray, None)
+    p = a + 1
+    assert p - a == 1
+    assert p - (a+0) == 1
+    assert a == (p - 1)
+    BPtr = new_pointer_type(new_primitive_type("short"))
+    q = newp(BPtr, None)
+    py.test.raises(TypeError, "p - q")
+    py.test.raises(TypeError, "q - p")
+    py.test.raises(TypeError, "a - q")
+    e = py.test.raises(TypeError, "q - a")
+    assert str(e.value) == "cannot subtract cdata 'short *' and cdata 'int *'"
+
+def test_cast_primitive_from_cdata():
+    p = new_primitive_type("int")
+    n = cast(p, cast(p, -42))
+    assert int(n) == -42
+    #
+    p = new_primitive_type("unsigned int")
+    n = cast(p, cast(p, 42))
+    assert int(n) == 42
+    #
+    p = new_primitive_type("long long")
+    n = cast(p, cast(p, -(1<<60)))
+    assert int(n) == -(1<<60)
+    #
+    p = new_primitive_type("unsigned long long")
+    n = cast(p, cast(p, 1<<63))
+    assert int(n) == 1<<63
+    #
+    p = new_primitive_type("float")
+    n = cast(p, cast(p, 42.5))
+    assert float(n) == 42.5
+    #
+    p = new_primitive_type("char")
+    n = cast(p, cast(p, "A"))
+    assert int(n) == ord("A")
+
+def test_new_primitive_from_cdata():
+    p = new_primitive_type("int")
+    p1 = new_pointer_type(p)
+    n = newp(p1, cast(p, -42))
+    assert n[0] == -42
+    #
+    p = new_primitive_type("unsigned int")
+    p1 = new_pointer_type(p)
+    n = newp(p1, cast(p, 42))
+    assert n[0] == 42
+    #
+    p = new_primitive_type("float")
+    p1 = new_pointer_type(p)
+    n = newp(p1, cast(p, 42.5))
+    assert n[0] == 42.5
+    #
+    p = new_primitive_type("char")
+    p1 = new_pointer_type(p)
+    n = newp(p1, cast(p, "A"))
+    assert n[0] == b"A"
+
+def test_cast_between_pointers():
+    BIntP = new_pointer_type(new_primitive_type("int"))
+    BIntA = new_array_type(BIntP, None)
+    a = newp(BIntA, [40, 41, 42, 43, 44])
+    BShortP = new_pointer_type(new_primitive_type("short"))
+    b = cast(BShortP, a)
+    c = cast(BIntP, b)
+    assert c[3] == 43
+    BLongLong = new_primitive_type("long long")
+    d = cast(BLongLong, c)
+    e = cast(BIntP, d)
+    assert e[3] == 43
+    f = cast(BIntP, int(d))
+    assert f[3] == 43
+    #
+    b = cast(BShortP, 0)
+    assert not b
+    c = cast(BIntP, b)
+    assert not c
+    assert int(cast(BLongLong, c)) == 0
+
+def test_alignof():
+    BInt = new_primitive_type("int")
+    assert alignof(BInt) == sizeof(BInt)
+    BPtr = new_pointer_type(BInt)
+    assert alignof(BPtr) == sizeof(BPtr)
+    BArray = new_array_type(BPtr, None)
+    assert alignof(BArray) == alignof(BInt)
+
+def test_new_struct_type():
+    BStruct = new_struct_type("foo")
+    assert repr(BStruct) == "<ctype 'struct foo'>"
+    BPtr = new_pointer_type(BStruct)
+    assert repr(BPtr) == "<ctype 'struct foo *'>"
+    py.test.raises(TypeError, alignof, BStruct)
+
+def test_new_union_type():
+    BUnion = new_union_type("foo")
+    assert repr(BUnion) == "<ctype 'union foo'>"
+    BPtr = new_pointer_type(BUnion)
+    assert repr(BPtr) == "<ctype 'union foo *'>"
+
+def test_complete_struct():
+    BLong = new_primitive_type("long")
+    BChar = new_primitive_type("char")
+    BShort = new_primitive_type("short")
+    BStruct = new_struct_type("foo")
+    assert _getfields(BStruct) is None
+    complete_struct_or_union(BStruct, [('a1', BLong, -1),
+                                       ('a2', BChar, -1),
+                                       ('a3', BShort, -1)])
+    d = _getfields(BStruct)
+    assert len(d) == 3
+    assert d[0][0] == 'a1'
+    assert d[0][1].type is BLong
+    assert d[0][1].offset == 0
+    assert d[0][1].bitshift == -1
+    assert d[0][1].bitsize == -1
+    assert d[1][0] == 'a2'
+    assert d[1][1].type is BChar
+    assert d[1][1].offset == sizeof(BLong)
+    assert d[1][1].bitshift == -1
+    assert d[1][1].bitsize == -1
+    assert d[2][0] == 'a3'
+    assert d[2][1].type is BShort
+    assert d[2][1].offset == sizeof(BLong) + sizeof(BShort)
+    assert d[2][1].bitshift == -1
+    assert d[2][1].bitsize == -1
+    assert sizeof(BStruct) == 2 * sizeof(BLong)
+    assert alignof(BStruct) == alignof(BLong)
+
+def test_complete_union():
+    BLong = new_primitive_type("long")
+    BChar = new_primitive_type("char")
+    BUnion = new_union_type("foo")
+    assert _getfields(BUnion) is None
+    complete_struct_or_union(BUnion, [('a1', BLong, -1),
+                                      ('a2', BChar, -1)])
+    d = _getfields(BUnion)
+    assert len(d) == 2
+    assert d[0][0] == 'a1'
+    assert d[0][1].type is BLong
+    assert d[0][1].offset == 0
+    assert d[1][0] == 'a2'
+    assert d[1][1].type is BChar
+    assert d[1][1].offset == 0
+    assert sizeof(BUnion) == sizeof(BLong)
+    assert alignof(BUnion) == alignof(BLong)
+
+def test_struct_instance():
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    p = cast(BStructPtr, 0)
+    py.test.raises(AttributeError, "p.a1")    # opaque
+    complete_struct_or_union(BStruct, [('a1', BInt, -1),
+                                       ('a2', BInt, -1)])
+    p = newp(BStructPtr, None)
+    s = p[0]
+    assert s.a1 == 0
+    s.a2 = 123
+    assert s.a1 == 0
+    assert s.a2 == 123
+    py.test.raises(OverflowError, "s.a1 = sys.maxsize+1")
+    assert s.a1 == 0
+    py.test.raises(AttributeError, "p.foobar")
+    py.test.raises(AttributeError, "s.foobar")
+
+def test_union_instance():
+    BInt = new_primitive_type("int")
+    BUInt = new_primitive_type("unsigned int")
+    BUnion = new_union_type("bar")
+    complete_struct_or_union(BUnion, [('a1', BInt, -1), ('a2', BUInt, -1)])
+    p = newp(new_pointer_type(BUnion), [-42])
+    bigval = -42 + (1 << (8*size_of_int()))
+    assert p.a1 == -42
+    assert p.a2 == bigval
+    p = newp(new_pointer_type(BUnion), {'a2': bigval})
+    assert p.a1 == -42
+    assert p.a2 == bigval
+    py.test.raises(OverflowError, newp, new_pointer_type(BUnion),
+                   {'a1': bigval})
+    p = newp(new_pointer_type(BUnion), [])
+    assert p.a1 == p.a2 == 0
+
+def test_struct_pointer():
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', BInt, -1),
+                                       ('a2', BInt, -1)])
+    p = newp(BStructPtr, None)
+    assert p.a1 == 0      # read/write via the pointer (C equivalent: '->')
+    p.a2 = 123
+    assert p.a1 == 0
+    assert p.a2 == 123
+
+def test_struct_init_list():
+    BVoidP = new_pointer_type(new_void_type())
+    BInt = new_primitive_type("int")
+    BIntPtr = new_pointer_type(BInt)
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', BInt, -1),
+                                       ('a2', BInt, -1),
+                                       ('a3', BInt, -1),
+                                       ('p4', BIntPtr, -1)])
+    s = newp(BStructPtr, [123, 456])
+    assert s.a1 == 123
+    assert s.a2 == 456
+    assert s.a3 == 0
+    assert s.p4 == cast(BVoidP, 0)
+    #
+    s = newp(BStructPtr, {'a2': 41122, 'a3': -123})
+    assert s.a1 == 0
+    assert s.a2 == 41122
+    assert s.a3 == -123
+    assert s.p4 == cast(BVoidP, 0)
+    #
+    py.test.raises(KeyError, newp, BStructPtr, {'foobar': 0})
+    #
+    p = newp(BIntPtr, 14141)
+    s = newp(BStructPtr, [12, 34, 56, p])
+    assert s.p4 == p
+    #
+    s = newp(BStructPtr, [12, 34, 56, cast(BVoidP, 0)])
+    assert s.p4 == cast(BVoidP, 0)
+    #
+    py.test.raises(TypeError, newp, BStructPtr, [12, 34, 56, None])
+
+def test_array_in_struct():
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("foo")
+    BArrayInt5 = new_array_type(new_pointer_type(BInt), 5)
+    complete_struct_or_union(BStruct, [('a1', BArrayInt5, -1)])
+    s = newp(new_pointer_type(BStruct), [[20, 24, 27, 29, 30]])
+    assert s.a1[2] == 27
+    assert repr(s.a1).startswith("<cdata 'int[5]' 0x")
+
+def test_offsetof():
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("foo")
+    py.test.raises(TypeError, offsetof, BInt, "abc")
+    py.test.raises(TypeError, offsetof, BStruct, "abc")
+    complete_struct_or_union(BStruct, [('abc', BInt, -1), ('def', BInt, -1)])
+    assert offsetof(BStruct, 'abc') == 0
+    assert offsetof(BStruct, 'def') == size_of_int()
+    py.test.raises(KeyError, offsetof, BStruct, "ghi")
+
+def test_function_type():
+    BInt = new_primitive_type("int")
+    BFunc = new_function_type((BInt, BInt), BInt, False)
+    assert repr(BFunc) == "<ctype 'int(*)(int, int)'>"
+    BFunc2 = new_function_type((), BFunc, False)
+    assert repr(BFunc2) == "<ctype 'int(*(*)())(int, int)'>"
+
+def test_function_type_taking_struct():
+    BChar = new_primitive_type("char")
+    BShort = new_primitive_type("short")
+    BStruct = new_struct_type("foo")
+    complete_struct_or_union(BStruct, [('a1', BChar, -1),
+                                       ('a2', BShort, -1)])
+    BFunc = new_function_type((BStruct,), BShort, False)
+    assert repr(BFunc) == "<ctype 'short(*)(struct foo)'>"
+
+def test_function_void_result():
+    BVoid = new_void_type()
+    BInt = new_primitive_type("int")
+    BFunc = new_function_type((BInt, BInt), BVoid, False)
+    assert repr(BFunc) == "<ctype 'void(*)(int, int)'>"
+
+def test_function_void_arg():
+    BVoid = new_void_type()
+    BInt = new_primitive_type("int")
+    py.test.raises(TypeError, new_function_type, (BVoid,), BInt, False)
+
+def test_call_function_0():
+    BSignedChar = new_primitive_type("signed char")
+    BFunc0 = new_function_type((BSignedChar, BSignedChar), BSignedChar, False)
+    f = cast(BFunc0, _testfunc(0))
+    assert f(40, 2) == 42
+    assert f(-100, -100) == -200 + 256
+    py.test.raises(OverflowError, f, 128, 0)
+    py.test.raises(OverflowError, f, 0, 128)
+
+def test_call_function_1():
+    BInt = new_primitive_type("int")
+    BLong = new_primitive_type("long")
+    BFunc1 = new_function_type((BInt, BLong), BLong, False)
+    f = cast(BFunc1, _testfunc(1))
+    assert f(40, 2) == 42
+    assert f(-100, -100) == -200
+    int_max = (1 << (8*size_of_int()-1)) - 1
+    long_max = (1 << (8*size_of_long()-1)) - 1
+    if int_max == long_max:
+        assert f(int_max, 1) == - int_max - 1
+    else:
+        assert f(int_max, 1) == int_max + 1
+
+def test_call_function_2():
+    BLongLong = new_primitive_type("long long")
+    BFunc2 = new_function_type((BLongLong, BLongLong), BLongLong, False)
+    f = cast(BFunc2, _testfunc(2))
+    longlong_max = (1 << (8*sizeof(BLongLong)-1)) - 1
+    assert f(longlong_max - 42, 42) == longlong_max
+    assert f(43, longlong_max - 42) == - longlong_max - 1
+
+def test_call_function_3():
+    BFloat = new_primitive_type("float")
+    BDouble = new_primitive_type("double")
+    BFunc3 = new_function_type((BFloat, BDouble), BDouble, False)
+    f = cast(BFunc3, _testfunc(3))
+    assert f(1.25, 5.1) == 1.25 + 5.1     # exact
+    res = f(1.3, 5.1)
+    assert res != 6.4 and abs(res - 6.4) < 1E-5    # inexact
+
+def test_call_function_4():
+    BFloat = new_primitive_type("float")
+    BDouble = new_primitive_type("double")
+    BFunc4 = new_function_type((BFloat, BDouble), BFloat, False)
+    f = cast(BFunc4, _testfunc(4))
+    res = f(1.25, 5.1)
+    assert res != 6.35 and abs(res - 6.35) < 1E-5    # inexact
+
+def test_call_function_5():
+    BVoid = new_void_type()
+    BFunc5 = new_function_type((), BVoid, False)
+    f = cast(BFunc5, _testfunc(5))
+    f()   # did not crash
+
+def test_call_function_6():
+    BInt = new_primitive_type("int")
+    BIntPtr = new_pointer_type(BInt)
+    BFunc6 = new_function_type((BIntPtr,), BIntPtr, False)
+    f = cast(BFunc6, _testfunc(6))
+    x = newp(BIntPtr, 42)
+    res = f(x)
+    assert typeof(res) is BIntPtr
+    assert res[0] == 42 - 1000
+    #
+    BIntArray = new_array_type(BIntPtr, None)
+    BFunc6bis = new_function_type((BIntArray,), BIntPtr, False)
+    f = cast(BFunc6bis, _testfunc(6))
+    #
+    res = f([142])
+    assert typeof(res) is BIntPtr
+    assert res[0] == 142 - 1000
+    #
+    res = f((143,))
+    assert typeof(res) is BIntPtr
+    assert res[0] == 143 - 1000
+    #
+    x = newp(BIntArray, [242])
+    res = f(x)
+    assert typeof(res) is BIntPtr
+    assert res[0] == 242 - 1000
+    #
+    py.test.raises(TypeError, f, 123456)
+    py.test.raises(TypeError, f, "foo")
+    py.test.raises(TypeError, f, u+"bar")
+
+def test_call_function_7():
+    BChar = new_primitive_type("char")
+    BShort = new_primitive_type("short")
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', BChar, -1),
+                                       ('a2', BShort, -1)])
+    BFunc7 = new_function_type((BStruct,), BShort, False)
+    f = cast(BFunc7, _testfunc(7))
+    res = f({'a1': b'A', 'a2': -4042})
+    assert res == -4042 + ord(b'A')
+    #
+    x = newp(BStructPtr, {'a1': b'A', 'a2': -4042})
+    res = f(x[0])
+    assert res == -4042 + ord(b'A')
+
+def test_call_function_20():
+    BChar = new_primitive_type("char")
+    BShort = new_primitive_type("short")
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', BChar, -1),
+                                       ('a2', BShort, -1)])
+    BFunc20 = new_function_type((BStructPtr,), BShort, False)
+    f = cast(BFunc20, _testfunc(20))
+    x = newp(BStructPtr, {'a1': b'A', 'a2': -4042})
+    # test the exception that allows us to pass a 'struct foo' where the
+    # function really expects a 'struct foo *'.
+    res = f(x[0])
+    assert res == -4042 + ord(b'A')
+    assert res == f(x)
+
+def test_call_function_21():
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("foo")
+    complete_struct_or_union(BStruct, [('a', BInt, -1),
+                                       ('b', BInt, -1),
+                                       ('c', BInt, -1),
+                                       ('d', BInt, -1),
+                                       ('e', BInt, -1),
+                                       ('f', BInt, -1),
+                                       ('g', BInt, -1),
+                                       ('h', BInt, -1),
+                                       ('i', BInt, -1),
+                                       ('j', BInt, -1)])
+    BFunc21 = new_function_type((BStruct,), BInt, False)
+    f = cast(BFunc21, _testfunc(21))
+    res = f(range(13, 3, -1))
+    lst = [(n << i) for (i, n) in enumerate(range(13, 3, -1))]
+    assert res == sum(lst)
+
+def test_call_function_9():
+    BInt = new_primitive_type("int")
+    BFunc9 = new_function_type((BInt,), BInt, True)    # vararg
+    f = cast(BFunc9, _testfunc(9))
+    assert f(0) == 0
+    assert f(1, cast(BInt, 42)) == 42
+    assert f(2, cast(BInt, 40), cast(BInt, 2)) == 42
+    py.test.raises(TypeError, f, 1, 42)
+    py.test.raises(TypeError, f, 2, None)
+    # promotion of chars and shorts to ints
+    BSChar = new_primitive_type("signed char")
+    BUChar = new_primitive_type("unsigned char")
+    BSShort = new_primitive_type("short")
+    assert f(3, cast(BSChar, -3), cast(BUChar, 200), cast(BSShort, -5)) == 192
+
+def test_cannot_call_with_a_autocompleted_struct():
+    BSChar = new_primitive_type("signed char")
+    BDouble = new_primitive_type("double")
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('c', BDouble, -1, 8),
+                                       ('a', BSChar, -1, 2),
+                                       ('b', BSChar, -1, 0)])
+    e = py.test.raises(TypeError, new_function_type, (BStruct,), BDouble)
+    msg ='cannot pass as an argument a struct that was completed with verify()'
+    assert msg in str(e.value)
+
+def test_new_charp():
+    BChar = new_primitive_type("char")
+    BCharP = new_pointer_type(BChar)
+    BCharA = new_array_type(BCharP, None)
+    x = newp(BCharA, 42)
+    assert len(x) == 42
+    x = newp(BCharA, b"foobar")
+    assert len(x) == 7
+
+def test_load_and_call_function():
+    BChar = new_primitive_type("char")
+    BCharP = new_pointer_type(BChar)
+    BLong = new_primitive_type("long")
+    BFunc = new_function_type((BCharP,), BLong, False)
+    ll = find_and_load_library('c')
+    strlen = ll.load_function(BFunc, "strlen")
+    input = newp(new_array_type(BCharP, None), b"foobar")
+    assert strlen(input) == 6
+    #
+    assert strlen(b"foobarbaz") == 9
+    #
+    BVoidP = new_pointer_type(new_void_type())
+    strlenaddr = ll.load_function(BVoidP, "strlen")
+    assert strlenaddr == cast(BVoidP, strlen)
+
+def test_read_variable():
+    if sys.platform == 'win32':
+        py.test.skip("untested")
+    BVoidP = new_pointer_type(new_void_type())
+    ll = find_and_load_library('c')
+    stderr = ll.read_variable(BVoidP, "stderr")
+    assert stderr == cast(BVoidP, _testfunc(8))
+
+def test_read_variable_as_unknown_length_array():
+    if sys.platform == 'win32':
+        py.test.skip("untested")
+    BCharP = new_pointer_type(new_primitive_type("char"))
+    BArray = new_array_type(BCharP, None)
+    ll = find_and_load_library('c')
+    stderr = ll.read_variable(BArray, "stderr")
+    assert repr(stderr).startswith("<cdata 'char *' 0x")
+    # ^^ and not 'char[]', which is basically not allowed and would crash
+
+def test_write_variable():
+    if sys.platform == 'win32':
+        py.test.skip("untested")
+    BVoidP = new_pointer_type(new_void_type())
+    ll = find_and_load_library('c')
+    stderr = ll.read_variable(BVoidP, "stderr")
+    ll.write_variable(BVoidP, "stderr", cast(BVoidP, 0))
+    assert ll.read_variable(BVoidP, "stderr") is not None
+    assert not ll.read_variable(BVoidP, "stderr")
+    ll.write_variable(BVoidP, "stderr", stderr)
+    assert ll.read_variable(BVoidP, "stderr") == stderr
+
+def test_callback():
+    BInt = new_primitive_type("int")
+    def make_callback():
+        def cb(n):
+            return n + 1
+        BFunc = new_function_type((BInt,), BInt, False)
+        return callback(BFunc, cb, 42)    # 'cb' and 'BFunc' go out of scope
+    f = make_callback()
+    assert f(-142) == -141
+    assert repr(f).startswith(
+        "<cdata 'int(*)(int)' calling <function ")
+    assert "cb at 0x" in repr(f)
+    e = py.test.raises(TypeError, f)
+    assert str(e.value) == "'int(*)(int)' expects 1 arguments, got 0"
+
+def test_callback_return_type():
+    for rettype in ["signed char", "short", "int", "long", "long long",
+                    "unsigned char", "unsigned short", "unsigned int",
+                    "unsigned long", "unsigned long long"]:
+        BRet = new_primitive_type(rettype)
+        def cb(n):
+            return n + 1
+        BFunc = new_function_type((BRet,), BRet)
+        f = callback(BFunc, cb, 42)
+        assert f(41) == 42
+        if rettype.startswith("unsigned "):
+            min = 0
+            max = (1 << (8*sizeof(BRet))) - 1
+        else:
+            min = -(1 << (8*sizeof(BRet)-1))
+            max = (1 << (8*sizeof(BRet)-1)) - 1
+        assert f(min) == min + 1
+        assert f(max - 1) == max
+        assert f(max) == 42
+
+def test_a_lot_of_callbacks():
+    BIGNUM = 10000
+    if 'PY_DOT_PY' in globals(): BIGNUM = 100   # tests on py.py
+    #
+    BInt = new_primitive_type("int")
+    BFunc = new_function_type((BInt,), BInt, False)
+    def make_callback(m):
+        def cb(n):
+            return n + m
+        return callback(BFunc, cb, 42)    # 'cb' and 'BFunc' go out of scope
+    #
+    flist = [make_callback(i) for i in range(BIGNUM)]
+    for i, f in enumerate(flist):
+        assert f(-142) == -142 + i
+
+def test_callback_returning_struct():
+    BSChar = new_primitive_type("signed char")
+    BInt = new_primitive_type("int")
+    BDouble = new_primitive_type("double")
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a', BSChar, -1),
+                                       ('b', BDouble, -1)])
+    def cb(n):
+        return newp(BStructPtr, [-n, 1E-42])[0]
+    BFunc = new_function_type((BInt,), BStruct)
+    f = callback(BFunc, cb)
+    s = f(10)
+    assert typeof(s) is BStruct
+    assert repr(s) in ["<cdata 'struct foo' owning 12 bytes>",
+                       "<cdata 'struct foo' owning 16 bytes>"]
+    assert s.a == -10
+    assert s.b == 1E-42
+
+def test_callback_returning_big_struct():
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a', BInt, -1),
+                                       ('b', BInt, -1),
+                                       ('c', BInt, -1),
+                                       ('d', BInt, -1),
+                                       ('e', BInt, -1),
+                                       ('f', BInt, -1),
+                                       ('g', BInt, -1),
+                                       ('h', BInt, -1),
+                                       ('i', BInt, -1),
+                                       ('j', BInt, -1)])
+    def cb():
+        return newp(BStructPtr, range(13, 3, -1))[0]
+    BFunc = new_function_type((), BStruct)
+    f = callback(BFunc, cb)
+    s = f()
+    assert typeof(s) is BStruct
+    assert repr(s) in ["<cdata 'struct foo' owning 40 bytes>",
+                       "<cdata 'struct foo' owning 80 bytes>"]
+    for i, name in enumerate("abcdefghij"):
+        assert getattr(s, name) == 13 - i
+
+def test_callback_returning_void():
+    BVoid = new_void_type()
+    BFunc = new_function_type((), BVoid, False)
+    def cb():
+        seen.append(42)
+    f = callback(BFunc, cb)
+    seen = []
+    f()
+    assert seen == [42]
+    py.test.raises(TypeError, callback, BFunc, cb, -42)
+
+def test_enum_type():
+    BEnum = new_enum_type("foo", (), ())
+    assert repr(BEnum) == "<ctype 'enum foo'>"
+    assert _getfields(BEnum) == []
+    #
+    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
+    assert _getfields(BEnum) == [(-20, 'ab'), (0, 'def'), (1, 'c')]
+
+def test_cast_to_enum():
+    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
+    e = cast(BEnum, 0)
+    assert repr(e) == "<cdata 'enum foo' 'def'>"
+    assert string(e) == 'def'
+    assert string(cast(BEnum, -20)) == 'ab'
+    assert string(cast(BEnum, 'c')) == 'c'
+    assert int(cast(BEnum, 'c')) == 1
+    assert int(cast(BEnum, 'def')) == 0
+    assert int(cast(BEnum, -242 + 2**128)) == -242
+    assert string(cast(BEnum, -242 + 2**128)) == '#-242'
+    assert string(cast(BEnum, '#-20')) == 'ab'
+    assert repr(cast(BEnum, '#-20')) == "<cdata 'enum foo' 'ab'>"
+    assert repr(cast(BEnum, '#-21')) == "<cdata 'enum foo' '#-21'>"
+
+def test_enum_with_non_injective_mapping():
+    BEnum = new_enum_type("foo", ('ab', 'cd'), (7, 7))
+    e = cast(BEnum, 7)
+    assert repr(e) == "<cdata 'enum foo' 'ab'>"
+    assert string(e) == 'ab'
+
+def test_enum_in_struct():
+    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
+    BStruct = new_struct_type("bar")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', BEnum, -1)])
+    p = newp(BStructPtr, [-20])
+    assert p.a1 == "ab"
+    p = newp(BStructPtr, ["c"])
+    assert p.a1 == "c"
+    e = py.test.raises(TypeError, newp, BStructPtr, [None])
+    assert "must be a str or int, not NoneType" in str(e.value)
+
+def test_callback_returning_enum():
+    BInt = new_primitive_type("int")
+    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
+    def cb(n):
+        return '#%d' % n
+    BFunc = new_function_type((BInt,), BEnum)
+    f = callback(BFunc, cb)
+    assert f(0) == 'def'
+    assert f(1) == 'c'
+    assert f(-20) == 'ab'
+    assert f(20) == '#20'
+
+def test_callback_returning_char():
+    BInt = new_primitive_type("int")
+    BChar = new_primitive_type("char")
+    def cb(n):
+        return bytechr(n)
+    BFunc = new_function_type((BInt,), BChar)
+    f = callback(BFunc, cb)
+    assert f(0) == b'\x00'
+    assert f(255) == b'\xFF'
+
+def _hacked_pypy_uni4():
+    pyuni4 = {1: True, 2: False}[len(u+'\U00012345')]
+    return 'PY_DOT_PY' in globals() and not pyuni4
+
+def test_callback_returning_wchar_t():
+    BInt = new_primitive_type("int")
+    BWChar = new_primitive_type("wchar_t")
+    def cb(n):
+        if n == -1:
+            return u+'\U00012345'
+        if n == -2:
+            raise ValueError
+        return unichr(n)
+    BFunc = new_function_type((BInt,), BWChar)
+    f = callback(BFunc, cb)
+    assert f(0) == unichr(0)
+    assert f(255) == unichr(255)
+    assert f(0x1234) == u+'\u1234'
+    if sizeof(BWChar) == 4 and not _hacked_pypy_uni4():
+        assert f(-1) == u+'\U00012345'
+    assert f(-2) == u+'\x00'   # and an exception printed to stderr
+
+def test_struct_with_bitfields():
+    BLong = new_primitive_type("long")
+    BStruct = new_struct_type("foo")
+    LONGBITS = 8 * sizeof(BLong)
+    complete_struct_or_union(BStruct, [('a1', BLong, 1),
+                                       ('a2', BLong, 2),
+                                       ('a3', BLong, 3),
+                                       ('a4', BLong, LONGBITS - 5)])
+    d = _getfields(BStruct)
+    assert d[0][1].offset == d[1][1].offset == d[2][1].offset == 0
+    assert d[3][1].offset == sizeof(BLong)
+    assert d[0][1].bitshift == 0
+    assert d[0][1].bitsize == 1
+    assert d[1][1].bitshift == 1
+    assert d[1][1].bitsize == 2
+    assert d[2][1].bitshift == 3
+    assert d[2][1].bitsize == 3
+    assert d[3][1].bitshift == 0
+    assert d[3][1].bitsize == LONGBITS - 5
+    assert sizeof(BStruct) == 2 * sizeof(BLong)
+    assert alignof(BStruct) == alignof(BLong)
+
+def test_bitfield_instance():
+    BInt = new_primitive_type("int")
+    BUnsignedInt = new_primitive_type("unsigned int")
+    BStruct = new_struct_type("foo")
+    complete_struct_or_union(BStruct, [('a1', BInt, 1),
+                                       ('a2', BUnsignedInt, 2),
+                                       ('a3', BInt, 3)])
+    p = newp(new_pointer_type(BStruct), None)
+    p.a1 = -1
+    assert p.a1 == -1
+    p.a1 = 0
+    py.test.raises(OverflowError, "p.a1 = 2")
+    assert p.a1 == 0
+    #
+    p.a1 = -1
+    p.a2 = 3
+    p.a3 = -4
+    py.test.raises(OverflowError, "p.a3 = 4")
+    e = py.test.raises(OverflowError, "p.a3 = -5")
+    assert str(e.value) == ("value -5 outside the range allowed by the "
+                            "bit field width: -4 <= x <= 3")
+    assert p.a1 == -1 and p.a2 == 3 and p.a3 == -4
+    #
+    # special case for convenience: "int x:1", while normally signed,
+    # allows also setting the value "1" (it still gets read back as -1)
+    p.a1 = 1
+    assert p.a1 == -1
+    e = py.test.raises(OverflowError, "p.a1 = -2")
+    assert str(e.value) == ("value -2 outside the range allowed by the "
+                            "bit field width: -1 <= x <= 1")
+
+def test_bitfield_instance_init():
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("foo")
+    complete_struct_or_union(BStruct, [('a1', BInt, 1)])
+    p = newp(new_pointer_type(BStruct), [-1])
+    assert p.a1 == -1
+    p = newp(new_pointer_type(BStruct), {'a1': -1})
+    assert p.a1 == -1
+    #
+    BUnion = new_union_type("bar")
+    complete_struct_or_union(BUnion, [('a1', BInt, 1)])
+    p = newp(new_pointer_type(BUnion), [-1])
+    assert p.a1 == -1
+
+def test_weakref():
+    import weakref
+    BInt = new_primitive_type("int")
+    BPtr = new_pointer_type(BInt)
+    weakref.ref(BInt)
+    weakref.ref(newp(BPtr, 42))
+    weakref.ref(cast(BPtr, 42))
+    weakref.ref(cast(BInt, 42))
+
+def test_no_inheritance():
+    BInt = new_primitive_type("int")
+    try:
+        class foo(type(BInt)): pass
+    except TypeError:
+        pass
+    else:
+        raise AssertionError
+    x = cast(BInt, 42)
+    try:
+        class foo(type(x)): pass
+    except TypeError:
+        pass
+    else:
+        raise AssertionError
+
+def test_assign_string():
+    BChar = new_primitive_type("char")
+    BArray1 = new_array_type(new_pointer_type(BChar), 5)
+    BArray2 = new_array_type(new_pointer_type(BArray1), 5)
+    a = newp(BArray2, [b"abc", b"de", b"ghij"])
+    assert string(a[1]) == b"de"
+    assert string(a[2]) == b"ghij"
+    a[2] = b"."
+    assert string(a[2]) == b"."
+    a[2] = b"12345"
+    assert string(a[2]) == b"12345"
+    e = py.test.raises(IndexError, 'a[2] = b"123456"')
+    assert 'char[5]' in str(e.value)
+    assert 'got 6 characters' in str(e.value)
+
+def test_add_error():
+    x = cast(new_primitive_type("int"), 42)
+    py.test.raises(TypeError, "x + 1")
+    py.test.raises(TypeError, "x - 1")
+
+def test_void_errors():
+    py.test.raises(TypeError, alignof, new_void_type())
+    py.test.raises(TypeError, newp, new_pointer_type(new_void_type()), None)
+    x = cast(new_pointer_type(new_void_type()), 42)
+    py.test.raises(TypeError, "x + 1")
+    py.test.raises(TypeError, "x - 1")
+
+def test_too_many_items():
+    BChar = new_primitive_type("char")
+    BArray = new_array_type(new_pointer_type(BChar), 5)
+    py.test.raises(IndexError, newp, BArray, tuple(b'123456'))
+    py.test.raises(IndexError, newp, BArray, list(b'123456'))
+    py.test.raises(IndexError, newp, BArray, b'123456')
+    BStruct = new_struct_type("foo")
+    complete_struct_or_union(BStruct, [])
+    py.test.raises(TypeError, newp, new_pointer_type(BStruct), b'')
+    py.test.raises(ValueError, newp, new_pointer_type(BStruct), [b'1'])
+
+def test_more_type_errors():
+    BInt = new_primitive_type("int")
+    BChar = new_primitive_type("char")
+    BArray = new_array_type(new_pointer_type(BChar), 5)
+    py.test.raises(TypeError, newp, BArray, 12.34)
+    BArray = new_array_type(new_pointer_type(BInt), 5)
+    py.test.raises(TypeError, newp, BArray, 12.34)
+    BFloat = new_primitive_type("float")
+    py.test.raises(TypeError, cast, BFloat, newp(BArray, None))
+
+def test_more_overflow_errors():
+    BUInt = new_primitive_type("unsigned int")
+    py.test.raises(OverflowError, newp, new_pointer_type(BUInt), -1)
+    py.test.raises(OverflowError, newp, new_pointer_type(BUInt), 2**32)
+
+def test_newp_copying():
+    """Test that we can do newp(<type>, <cdata of the given type>) for most
+    types, with the exception of arrays, like in C.
+    """
+    BInt = new_primitive_type("int")
+    p = newp(new_pointer_type(BInt), cast(BInt, 42))
+    assert p[0] == 42
+    #
+    BUInt = new_primitive_type("unsigned int")
+    p = newp(new_pointer_type(BUInt), cast(BUInt, 42))
+    assert p[0] == 42
+    #
+    BChar = new_primitive_type("char")
+    p = newp(new_pointer_type(BChar), cast(BChar, '!'))
+    assert p[0] == b'!'
+    #
+    BFloat = new_primitive_type("float")
+    p = newp(new_pointer_type(BFloat), cast(BFloat, 12.25))
+    assert p[0] == 12.25
+    #
+    BStruct = new_struct_type("foo_s")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', BInt, -1)])
+    s1 = newp(BStructPtr, [42])
+    p1 = newp(new_pointer_type(BStructPtr), s1)
+    assert p1[0] == s1
+    #
+    BArray = new_array_type(new_pointer_type(BInt), None)
+    a1 = newp(BArray, [1, 2, 3, 4])
+    py.test.raises(TypeError, newp, BArray, a1)
+    BArray6 = new_array_type(new_pointer_type(BInt), 6)
+    a1 = newp(BArray6, None)
+    py.test.raises(TypeError, newp, BArray6, a1)
+    #
+    s1 = newp(BStructPtr, [42])
+    s2 = newp(BStructPtr, s1[0])
+    assert s2.a1 == 42
+    #
+    BUnion = new_union_type("foo_u")
+    BUnionPtr = new_pointer_type(BUnion)
+    complete_struct_or_union(BUnion, [('a1', BInt, -1)])
+    u1 = newp(BUnionPtr, [42])
+    u2 = newp(BUnionPtr, u1[0])
+    assert u2.a1 == 42
+    #
+    BFunc = new_function_type((BInt,), BUInt)
+    p1 = cast(BFunc, 42)
+    p2 = newp(new_pointer_type(BFunc), p1)
+    assert p2[0] == p1
+
+def test_string():
+    BChar = new_primitive_type("char")
+    assert string(cast(BChar, 42)) == b'*'
+    assert string(cast(BChar, 0)) == b'\x00'
+    BCharP = new_pointer_type(BChar)
+    BArray = new_array_type(BCharP, 10)
+    a = newp(BArray, b"hello")
+    assert len(a) == 10
+    assert string(a) == b"hello"
+    p = a + 2
+    assert string(p) == b"llo"
+    assert string(newp(new_array_type(BCharP, 4), b"abcd")) == b"abcd"
+    py.test.raises(RuntimeError, string, cast(BCharP, 0))
+    assert string(a, 4) == b"hell"
+    assert string(a, 5) == b"hello"
+    assert string(a, 6) == b"hello"
+
+def test_string_byte():
+    BByte = new_primitive_type("signed char")
+    assert string(cast(BByte, 42)) == b'*'
+    assert string(cast(BByte, 0)) == b'\x00'
+    BArray = new_array_type(new_pointer_type(BByte), None)
+    a = newp(BArray, [65, 66, 67])
+    assert type(string(a)) is bytes and string(a) == b'ABC'
+    #
+    BByte = new_primitive_type("unsigned char")
+    assert string(cast(BByte, 42)) == b'*'
+    assert string(cast(BByte, 0)) == b'\x00'
+    BArray = new_array_type(new_pointer_type(BByte), None)
+    a = newp(BArray, [65, 66, 67])
+    assert type(string(a)) is bytes and string(a) == b'ABC'
+    if 'PY_DOT_PY' not in globals() and sys.version_info < (3,):
+        assert string(a, 8).startswith(b'ABC')  # may contain additional garbage
+
+def test_string_wchar():
+    BWChar = new_primitive_type("wchar_t")
+    assert string(cast(BWChar, 42)) == u+'*'
+    assert string(cast(BWChar, 0x4253)) == u+'\u4253'
+    assert string(cast(BWChar, 0)) == u+'\x00'
+    BArray = new_array_type(new_pointer_type(BWChar), None)
+    a = newp(BArray, [u+'A', u+'B', u+'C'])
+    assert type(string(a)) is unicode and string(a) == u+'ABC'
+    if 'PY_DOT_PY' not in globals() and sys.version_info < (3,):
+        assert string(a, 8).startswith(u+'ABC') # may contain additional garbage
+
+def test_string_typeerror():
+    BShort = new_primitive_type("short")
+    BArray = new_array_type(new_pointer_type(BShort), None)
+    a = newp(BArray, [65, 66, 67])
+    py.test.raises(TypeError, string, a)
+
+def test_bug_convert_to_ptr():
+    BChar = new_primitive_type("char")
+    BCharP = new_pointer_type(BChar)
+    BDouble = new_primitive_type("double")
+    x = cast(BDouble, 42)
+    py.test.raises(TypeError, newp, new_pointer_type(BCharP), x)
+
+def test_set_struct_fields():
+    BChar = new_primitive_type("char")
+    BCharP = new_pointer_type(BChar)
+    BCharArray10 = new_array_type(BCharP, 10)
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', BCharArray10, -1)])
+    p = newp(BStructPtr, None)
+    assert string(p.a1) == b''
+    p.a1 = b'foo'
+    assert string(p.a1) == b'foo'
+    assert list(p.a1) == [b'f', b'o', b'o'] + [b'\x00'] * 7
+    p.a1 = [b'x', b'y']
+    assert string(p.a1) == b'xyo'
+
+def test_invalid_function_result_types():
+    BFunc = new_function_type((), new_void_type())
+    BArray = new_array_type(new_pointer_type(BFunc), 5)        # works
+    new_function_type((), BFunc)    # works
+    new_function_type((), new_primitive_type("int"))
+    new_function_type((), new_pointer_type(BFunc))
+    BUnion = new_union_type("foo_u")
+    complete_struct_or_union(BUnion, [])
+    py.test.raises(NotImplementedError, new_function_type, (), BUnion)
+    py.test.raises(TypeError, new_function_type, (), BArray)
+
+def test_struct_return_in_func():
+    BChar = new_primitive_type("char")
+    BShort = new_primitive_type("short")
+    BFloat = new_primitive_type("float")
+    BDouble = new_primitive_type("double")
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("foo_s")
+    complete_struct_or_union(BStruct, [('a1', BChar, -1),
+                                       ('a2', BShort, -1)])
+    BFunc10 = new_function_type((BInt,), BStruct)
+    f = cast(BFunc10, _testfunc(10))
+    s = f(40)
+    assert repr(s) == "<cdata 'struct foo_s' owning 4 bytes>"
+    assert s.a1 == bytechr(40)
+    assert s.a2 == 40 * 40
+    #
+    BStruct11 = new_struct_type("test11")
+    complete_struct_or_union(BStruct11, [('a1', BInt, -1),
+                                         ('a2', BInt, -1)])
+    BFunc11 = new_function_type((BInt,), BStruct11)
+    f = cast(BFunc11, _testfunc(11))
+    s = f(40)
+    assert repr(s) == "<cdata 'struct test11' owning 8 bytes>"
+    assert s.a1 == 40
+    assert s.a2 == 40 * 40
+    #
+    BStruct12 = new_struct_type("test12")
+    complete_struct_or_union(BStruct12, [('a1', BDouble, -1),
+                                         ])
+    BFunc12 = new_function_type((BInt,), BStruct12)
+    f = cast(BFunc12, _testfunc(12))
+    s = f(40)
+    assert repr(s) == "<cdata 'struct test12' owning 8 bytes>"
+    assert s.a1 == 40.0
+    #
+    BStruct13 = new_struct_type("test13")
+    complete_struct_or_union(BStruct13, [('a1', BInt, -1),
+                                         ('a2', BInt, -1),
+                                         ('a3', BInt, -1)])
+    BFunc13 = new_function_type((BInt,), BStruct13)
+    f = cast(BFunc13, _testfunc(13))
+    s = f(40)
+    assert repr(s) == "<cdata 'struct test13' owning 12 bytes>"
+    assert s.a1 == 40
+    assert s.a2 == 40 * 40
+    assert s.a3 == 40 * 40 * 40
+    #
+    BStruct14 = new_struct_type("test14")
+    complete_struct_or_union(BStruct14, [('a1', BFloat, -1),
+                                         ])
+    BFunc14 = new_function_type((BInt,), BStruct14)
+    f = cast(BFunc14, _testfunc(14))
+    s = f(40)
+    assert repr(s) == "<cdata 'struct test14' owning 4 bytes>"
+    assert s.a1 == 40.0
+    #
+    BStruct15 = new_struct_type("test15")
+    complete_struct_or_union(BStruct15, [('a1', BFloat, -1),
+                                         ('a2', BInt, -1)])
+    BFunc15 = new_function_type((BInt,), BStruct15)
+    f = cast(BFunc15, _testfunc(15))
+    s = f(40)
+    assert repr(s) == "<cdata 'struct test15' owning 8 bytes>"
+    assert s.a1 == 40.0
+    assert s.a2 == 40 * 40
+    #
+    BStruct16 = new_struct_type("test16")
+    complete_struct_or_union(BStruct16, [('a1', BFloat, -1),
+                                         ('a2', BFloat, -1)])
+    BFunc16 = new_function_type((BInt,), BStruct16)
+    f = cast(BFunc16, _testfunc(16))
+    s = f(40)
+    assert repr(s) == "<cdata 'struct test16' owning 8 bytes>"
+    assert s.a1 == 40.0
+    assert s.a2 == -40.0
+    #
+    BStruct17 = new_struct_type("test17")
+    complete_struct_or_union(BStruct17, [('a1', BInt, -1),
+                                         ('a2', BFloat, -1)])
+    BFunc17 = new_function_type((BInt,), BStruct17)
+    f = cast(BFunc17, _testfunc(17))
+    s = f(40)
+    assert repr(s) == "<cdata 'struct test17' owning 8 bytes>"
+    assert s.a1 == 40
+    assert s.a2 == 40.0 * 40.0
+    #
+    BStruct17Ptr = new_pointer_type(BStruct17)
+    BFunc18 = new_function_type((BStruct17Ptr,), BInt)
+    f = cast(BFunc18, _testfunc(18))
+    x = f([[40, 2.5]])
+    assert x == 42
+    x = f([{'a2': 43.1}])
+    assert x == 43
+
+def test_cast_with_functionptr():
+    BFunc = new_function_type((), new_void_type())
+    BFunc2 = new_function_type((), new_primitive_type("short"))
+    BCharP = new_pointer_type(new_primitive_type("char"))
+    BIntP = new_pointer_type(new_primitive_type("int"))
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', BFunc, -1)])
+    newp(BStructPtr, [cast(BFunc, 0)])
+    newp(BStructPtr, [cast(BCharP, 0)])
+    py.test.raises(TypeError, newp, BStructPtr, [cast(BIntP, 0)])
+    py.test.raises(TypeError, newp, BStructPtr, [cast(BFunc2, 0)])
+
+def test_wchar():
+    BWChar = new_primitive_type("wchar_t")
+    BInt = new_primitive_type("int")
+    pyuni4 = {1: True, 2: False}[len(u+'\U00012345')]
+    wchar4 = {2: False, 4: True}[sizeof(BWChar)]
+    assert str(cast(BWChar, 0x45)) == "<cdata 'wchar_t' %s'E'>" % (
+        mandatory_u_prefix,)
+    assert str(cast(BWChar, 0x1234)) == "<cdata 'wchar_t' %s'\u1234'>" % (
+        mandatory_u_prefix,)
+    if wchar4:
+        if not _hacked_pypy_uni4():
+            x = cast(BWChar, 0x12345)
+            assert str(x) == "<cdata 'wchar_t' %s'\U00012345'>" % (
+                mandatory_u_prefix,)
+            assert int(x) == 0x12345
+    else:
+        assert not pyuni4
+    #
+    BWCharP = new_pointer_type(BWChar)
+    BStruct = new_struct_type("foo_s")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', BWChar, -1),
+                                       ('a2', BWCharP, -1)])
+    s = newp(BStructPtr)
+    s.a1 = u+'\x00'
+    assert s.a1 == u+'\x00'
+    py.test.raises(TypeError, "s.a1 = b'a'")
+    py.test.raises(TypeError, "s.a1 = bytechr(0xFF)")
+    s.a1 = u+'\u1234'
+    assert s.a1 == u+'\u1234'
+    if pyuni4:
+        assert wchar4
+        s.a1 = u+'\U00012345'
+        assert s.a1 == u+'\U00012345'
+    elif wchar4:
+        if not _hacked_pypy_uni4():
+            s.a1 = cast(BWChar, 0x12345)
+            assert s.a1 == u+'\ud808\udf45'
+            s.a1 = u+'\ud807\udf44'
+            assert s.a1 == u+'\U00011f44'
+    else:
+        py.test.raises(TypeError, "s.a1 = u+'\U00012345'")
+    #
+    BWCharArray = new_array_type(BWCharP, None)
+    a = newp(BWCharArray, u+'hello \u1234 world')
+    assert len(a) == 14   # including the final null
+    assert string(a) == u+'hello \u1234 world'
+    a[13] = u+'!'
+    assert string(a) == u+'hello \u1234 world!'
+    assert str(a) == repr(a)
+    assert a[6] == u+'\u1234'
+    a[6] = u+'-'
+    assert string(a) == u+'hello - world!'
+    assert str(a) == repr(a)
+    #
+    if wchar4 and not _hacked_pypy_uni4():
+        u1 = u+'\U00012345\U00012346\U00012347'
+        a = newp(BWCharArray, u1)
+        assert len(a) == 4
+        assert string(a) == u1
+        assert len(list(a)) == 4
+        expected = [u+'\U00012345', u+'\U00012346', u+'\U00012347', unichr(0)]
+        assert list(a) == expected
+        got = [a[i] for i in range(4)]
+        assert got == expected
+        py.test.raises(IndexError, 'a[4]')
+    #
+    w = cast(BWChar, 'a')
+    assert repr(w) == "<cdata 'wchar_t' %s'a'>" % mandatory_u_prefix
+    assert str(w) == repr(w)
+    assert string(w) == u+'a'
+    assert int(w) == ord('a')
+    w = cast(BWChar, 0x1234)
+    assert repr(w) == "<cdata 'wchar_t' %s'\u1234'>" % mandatory_u_prefix
+    assert str(w) == repr(w)
+    assert string(w) == u+'\u1234'
+    assert int(w) == 0x1234
+    w = cast(BWChar, u+'\u8234')
+    assert repr(w) == "<cdata 'wchar_t' %s'\u8234'>" % mandatory_u_prefix
+    assert str(w) == repr(w)
+    assert string(w) == u+'\u8234'
+    assert int(w) == 0x8234
+    w = cast(BInt, u+'\u1234')
+    assert repr(w) == "<cdata 'int' 4660>"
+    if wchar4 and not _hacked_pypy_uni4():
+        w = cast(BWChar, u+'\U00012345')
+        assert repr(w) == "<cdata 'wchar_t' %s'\U00012345'>" % (
+            mandatory_u_prefix,)
+        assert str(w) == repr(w)
+        assert string(w) == u+'\U00012345'
+        assert int(w) == 0x12345
+        w = cast(BInt, u+'\U00012345')
+        assert repr(w) == "<cdata 'int' 74565>"
+    py.test.raises(TypeError, cast, BInt, u+'')
+    py.test.raises(TypeError, cast, BInt, u+'XX')
+    assert int(cast(BInt, u+'a')) == ord('a')
+    #
+    a = newp(BWCharArray, u+'hello - world')
+    p = cast(BWCharP, a)
+    assert string(p) == u+'hello - world'
+    p[6] = u+'\u2345'
+    assert string(p) == u+'hello \u2345 world'
+    #
+    s = newp(BStructPtr, [u+'\u1234', p])
+    assert s.a1 == u+'\u1234'
+    assert s.a2 == p
+    assert str(s.a2) == repr(s.a2)
+    assert string(s.a2) == u+'hello \u2345 world'
+    #
+    q = cast(BWCharP, 0)
+    assert str(q) == repr(q)
+    py.test.raises(RuntimeError, string, q)
+    #
+    def cb(p):
+        assert repr(p).startswith("<cdata 'wchar_t *' 0x")
+        return len(string(p))
+    BFunc = new_function_type((BWCharP,), BInt, False)
+    f = callback(BFunc, cb, -42)
+    assert f(u+'a\u1234b') == 3
+    #
+    if wchar4 and not pyuni4 and not _hacked_pypy_uni4():
+        # try out-of-range wchar_t values
+        x = cast(BWChar, 1114112)
+        py.test.raises(ValueError, string, x)
+        x = cast(BWChar, -1)
+        py.test.raises(ValueError, string, x)
+
+def test_keepalive_struct():
+    # exception to the no-keepalive rule: p=newp(BStructPtr) returns a
+    # pointer owning the memory, and p[0] returns a pointer to the
+    # struct that *also* owns the memory
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1),
+                                       ('a2', new_primitive_type("int"), -1),
+                                       ('a3', new_primitive_type("int"), -1)])
+    p = newp(BStructPtr)
+    assert repr(p) == "<cdata 'struct foo *' owning 12 bytes>"
+    q = p[0]
+    assert repr(q) == "<cdata 'struct foo' owning 12 bytes>"
+    q.a1 = 123456
+    assert p.a1 == 123456
+    r = cast(BStructPtr, p)
+    assert repr(r[0]).startswith("<cdata 'struct foo &' 0x")
+    del p
+    import gc; gc.collect()
+    assert q.a1 == 123456
+    assert repr(q) == "<cdata 'struct foo' owning 12 bytes>"
+    assert q.a1 == 123456
+
+def test_nokeepalive_struct():
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    BStructPtrPtr = new_pointer_type(BStructPtr)
+    complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1)])
+    p = newp(BStructPtr)
+    pp = newp(BStructPtrPtr)
+    pp[0] = p
+    s = pp[0][0]
+    assert repr(s).startswith("<cdata 'struct foo &' 0x")
+
+def test_owning_repr():
+    BInt = new_primitive_type("int")
+    BArray = new_array_type(new_pointer_type(BInt), None)   # int[]
+    p = newp(BArray, 7)
+    assert repr(p) == "<cdata 'int[]' owning 28 bytes>"
+    assert sizeof(p) == 28
+    #
+    BArray = new_array_type(new_pointer_type(BInt), 7)   # int[7]
+    p = newp(BArray, None)
+    assert repr(p) == "<cdata 'int[7]' owning 28 bytes>"
+    assert sizeof(p) == 28
+
+def test_cannot_dereference_void():
+    BVoidP = new_pointer_type(new_void_type())
+    p = cast(BVoidP, 123456)
+    py.test.raises(TypeError, "p[0]")
+    p = cast(BVoidP, 0)
+    if 'PY_DOT_PY' in globals(): py.test.skip("NULL crashes early on py.py")
+    py.test.raises(TypeError, "p[0]")
+
+def test_iter():
+    BInt = new_primitive_type("int")
+    BIntP = new_pointer_type(BInt)
+    BArray = new_array_type(BIntP, None)   # int[]
+    p = newp(BArray, 7)
+    assert list(p) == list(iter(p)) == [0] * 7
+    #
+    py.test.raises(TypeError, iter, cast(BInt, 5))
+    py.test.raises(TypeError, iter, cast(BIntP, 123456))
+
+def test_cmp():
+    BInt = new_primitive_type("int")
+    BIntP = new_pointer_type(BInt)
+    BVoidP = new_pointer_type(new_void_type())
+    p = newp(BIntP, 123)
+    q = cast(BInt, 124)
+    py.test.raises(TypeError, "p < q")
+    py.test.raises(TypeError, "p <= q")
+    assert (p == q) is False
+    assert (p != q) is True
+    py.test.raises(TypeError, "p > q")
+    py.test.raises(TypeError, "p >= q")
+    r = cast(BVoidP, p)
+    assert (p <  r) is False
+    assert (p <= r) is True
+    assert (p == r) is True
+    assert (p != r) is False
+    assert (p >  r) is False
+    assert (p >= r) is True
+    s = newp(BIntP, 125)
+    assert (p == s) is False
+    assert (p != s) is True
+    assert (p < s) is (p <= s) is (s > p) is (s >= p)
+    assert (p > s) is (p >= s) is (s < p) is (s <= p)
+    assert (p < s) ^ (p > s)
+
+def test_buffer():
+    BShort = new_primitive_type("short")
+    s = newp(new_pointer_type(BShort), 100)
+    assert sizeof(s) == size_of_ptr()
+    assert sizeof(BShort) == 2
+    assert len(readbuf(buffer(s))) == 2
+    #
+    BChar = new_primitive_type("char")
+    BCharArray = new_array_type(new_pointer_type(BChar), None)
+    c = newp(BCharArray, b"hi there")
+    buf = buffer(c)
+    assert readbuf(buf) == b"hi there\x00"
+    assert len(buf) == len(b"hi there\x00")
+    assert buf[0] == bufchar('h')
+    assert buf[2] == bufchar(' ')
+    assert list(buf) == list(map(bufchar, "hi there\x00"))
+    buf[2] = bufchar('-')
+    assert c[2] == b'-'
+    assert readbuf(buf) == b"hi-there\x00"
+    c[2] = b'!'
+    assert buf[2] == bufchar('!')
+    assert readbuf(buf) == b"hi!there\x00"
+    c[2] = b'-'
+    buf[:2] = b'HI'
+    assert string(c) == b'HI-there'
+    assert buf[:4:2] == b'H-'
+    if '__pypy__' not in sys.builtin_module_names:
+        # XXX pypy doesn't support the following assignment so far
+        buf[:4:2] = b'XY'
+        assert string(c) == b'XIYthere'
+
+def test_getcname():
+    BUChar = new_primitive_type("unsigned char")
+    BArray = new_array_type(new_pointer_type(BUChar), 123)
+    assert getcname(BArray, "<-->") == "unsigned char<-->[123]"
+
+def test_errno():
+    BVoid = new_void_type()
+    BFunc5 = new_function_type((), BVoid)
+    f = cast(BFunc5, _testfunc(5))
+    set_errno(50)
+    f()
+    assert get_errno() == 65
+    f(); f()
+    assert get_errno() == 95
+
+def test_errno_callback():
+    if globals().get('PY_DOT_PY') == '2.5':
+        py.test.skip("cannot run this test on py.py with Python 2.5")
+    def cb():
+        e = get_errno()
+        set_errno(e - 6)
+    BVoid = new_void_type()
+    BFunc5 = new_function_type((), BVoid)
+    f = callback(BFunc5, cb)
+    f()
+    assert get_errno() == 89
+    f(); f()
+    assert get_errno() == 77
+
+def test_abi():
+    assert isinstance(FFI_DEFAULT_ABI, int)
+
+def test_cast_to_array():
+    # not valid in C!  extension to get a non-owning <cdata 'int[3]'>
+    BInt = new_primitive_type("int")
+    BIntP = new_pointer_type(BInt)
+    BArray = new_array_type(BIntP, 3)
+    x = cast(BArray, 0)
+    assert repr(x) == "<cdata 'int[3]' NULL>"
+
+def test_cast_invalid():
+    BStruct = new_struct_type("foo")
+    complete_struct_or_union(BStruct, [])
+    p = cast(new_pointer_type(BStruct), 123456)
+    s = p[0]
+    py.test.raises(TypeError, cast, BStruct, s)
+
+def test_bug_float_convertion():
+    BDouble = new_primitive_type("double")
+    BDoubleP = new_pointer_type(BDouble)
+    py.test.raises(TypeError, newp, BDoubleP, "foobar")
+
+def test_bug_delitem():
+    BChar = new_primitive_type("char")
+    BCharP = new_pointer_type(BChar)
+    x = newp(BCharP)
+    py.test.raises(TypeError, "del x[0]")
+
+def test_bug_delattr():
+    BLong = new_primitive_type("long")
+    BStruct = new_struct_type("foo")
+    complete_struct_or_union(BStruct, [('a1', BLong, -1)])
+    x = newp(new_pointer_type(BStruct))
+    py.test.raises(AttributeError, "del x.a1")
+
+def test_variable_length_struct():
+    py.test.skip("later")
+    BLong = new_primitive_type("long")
+    BArray = new_array_type(new_pointer_type(BLong), None)
+    BStruct = new_struct_type("foo")
+    BStructP = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a1', BLong, -1),
+                                       ('a2', BArray, -1)])
+    assert sizeof(BStruct) == size_of_long()
+    assert alignof(BStruct) == alignof(BLong)
+    #
+    py.test.raises(TypeError, newp, BStructP, None)
+    x = newp(BStructP, 5)
+    assert sizeof(x) == 6 * size_of_long()
+    x[4] = 123
+    assert x[4] == 123
+    py.test.raises(IndexError, "x[5]")
+    assert len(x.a2) == 5
+    #
+    py.test.raises(TypeError, newp, BStructP, [123])
+    x = newp(BStructP, [123, 5])
+    assert x.a1 == 123
+    assert len(x.a2) == 5
+    assert list(x.a2) == [0] * 5
+    #
+    x = newp(BStructP, {'a2': 5})
+    assert x.a1 == 0
+    assert len(x.a2) == 5
+    assert list(x.a2) == [0] * 5
+    #
+    x = newp(BStructP, [123, (4, 5)])
+    assert x.a1 == 123
+    assert len(x.a2) == 2
+    assert list(x.a2) == [4, 5]
+    #
+    x = newp(BStructP, {'a2': (4, 5)})
+    assert x.a1 == 0
+    assert len(x.a2) == 2
+    assert list(x.a2) == [4, 5]
+
+def test_autocast_int():
+    BInt = new_primitive_type("int")
+    BIntPtr = new_pointer_type(BInt)
+    BLongLong = new_primitive_type("long long")
+    BULongLong = new_primitive_type("unsigned long long")
+    BULongLongPtr = new_pointer_type(BULongLong)
+    x = newp(BIntPtr, cast(BInt, 42))
+    assert x[0] == 42
+    x = newp(BIntPtr, cast(BLongLong, 42))
+    assert x[0] == 42
+    x = newp(BIntPtr, cast(BULongLong, 42))
+    assert x[0] == 42
+    x = newp(BULongLongPtr, cast(BInt, 42))
+    assert x[0] == 42
+    py.test.raises(OverflowError, newp, BULongLongPtr, cast(BInt, -42))
+    x = cast(BInt, cast(BInt, 42))
+    assert int(x) == 42
+    x = cast(BInt, cast(BLongLong, 42))
+    assert int(x) == 42
+    x = cast(BInt, cast(BULongLong, 42))
+    assert int(x) == 42
+    x = cast(BULongLong, cast(BInt, 42))
+    assert int(x) == 42
+    x = cast(BULongLong, cast(BInt, -42))
+    assert int(x) == 2 ** 64 - 42
+    x = cast(BIntPtr, cast(BInt, 42))
+    assert int(cast(BInt, x)) == 42
+
+def test_autocast_float():
+    BFloat = new_primitive_type("float")
+    BDouble = new_primitive_type("float")
+    BFloatPtr = new_pointer_type(BFloat)
+    x = newp(BFloatPtr, cast(BDouble, 12.5))
+    assert x[0] == 12.5
+    x = cast(BFloat, cast(BDouble, 12.5))
+    assert float(x) == 12.5
+
+def test_longdouble():
+    py_py = 'PY_DOT_PY' in globals()
+    BLongDouble = new_primitive_type("long double")
+    BLongDoublePtr = new_pointer_type(BLongDouble)
+    BLongDoubleArray = new_array_type(BLongDoublePtr, None)
+    a = newp(BLongDoubleArray, 1)
+    x = a[0]
+    if not py_py:
+        assert repr(x).startswith("<cdata 'long double' 0.0")
+    assert float(x) == 0.0
+    assert int(x) == 0
+    #
+    b = newp(BLongDoubleArray, [1.23])
+    x = b[0]
+    if not py_py:
+        assert repr(x).startswith("<cdata 'long double' 1.23")
+    assert float(x) == 1.23
+    assert int(x) == 1
+    #
+    BFunc19 = new_function_type((BLongDouble,), BLongDouble)
+    f = cast(BFunc19, _testfunc(19))
+    start = 8
+    for i in range(107):
+        start = f(start)
+    if sizeof(BLongDouble) > sizeof(new_primitive_type("double")):
+        if not py_py:
+            assert repr(start).startswith("<cdata 'long double' 6.15")
+            assert repr(start).endswith("E+902>")
+        #
+        c = newp(BLongDoubleArray, [start])
+        x = c[0]
+        if not py_py:
+            assert repr(x).endswith("E+902>")
+            assert float(x) == float("inf")
+
+def test_get_array_of_length_zero():
+    for length in [0, 5, 10]:
+        BLong = new_primitive_type("long")
+        BLongP = new_pointer_type(BLong)
+        BArray0 = new_array_type(BLongP, length)
+        BStruct = new_struct_type("foo")
+        BStructPtr = new_pointer_type(BStruct)
+        complete_struct_or_union(BStruct, [('a1', BArray0, -1)])
+        p = newp(BStructPtr, None)
+        if length == 0:
+            assert repr(p.a1).startswith("<cdata 'long *' 0x")
+        else:
+            assert repr(p.a1).startswith("<cdata 'long[%d]' 0x" % length)
+
+def test_nested_anonymous_struct():
+    BInt = new_primitive_type("int")
+    BChar = new_primitive_type("char")
+    BStruct = new_struct_type("foo")
+    BInnerStruct = new_struct_type("foo")
+    complete_struct_or_union(BInnerStruct, [('a1', BInt, -1),
+                                            ('a2', BChar, -1)])
+    complete_struct_or_union(BStruct, [('', BInnerStruct, -1),
+                                       ('a3', BChar, -1)])
+    assert sizeof(BInnerStruct) == sizeof(BInt) * 2   # with alignment
+    assert sizeof(BStruct) == sizeof(BInt) * 3        # 'a3' is placed after
+    d = _getfields(BStruct)
+    assert len(d) == 3
+    assert d[0][0] == 'a1'
+    assert d[0][1].type is BInt
+    assert d[0][1].offset == 0
+    assert d[0][1].bitshift == -1
+    assert d[0][1].bitsize == -1
+    assert d[1][0] == 'a2'
+    assert d[1][1].type is BChar
+    assert d[1][1].offset == sizeof(BInt)
+    assert d[1][1].bitshift == -1
+    assert d[1][1].bitsize == -1
+    assert d[2][0] == 'a3'
+    assert d[2][1].type is BChar
+    assert d[2][1].offset == sizeof(BInt) * 2
+    assert d[2][1].bitshift == -1
+    assert d[2][1].bitsize == -1
+
+def test_sizeof_union():
+    # a union has the largest alignment of its members, and a total size
+    # that is the largest of its items *possibly further aligned* if
+    # another smaller item has a larger alignment...
+    BChar = new_primitive_type("char")
+    BShort = new_primitive_type("short")
+    assert sizeof(BShort) == alignof(BShort) == 2
+    BStruct = new_struct_type("foo")
+    complete_struct_or_union(BStruct, [('a1', BChar),
+                                       ('a2', BChar),
+                                       ('a3', BChar)])
+    assert sizeof(BStruct) == 3 and alignof(BStruct) == 1
+    BUnion = new_union_type("u")
+    complete_struct_or_union(BUnion, [('s', BStruct),
+                                      ('i', BShort)])
+    assert sizeof(BUnion) == 4
+    assert alignof(BUnion) == 2
diff --git a/pypy/module/_cffi_backend/test/_test_lib.c b/pypy/module/_cffi_backend/test/_test_lib.c
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/test/_test_lib.c
@@ -0,0 +1,194 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#define DLLEXPORT __declspec(dllexport)
+#else
+#define DLLEXPORT
+#endif
+
+static char _testfunc0(char a, char b)
+{
+    return a + b;
+}
+static long _testfunc1(int a, long b)
+{
+    return (long)a + b;
+}
+static long long _testfunc2(long long a, long long b)
+{
+    return a + b;
+}
+static double _testfunc3(float a, double b)
+{
+    return a + b;
+}
+static float _testfunc4(float a, double b)
+{
+    return (float)(a + b);
+}
+static void _testfunc5(void)
+{
+    errno = errno + 15;
+}
+static int *_testfunc6(int *x)
+{
+    static int y;
+    y = *x - 1000;
+    return &y;
+}
+struct _testfunc7_s { unsigned char a1; short a2; };
+static short _testfunc7(struct _testfunc7_s inlined)
+{
+    return inlined.a1 + inlined.a2;
+}
+static int _testfunc9(int num, ...)
+{
+    va_list vargs;
+    int i, total = 0;
+    va_start(vargs, num);
+    for (i=0; i<num; i++) {
+        int value = va_arg(vargs, int);
+        if (value == 0)
+            value = -66666666;
+        total += value;
+    }
+    va_end(vargs);
+    return total;
+}
+
+static struct _testfunc7_s _testfunc10(int n)
+{
+    struct _testfunc7_s result;
+    result.a1 = n;
+    result.a2 = n * n;
+    return result;
+}
+
+struct _testfunc11_s { int a1, a2; };
+static struct _testfunc11_s _testfunc11(int n)
+{
+    struct _testfunc11_s result;
+    result.a1 = n;
+    result.a2 = n * n;
+    return result;
+}
+
+struct _testfunc12_s { double a1; };
+static struct _testfunc12_s _testfunc12(int n)
+{
+    struct _testfunc12_s result;
+    result.a1 = n;
+    return result;
+}
+
+struct _testfunc13_s { int a1, a2, a3; };
+static struct _testfunc13_s _testfunc13(int n)
+{
+    struct _testfunc13_s result;
+    result.a1 = n;
+    result.a2 = n * n;
+    result.a3 = n * n * n;
+    return result;
+}
+
+struct _testfunc14_s { float a1; };
+static struct _testfunc14_s _testfunc14(int n)
+{
+    struct _testfunc14_s result;
+    result.a1 = (float)n;
+    return result;
+}
+
+struct _testfunc15_s { float a1; int a2; };
+static struct _testfunc15_s _testfunc15(int n)
+{
+    struct _testfunc15_s result;
+    result.a1 = (float)n;
+    result.a2 = n * n;
+    return result;
+}
+
+struct _testfunc16_s { float a1, a2; };
+static struct _testfunc16_s _testfunc16(int n)
+{
+    struct _testfunc16_s result;
+    result.a1 = (float)n;
+    result.a2 = -(float)n;
+    return result;
+}
+
+struct _testfunc17_s { int a1; float a2; };
+static struct _testfunc17_s _testfunc17(int n)
+{
+    struct _testfunc17_s result;
+    result.a1 = n;
+    result.a2 = (float)n * (float)n;
+    return result;
+}
+
+static int _testfunc18(struct _testfunc17_s *ptr)
+{
+    return ptr->a1 + (int)ptr->a2;
+}
+
+static long double _testfunc19(long double x)
+{
+    int i;
+    for (i=0; i<28; i++)
+        x += x;
+    return x;
+}
+
+static short _testfunc20(struct _testfunc7_s *ptr)
+{
+    return ptr->a1 + ptr->a2;
+}
+
+struct _testfunc21_s { int a, b, c, d, e, f, g, h, i, j; };
+static int _testfunc21(struct _testfunc21_s inlined)
+{
+    return ((inlined.a << 0) +
+            (inlined.b << 1) +
+            (inlined.c << 2) +
+            (inlined.d << 3) +
+            (inlined.e << 4) +
+            (inlined.f << 5) +
+            (inlined.g << 6) +
+            (inlined.h << 7) +
+            (inlined.i << 8) +
+            (inlined.j << 9));
+}
+
+DLLEXPORT void *gettestfunc(int num)
+{
+    void *f;
+    switch (num) {
+    case 0: f = &_testfunc0; break;
+    case 1: f = &_testfunc1; break;
+    case 2: f = &_testfunc2; break;
+    case 3: f = &_testfunc3; break;
+    case 4: f = &_testfunc4; break;
+    case 5: f = &_testfunc5; break;
+    case 6: f = &_testfunc6; break;
+    case 7: f = &_testfunc7; break;
+    case 8: f = stderr; break;
+    case 9: f = &_testfunc9; break;
+    case 10: f = &_testfunc10; break;
+    case 11: f = &_testfunc11; break;
+    case 12: f = &_testfunc12; break;
+    case 13: f = &_testfunc13; break;
+    case 14: f = &_testfunc14; break;
+    case 15: f = &_testfunc15; break;
+    case 16: f = &_testfunc16; break;
+    case 17: f = &_testfunc17; break;
+    case 18: f = &_testfunc18; break;
+    case 19: f = &_testfunc19; break;
+    case 20: f = &_testfunc20; break;
+    case 21: f = &_testfunc21; break;
+    default:
+        return NULL;
+    }
+    return f;
+}
diff --git a/pypy/module/_cffi_backend/test/test_c.py b/pypy/module/_cffi_backend/test/test_c.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/test/test_c.py
@@ -0,0 +1,119 @@
+from __future__ import with_statement
+"""
+This file is OBSCURE.  Really.  The purpose is to avoid copying and changing
+'test_c.py' from cffi/c/ in the original CFFI repository:
+    https://bitbucket.org/cffi/cffi
+
+Adding a test here involves:
+1. add a test to cffi/c/test.py
+   - if you need a C function to call, add it into _cffi_backend.c
+     as a testfuncNN().
+2. have it pass when you run 'py.test test_c.py' in cffi
+3. check in and (if you can) push the changes
+4. copy test_c.py into _backend_test.py here, killing the few lines of header
+   - if you added a C function, it goes into _test_lib.c here
+   - if you could complete step 3, try running 'py.test test_file.py' here
+5. make the test pass in pypy ('py.test test_c.py')
+"""
+import py, sys, ctypes
+if sys.version_info < (2, 6):
+    py.test.skip("requires the b'' literal syntax")
+
+from pypy.tool.udir import udir
+from pypy.conftest import gettestobjspace, option
+from pypy.interpreter import gateway
+from pypy.module._cffi_backend.test import _backend_test_c
+from pypy.module._cffi_backend import Module
+from pypy.translator.platform import host
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+
+
+class AppTestC(object):
+    """Populated below, hack hack hack."""
+
+    def setup_class(cls):
+        space = gettestobjspace(usemodules=('_cffi_backend',))
+        cls.space = space
+        testfuncs_w = []
+        keepalive_funcs = []
+
+        def find_and_load_library_for_test(space, w_name, w_is_global=0):
+            if space.is_w(w_name, space.w_None):
+                path = None
+            else:
+                import ctypes.util
+                path = ctypes.util.find_library(space.str_w(w_name))
+            return space.appexec([space.wrap(path), w_is_global],
+            """(path, is_global):
+                import _cffi_backend
+                return _cffi_backend.load_library(path, is_global)""")
+
+        test_lib_c = tmpdir.join('_test_lib.c')
+        src_test_lib_c = py.path.local(__file__).dirpath().join('_test_lib.c')
+        src_test_lib_c.copy(test_lib_c)
+        eci = ExternalCompilationInfo()
+        test_lib = host.compile([test_lib_c], eci, standalone=False)
+
+        cdll = ctypes.CDLL(str(test_lib))
+        cdll.gettestfunc.restype = ctypes.c_void_p
+
+        def testfunc_for_test(space, w_num):
+            if hasattr(space, 'int_w'):
+                w_num = space.int_w(w_num)
+            addr = cdll.gettestfunc(w_num)
+            return space.wrap(addr)
+
+        if option.runappdirect:
+            def interp2app(func):
+                def run(*args):
+                    return func(space, *args)
+                return run
+        else:
+            interp2app = gateway.interp2app
+
+        w_func = space.wrap(interp2app(find_and_load_library_for_test))
+        w_testfunc = space.wrap(interp2app(testfunc_for_test))
+        space.appexec([space.wrap(str(tmpdir)), w_func, w_testfunc,
+                       space.wrap(sys.version[:3])],
+        """(path, func, testfunc, underlying_version):
+            import sys
+            sys.path.append(path)
+            import _all_test_c
+            _all_test_c.PY_DOT_PY = underlying_version
+            _all_test_c.find_and_load_library = func
+            _all_test_c._testfunc = testfunc
+        """)
+
+
+all_names = ', '.join(Module.interpleveldefs.keys())
+
+lst = []
+for name, value in _backend_test_c.__dict__.items():
+    if name.startswith('test_'):
+        lst.append(value)
+lst.sort(key=lambda func: func.func_code.co_firstlineno)
+
+tmpdir = udir.join('test_c').ensure(dir=1)
+
+tmpname = tmpdir.join('_test_c.py')
+with tmpname.open('w') as f:
+    for func in lst:
+        print >> f, 'def %s(self):' % (func.__name__,)
+        print >> f, '    import _all_test_c'
+        print >> f, '    _all_test_c.%s()' % (func.__name__,)
+
+tmpname2 = tmpdir.join('_all_test_c.py')
+with tmpname2.open('w') as f:
+    print >> f, 'import sys'
+    print >> f, 'from _cffi_backend import %s' % all_names
+    print >> f, 'class py:'
+    print >> f, '    class test:'
+    print >> f, '        raises = staticmethod(raises)'
+    print >> f, '        skip = staticmethod(skip)'
+    print >> f, py.path.local(__file__).join('..', '_backend_test_c.py').read()
+
+
+mod = tmpname.pyimport()
+for key, value in mod.__dict__.items():
+    if key.startswith('test_'):
+        setattr(AppTestC, key, value)
diff --git a/pypy/module/_cffi_backend/test/test_file.py b/pypy/module/_cffi_backend/test/test_file.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/test/test_file.py
@@ -0,0 +1,13 @@
+import urllib2, py
+
+
+def test_same_file():
+    # '_backend_test_c.py' is a copy of 'c/test_c.py' from the CFFI repo,
+    # with the header lines (up to '# _____') stripped.
+    url = 'https://bitbucket.org/cffi/cffi/raw/default/c/test_c.py'
+    source = urllib2.urlopen(url).read()
+    #
+    dest = py.path.local(__file__).join('..', '_backend_test_c.py').read()
+    #
+    source = source[source.index('# _____________'):]
+    assert source == dest
diff --git a/pypy/module/_cffi_backend/test/test_ztranslation.py b/pypy/module/_cffi_backend/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/test/test_ztranslation.py
@@ -0,0 +1,8 @@
+from pypy.objspace.fake.checkmodule import checkmodule
+
+# side-effect: FORMAT_LONGDOUBLE must be built before test_checkmodule()
+from pypy.module._cffi_backend import misc
+
+
+def test_checkmodule():
+    checkmodule('_cffi_backend')
diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py
--- a/pypy/module/_io/interp_iobase.py
+++ b/pypy/module/_io/interp_iobase.py
@@ -326,13 +326,11 @@
             try:
                 space.call_method(w_iobase, 'flush')
             except OperationError, e:
-                # if it's an IOError or ValueError, ignore it (ValueError is
-                # raised if by chance we are trying to flush a file which has
-                # already been closed)
-                if not (e.match(space, space.w_IOError) or
-                        e.match(space, space.w_ValueError)):
-                    raise
-        
+                # Silencing all errors is bad, but getting randomly
+                # interrupted here is equally as bad, and potentially
+                # more frequent (because of shutdown issues).
+                pass 
+
 
 class AutoFlusher(object):
     
diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py
--- a/pypy/module/_minimal_curses/fficurses.py
+++ b/pypy/module/_minimal_curses/fficurses.py
@@ -9,10 +9,12 @@
 from pypy.module._minimal_curses import interp_curses
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from sys import platform
+import os.path
 
 _CYGWIN = platform == 'cygwin'
+_NCURSES_CURSES = os.path.isfile("/usr/include/ncurses/curses.h") 
 
-if _CYGWIN:
+if _CYGWIN or _NCURSES_CURSES:
     eci = ExternalCompilationInfo(
         includes = ['ncurses/curses.h', 'ncurses/term.h'],
         libraries = ['curses'],
diff --git a/pypy/module/_multiprocessing/test/test_semaphore.py b/pypy/module/_multiprocessing/test/test_semaphore.py
--- a/pypy/module/_multiprocessing/test/test_semaphore.py
+++ b/pypy/module/_multiprocessing/test/test_semaphore.py
@@ -18,6 +18,8 @@
         kind = self.SEMAPHORE
         value = 1
         maxvalue = 1
+        # the following line gets OSError: [Errno 38] Function not implemented
+        # if /dev/shm is not mounted on Linux
         sem = SemLock(kind, value, maxvalue)
         assert sem.kind == kind
         assert sem.maxvalue == maxvalue
@@ -49,6 +51,8 @@
         kind = self.RECURSIVE
         value = 1
         maxvalue = 1
+        # the following line gets OSError: [Errno 38] Function not implemented
+        # if /dev/shm is not mounted on Linux
         sem = SemLock(kind, value, maxvalue)
 
         sem.acquire()
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -602,8 +602,10 @@
 
         try:
             if find_info.modtype == PY_SOURCE:
-                load_source_module(space, w_modulename, w_mod, find_info.filename,
-                                   find_info.stream.readall())
+                load_source_module(
+                    space, w_modulename, w_mod, 
+                    find_info.filename, find_info.stream.readall(),
+                    find_info.stream.try_to_find_file_descriptor())
                 return w_mod
             elif find_info.modtype == PY_COMPILED:
                 magic = _r_long(find_info.stream)
@@ -878,7 +880,7 @@
 
 
 @jit.dont_look_inside
-def load_source_module(space, w_modulename, w_mod, pathname, source,
+def load_source_module(space, w_modulename, w_mod, pathname, source, fd,
                        write_pyc=True):
     """
     Load a source module from a given file and return its module
@@ -887,8 +889,8 @@
     w = space.wrap
 
     if space.config.objspace.usepycfiles:
+        src_stat = os.fstat(fd)
         cpathname = pathname + 'c'
-        src_stat = os.stat(pathname)
         mtime = int(src_stat[stat.ST_MTIME])
         mode = src_stat[stat.ST_MODE]
         stream = check_compiled_module(space, cpathname, mtime)
diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py
--- a/pypy/module/imp/interp_imp.py
+++ b/pypy/module/imp/interp_imp.py
@@ -101,7 +101,8 @@
     importing._prepare_module(space, w_mod, filename, None)
 
     importing.load_source_module(
-        space, w_modulename, w_mod, filename, stream.readall())
+        space, w_modulename, w_mod,
+        filename, stream.readall(), stream.try_to_find_file_descriptor())
     if space.is_w(w_file, space.w_None):
         stream.close()
     return w_mod
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -104,11 +104,10 @@
         filename = str(p.join("x.py"))
         stream = streamio.open_file_as_stream(filename, "r")
         try:
-            importing.load_source_module(space,
-                                         w_modname,
-                                         w(importing.Module(space, w_modname)),
-                                         filename,
-                                         stream.readall())
+            importing.load_source_module(
+                space, w_modname, w(importing.Module(space, w_modname)),
+                filename, stream.readall(),
+                stream.try_to_find_file_descriptor())
         finally:
             stream.close()
         if space.config.objspace.usepycfiles:
@@ -618,6 +617,19 @@
             sys.path.insert(0, sys.path.pop())
         del sys.modules['itertools']
 
+    def test_invalid_pathname(self):
+        import imp
+        import pkg
+        import os
+
+        info = ('.py', 'r', imp.PY_SOURCE)
+        pathname = os.path.join(os.path.dirname(pkg.__file__), 'a.py')
+        
+        module = imp.load_module('a', open(pathname),
+                                 'invalid_path_name', ('.py', 'r', imp.PY_SOURCE))
+        assert module.__name__ == 'a'
+        assert module.__file__ == 'invalid_path_name'
+
 
 class TestAbi:
     def test_abi_tag(self):
@@ -783,11 +795,10 @@
         pathname = _testfilesource()
         stream = streamio.open_file_as_stream(pathname, "r")
         try:
-            w_ret = importing.load_source_module(space,
-                                                 w_modulename,
-                                                 w_mod,
-                                                 pathname,
-                                                 stream.readall())
+            w_ret = importing.load_source_module(
+                space, w_modulename, w_mod,
+                pathname, stream.readall(),
+                stream.try_to_find_file_descriptor())
         finally:
             stream.close()
         assert w_mod is w_ret
@@ -806,12 +817,11 @@
         pathname = _testfilesource()
         stream = streamio.open_file_as_stream(pathname, "r")
         try:
-            w_ret = importing.load_source_module(space,
-                                                 w_modulename,
-                                                 w_mod,
-                                                 pathname,
-                                                 stream.readall(),
-                                                 write_pyc=False)
+            w_ret = importing.load_source_module(
+                space, w_modulename, w_mod,
+                pathname, stream.readall(),
+                stream.try_to_find_file_descriptor(),
+                write_pyc=False)
         finally:
             stream.close()
         cpathname = udir.join('test.pyc')
@@ -826,11 +836,10 @@
         try:
             space.setattr(space.sys, space.wrap('dont_write_bytecode'),
                           space.w_True)
-            w_ret = importing.load_source_module(space,
-                                                 w_modulename,
-                                                 w_mod,
-                                                 pathname,
-                                                 stream.readall())
+            w_ret = importing.load_source_module(
+                space, w_modulename, w_mod,
+                pathname, stream.readall(),
+                stream.try_to_find_file_descriptor())
         finally:
             space.setattr(space.sys, space.wrap('dont_write_bytecode'),
                           space.w_False)
@@ -846,11 +855,10 @@
         pathname = _testfilesource(source="<Syntax Error>")
         stream = streamio.open_file_as_stream(pathname, "r")
         try:
-            w_ret = importing.load_source_module(space,
-                                                 w_modulename,
-                                                 w_mod,
-                                                 pathname,
-                                                 stream.readall())
+            w_ret = importing.load_source_module(
+                space, w_modulename, w_mod,
+                pathname, stream.readall(),
+                stream.try_to_find_file_descriptor())
         except OperationError:
             # OperationError("Syntax Error")
             pass
@@ -867,11 +875,10 @@
         pathname = _testfilesource(source="a = unknown_name")
         stream = streamio.open_file_as_stream(pathname, "r")
         try:
-            w_ret = importing.load_source_module(space,
-                                                 w_modulename,
-                                                 w_mod,
-                                                 pathname,
-                                                 stream.readall())
+            w_ret = importing.load_source_module(
+                space, w_modulename, w_mod,
+                pathname, stream.readall(),
+                stream.try_to_find_file_descriptor())
         except OperationError:
             # OperationError("NameError", "global name 'unknown_name' is not defined")
             pass
diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py
--- a/pypy/module/itertools/test/test_itertools.py
+++ b/pypy/module/itertools/test/test_itertools.py
@@ -88,6 +88,13 @@
         list(it)
         assert repr(it) == "repeat('foobar', 0)"
 
+    def test_repeat_len(self):
+        import itertools
+
+        r = itertools.repeat('a', 15)
+        r.next()
+        raises(TypeError, "len(itertools.repeat('xkcd'))")
+
     def test_takewhile(self):
         import itertools
 
diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py
--- a/pypy/module/micronumpy/interp_boxes.py
+++ b/pypy/module/micronumpy/interp_boxes.py
@@ -229,7 +229,7 @@
         except KeyError:
             raise OperationError(space.w_IndexError,
                                  space.wrap("Field %s does not exist" % item))
-        return dtype.itemtype.read(self.arr, 1, self.ofs, ofs, dtype)
+        return dtype.itemtype.read(self.arr, self.ofs, ofs, dtype)
 
     @unwrap_spec(item=str)
     def descr_setitem(self, space, item, w_value):
@@ -238,7 +238,7 @@
         except KeyError:
             raise OperationError(space.w_IndexError,
                                  space.wrap("Field %s does not exist" % item))
-        dtype.itemtype.store(self.arr, 1, self.ofs, ofs,
+        dtype.itemtype.store(self.arr, self.ofs, ofs,
                              dtype.coerce(space, w_value))
 
 class W_CharacterBox(W_FlexibleBox):
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -44,13 +44,13 @@
         return self.itemtype.coerce(space, self, w_item)
 
     def getitem(self, arr, i):
-        return self.itemtype.read(arr, 1, i, 0)
+        return self.itemtype.read(arr, i, 0)
 
     def getitem_bool(self, arr, i):
-        return self.itemtype.read_bool(arr, 1, i, 0)
+        return self.itemtype.read_bool(arr, i, 0)
 
     def setitem(self, arr, i, box):
-        self.itemtype.store(arr, 1, i, 0, box)
+        self.itemtype.store(arr, i, 0, box)
 
     def fill(self, storage, box, start, stop):
         self.itemtype.fill(storage, self.get_size(), box, start, stop, 0)
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -13,11 +13,11 @@
     find_shape_and_elems, get_shape_from_iterable, calc_new_strides, to_coords)
 from pypy.rlib import jit
 from pypy.rlib.rstring import StringBuilder
+from pypy.rlib.rawstorage import free_raw_storage
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.module.micronumpy.interp_support import unwrap_axis_arg
 
-
 count_driver = jit.JitDriver(
     greens=['shapelen'],
     virtualizables=['frame'],
@@ -1209,7 +1209,7 @@
         return signature.ArraySignature(self.dtype)
 
     def __del__(self):
-        lltype.free(self.storage, flavor='raw', track_allocation=False)
+        free_raw_storage(self.storage, track_allocation=False)
 
 def _find_shape(space, w_size):
     if space.isinstance_w(w_size, space.w_int):
diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py
--- a/pypy/module/micronumpy/strides.py
+++ b/pypy/module/micronumpy/strides.py
@@ -48,9 +48,12 @@
     return rstrides, rbackstrides
 
 def is_single_elem(space, w_elem, is_rec_type):
+    from pypy.module.micronumpy.interp_numarray import BaseArray
     if (is_rec_type and space.isinstance_w(w_elem, space.w_tuple)):
         return True
-    if space.issequence_w(w_elem):
+    if (space.isinstance_w(w_elem, space.w_tuple) or
+        isinstance(w_elem, BaseArray) or    
+        space.isinstance_w(w_elem, space.w_list)):
         return False
     return True
 
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -193,6 +193,19 @@
         assert _to_coords(5, 'F') == [1, 2, 0]
         assert _to_coords(13, 'F') == [1, 0, 2]
 
+    def test_find_shape(self):
+        from pypy.module.micronumpy.strides import find_shape_and_elems
+
+        space = self.space
+        shape, elems = find_shape_and_elems(space,
+                                            space.newlist([space.wrap("a"),
+                                                           space.wrap("b")]),
+                                            None)
+        assert shape == [2]
+        assert space.str_w(elems[0]) == "a"
+        assert space.str_w(elems[1]) == "b"
+        
+
 class AppTestNumArray(BaseNumpyAppTest):
     def w_CustomIndexObject(self, index):
         class CustomIndexObject(object):
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -83,8 +83,8 @@
 
     def test_add(self):
         result = self.run("add")
-        self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add': 1,
-                                'setinteriorfield_raw': 1, 'int_add': 1,
+        self.check_simple_loop({'raw_load': 2, 'float_add': 1,
+                                'raw_store': 1, 'int_add': 1,
                                 'int_ge': 1, 'guard_false': 1, 'jump': 1,
                                 'arraylen_gc': 1})
         assert result == 3 + 3
@@ -98,8 +98,8 @@
     def test_floatadd(self):
         result = self.run("float_add")
         assert result == 3 + 3
-        self.check_simple_loop({"getinteriorfield_raw": 1, "float_add": 1,
-                                "setinteriorfield_raw": 1, "int_add": 1,
+        self.check_simple_loop({"raw_load": 1, "float_add": 1,
+                                "raw_store": 1, "int_add": 1,
                                 "int_ge": 1, "guard_false": 1, "jump": 1,
                                 'arraylen_gc': 1})
 
@@ -113,7 +113,7 @@
     def test_sum(self):
         result = self.run("sum")
         assert result == 2 * sum(range(30))
-        self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 2,
+        self.check_simple_loop({"raw_load": 2, "float_add": 2,
                                 "int_add": 1, "int_ge": 1, "guard_false": 1,
                                 "jump": 1, 'arraylen_gc': 1})
 
@@ -129,8 +129,8 @@
         assert result == 30
         # XXX note - the bridge here is fairly crucial and yet it's pretty
         #            bogus. We need to improve the situation somehow.
-        self.check_simple_loop({'getinteriorfield_raw': 2,
-                                'setinteriorfield_raw': 1,
+        self.check_simple_loop({'raw_load': 2,
+                                'raw_store': 1,
                                 'arraylen_gc': 2,
                                 'guard_true': 1,
                                 'int_lt': 1,
@@ -152,7 +152,7 @@
         for i in range(30):
             expected *= i * 2
         assert result == expected
-        self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
+        self.check_simple_loop({"raw_load": 2, "float_add": 1,
                                 "float_mul": 1, "int_add": 1,
                                 "int_ge": 1, "guard_false": 1, "jump": 1,
                                 'arraylen_gc': 1})
@@ -169,7 +169,7 @@
         result = self.run("max")
         assert result == 256
         py.test.skip("not there yet, getting though")
-        self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
+        self.check_simple_loop({"raw_load": 2, "float_add": 1,
                                 "float_mul": 1, "int_add": 1,
                                 "int_lt": 1, "guard_true": 1, "jump": 1})
 
@@ -182,7 +182,7 @@
         min(b)
         """)
         assert result == -24
-        self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
+        self.check_simple_loop({"raw_load": 2, "float_add": 1,
                                 "float_mul": 1, "int_add": 1,
                                 "int_lt": 1, "guard_true": 1, "jump": 1})
 
@@ -197,7 +197,7 @@
     def test_any(self):
         result = self.run("any")
         assert result == 1
-        self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
+        self.check_simple_loop({"raw_load": 2, "float_add": 1,
                                 "int_and": 1, "int_add": 1,
                                 'cast_float_to_int': 1,
                                 "int_ge": 1, "jump": 1,
@@ -219,12 +219,12 @@
         # optimization then you end up with 2 float_adds, so we can still be
         # sure it was optimized correctly.
         py.test.skip("too fragile")
-        self.check_resops({'setinteriorfield_raw': 4, 'getfield_gc': 22,
+        self.check_resops({'raw_store': 4, 'getfield_gc': 22,
                            'getarrayitem_gc': 4, 'getarrayitem_gc_pure': 2,
                            'getfield_gc_pure': 8,
                            'guard_class': 8, 'int_add': 8, 'float_mul': 2,
                            'jump': 2, 'int_ge': 4,
-                           'getinteriorfield_raw': 4, 'float_add': 2,
+                           'raw_load': 4, 'float_add': 2,
                            'guard_false': 4, 'arraylen_gc': 2, 'same_as': 2})
 
     def define_ufunc():
@@ -238,9 +238,9 @@
     def test_ufunc(self):
         result = self.run("ufunc")
         assert result == -6
-        self.check_simple_loop({"getinteriorfield_raw": 2, "float_add": 1,
+        self.check_simple_loop({"raw_load": 2, "float_add": 1,
                                 "float_neg": 1,
-                                "setinteriorfield_raw": 1, "int_add": 1,
+                                "raw_store": 1, "int_add": 1,
                                 "int_ge": 1, "guard_false": 1, "jump": 1,
                                 'arraylen_gc': 1})
 
@@ -280,9 +280,9 @@
     def test_slice(self):
         result = self.run("slice")
         assert result == 18
-        self.check_simple_loop({'getinteriorfield_raw': 2,
+        self.check_simple_loop({'raw_load': 2,
                                 'float_add': 1,
-                                'setinteriorfield_raw': 1,
+                                'raw_store': 1,
                                 'int_add': 3,
                                 'int_ge': 1, 'guard_false': 1,
                                 'jump': 1,
@@ -298,12 +298,12 @@
     def test_take(self):
         result = self.run("take")
         assert result == 3
-        self.check_simple_loop({'getinteriorfield_raw': 2,
+        self.check_simple_loop({'raw_load': 2,
                                 'cast_float_to_int': 1,
                                 'int_lt': 1,
                                 'int_ge': 2,
                                 'guard_false': 3,
-                                'setinteriorfield_raw': 1,
+                                'raw_store': 1,
                                 'int_mul': 1,
                                 'int_add': 3,
                                 'jump': 1,
@@ -321,9 +321,9 @@
         assert result == 8
         # int_add might be 1 here if we try slightly harder with
         # reusing indexes or some optimization
-        self.check_simple_loop({'float_add': 1, 'getinteriorfield_raw': 2,
+        self.check_simple_loop({'float_add': 1, 'raw_load': 2,
                                 'guard_false': 1, 'int_add': 1, 'int_ge': 1,
-                                'jump': 1, 'setinteriorfield_raw': 1,
+                                'jump': 1, 'raw_store': 1,
                                 'arraylen_gc': 1})
 
     def define_multidim_slice():
@@ -370,8 +370,8 @@
         result = self.run("setslice")
         assert result == 11.0
         self.check_trace_count(1)
-        self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add': 1,
-                                'setinteriorfield_raw': 1, 'int_add': 2,
+        self.check_simple_loop({'raw_load': 2, 'float_add': 1,
+                                'raw_store': 1, 'int_add': 2,
                                 'int_eq': 1, 'guard_false': 1, 'jump': 1,
                                 'arraylen_gc': 1})
 
@@ -387,8 +387,8 @@
         result = self.run("virtual_slice")
         assert result == 4
         self.check_trace_count(1)
-        self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add': 1,
-                                'setinteriorfield_raw': 1, 'int_add': 1,
+        self.check_simple_loop({'raw_load': 2, 'float_add': 1,
+                                'raw_store': 1, 'int_add': 1,
                                 'int_ge': 1, 'guard_false': 1, 'jump': 1,
                                 'arraylen_gc': 1})
     def define_flat_iter():
@@ -403,8 +403,8 @@
         result = self.run("flat_iter")
         assert result == 6
         self.check_trace_count(1)
-        self.check_simple_loop({'getinteriorfield_raw': 2, 'float_add': 1,
-                                'setinteriorfield_raw': 1, 'int_add': 2,
+        self.check_simple_loop({'raw_load': 2, 'float_add': 1,


More information about the pypy-commit mailing list