[pypy-commit] pypy better-jit-hooks: merge in default

fijal noreply at buildbot.pypy.org
Tue Dec 20 21:58:17 CET 2011


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: better-jit-hooks
Changeset: r50775:342a652c6fed
Date: 2011-12-20 22:01 +0200
http://bitbucket.org/pypy/pypy/changeset/342a652c6fed/

Log:	merge in default

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
@@ -37,7 +37,7 @@
     def get_arg_types(self):
         return self.arg_types
 
-    def get_return_type(self):
+    def get_result_type(self):
         return self.typeinfo
 
     def get_extra_info(self):
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
@@ -5,11 +5,7 @@
 from pypy.jit.metainterp.history import AbstractDescr, getkind
 from pypy.jit.metainterp import history
 from pypy.jit.codewriter import heaptracker, longlong
-
-# The point of the class organization in this file is to make instances
-# as compact as possible.  This is done by not storing the field size or
-# the 'is_pointer_field' flag in the instance itself but in the class
-# (in methods actually) using a few classes instead of just one.
+from pypy.jit.codewriter.longlong import is_longlong
 
 
 class GcCache(object):
@@ -19,6 +15,7 @@
         self._cache_size = {}
         self._cache_field = {}
         self._cache_array = {}
+        self._cache_arraylen = {}
         self._cache_call = {}
         self._cache_interiorfield = {}
 
@@ -26,24 +23,15 @@
         assert isinstance(STRUCT, lltype.GcStruct)
 
     def init_array_descr(self, ARRAY, arraydescr):
-        assert isinstance(ARRAY, lltype.GcArray)
+        assert (isinstance(ARRAY, lltype.GcArray) or
+                isinstance(ARRAY, lltype.GcStruct) and ARRAY._arrayfld)
 
 
-if lltype.SignedLongLong is lltype.Signed:
-    def is_longlong(TYPE):
-        return False
-else:
-    assert rffi.sizeof(lltype.SignedLongLong) == rffi.sizeof(lltype.Float)
-    def is_longlong(TYPE):
-        return TYPE in (lltype.SignedLongLong, lltype.UnsignedLongLong)
-
 # ____________________________________________________________
 # SizeDescrs
 
 class SizeDescr(AbstractDescr):
     size = 0      # help translation
-    is_immutable = False
-
     tid = llop.combine_ushort(lltype.Signed, 0, 0)
 
     def __init__(self, size, count_fields_if_immut=-1):
@@ -77,265 +65,247 @@
         cache[STRUCT] = sizedescr
         return sizedescr
 
+
 # ____________________________________________________________
 # FieldDescrs
 
-class BaseFieldDescr(AbstractDescr):
+FLAG_POINTER  = 'P'
+FLAG_FLOAT    = 'F'
+FLAG_UNSIGNED = 'U'
+FLAG_SIGNED   = 'S'
+FLAG_STRUCT   = 'X'
+FLAG_VOID     = 'V'
+
+class FieldDescr(AbstractDescr):
+    name = ''
     offset = 0      # help translation
-    name = ''
-    _clsname = ''
+    field_size = 0
+    flag = '\x00'
 
-    def __init__(self, name, offset):
+    def __init__(self, name, offset, field_size, flag):
         self.name = name
         self.offset = offset
+        self.field_size = field_size
+        self.flag = flag
+
+    def is_pointer_field(self):
+        return self.flag == FLAG_POINTER
+
+    def is_float_field(self):
+        return self.flag == FLAG_FLOAT
+
+    def is_field_signed(self):
+        return self.flag == FLAG_SIGNED
 
     def sort_key(self):
         return self.offset
 
-    def get_field_size(self, translate_support_code):
-        raise NotImplementedError
+    def repr_of_descr(self):
+        return '<Field%s %s %s>' % (self.flag, self.name, self.offset)
 
-    _is_pointer_field = False   # unless overridden by GcPtrFieldDescr
-    _is_float_field = False     # unless overridden by FloatFieldDescr
-    _is_field_signed = False    # unless overridden by XxxFieldDescr
-
-    def is_pointer_field(self):
-        return self._is_pointer_field
-
-    def is_float_field(self):
-        return self._is_float_field
-
-    def is_field_signed(self):
-        return self._is_field_signed
-
-    def repr_of_descr(self):
-        return '<%s %s %s>' % (self._clsname, self.name, self.offset)
-
-class DynamicFieldDescr(BaseFieldDescr):
-    def __init__(self, offset, fieldsize, is_pointer, is_float, is_signed):
-        self.offset = offset
-        self._fieldsize = fieldsize
-        self._is_pointer_field = is_pointer
-        self._is_float_field = is_float
-        self._is_field_signed = is_signed
-
-    def get_field_size(self, translate_support_code):
-        return self._fieldsize
-
-class NonGcPtrFieldDescr(BaseFieldDescr):
-    _clsname = 'NonGcPtrFieldDescr'
-    def get_field_size(self, translate_support_code):
-        return symbolic.get_size_of_ptr(translate_support_code)
-
-class GcPtrFieldDescr(NonGcPtrFieldDescr):
-    _clsname = 'GcPtrFieldDescr'
-    _is_pointer_field = True
-
-def getFieldDescrClass(TYPE):
-    return getDescrClass(TYPE, BaseFieldDescr, GcPtrFieldDescr,
-                         NonGcPtrFieldDescr, 'Field', 'get_field_size',
-                         '_is_float_field', '_is_field_signed')
 
 def get_field_descr(gccache, STRUCT, fieldname):
     cache = gccache._cache_field
     try:
         return cache[STRUCT][fieldname]
     except KeyError:
-        offset, _ = symbolic.get_field_token(STRUCT, fieldname,
-                                             gccache.translate_support_code)
+        offset, size = symbolic.get_field_token(STRUCT, fieldname,
+                                                gccache.translate_support_code)
         FIELDTYPE = getattr(STRUCT, fieldname)
+        flag = get_type_flag(FIELDTYPE)
         name = '%s.%s' % (STRUCT._name, fieldname)
-        fielddescr = getFieldDescrClass(FIELDTYPE)(name, offset)
+        fielddescr = FieldDescr(name, offset, size, flag)
         cachedict = cache.setdefault(STRUCT, {})
         cachedict[fieldname] = fielddescr
         return fielddescr
 
+def get_type_flag(TYPE):
+    if isinstance(TYPE, lltype.Ptr):
+        if TYPE.TO._gckind == 'gc':
+            return FLAG_POINTER
+        else:
+            return FLAG_UNSIGNED
+    if isinstance(TYPE, lltype.Struct):
+        return FLAG_STRUCT
+    if TYPE is lltype.Float or is_longlong(TYPE):
+        return FLAG_FLOAT
+    if (TYPE is not lltype.Bool and isinstance(TYPE, lltype.Number) and
+           rffi.cast(TYPE, -1) == -1):
+        return FLAG_SIGNED
+    return FLAG_UNSIGNED
+
+def get_field_arraylen_descr(gccache, ARRAY_OR_STRUCT):
+    cache = gccache._cache_arraylen
+    try:
+        return cache[ARRAY_OR_STRUCT]
+    except KeyError:
+        tsc = gccache.translate_support_code
+        (_, _, ofs) = symbolic.get_array_token(ARRAY_OR_STRUCT, tsc)
+        size = symbolic.get_size(lltype.Signed, tsc)
+        result = FieldDescr("len", ofs, size, get_type_flag(lltype.Signed))
+        cache[ARRAY_OR_STRUCT] = result
+        return result
+
+
 # ____________________________________________________________
 # ArrayDescrs
 
-_A = lltype.GcArray(lltype.Signed)     # a random gcarray
-_AF = lltype.GcArray(lltype.Float)     # an array of C doubles
+class ArrayDescr(AbstractDescr):
+    tid = 0
+    basesize = 0       # workaround for the annotator
+    itemsize = 0
+    lendescr = None
+    flag = '\x00'
 
-
-class BaseArrayDescr(AbstractDescr):
-    _clsname = ''
-    tid = llop.combine_ushort(lltype.Signed, 0, 0)
-
-    def get_base_size(self, translate_support_code):
-        basesize, _, _ = symbolic.get_array_token(_A, translate_support_code)
-        return basesize
-
-    def get_ofs_length(self, translate_support_code):
-        _, _, ofslength = symbolic.get_array_token(_A, translate_support_code)
-        return ofslength
-
-    def get_item_size(self, translate_support_code):
-        raise NotImplementedError
-
-    _is_array_of_pointers = False      # unless overridden by GcPtrArrayDescr
-    _is_array_of_floats   = False      # unless overridden by FloatArrayDescr
-    _is_array_of_structs  = False      # unless overridden by StructArrayDescr
-    _is_item_signed       = False      # unless overridden by XxxArrayDescr
+    def __init__(self, basesize, itemsize, lendescr, flag):
+        self.basesize = basesize
+        self.itemsize = itemsize
+        self.lendescr = lendescr    # or None, if no length
+        self.flag = flag
 
     def is_array_of_pointers(self):
-        return self._is_array_of_pointers
+        return self.flag == FLAG_POINTER
 
     def is_array_of_floats(self):
-        return self._is_array_of_floats
+        return self.flag == FLAG_FLOAT
+
+    def is_item_signed(self):
+        return self.flag == FLAG_SIGNED
 
     def is_array_of_structs(self):
-        return self._is_array_of_structs
-
-    def is_item_signed(self):
-        return self._is_item_signed
+        return self.flag == FLAG_STRUCT
 
     def repr_of_descr(self):
-        return '<%s>' % self._clsname
+        return '<Array%s %s>' % (self.flag, self.itemsize)
 
 
-class NonGcPtrArrayDescr(BaseArrayDescr):
-    _clsname = 'NonGcPtrArrayDescr'
-    def get_item_size(self, translate_support_code):
-        return symbolic.get_size_of_ptr(translate_support_code)
-
-class GcPtrArrayDescr(NonGcPtrArrayDescr):
-    _clsname = 'GcPtrArrayDescr'
-    _is_array_of_pointers = True
-
-class FloatArrayDescr(BaseArrayDescr):
-    _clsname = 'FloatArrayDescr'
-    _is_array_of_floats = True
-    def get_base_size(self, translate_support_code):
-        basesize, _, _ = symbolic.get_array_token(_AF, translate_support_code)
-        return basesize
-    def get_item_size(self, translate_support_code):
-        return symbolic.get_size(lltype.Float, translate_support_code)
-
-class StructArrayDescr(BaseArrayDescr):
-    _clsname = 'StructArrayDescr'
-    _is_array_of_structs = True
-
-class BaseArrayNoLengthDescr(BaseArrayDescr):
-    def get_base_size(self, translate_support_code):
-        return 0
-
-    def get_ofs_length(self, translate_support_code):
-        return -1
-
-class DynamicArrayNoLengthDescr(BaseArrayNoLengthDescr):
-    def __init__(self, itemsize):
-        self.itemsize = itemsize
-
-    def get_item_size(self, translate_support_code):
-        return self.itemsize
-
-class NonGcPtrArrayNoLengthDescr(BaseArrayNoLengthDescr):
-    _clsname = 'NonGcPtrArrayNoLengthDescr'
-    def get_item_size(self, translate_support_code):
-        return symbolic.get_size_of_ptr(translate_support_code)
-
-class GcPtrArrayNoLengthDescr(NonGcPtrArrayNoLengthDescr):
-    _clsname = 'GcPtrArrayNoLengthDescr'
-    _is_array_of_pointers = True
-
-def getArrayDescrClass(ARRAY):
-    if ARRAY.OF is lltype.Float:
-        return FloatArrayDescr
-    elif isinstance(ARRAY.OF, lltype.Struct):
-        class Descr(StructArrayDescr):
-            _clsname = '%sArrayDescr' % ARRAY.OF._name
-            def get_item_size(self, translate_support_code):
-                return symbolic.get_size(ARRAY.OF, translate_support_code)
-        Descr.__name__ = Descr._clsname
-        return Descr
-    return getDescrClass(ARRAY.OF, BaseArrayDescr, GcPtrArrayDescr,
-                         NonGcPtrArrayDescr, 'Array', 'get_item_size',
-                         '_is_array_of_floats', '_is_item_signed')
-
-def getArrayNoLengthDescrClass(ARRAY):
-    return getDescrClass(ARRAY.OF, BaseArrayNoLengthDescr, GcPtrArrayNoLengthDescr,
-                         NonGcPtrArrayNoLengthDescr, 'ArrayNoLength', 'get_item_size',
-                         '_is_array_of_floats', '_is_item_signed')
-
-def get_array_descr(gccache, ARRAY):
+def get_array_descr(gccache, ARRAY_OR_STRUCT):
     cache = gccache._cache_array
     try:
-        return cache[ARRAY]
+        return cache[ARRAY_OR_STRUCT]
     except KeyError:
-        # we only support Arrays that are either GcArrays, or raw no-length
-        # non-gc Arrays.
-        if ARRAY._hints.get('nolength', False):
-            assert not isinstance(ARRAY, lltype.GcArray)
-            arraydescr = getArrayNoLengthDescrClass(ARRAY)()
+        tsc = gccache.translate_support_code
+        basesize, itemsize, _ = symbolic.get_array_token(ARRAY_OR_STRUCT, tsc)
+        if isinstance(ARRAY_OR_STRUCT, lltype.Array):
+            ARRAY_INSIDE = ARRAY_OR_STRUCT
         else:
-            assert isinstance(ARRAY, lltype.GcArray)
-            arraydescr = getArrayDescrClass(ARRAY)()
-        # verify basic assumption that all arrays' basesize and ofslength
-        # are equal
-        basesize, itemsize, ofslength = symbolic.get_array_token(ARRAY, False)
-        assert basesize == arraydescr.get_base_size(False)
-        assert itemsize == arraydescr.get_item_size(False)
-        if not ARRAY._hints.get('nolength', False):
-            assert ofslength == arraydescr.get_ofs_length(False)
-        if isinstance(ARRAY, lltype.GcArray):
-            gccache.init_array_descr(ARRAY, arraydescr)
-        cache[ARRAY] = arraydescr
+            ARRAY_INSIDE = ARRAY_OR_STRUCT._flds[ARRAY_OR_STRUCT._arrayfld]
+        if ARRAY_INSIDE._hints.get('nolength', False):
+            lendescr = None
+        else:
+            lendescr = get_field_arraylen_descr(gccache, ARRAY_OR_STRUCT)
+        flag = get_type_flag(ARRAY_INSIDE.OF)
+        arraydescr = ArrayDescr(basesize, itemsize, lendescr, flag)
+        if ARRAY_OR_STRUCT._gckind == 'gc':
+            gccache.init_array_descr(ARRAY_OR_STRUCT, arraydescr)
+        cache[ARRAY_OR_STRUCT] = arraydescr
         return arraydescr
 
+
 # ____________________________________________________________
 # InteriorFieldDescr
 
 class InteriorFieldDescr(AbstractDescr):
-    arraydescr = BaseArrayDescr()     # workaround for the annotator
-    fielddescr = BaseFieldDescr('', 0)
+    arraydescr = ArrayDescr(0, 0, None, '\x00')  # workaround for the annotator
+    fielddescr = FieldDescr('', 0, 0, '\x00')
 
     def __init__(self, arraydescr, fielddescr):
+        assert arraydescr.flag == FLAG_STRUCT
         self.arraydescr = arraydescr
         self.fielddescr = fielddescr
 
+    def sort_key(self):
+        return self.fielddescr.sort_key()
+
     def is_pointer_field(self):
         return self.fielddescr.is_pointer_field()
 
     def is_float_field(self):
         return self.fielddescr.is_float_field()
 
-    def sort_key(self):
-        return self.fielddescr.sort_key()
-
     def repr_of_descr(self):
         return '<InteriorFieldDescr %s>' % self.fielddescr.repr_of_descr()
 
-def get_interiorfield_descr(gc_ll_descr, ARRAY, FIELDTP, name):
+def get_interiorfield_descr(gc_ll_descr, ARRAY, name):
     cache = gc_ll_descr._cache_interiorfield
     try:
-        return cache[(ARRAY, FIELDTP, name)]
+        return cache[(ARRAY, name)]
     except KeyError:
         arraydescr = get_array_descr(gc_ll_descr, ARRAY)
-        fielddescr = get_field_descr(gc_ll_descr, FIELDTP, name)
+        fielddescr = get_field_descr(gc_ll_descr, ARRAY.OF, name)
         descr = InteriorFieldDescr(arraydescr, fielddescr)
-        cache[(ARRAY, FIELDTP, name)] = descr
+        cache[(ARRAY, name)] = descr
         return descr
 
+def get_dynamic_interiorfield_descr(gc_ll_descr, offset, width, fieldsize,
+                                    is_pointer, is_float, is_signed):
+    arraydescr = ArrayDescr(0, width, None, FLAG_STRUCT)
+    if is_pointer:
+        assert not is_float
+        flag = FLAG_POINTER
+    elif is_float:
+        flag = FLAG_FLOAT
+    elif is_signed:
+        flag = FLAG_SIGNED
+    else:
+        flag = FLAG_UNSIGNED
+    fielddescr = FieldDescr('dynamic', offset, fieldsize, flag)
+    return InteriorFieldDescr(arraydescr, fielddescr)
+
+
 # ____________________________________________________________
 # CallDescrs
 
-class BaseCallDescr(AbstractDescr):
-    _clsname = ''
-    loop_token = None
+class CallDescr(AbstractDescr):
     arg_classes = ''     # <-- annotation hack
+    result_type = '\x00'
+    result_flag = '\x00'
     ffi_flags = 1
+    call_stub_i = staticmethod(lambda func, args_i, args_r, args_f:
+                               0)
+    call_stub_r = staticmethod(lambda func, args_i, args_r, args_f:
+                               lltype.nullptr(llmemory.GCREF.TO))
+    call_stub_f = staticmethod(lambda func,args_i,args_r,args_f:
+                               longlong.ZEROF)
 
-    def __init__(self, arg_classes, extrainfo=None, ffi_flags=1):
-        self.arg_classes = arg_classes    # string of "r" and "i" (ref/int)
+    def __init__(self, arg_classes, result_type, result_signed, result_size,
+                 extrainfo=None, ffi_flags=1):
+        """
+            'arg_classes' is a string of characters, one per argument:
+                'i', 'r', 'f', 'L', 'S'
+
+            'result_type' is one character from the same list or 'v'
+
+            'result_signed' is a boolean True/False
+        """
+        self.arg_classes = arg_classes
+        self.result_type = result_type
+        self.result_size = result_size
         self.extrainfo = extrainfo
         self.ffi_flags = ffi_flags
         # NB. the default ffi_flags is 1, meaning FUNCFLAG_CDECL, which
         # makes sense on Windows as it's the one for all the C functions
         # we are compiling together with the JIT.  On non-Windows platforms
         # it is just ignored anyway.
+        if result_type == 'v':
+            result_flag = FLAG_VOID
+        elif result_type == 'i':
+            if result_signed:
+                result_flag = FLAG_SIGNED
+            else:
+                result_flag = FLAG_UNSIGNED
+        elif result_type == history.REF:
+            result_flag = FLAG_POINTER
+        elif result_type == history.FLOAT or result_type == 'L':
+            result_flag = FLAG_FLOAT
+        elif result_type == 'S':
+            result_flag = FLAG_UNSIGNED
+        else:
+            raise NotImplementedError("result_type = '%s'" % (result_type,))
+        self.result_flag = result_flag
 
     def __repr__(self):
-        res = '%s(%s)' % (self.__class__.__name__, self.arg_classes)
+        res = 'CallDescr(%s)' % (self.arg_classes,)
         extraeffect = getattr(self.extrainfo, 'extraeffect', None)
         if extraeffect is not None:
             res += ' EF=%r' % extraeffect
@@ -363,14 +333,14 @@
     def get_arg_types(self):
         return self.arg_classes
 
-    def get_return_type(self):
-        return self._return_type
+    def get_result_type(self):
+        return self.result_type
 
-    def get_result_size(self, translate_support_code):
-        raise NotImplementedError
+    def get_result_size(self):
+        return self.result_size
 
     def is_result_signed(self):
-        return False    # unless overridden
+        return self.result_flag == FLAG_SIGNED
 
     def create_call_stub(self, rtyper, RESULT):
         from pypy.rlib.clibffi import FFI_DEFAULT_ABI
@@ -408,18 +378,26 @@
         seen = {'i': 0, 'r': 0, 'f': 0}
         args = ", ".join([process(c) for c in self.arg_classes])
 
-        if self.get_return_type() == history.INT:
+        result_type = self.get_result_type()
+        if result_type == history.INT:
             result = 'rffi.cast(lltype.Signed, res)'
-        elif self.get_return_type() == history.REF:
+            category = 'i'
+        elif result_type == history.REF:
+            assert RESULT == llmemory.GCREF   # should be ensured by the caller
             result = 'lltype.cast_opaque_ptr(llmemory.GCREF, res)'
-        elif self.get_return_type() == history.FLOAT:
+            category = 'r'
+        elif result_type == history.FLOAT:
             result = 'longlong.getfloatstorage(res)'
-        elif self.get_return_type() == 'L':
+            category = 'f'
+        elif result_type == 'L':
             result = 'rffi.cast(lltype.SignedLongLong, res)'
-        elif self.get_return_type() == history.VOID:
-            result = 'None'
-        elif self.get_return_type() == 'S':
+            category = 'f'
+        elif result_type == history.VOID:
+            result = '0'
+            category = 'i'
+        elif result_type == 'S':
             result = 'longlong.singlefloat2int(res)'
+            category = 'i'
         else:
             assert 0
         source = py.code.Source("""
@@ -433,10 +411,13 @@
         d = globals().copy()
         d.update(locals())
         exec source.compile() in d
-        self.call_stub = d['call_stub']
+        call_stub = d['call_stub']
+        # store the function into one of three attributes, to preserve
+        # type-correctness of the return value
+        setattr(self, 'call_stub_%s' % category, call_stub)
 
     def verify_types(self, args_i, args_r, args_f, return_type):
-        assert self._return_type in return_type
+        assert self.result_type in return_type
         assert (self.arg_classes.count('i') +
                 self.arg_classes.count('S')) == len(args_i or ())
         assert self.arg_classes.count('r') == len(args_r or ())
@@ -444,161 +425,56 @@
                 self.arg_classes.count('L')) == len(args_f or ())
 
     def repr_of_descr(self):
-        return '<%s>' % self._clsname
+        res = 'Call%s %d' % (self.result_type, self.result_size)
+        if self.arg_classes:
+            res += ' ' + self.arg_classes
+        if self.extrainfo:
+            res += ' EF=%d' % self.extrainfo.extraeffect
+            oopspecindex = self.extrainfo.oopspecindex
+            if oopspecindex:
+                res += ' OS=%d' % oopspecindex
+        return '<%s>' % res
 
 
-class BaseIntCallDescr(BaseCallDescr):
-    # Base class of the various subclasses of descrs corresponding to
-    # calls having a return kind of 'int' (including non-gc pointers).
-    # The inheritance hierarchy is a bit different than with other Descr
-    # classes because of the 'call_stub' attribute, which is of type
-    #
-    #     lambda func, args_i, args_r, args_f --> int/ref/float/void
-    #
-    # The purpose of BaseIntCallDescr is to be the parent of all classes
-    # in which 'call_stub' has a return kind of 'int'.
-    _return_type = history.INT
-    call_stub = staticmethod(lambda func, args_i, args_r, args_f: 0)
-
-    _is_result_signed = False      # can be overridden in XxxCallDescr
-    def is_result_signed(self):
-        return self._is_result_signed
-
-class DynamicIntCallDescr(BaseIntCallDescr):
-    """
-    calldescr that works for every integer type, by explicitly passing it the
-    size of the result. Used only by get_call_descr_dynamic
-    """
-    _clsname = 'DynamicIntCallDescr'
-
-    def __init__(self, arg_classes, result_size, result_sign, extrainfo, ffi_flags):
-        BaseIntCallDescr.__init__(self, arg_classes, extrainfo, ffi_flags)
-        assert isinstance(result_sign, bool)
-        self._result_size = chr(result_size)
-        self._result_sign = result_sign
-
-    def get_result_size(self, translate_support_code):
-        return ord(self._result_size)
-
-    def is_result_signed(self):
-        return self._result_sign
-
-
-class NonGcPtrCallDescr(BaseIntCallDescr):
-    _clsname = 'NonGcPtrCallDescr'
-    def get_result_size(self, translate_support_code):
-        return symbolic.get_size_of_ptr(translate_support_code)
-
-class GcPtrCallDescr(BaseCallDescr):
-    _clsname = 'GcPtrCallDescr'
-    _return_type = history.REF
-    call_stub = staticmethod(lambda func, args_i, args_r, args_f:
-                             lltype.nullptr(llmemory.GCREF.TO))
-    def get_result_size(self, translate_support_code):
-        return symbolic.get_size_of_ptr(translate_support_code)
-
-class FloatCallDescr(BaseCallDescr):
-    _clsname = 'FloatCallDescr'
-    _return_type = history.FLOAT
-    call_stub = staticmethod(lambda func,args_i,args_r,args_f: longlong.ZEROF)
-    def get_result_size(self, translate_support_code):
-        return symbolic.get_size(lltype.Float, translate_support_code)
-
-class LongLongCallDescr(FloatCallDescr):
-    _clsname = 'LongLongCallDescr'
-    _return_type = 'L'
-
-class VoidCallDescr(BaseCallDescr):
-    _clsname = 'VoidCallDescr'
-    _return_type = history.VOID
-    call_stub = staticmethod(lambda func, args_i, args_r, args_f: None)
-    def get_result_size(self, translate_support_code):
-        return 0
-
-_SingleFloatCallDescr = None   # built lazily
-
-def getCallDescrClass(RESULT):
-    if RESULT is lltype.Void:
-        return VoidCallDescr
-    if RESULT is lltype.Float:
-        return FloatCallDescr
-    if RESULT is lltype.SingleFloat:
-        global _SingleFloatCallDescr
-        if _SingleFloatCallDescr is None:
-            assert rffi.sizeof(rffi.UINT) == rffi.sizeof(RESULT)
-            class SingleFloatCallDescr(getCallDescrClass(rffi.UINT)):
-                _clsname = 'SingleFloatCallDescr'
-                _return_type = 'S'
-            _SingleFloatCallDescr = SingleFloatCallDescr
-        return _SingleFloatCallDescr
-    if is_longlong(RESULT):
-        return LongLongCallDescr
-    return getDescrClass(RESULT, BaseIntCallDescr, GcPtrCallDescr,
-                         NonGcPtrCallDescr, 'Call', 'get_result_size',
-                         Ellipsis,  # <= floatattrname should not be used here
-                         '_is_result_signed')
-getCallDescrClass._annspecialcase_ = 'specialize:memo'
+def map_type_to_argclass(ARG, accept_void=False):
+    kind = getkind(ARG)
+    if   kind == 'int':
+        if ARG is lltype.SingleFloat: return 'S'
+        else:                         return 'i'
+    elif kind == 'ref':               return 'r'
+    elif kind == 'float':
+        if is_longlong(ARG):          return 'L'
+        else:                         return 'f'
+    elif kind == 'void':
+        if accept_void:               return 'v'
+    raise NotImplementedError('ARG = %r' % (ARG,))
 
 def get_call_descr(gccache, ARGS, RESULT, extrainfo=None):
-    arg_classes = []
-    for ARG in ARGS:
-        kind = getkind(ARG)
-        if   kind == 'int':
-            if ARG is lltype.SingleFloat:
-                arg_classes.append('S')
+    arg_classes = map(map_type_to_argclass, ARGS)
+    arg_classes = ''.join(arg_classes)
+    result_type = map_type_to_argclass(RESULT, accept_void=True)
+    RESULT_ERASED = RESULT
+    if RESULT is lltype.Void:
+        result_size = 0
+        result_signed = False
+    else:
+        if isinstance(RESULT, lltype.Ptr):
+            # avoid too many CallDescrs
+            if result_type == 'r':
+                RESULT_ERASED = llmemory.GCREF
             else:
-                arg_classes.append('i')
-        elif kind == 'ref': arg_classes.append('r')
-        elif kind == 'float':
-            if is_longlong(ARG):
-                arg_classes.append('L')
-            else:
-                arg_classes.append('f')
-        else:
-            raise NotImplementedError('ARG = %r' % (ARG,))
-    arg_classes = ''.join(arg_classes)
-    cls = getCallDescrClass(RESULT)
-    key = (cls, arg_classes, extrainfo)
+                RESULT_ERASED = llmemory.Address
+        result_size = symbolic.get_size(RESULT_ERASED,
+                                        gccache.translate_support_code)
+        result_signed = get_type_flag(RESULT) == FLAG_SIGNED
+    key = (arg_classes, result_type, result_signed, RESULT_ERASED, extrainfo)
     cache = gccache._cache_call
     try:
-        return cache[key]
+        calldescr = cache[key]
     except KeyError:
-        calldescr = cls(arg_classes, extrainfo)
-        calldescr.create_call_stub(gccache.rtyper, RESULT)
+        calldescr = CallDescr(arg_classes, result_type, result_signed,
+                              result_size, extrainfo)
+        calldescr.create_call_stub(gccache.rtyper, RESULT_ERASED)
         cache[key] = calldescr
-        return calldescr
-
-
-# ____________________________________________________________
-
-def getDescrClass(TYPE, BaseDescr, GcPtrDescr, NonGcPtrDescr,
-                  nameprefix, methodname, floatattrname, signedattrname,
-                  _cache={}):
-    if isinstance(TYPE, lltype.Ptr):
-        if TYPE.TO._gckind == 'gc':
-            return GcPtrDescr
-        else:
-            return NonGcPtrDescr
-    if TYPE is lltype.SingleFloat:
-        assert rffi.sizeof(rffi.UINT) == rffi.sizeof(TYPE)
-        TYPE = rffi.UINT
-    try:
-        return _cache[nameprefix, TYPE]
-    except KeyError:
-        #
-        class Descr(BaseDescr):
-            _clsname = '%s%sDescr' % (TYPE._name, nameprefix)
-        Descr.__name__ = Descr._clsname
-        #
-        def method(self, translate_support_code):
-            return symbolic.get_size(TYPE, translate_support_code)
-        setattr(Descr, methodname, method)
-        #
-        if TYPE is lltype.Float or is_longlong(TYPE):
-            setattr(Descr, floatattrname, True)
-        elif (TYPE is not lltype.Bool and isinstance(TYPE, lltype.Number) and
-              rffi.cast(TYPE, -1) == -1):
-            setattr(Descr, signedattrname, True)
-        #
-        _cache[nameprefix, TYPE] = Descr
-        return Descr
+    assert repr(calldescr.result_size) == repr(result_size)
+    return calldescr
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,9 +1,7 @@
 from pypy.rlib.rarithmetic import intmask
 from pypy.jit.metainterp import history
 from pypy.rpython.lltypesystem import rffi
-from pypy.jit.backend.llsupport.descr import (
-    DynamicIntCallDescr, NonGcPtrCallDescr, FloatCallDescr, VoidCallDescr,
-    LongLongCallDescr, getCallDescrClass)
+from pypy.jit.backend.llsupport.descr import CallDescr
 
 class UnsupportedKind(Exception):
     pass
@@ -16,29 +14,13 @@
         argkinds = [get_ffi_type_kind(cpu, arg) for arg in ffi_args]
     except UnsupportedKind:
         return None
-    arg_classes = ''.join(argkinds)
-    if reskind == history.INT:
-        size = intmask(ffi_result.c_size)
-        signed = is_ffi_type_signed(ffi_result)
-        return DynamicIntCallDescr(arg_classes, size, signed, extrainfo,
-                                   ffi_flags=ffi_flags)
-    elif reskind == history.REF:
-        return  NonGcPtrCallDescr(arg_classes, extrainfo,
-                                  ffi_flags=ffi_flags)
-    elif reskind == history.FLOAT:
-        return FloatCallDescr(arg_classes, extrainfo,
-                              ffi_flags=ffi_flags)
-    elif reskind == history.VOID:
-        return VoidCallDescr(arg_classes, extrainfo,
-                             ffi_flags=ffi_flags)
-    elif reskind == 'L':
-        return LongLongCallDescr(arg_classes, extrainfo,
-                                 ffi_flags=ffi_flags)
-    elif reskind == 'S':
-        SingleFloatCallDescr = getCallDescrClass(rffi.FLOAT)
-        return SingleFloatCallDescr(arg_classes, extrainfo,
-                                    ffi_flags=ffi_flags)
-    assert False
+    if reskind == history.VOID:
+        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)
 
 def get_ffi_type_kind(cpu, ffi_type):
     from pypy.rlib.libffi import types
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -1,6 +1,6 @@
 import os
 from pypy.rlib import rgc
-from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.objectmodel import we_are_translated, specialize
 from pypy.rlib.debug import fatalerror
 from pypy.rlib.rarithmetic import ovfcheck
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr
@@ -8,52 +8,93 @@
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.annlowlevel import llhelper
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt, ConstPtr
-from pypy.jit.metainterp.history import AbstractDescr
+from pypy.jit.codewriter import heaptracker
+from pypy.jit.metainterp.history import ConstPtr, AbstractDescr
 from pypy.jit.metainterp.resoperation import ResOperation, rop
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.backend.llsupport.symbolic import WORD
-from pypy.jit.backend.llsupport.descr import BaseSizeDescr, BaseArrayDescr
+from pypy.jit.backend.llsupport.descr import SizeDescr, ArrayDescr
 from pypy.jit.backend.llsupport.descr import GcCache, get_field_descr
-from pypy.jit.backend.llsupport.descr import GcPtrFieldDescr
+from pypy.jit.backend.llsupport.descr import get_array_descr
 from pypy.jit.backend.llsupport.descr import get_call_descr
+from pypy.jit.backend.llsupport.rewrite import GcRewriterAssembler
 from pypy.rpython.memory.gctransform import asmgcroot
 
 # ____________________________________________________________
 
 class GcLLDescription(GcCache):
-    minimal_size_in_nursery = 0
-    get_malloc_slowpath_addr = None
 
     def __init__(self, gcdescr, translator=None, rtyper=None):
         GcCache.__init__(self, translator is not None, rtyper)
         self.gcdescr = gcdescr
+        if translator and translator.config.translation.gcremovetypeptr:
+            self.fielddescr_vtable = None
+        else:
+            self.fielddescr_vtable = get_field_descr(self, rclass.OBJECT,
+                                                     'typeptr')
+        self._generated_functions = []
+
+    def _setup_str(self):
+        self.str_descr     = get_array_descr(self, rstr.STR)
+        self.unicode_descr = get_array_descr(self, rstr.UNICODE)
+
+    def generate_function(self, funcname, func, ARGS, RESULT=llmemory.GCREF):
+        """Generates a variant of malloc with the given name and the given
+        arguments.  It should return NULL if out of memory.  If it raises
+        anything, it must be an optional MemoryError.
+        """
+        FUNCPTR = lltype.Ptr(lltype.FuncType(ARGS, RESULT))
+        descr = get_call_descr(self, ARGS, RESULT)
+        setattr(self, funcname, func)
+        setattr(self, funcname + '_FUNCPTR', FUNCPTR)
+        setattr(self, funcname + '_descr', descr)
+        self._generated_functions.append(funcname)
+
+    @specialize.arg(1)
+    def get_malloc_fn(self, funcname):
+        func = getattr(self, funcname)
+        FUNC = getattr(self, funcname + '_FUNCPTR')
+        return llhelper(FUNC, func)
+
+    @specialize.arg(1)
+    def get_malloc_fn_addr(self, funcname):
+        ll_func = self.get_malloc_fn(funcname)
+        return heaptracker.adr2int(llmemory.cast_ptr_to_adr(ll_func))
+
     def _freeze_(self):
         return True
     def initialize(self):
         pass
     def do_write_barrier(self, gcref_struct, gcref_newptr):
         pass
-    def rewrite_assembler(self, cpu, operations, gcrefs_output_list):
-        return operations
-    def can_inline_malloc(self, descr):
-        return False
-    def can_inline_malloc_varsize(self, descr, num_elem):
+    def can_use_nursery_malloc(self, size):
         return False
     def has_write_barrier_class(self):
         return None
     def freeing_block(self, start, stop):
         pass
+    def get_nursery_free_addr(self):
+        raise NotImplementedError
+    def get_nursery_top_addr(self):
+        raise NotImplementedError
 
-    def get_funcptr_for_newarray(self):
-        return llhelper(self.GC_MALLOC_ARRAY, self.malloc_array)
-    def get_funcptr_for_newstr(self):
-        return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_str)
-    def get_funcptr_for_newunicode(self):
-        return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_unicode)
+    def gc_malloc(self, sizedescr):
+        """Blackhole: do a 'bh_new'.  Also used for 'bh_new_with_vtable',
+        with the vtable pointer set manually afterwards."""
+        assert isinstance(sizedescr, SizeDescr)
+        return self._bh_malloc(sizedescr)
 
+    def gc_malloc_array(self, arraydescr, num_elem):
+        assert isinstance(arraydescr, ArrayDescr)
+        return self._bh_malloc_array(arraydescr, num_elem)
 
-    def record_constptrs(self, op, gcrefs_output_list):
+    def gc_malloc_str(self, num_elem):
+        return self._bh_malloc_array(self.str_descr, num_elem)
+
+    def gc_malloc_unicode(self, num_elem):
+        return self._bh_malloc_array(self.unicode_descr, num_elem)
+
+    def _record_constptrs(self, op, gcrefs_output_list):
         for i in range(op.numargs()):
             v = op.getarg(i)
             if isinstance(v, ConstPtr) and bool(v.value):
@@ -61,11 +102,27 @@
                 rgc._make_sure_does_not_move(p)
                 gcrefs_output_list.append(p)
 
+    def rewrite_assembler(self, cpu, operations, gcrefs_output_list):
+        rewriter = GcRewriterAssembler(self, cpu)
+        newops = rewriter.rewrite(operations)
+        # record all GCREFs, because the GC (or Boehm) cannot see them and
+        # keep them alive if they end up as constants in the assembler
+        for op in newops:
+            self._record_constptrs(op, gcrefs_output_list)
+        return newops
+
 # ____________________________________________________________
 
 class GcLLDescr_boehm(GcLLDescription):
-    moving_gc = False
-    gcrootmap = None
+    kind                  = 'boehm'
+    moving_gc             = False
+    round_up              = False
+    gcrootmap             = None
+    write_barrier_descr   = None
+    fielddescr_tid        = None
+    str_type_id           = 0
+    unicode_type_id       = 0
+    get_malloc_slowpath_addr = None
 
     @classmethod
     def configure_boehm_once(cls):
@@ -76,6 +133,16 @@
         from pypy.rpython.tool import rffi_platform
         compilation_info = rffi_platform.configure_boehm()
 
+        # on some platform GC_init is required before any other
+        # GC_* functions, call it here for the benefit of tests
+        # XXX move this to tests
+        init_fn_ptr = rffi.llexternal("GC_init",
+                                      [], lltype.Void,
+                                      compilation_info=compilation_info,
+                                      sandboxsafe=True,
+                                      _nowrapper=True)
+        init_fn_ptr()
+
         # Versions 6.x of libgc needs to use GC_local_malloc().
         # Versions 7.x of libgc removed this function; GC_malloc() has
         # the same behavior if libgc was compiled with
@@ -95,96 +162,42 @@
                                         sandboxsafe=True,
                                         _nowrapper=True)
         cls.malloc_fn_ptr = malloc_fn_ptr
-        cls.compilation_info = compilation_info
         return malloc_fn_ptr
 
     def __init__(self, gcdescr, translator, rtyper):
         GcLLDescription.__init__(self, gcdescr, translator, rtyper)
         # grab a pointer to the Boehm 'malloc' function
-        malloc_fn_ptr = self.configure_boehm_once()
-        self.funcptr_for_new = malloc_fn_ptr
+        self.malloc_fn_ptr = self.configure_boehm_once()
+        self._setup_str()
+        self._make_functions()
 
-        def malloc_array(basesize, itemsize, ofs_length, num_elem):
+    def _make_functions(self):
+
+        def malloc_fixedsize(size):
+            return self.malloc_fn_ptr(size)
+        self.generate_function('malloc_fixedsize', malloc_fixedsize,
+                               [lltype.Signed])
+
+        def malloc_array(basesize, num_elem, itemsize, ofs_length):
             try:
-                size = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
+                totalsize = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
             except OverflowError:
                 return lltype.nullptr(llmemory.GCREF.TO)
-            res = self.funcptr_for_new(size)
-            if not res:
-                return res
-            rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
+            res = self.malloc_fn_ptr(totalsize)
+            if res:
+                arrayptr = rffi.cast(rffi.CArrayPtr(lltype.Signed), res)
+                arrayptr[ofs_length/WORD] = num_elem
             return res
-        self.malloc_array = malloc_array
-        self.GC_MALLOC_ARRAY = lltype.Ptr(lltype.FuncType(
-            [lltype.Signed] * 4, llmemory.GCREF))
+        self.generate_function('malloc_array', malloc_array,
+                               [lltype.Signed] * 4)
 
+    def _bh_malloc(self, sizedescr):
+        return self.malloc_fixedsize(sizedescr.size)
 
-        (str_basesize, str_itemsize, str_ofs_length
-         ) = symbolic.get_array_token(rstr.STR, self.translate_support_code)
-        (unicode_basesize, unicode_itemsize, unicode_ofs_length
-         ) = symbolic.get_array_token(rstr.UNICODE, self.translate_support_code)
-        def malloc_str(length):
-            return self.malloc_array(
-                str_basesize, str_itemsize, str_ofs_length, length
-            )
-        def malloc_unicode(length):
-            return self.malloc_array(
-                unicode_basesize, unicode_itemsize, unicode_ofs_length, length
-            )
-        self.malloc_str = malloc_str
-        self.malloc_unicode = malloc_unicode
-        self.GC_MALLOC_STR_UNICODE = lltype.Ptr(lltype.FuncType(
-            [lltype.Signed], llmemory.GCREF))
-
-
-        # on some platform GC_init is required before any other
-        # GC_* functions, call it here for the benefit of tests
-        # XXX move this to tests
-        init_fn_ptr = rffi.llexternal("GC_init",
-                                      [], lltype.Void,
-                                      compilation_info=self.compilation_info,
-                                      sandboxsafe=True,
-                                      _nowrapper=True)
-
-        init_fn_ptr()
-
-    def gc_malloc(self, sizedescr):
-        assert isinstance(sizedescr, BaseSizeDescr)
-        return self.funcptr_for_new(sizedescr.size)
-
-    def gc_malloc_array(self, arraydescr, num_elem):
-        assert isinstance(arraydescr, BaseArrayDescr)
-        ofs_length = arraydescr.get_ofs_length(self.translate_support_code)
-        basesize = arraydescr.get_base_size(self.translate_support_code)
-        itemsize = arraydescr.get_item_size(self.translate_support_code)
-        return self.malloc_array(basesize, itemsize, ofs_length, num_elem)
-
-    def gc_malloc_str(self, num_elem):
-        return self.malloc_str(num_elem)
-
-    def gc_malloc_unicode(self, num_elem):
-        return self.malloc_unicode(num_elem)
-
-    def args_for_new(self, sizedescr):
-        assert isinstance(sizedescr, BaseSizeDescr)
-        return [sizedescr.size]
-
-    def args_for_new_array(self, arraydescr):
-        ofs_length = arraydescr.get_ofs_length(self.translate_support_code)
-        basesize = arraydescr.get_base_size(self.translate_support_code)
-        itemsize = arraydescr.get_item_size(self.translate_support_code)
-        return [basesize, itemsize, ofs_length]
-
-    def get_funcptr_for_new(self):
-        return self.funcptr_for_new
-
-    def rewrite_assembler(self, cpu, operations, gcrefs_output_list):
-        # record all GCREFs too, because Boehm cannot see them and keep them
-        # alive if they end up as constants in the assembler
-        for op in operations:
-            self.record_constptrs(op, gcrefs_output_list)
-        return GcLLDescription.rewrite_assembler(self, cpu, operations,
-                                                 gcrefs_output_list)
+    def _bh_malloc_array(self, arraydescr, num_elem):
+        return self.malloc_array(arraydescr.basesize, num_elem,
+                                 arraydescr.itemsize,
+                                 arraydescr.lendescr.offset)
 
 
 # ____________________________________________________________
@@ -554,12 +567,14 @@
 
 class WriteBarrierDescr(AbstractDescr):
     def __init__(self, gc_ll_descr):
-        GCClass = gc_ll_descr.GCClass
         self.llop1 = gc_ll_descr.llop1
         self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR
         self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR
-        self.fielddescr_tid = get_field_descr(gc_ll_descr, GCClass.HDR, 'tid')
+        self.fielddescr_tid = gc_ll_descr.fielddescr_tid
         #
+        GCClass = gc_ll_descr.GCClass
+        if GCClass is None:     # for tests
+            return
         self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG
         self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = (
             self.extract_flag_byte(self.jit_wb_if_flag))
@@ -596,48 +611,74 @@
         funcaddr = llmemory.cast_ptr_to_adr(funcptr)
         return cpu.cast_adr_to_int(funcaddr)    # this may return 0
 
+    def has_write_barrier_from_array(self, cpu):
+        return self.get_write_barrier_from_array_fn(cpu) != 0
+
 
 class GcLLDescr_framework(GcLLDescription):
     DEBUG = False    # forced to True by x86/test/test_zrpy_gc.py
+    kind = 'framework'
+    round_up = True
 
-    def __init__(self, gcdescr, translator, rtyper, llop1=llop):
-        from pypy.rpython.memory.gctypelayout import check_typeid
-        from pypy.rpython.memory.gcheader import GCHeaderBuilder
-        from pypy.rpython.memory.gctransform import framework
+    def __init__(self, gcdescr, translator, rtyper, llop1=llop,
+                 really_not_translated=False):
         GcLLDescription.__init__(self, gcdescr, translator, rtyper)
-        assert self.translate_support_code, "required with the framework GC"
         self.translator = translator
         self.llop1 = llop1
+        if really_not_translated:
+            assert not self.translate_support_code  # but half does not work
+            self._initialize_for_tests()
+        else:
+            assert self.translate_support_code,"required with the framework GC"
+            self._check_valid_gc()
+            self._make_gcrootmap()
+            self._make_layoutbuilder()
+            self._setup_gcclass()
+            self._setup_tid()
+        self._setup_write_barrier()
+        self._setup_str()
+        self._make_functions(really_not_translated)
 
+    def _initialize_for_tests(self):
+        self.layoutbuilder = None
+        self.fielddescr_tid = AbstractDescr()
+        self.max_size_of_young_obj = 1000
+        self.GCClass = None
+
+    def _check_valid_gc(self):
         # we need the hybrid or minimark GC for rgc._make_sure_does_not_move()
         # to work
-        if gcdescr.config.translation.gc not in ('hybrid', 'minimark'):
+        if self.gcdescr.config.translation.gc not in ('hybrid', 'minimark'):
             raise NotImplementedError("--gc=%s not implemented with the JIT" %
                                       (gcdescr.config.translation.gc,))
 
+    def _make_gcrootmap(self):
         # to find roots in the assembler, make a GcRootMap
-        name = gcdescr.config.translation.gcrootfinder
+        name = self.gcdescr.config.translation.gcrootfinder
         try:
             cls = globals()['GcRootMap_' + name]
         except KeyError:
             raise NotImplementedError("--gcrootfinder=%s not implemented"
                                       " with the JIT" % (name,))
-        gcrootmap = cls(gcdescr)
+        gcrootmap = cls(self.gcdescr)
         self.gcrootmap = gcrootmap
 
+    def _make_layoutbuilder(self):
         # make a TransformerLayoutBuilder and save it on the translator
         # where it can be fished and reused by the FrameworkGCTransformer
+        from pypy.rpython.memory.gctransform import framework
+        translator = self.translator
         self.layoutbuilder = framework.TransformerLayoutBuilder(translator)
         self.layoutbuilder.delay_encoding()
-        self.translator._jit2gc = {'layoutbuilder': self.layoutbuilder}
-        gcrootmap.add_jit2gc_hooks(self.translator._jit2gc)
+        translator._jit2gc = {'layoutbuilder': self.layoutbuilder}
+        self.gcrootmap.add_jit2gc_hooks(translator._jit2gc)
 
+    def _setup_gcclass(self):
+        from pypy.rpython.memory.gcheader import GCHeaderBuilder
         self.GCClass = self.layoutbuilder.GCClass
         self.moving_gc = self.GCClass.moving_gc
         self.HDRPTR = lltype.Ptr(self.GCClass.HDR)
         self.gcheaderbuilder = GCHeaderBuilder(self.HDRPTR.TO)
-        (self.array_basesize, _, self.array_length_ofs) = \
-             symbolic.get_array_token(lltype.GcArray(lltype.Signed), True)
         self.max_size_of_young_obj = self.GCClass.JIT_max_size_of_young_obj()
         self.minimal_size_in_nursery=self.GCClass.JIT_minimal_size_in_nursery()
 
@@ -645,87 +686,124 @@
         assert self.GCClass.inline_simple_malloc
         assert self.GCClass.inline_simple_malloc_varsize
 
-        # make a malloc function, with two arguments
-        def malloc_basic(size, tid):
-            type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
-            check_typeid(type_id)
-            res = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
-                                                  type_id, size,
-                                                  False, False, False)
-            # In case the operation above failed, we are returning NULL
-            # from this function to assembler.  There is also an RPython
-            # exception set, typically MemoryError; but it's easier and
-            # faster to check for the NULL return value, as done by
-            # translator/exceptiontransform.py.
-            #llop.debug_print(lltype.Void, "\tmalloc_basic", size, type_id,
-            #                 "-->", res)
-            return res
-        self.malloc_basic = malloc_basic
-        self.GC_MALLOC_BASIC = lltype.Ptr(lltype.FuncType(
-            [lltype.Signed, lltype.Signed], llmemory.GCREF))
+    def _setup_tid(self):
+        self.fielddescr_tid = get_field_descr(self, self.GCClass.HDR, 'tid')
+
+    def _setup_write_barrier(self):
         self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType(
             [llmemory.Address, llmemory.Address], lltype.Void))
         self.WB_ARRAY_FUNCPTR = lltype.Ptr(lltype.FuncType(
             [llmemory.Address, lltype.Signed, llmemory.Address], lltype.Void))
         self.write_barrier_descr = WriteBarrierDescr(self)
-        #
+
+    def _make_functions(self, really_not_translated):
+        from pypy.rpython.memory.gctypelayout import check_typeid
+        llop1 = self.llop1
+        (self.standard_array_basesize, _, self.standard_array_length_ofs) = \
+             symbolic.get_array_token(lltype.GcArray(lltype.Signed),
+                                      not really_not_translated)
+
+        def malloc_nursery_slowpath(size):
+            """Allocate 'size' null bytes out of the nursery.
+            Note that the fast path is typically inlined by the backend."""
+            if self.DEBUG:
+                self._random_usage_of_xmm_registers()
+            type_id = rffi.cast(llgroup.HALFWORD, 0)    # missing here
+            return llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
+                                                   type_id, size,
+                                                   False, False, False)
+        self.generate_function('malloc_nursery', malloc_nursery_slowpath,
+                               [lltype.Signed])
+
         def malloc_array(itemsize, tid, num_elem):
+            """Allocate an array with a variable-size num_elem.
+            Only works for standard arrays."""
             type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
             check_typeid(type_id)
             return llop1.do_malloc_varsize_clear(
                 llmemory.GCREF,
-                type_id, num_elem, self.array_basesize, itemsize,
-                self.array_length_ofs)
-        self.malloc_array = malloc_array
-        self.GC_MALLOC_ARRAY = lltype.Ptr(lltype.FuncType(
-            [lltype.Signed] * 3, llmemory.GCREF))
-        #
-        (str_basesize, str_itemsize, str_ofs_length
-         ) = symbolic.get_array_token(rstr.STR, True)
-        (unicode_basesize, unicode_itemsize, unicode_ofs_length
-         ) = symbolic.get_array_token(rstr.UNICODE, True)
-        str_type_id = self.layoutbuilder.get_type_id(rstr.STR)
-        unicode_type_id = self.layoutbuilder.get_type_id(rstr.UNICODE)
-        #
+                type_id, num_elem, self.standard_array_basesize, itemsize,
+                self.standard_array_length_ofs)
+        self.generate_function('malloc_array', malloc_array,
+                               [lltype.Signed] * 3)
+
+        def malloc_array_nonstandard(basesize, itemsize, lengthofs, tid,
+                                     num_elem):
+            """For the rare case of non-standard arrays, i.e. arrays where
+            self.standard_array_{basesize,length_ofs} is wrong.  It can
+            occur e.g. with arrays of floats on Win32."""
+            type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
+            check_typeid(type_id)
+            return llop1.do_malloc_varsize_clear(
+                llmemory.GCREF,
+                type_id, num_elem, basesize, itemsize, lengthofs)
+        self.generate_function('malloc_array_nonstandard',
+                               malloc_array_nonstandard,
+                               [lltype.Signed] * 5)
+
+        str_type_id    = self.str_descr.tid
+        str_basesize   = self.str_descr.basesize
+        str_itemsize   = self.str_descr.itemsize
+        str_ofs_length = self.str_descr.lendescr.offset
+        unicode_type_id    = self.unicode_descr.tid
+        unicode_basesize   = self.unicode_descr.basesize
+        unicode_itemsize   = self.unicode_descr.itemsize
+        unicode_ofs_length = self.unicode_descr.lendescr.offset
+
         def malloc_str(length):
             return llop1.do_malloc_varsize_clear(
                 llmemory.GCREF,
                 str_type_id, length, str_basesize, str_itemsize,
                 str_ofs_length)
+        self.generate_function('malloc_str', malloc_str,
+                               [lltype.Signed])
+
         def malloc_unicode(length):
             return llop1.do_malloc_varsize_clear(
                 llmemory.GCREF,
-                unicode_type_id, length, unicode_basesize,unicode_itemsize,
+                unicode_type_id, length, unicode_basesize, unicode_itemsize,
                 unicode_ofs_length)
-        self.malloc_str = malloc_str
-        self.malloc_unicode = malloc_unicode
-        self.GC_MALLOC_STR_UNICODE = lltype.Ptr(lltype.FuncType(
-            [lltype.Signed], llmemory.GCREF))
-        #
-        class ForTestOnly:
-            pass
-        for_test_only = ForTestOnly()
-        for_test_only.x = 1.23
-        def random_usage_of_xmm_registers():
-            x0 = for_test_only.x
-            x1 = x0 * 0.1
-            x2 = x0 * 0.2
-            x3 = x0 * 0.3
-            for_test_only.x = x0 + x1 + x2 + x3
-        #
-        def malloc_slowpath(size):
-            if self.DEBUG:
-                random_usage_of_xmm_registers()
-            assert size >= self.minimal_size_in_nursery
-            # NB. although we call do_malloc_fixedsize_clear() here,
-            # it's a bit of a hack because we set tid to 0 and may
-            # also use it to allocate varsized objects.  The tid
-            # and possibly the length are both set afterward.
-            gcref = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
-                                        0, size, False, False, False)
-            return rffi.cast(lltype.Signed, gcref)
-        self.malloc_slowpath = malloc_slowpath
-        self.MALLOC_SLOWPATH = lltype.FuncType([lltype.Signed], lltype.Signed)
+        self.generate_function('malloc_unicode', malloc_unicode,
+                               [lltype.Signed])
+
+        # Rarely called: allocate a fixed-size amount of bytes, but
+        # not in the nursery, because it is too big.  Implemented like
+        # malloc_nursery_slowpath() above.
+        self.generate_function('malloc_fixedsize', malloc_nursery_slowpath,
+                               [lltype.Signed])
+
+    def _bh_malloc(self, sizedescr):
+        from pypy.rpython.memory.gctypelayout import check_typeid
+        llop1 = self.llop1
+        type_id = llop.extract_ushort(llgroup.HALFWORD, sizedescr.tid)
+        check_typeid(type_id)
+        return llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
+                                               type_id, sizedescr.size,
+                                               False, False, False)
+
+    def _bh_malloc_array(self, arraydescr, num_elem):
+        from pypy.rpython.memory.gctypelayout import check_typeid
+        llop1 = self.llop1
+        type_id = llop.extract_ushort(llgroup.HALFWORD, arraydescr.tid)
+        check_typeid(type_id)
+        return llop1.do_malloc_varsize_clear(llmemory.GCREF,
+                                             type_id, num_elem,
+                                             arraydescr.basesize,
+                                             arraydescr.itemsize,
+                                             arraydescr.lendescr.offset)
+
+
+    class ForTestOnly:
+        pass
+    for_test_only = ForTestOnly()
+    for_test_only.x = 1.23
+
+    def _random_usage_of_xmm_registers(self):
+        x0 = self.for_test_only.x
+        x1 = x0 * 0.1
+        x2 = x0 * 0.2
+        x3 = x0 * 0.3
+        self.for_test_only.x = x0 + x1 + x2 + x3
 
     def get_nursery_free_addr(self):
         nurs_addr = llop.gc_adr_of_nursery_free(llmemory.Address)
@@ -735,49 +813,26 @@
         nurs_top_addr = llop.gc_adr_of_nursery_top(llmemory.Address)
         return rffi.cast(lltype.Signed, nurs_top_addr)
 
-    def get_malloc_slowpath_addr(self):
-        fptr = llhelper(lltype.Ptr(self.MALLOC_SLOWPATH), self.malloc_slowpath)
-        return rffi.cast(lltype.Signed, fptr)
-
     def initialize(self):
         self.gcrootmap.initialize()
 
     def init_size_descr(self, S, descr):
-        type_id = self.layoutbuilder.get_type_id(S)
-        assert not self.layoutbuilder.is_weakref_type(S)
-        assert not self.layoutbuilder.has_finalizer(S)
-        descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
+        if self.layoutbuilder is not None:
+            type_id = self.layoutbuilder.get_type_id(S)
+            assert not self.layoutbuilder.is_weakref_type(S)
+            assert not self.layoutbuilder.has_finalizer(S)
+            descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
 
     def init_array_descr(self, A, descr):
-        type_id = self.layoutbuilder.get_type_id(A)
-        descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
+        if self.layoutbuilder is not None:
+            type_id = self.layoutbuilder.get_type_id(A)
+            descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
 
-    def gc_malloc(self, sizedescr):
-        assert isinstance(sizedescr, BaseSizeDescr)
-        return self.malloc_basic(sizedescr.size, sizedescr.tid)
-
-    def gc_malloc_array(self, arraydescr, num_elem):
-        assert isinstance(arraydescr, BaseArrayDescr)
-        itemsize = arraydescr.get_item_size(self.translate_support_code)
-        return self.malloc_array(itemsize, arraydescr.tid, num_elem)
-
-    def gc_malloc_str(self, num_elem):
-        return self.malloc_str(num_elem)
-
-    def gc_malloc_unicode(self, num_elem):
-        return self.malloc_unicode(num_elem)
-
-    def args_for_new(self, sizedescr):
-        assert isinstance(sizedescr, BaseSizeDescr)
-        return [sizedescr.size, sizedescr.tid]
-
-    def args_for_new_array(self, arraydescr):
-        assert isinstance(arraydescr, BaseArrayDescr)
-        itemsize = arraydescr.get_item_size(self.translate_support_code)
-        return [itemsize, arraydescr.tid]
-
-    def get_funcptr_for_new(self):
-        return llhelper(self.GC_MALLOC_BASIC, self.malloc_basic)
+    def _set_tid(self, gcptr, tid):
+        hdr_addr = llmemory.cast_ptr_to_adr(gcptr)
+        hdr_addr -= self.gcheaderbuilder.size_gc_header
+        hdr = llmemory.cast_adr_to_ptr(hdr_addr, self.HDRPTR)
+        hdr.tid = tid
 
     def do_write_barrier(self, gcref_struct, gcref_newptr):
         hdr_addr = llmemory.cast_ptr_to_adr(gcref_struct)
@@ -791,108 +846,8 @@
             funcptr(llmemory.cast_ptr_to_adr(gcref_struct),
                     llmemory.cast_ptr_to_adr(gcref_newptr))
 
-    def rewrite_assembler(self, cpu, operations, gcrefs_output_list):
-        # Perform two kinds of rewrites in parallel:
-        #
-        # - Add COND_CALLs to the write barrier before SETFIELD_GC and
-        #   SETARRAYITEM_GC operations.
-        #
-        # - Record the ConstPtrs from the assembler.
-        #
-        newops = []
-        known_lengths = {}
-        # we can only remember one malloc since the next malloc can possibly
-        # collect
-        last_malloc = None
-        for op in operations:
-            if op.getopnum() == rop.DEBUG_MERGE_POINT:
-                continue
-            # ---------- record the ConstPtrs ----------
-            self.record_constptrs(op, gcrefs_output_list)
-            if op.is_malloc():
-                last_malloc = op.result
-            elif op.can_malloc():
-                last_malloc = None
-            # ---------- write barrier for SETFIELD_GC ----------
-            if op.getopnum() == rop.SETFIELD_GC:
-                val = op.getarg(0)
-                # no need for a write barrier in the case of previous malloc
-                if val is not last_malloc:
-                    v = op.getarg(1)
-                    if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
-                                            bool(v.value)): # store a non-NULL
-                        self._gen_write_barrier(newops, op.getarg(0), v)
-                        op = op.copy_and_change(rop.SETFIELD_RAW)
-            # ---------- write barrier for SETINTERIORFIELD_GC ------
-            if op.getopnum() == rop.SETINTERIORFIELD_GC:
-                val = op.getarg(0)
-                if val is not last_malloc:
-                    v = op.getarg(2)
-                    if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
-                                            bool(v.value)): # store a non-NULL
-                        self._gen_write_barrier(newops, op.getarg(0), v)
-                        op = op.copy_and_change(rop.SETINTERIORFIELD_RAW)
-            # ---------- write barrier for SETARRAYITEM_GC ----------
-            if op.getopnum() == rop.SETARRAYITEM_GC:
-                val = op.getarg(0)
-                # no need for a write barrier in the case of previous malloc
-                if val is not last_malloc:
-                    v = op.getarg(2)
-                    if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
-                                            bool(v.value)): # store a non-NULL
-                        self._gen_write_barrier_array(newops, op.getarg(0),
-                                                      op.getarg(1), v,
-                                                      cpu, known_lengths)
-                        op = op.copy_and_change(rop.SETARRAYITEM_RAW)
-            elif op.getopnum() == rop.NEW_ARRAY:
-                v_length = op.getarg(0)
-                if isinstance(v_length, ConstInt):
-                    known_lengths[op.result] = v_length.getint()
-            # ----------
-            newops.append(op)
-        return newops
-
-    def _gen_write_barrier(self, newops, v_base, v_value):
-        args = [v_base, v_value]
-        newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None,
-                                   descr=self.write_barrier_descr))
-
-    def _gen_write_barrier_array(self, newops, v_base, v_index, v_value,
-                                 cpu, known_lengths):
-        if self.write_barrier_descr.get_write_barrier_from_array_fn(cpu) != 0:
-            # If we know statically the length of 'v', and it is not too
-            # big, then produce a regular write_barrier.  If it's unknown or
-            # too big, produce instead a write_barrier_from_array.
-            LARGE = 130
-            length = known_lengths.get(v_base, LARGE)
-            if length >= LARGE:
-                # unknown or too big: produce a write_barrier_from_array
-                args = [v_base, v_index, v_value]
-                newops.append(ResOperation(rop.COND_CALL_GC_WB_ARRAY, args,
-                                           None,
-                                           descr=self.write_barrier_descr))
-                return
-        # fall-back case: produce a write_barrier
-        self._gen_write_barrier(newops, v_base, v_value)
-
-    def can_inline_malloc(self, descr):
-        assert isinstance(descr, BaseSizeDescr)
-        if descr.size < self.max_size_of_young_obj:
-            has_finalizer = bool(descr.tid & (1<<llgroup.HALFSHIFT))
-            if has_finalizer:
-                return False
-            return True
-        return False
-
-    def can_inline_malloc_varsize(self, arraydescr, num_elem):
-        assert isinstance(arraydescr, BaseArrayDescr)
-        basesize = arraydescr.get_base_size(self.translate_support_code)
-        itemsize = arraydescr.get_item_size(self.translate_support_code)
-        try:
-            size = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
-            return size < self.max_size_of_young_obj
-        except OverflowError:
-            return False
+    def can_use_nursery_malloc(self, size):
+        return size < self.max_size_of_young_obj
 
     def has_write_barrier_class(self):
         return WriteBarrierDescr
@@ -900,6 +855,9 @@
     def freeing_block(self, start, stop):
         self.gcrootmap.freeing_block(start, stop)
 
+    def get_malloc_slowpath_addr(self):
+        return self.get_malloc_fn_addr('malloc_nursery')
+
 # ____________________________________________________________
 
 def get_ll_description(gcdescr, translator=None, rtyper=None):
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
@@ -8,11 +8,10 @@
 from pypy.jit.backend.model import AbstractCPU
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.backend.llsupport.symbolic import WORD, unroll_basic_sizes
-from pypy.jit.backend.llsupport.descr import (get_size_descr,
-     get_field_descr, BaseFieldDescr, DynamicFieldDescr, get_array_descr,
-     BaseArrayDescr, DynamicArrayNoLengthDescr, get_call_descr,
-     BaseIntCallDescr, GcPtrCallDescr, FloatCallDescr, VoidCallDescr,
-     InteriorFieldDescr, get_interiorfield_descr)
+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)
 from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager
 
 
@@ -107,9 +106,15 @@
             _exception_emulator[1] = 0
             self.saved_exc_value = rffi.cast(llmemory.GCREF, v_i)
 
+        def save_exception_memoryerr():
+            save_exception()
+            if not self.saved_exc_value:
+                self.saved_exc_value = "memoryerror!"    # for tests
+
         self.pos_exception = pos_exception
         self.pos_exc_value = pos_exc_value
         self.save_exception = save_exception
+        self.save_exception_memoryerr = save_exception_memoryerr
         self.insert_stack_check = lambda: (0, 0, 0)
 
 
@@ -134,6 +139,15 @@
             # in the assignment to self.saved_exc_value, as needed.
             self.saved_exc_value = exc_value
 
+        def save_exception_memoryerr():
+            from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
+            save_exception()
+            if not self.saved_exc_value:
+                exc = MemoryError()
+                exc = cast_instance_to_base_ptr(exc)
+                exc = lltype.cast_opaque_ptr(llmemory.GCREF, exc)
+                self.saved_exc_value = exc
+
         from pypy.rlib import rstack
         STACK_CHECK_SLOWPATH = lltype.Ptr(lltype.FuncType([lltype.Signed],
                                                           lltype.Void))
@@ -147,16 +161,19 @@
         self.pos_exception = pos_exception
         self.pos_exc_value = pos_exc_value
         self.save_exception = save_exception
+        self.save_exception_memoryerr = save_exception_memoryerr
         self.insert_stack_check = insert_stack_check
 
     def _setup_on_leave_jitted_untranslated(self):
         # assume we don't need a backend leave in this case
         self.on_leave_jitted_save_exc = self.save_exception
+        self.on_leave_jitted_memoryerr = self.save_exception_memoryerr
         self.on_leave_jitted_noexc = lambda : None
 
     def _setup_on_leave_jitted_translated(self):
         on_leave_jitted_hook = self.get_on_leave_jitted_hook()
         save_exception = self.save_exception
+        save_exception_memoryerr = self.save_exception_memoryerr
 
         def on_leave_jitted_noexc():
             on_leave_jitted_hook()
@@ -165,16 +182,24 @@
             save_exception()
             on_leave_jitted_hook()
 
+        def on_leave_jitted_memoryerr():
+            save_exception_memoryerr()
+            on_leave_jitted_hook()
+
         self.on_leave_jitted_noexc = on_leave_jitted_noexc
         self.on_leave_jitted_save_exc = on_leave_jitted_save_exc
+        self.on_leave_jitted_memoryerr = on_leave_jitted_memoryerr
 
     def get_on_leave_jitted_hook(self):
         return lambda : None
 
     _ON_JIT_LEAVE_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void))
 
-    def get_on_leave_jitted_int(self, save_exception):
-        if save_exception:
+    def get_on_leave_jitted_int(self, save_exception,
+                                default_to_memoryerror=False):
+        if default_to_memoryerror:
+            f = llhelper(self._ON_JIT_LEAVE_FUNC, self.on_leave_jitted_memoryerr)
+        elif save_exception:
             f = llhelper(self._ON_JIT_LEAVE_FUNC, self.on_leave_jitted_save_exc)
         else:
             f = llhelper(self._ON_JIT_LEAVE_FUNC, self.on_leave_jitted_noexc)
@@ -221,14 +246,14 @@
         return get_field_descr(self.gc_ll_descr, STRUCT, fieldname)
 
     def unpack_fielddescr(self, fielddescr):
-        assert isinstance(fielddescr, BaseFieldDescr)
+        assert isinstance(fielddescr, FieldDescr)
         return fielddescr.offset
     unpack_fielddescr._always_inline_ = True
 
     def unpack_fielddescr_size(self, fielddescr):
-        assert isinstance(fielddescr, BaseFieldDescr)
+        assert isinstance(fielddescr, FieldDescr)
         ofs = fielddescr.offset
-        size = fielddescr.get_field_size(self.translate_support_code)
+        size = fielddescr.field_size
         sign = fielddescr.is_field_signed()
         return ofs, size, sign
     unpack_fielddescr_size._always_inline_ = True
@@ -237,23 +262,23 @@
         return get_array_descr(self.gc_ll_descr, A)
 
     def interiorfielddescrof(self, A, fieldname):
-        return get_interiorfield_descr(self.gc_ll_descr, A, A.OF, fieldname)
+        return get_interiorfield_descr(self.gc_ll_descr, A, fieldname)
 
     def interiorfielddescrof_dynamic(self, offset, width, fieldsize,
-        is_pointer, is_float, is_signed):
-        arraydescr = DynamicArrayNoLengthDescr(width)
-        fielddescr = DynamicFieldDescr(offset, fieldsize, is_pointer, is_float, is_signed)
-        return InteriorFieldDescr(arraydescr, fielddescr)
+                                     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, BaseArrayDescr)
-        return arraydescr.get_base_size(self.translate_support_code)
+        assert isinstance(arraydescr, ArrayDescr)
+        return arraydescr.basesize
     unpack_arraydescr._always_inline_ = True
 
     def unpack_arraydescr_size(self, arraydescr):
-        assert isinstance(arraydescr, BaseArrayDescr)
-        ofs = arraydescr.get_base_size(self.translate_support_code)
-        size = arraydescr.get_item_size(self.translate_support_code)
+        assert isinstance(arraydescr, ArrayDescr)
+        ofs = arraydescr.basesize
+        size = arraydescr.itemsize
         sign = arraydescr.is_item_signed()
         return ofs, size, sign
     unpack_arraydescr_size._always_inline_ = True
@@ -281,8 +306,8 @@
     # ____________________________________________________________
 
     def bh_arraylen_gc(self, arraydescr, array):
-        assert isinstance(arraydescr, BaseArrayDescr)
-        ofs = arraydescr.get_ofs_length(self.translate_support_code)
+        assert isinstance(arraydescr, ArrayDescr)
+        ofs = arraydescr.lendescr.offset
         return rffi.cast(rffi.CArrayPtr(lltype.Signed), array)[ofs/WORD]
 
     @specialize.argtype(2)
@@ -367,7 +392,7 @@
         arraydescr = descr.arraydescr
         ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
         ofs += descr.fielddescr.offset
-        fieldsize = descr.fielddescr.get_field_size(self.translate_support_code)
+        fieldsize = descr.fielddescr.field_size
         sign = descr.fielddescr.is_field_signed()
         fullofs = itemindex * size + ofs
         # --- start of GC unsafe code (no GC operation!) ---
@@ -418,7 +443,7 @@
         arraydescr = descr.arraydescr
         ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
         ofs += descr.fielddescr.offset
-        fieldsize = descr.fielddescr.get_field_size(self.translate_support_code)
+        fieldsize = descr.fielddescr.field_size
         ofs = itemindex * size + ofs
         # --- start of GC unsafe code (no GC operation!) ---
         items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs)
@@ -604,25 +629,26 @@
         rstr.copy_unicode_contents(src, dst, srcstart, dststart, length)
 
     def bh_call_i(self, func, calldescr, args_i, args_r, args_f):
-        assert isinstance(calldescr, BaseIntCallDescr)
+        assert isinstance(calldescr, CallDescr)
         if not we_are_translated():
             calldescr.verify_types(args_i, args_r, args_f, history.INT + 'S')
-        return calldescr.call_stub(func, args_i, args_r, args_f)
+        return calldescr.call_stub_i(func, args_i, args_r, args_f)
 
     def bh_call_r(self, func, calldescr, args_i, args_r, args_f):
-        assert isinstance(calldescr, GcPtrCallDescr)
+        assert isinstance(calldescr, CallDescr)
         if not we_are_translated():
             calldescr.verify_types(args_i, args_r, args_f, history.REF)
-        return calldescr.call_stub(func, args_i, args_r, args_f)
+        return calldescr.call_stub_r(func, args_i, args_r, args_f)
 
     def bh_call_f(self, func, calldescr, args_i, args_r, args_f):
-        assert isinstance(calldescr, FloatCallDescr)  # or LongLongCallDescr
+        assert isinstance(calldescr, CallDescr)
         if not we_are_translated():
             calldescr.verify_types(args_i, args_r, args_f, history.FLOAT + 'L')
-        return calldescr.call_stub(func, args_i, args_r, args_f)
+        return calldescr.call_stub_f(func, args_i, args_r, args_f)
 
     def bh_call_v(self, func, calldescr, args_i, args_r, args_f):
-        assert isinstance(calldescr, VoidCallDescr)
+        assert isinstance(calldescr, CallDescr)
         if not we_are_translated():
             calldescr.verify_types(args_i, args_r, args_f, history.VOID)
-        return calldescr.call_stub(func, args_i, args_r, args_f)
+        # the 'i' return value is ignored (and nonsense anyway)
+        calldescr.call_stub_i(func, args_i, args_r, args_f)
diff --git a/pypy/jit/backend/llsupport/rewrite.py b/pypy/jit/backend/llsupport/rewrite.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/backend/llsupport/rewrite.py
@@ -0,0 +1,328 @@
+import sys
+from pypy.rlib.rarithmetic import ovfcheck
+from pypy.jit.metainterp.history import ConstInt, BoxPtr, ConstPtr
+from pypy.jit.metainterp.resoperation import ResOperation, rop
+from pypy.jit.codewriter import heaptracker
+from pypy.jit.backend.llsupport.symbolic import WORD
+from pypy.jit.backend.llsupport.descr import SizeDescr, ArrayDescr
+
+
+class GcRewriterAssembler(object):
+    # This class performs the following rewrites on the list of operations:
+    #
+    # - Remove the DEBUG_MERGE_POINTs.
+    #
+    # - Turn all NEW_xxx to either a CALL_MALLOC_GC, or a CALL_MALLOC_NURSERY
+    #   followed by SETFIELDs in order to initialize their GC fields.  The
+    #   two advantages of CALL_MALLOC_NURSERY is that it inlines the common
+    #   path, and we need only one such operation to allocate several blocks
+    #   of memory at once.
+    #
+    # - Add COND_CALLs to the write barrier before SETFIELD_GC and
+    #   SETARRAYITEM_GC operations.
+
+    _previous_size = -1
+    _op_malloc_nursery = None
+    _v_last_malloced_nursery = None
+    c_zero = ConstInt(0)
+
+    def __init__(self, gc_ll_descr, cpu):
+        self.gc_ll_descr = gc_ll_descr
+        self.cpu = cpu
+        self.newops = []
+        self.known_lengths = {}
+        self.recent_mallocs = {}     # set of variables
+
+    def rewrite(self, operations):
+        # we can only remember one malloc since the next malloc can possibly
+        # collect; but we can try to collapse several known-size mallocs into
+        # one, both for performance and to reduce the number of write
+        # barriers.  We do this on each "basic block" of operations, which in
+        # this case means between CALLs or unknown-size mallocs.
+        #
+        for op in operations:
+            if op.getopnum() == rop.DEBUG_MERGE_POINT:
+                continue
+            # ---------- turn NEWxxx into CALL_MALLOC_xxx ----------
+            if op.is_malloc():
+                self.handle_malloc_operation(op)
+                continue
+            elif op.can_malloc():
+                self.emitting_an_operation_that_can_collect()
+            elif op.getopnum() == rop.LABEL:
+                self.emitting_an_operation_that_can_collect()
+                self.known_lengths.clear()
+            # ---------- write barriers ----------
+            if self.gc_ll_descr.write_barrier_descr is not None:
+                if op.getopnum() == rop.SETFIELD_GC:
+                    self.handle_write_barrier_setfield(op)
+                    continue
+                if op.getopnum() == rop.SETINTERIORFIELD_GC:
+                    self.handle_write_barrier_setinteriorfield(op)
+                    continue
+                if op.getopnum() == rop.SETARRAYITEM_GC:
+                    self.handle_write_barrier_setarrayitem(op)
+                    continue
+            # ----------
+            self.newops.append(op)
+        return self.newops
+
+    # ----------
+
+    def handle_malloc_operation(self, op):
+        opnum = op.getopnum()
+        if opnum == rop.NEW:
+            self.handle_new_fixedsize(op.getdescr(), op)
+        elif opnum == rop.NEW_WITH_VTABLE:
+            classint = op.getarg(0).getint()
+            descr = heaptracker.vtable2descr(self.cpu, classint)
+            self.handle_new_fixedsize(descr, op)
+            if self.gc_ll_descr.fielddescr_vtable is not None:
+                op = ResOperation(rop.SETFIELD_GC,
+                                  [op.result, ConstInt(classint)], None,
+                                  descr=self.gc_ll_descr.fielddescr_vtable)
+                self.newops.append(op)
+        elif opnum == rop.NEW_ARRAY:
+            descr = op.getdescr()
+            assert isinstance(descr, ArrayDescr)
+            self.handle_new_array(descr, op)
+        elif opnum == rop.NEWSTR:
+            self.handle_new_array(self.gc_ll_descr.str_descr, op)
+        elif opnum == rop.NEWUNICODE:
+            self.handle_new_array(self.gc_ll_descr.unicode_descr, op)
+        else:
+            raise NotImplementedError(op.getopname())
+
+    def handle_new_fixedsize(self, descr, op):
+        assert isinstance(descr, SizeDescr)
+        size = descr.size
+        self.gen_malloc_nursery(size, op.result)
+        self.gen_initialize_tid(op.result, descr.tid)
+
+    def handle_new_array(self, arraydescr, op):
+        v_length = op.getarg(0)
+        total_size = -1
+        if isinstance(v_length, ConstInt):
+            num_elem = v_length.getint()
+            self.known_lengths[op.result] = num_elem
+            try:
+                var_size = ovfcheck(arraydescr.itemsize * num_elem)
+                total_size = ovfcheck(arraydescr.basesize + var_size)
+            except OverflowError:
+                pass    # total_size is still -1
+        elif arraydescr.itemsize == 0:
+            total_size = arraydescr.basesize
+        if 0 <= total_size <= 0xffffff:     # up to 16MB, arbitrarily
+            self.gen_malloc_nursery(total_size, op.result)
+            self.gen_initialize_tid(op.result, arraydescr.tid)
+            self.gen_initialize_len(op.result, v_length, arraydescr.lendescr)
+        elif self.gc_ll_descr.kind == 'boehm':
+            self.gen_boehm_malloc_array(arraydescr, v_length, op.result)
+        else:
+            opnum = op.getopnum()
+            if opnum == rop.NEW_ARRAY:
+                self.gen_malloc_array(arraydescr, v_length, op.result)
+            elif opnum == rop.NEWSTR:
+                self.gen_malloc_str(v_length, op.result)
+            elif opnum == rop.NEWUNICODE:
+                self.gen_malloc_unicode(v_length, op.result)
+            else:
+                raise NotImplementedError(op.getopname())
+
+    # ----------
+
+    def emitting_an_operation_that_can_collect(self):
+        # must be called whenever we emit an operation that can collect:
+        # forgets the previous MALLOC_NURSERY, if any; and empty the
+        # set 'recent_mallocs', so that future SETFIELDs will generate
+        # a write barrier as usual.
+        self._op_malloc_nursery = None
+        self.recent_mallocs.clear()
+
+    def _gen_call_malloc_gc(self, args, v_result, descr):
+        """Generate a CALL_MALLOC_GC with the given args."""
+        self.emitting_an_operation_that_can_collect()
+        op = ResOperation(rop.CALL_MALLOC_GC, args, v_result, descr)
+        self.newops.append(op)
+        # mark 'v_result' as freshly malloced
+        self.recent_mallocs[v_result] = None
+
+    def gen_malloc_fixedsize(self, size, v_result):
+        """Generate a CALL_MALLOC_GC(malloc_fixedsize_fn, Const(size)).
+        Note that with the framework GC, this should be called very rarely.
+        """
+        addr = self.gc_ll_descr.get_malloc_fn_addr('malloc_fixedsize')
+        self._gen_call_malloc_gc([ConstInt(addr), ConstInt(size)], v_result,
+                                 self.gc_ll_descr.malloc_fixedsize_descr)
+
+    def gen_boehm_malloc_array(self, arraydescr, v_num_elem, v_result):
+        """Generate a CALL_MALLOC_GC(malloc_array_fn, ...) for Boehm."""
+        addr = self.gc_ll_descr.get_malloc_fn_addr('malloc_array')
+        self._gen_call_malloc_gc([ConstInt(addr),
+                                  ConstInt(arraydescr.basesize),
+                                  v_num_elem,
+                                  ConstInt(arraydescr.itemsize),
+                                  ConstInt(arraydescr.lendescr.offset)],
+                                 v_result,
+                                 self.gc_ll_descr.malloc_array_descr)
+
+    def gen_malloc_array(self, arraydescr, v_num_elem, v_result):
+        """Generate a CALL_MALLOC_GC(malloc_array_fn, ...) going either
+        to the standard or the nonstandard version of the function."""
+        #
+        if (arraydescr.basesize == self.gc_ll_descr.standard_array_basesize
+            and arraydescr.lendescr.offset ==
+                self.gc_ll_descr.standard_array_length_ofs):
+            # this is a standard-looking array, common case
+            addr = self.gc_ll_descr.get_malloc_fn_addr('malloc_array')
+            args = [ConstInt(addr),
+                    ConstInt(arraydescr.itemsize),
+                    ConstInt(arraydescr.tid),
+                    v_num_elem]
+            calldescr = self.gc_ll_descr.malloc_array_descr
+        else:
+            # rare case, so don't care too much about the number of arguments
+            addr = self.gc_ll_descr.get_malloc_fn_addr(
+                                              'malloc_array_nonstandard')
+            args = [ConstInt(addr),
+                    ConstInt(arraydescr.basesize),
+                    ConstInt(arraydescr.itemsize),
+                    ConstInt(arraydescr.lendescr.offset),
+                    ConstInt(arraydescr.tid),
+                    v_num_elem]
+            calldescr = self.gc_ll_descr.malloc_array_nonstandard_descr
+        self._gen_call_malloc_gc(args, v_result, calldescr)
+
+    def gen_malloc_str(self, v_num_elem, v_result):
+        """Generate a CALL_MALLOC_GC(malloc_str_fn, ...)."""
+        addr = self.gc_ll_descr.get_malloc_fn_addr('malloc_str')
+        self._gen_call_malloc_gc([ConstInt(addr), v_num_elem], v_result,
+                                 self.gc_ll_descr.malloc_str_descr)
+
+    def gen_malloc_unicode(self, v_num_elem, v_result):
+        """Generate a CALL_MALLOC_GC(malloc_unicode_fn, ...)."""
+        addr = self.gc_ll_descr.get_malloc_fn_addr('malloc_unicode')
+        self._gen_call_malloc_gc([ConstInt(addr), v_num_elem], v_result,
+                                 self.gc_ll_descr.malloc_unicode_descr)
+
+    def gen_malloc_nursery(self, size, v_result):
+        """Try to generate or update a CALL_MALLOC_NURSERY.
+        If that fails, generate a plain CALL_MALLOC_GC instead.
+        """
+        size = self.round_up_for_allocation(size)
+        if not self.gc_ll_descr.can_use_nursery_malloc(size):
+            self.gen_malloc_fixedsize(size, v_result)
+            return
+        #
+        op = None
+        if self._op_malloc_nursery is not None:
+            # already a MALLOC_NURSERY: increment its total size
+            total_size = self._op_malloc_nursery.getarg(0).getint()
+            total_size += size
+            if self.gc_ll_descr.can_use_nursery_malloc(total_size):
+                # if the total size is still reasonable, merge it
+                self._op_malloc_nursery.setarg(0, ConstInt(total_size))
+                op = ResOperation(rop.INT_ADD,
+                                  [self._v_last_malloced_nursery,
+                                   ConstInt(self._previous_size)],
+                                  v_result)
+        if op is None:
+            # if we failed to merge with a previous MALLOC_NURSERY, emit one
+            self.emitting_an_operation_that_can_collect()
+            op = ResOperation(rop.CALL_MALLOC_NURSERY,
+                              [ConstInt(size)],
+                              v_result)
+            self._op_malloc_nursery = op
+        #
+        self.newops.append(op)
+        self._previous_size = size
+        self._v_last_malloced_nursery = v_result
+        self.recent_mallocs[v_result] = None
+
+    def gen_initialize_tid(self, v_newgcobj, tid):
+        if self.gc_ll_descr.fielddescr_tid is not None:
+            # produce a SETFIELD to initialize the GC header
+            op = ResOperation(rop.SETFIELD_GC,
+                              [v_newgcobj, ConstInt(tid)], None,
+                              descr=self.gc_ll_descr.fielddescr_tid)
+            self.newops.append(op)
+
+    def gen_initialize_len(self, v_newgcobj, v_length, arraylen_descr):
+        # produce a SETFIELD to initialize the array length
+        op = ResOperation(rop.SETFIELD_GC,
+                          [v_newgcobj, v_length], None,
+                          descr=arraylen_descr)
+        self.newops.append(op)
+
+    # ----------
+
+    def handle_write_barrier_setfield(self, op):
+        val = op.getarg(0)
+        # no need for a write barrier in the case of previous malloc
+        if val not in self.recent_mallocs:
+            v = op.getarg(1)
+            if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
+                                         bool(v.value)): # store a non-NULL
+                self.gen_write_barrier(op.getarg(0), v)
+                op = op.copy_and_change(rop.SETFIELD_RAW)
+        self.newops.append(op)
+
+    def handle_write_barrier_setinteriorfield(self, op):
+        val = op.getarg(0)
+        # no need for a write barrier in the case of previous malloc
+        if val not in self.recent_mallocs:
+            v = op.getarg(2)
+            if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
+                                         bool(v.value)): # store a non-NULL
+                self.gen_write_barrier(op.getarg(0), v)
+                op = op.copy_and_change(rop.SETINTERIORFIELD_RAW)
+        self.newops.append(op)
+
+    def handle_write_barrier_setarrayitem(self, op):
+        val = op.getarg(0)
+        # no need for a write barrier in the case of previous malloc
+        if val not in self.recent_mallocs:
+            v = op.getarg(2)
+            if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
+                                         bool(v.value)): # store a non-NULL
+                self.gen_write_barrier_array(op.getarg(0),
+                                             op.getarg(1), v)
+                op = op.copy_and_change(rop.SETARRAYITEM_RAW)
+        self.newops.append(op)
+
+    def gen_write_barrier(self, v_base, v_value):
+        write_barrier_descr = self.gc_ll_descr.write_barrier_descr
+        args = [v_base, v_value]
+        self.newops.append(ResOperation(rop.COND_CALL_GC_WB, args, None,
+                                        descr=write_barrier_descr))
+
+    def gen_write_barrier_array(self, v_base, v_index, v_value):
+        write_barrier_descr = self.gc_ll_descr.write_barrier_descr
+        if write_barrier_descr.has_write_barrier_from_array(self.cpu):
+            # If we know statically the length of 'v', and it is not too
+            # big, then produce a regular write_barrier.  If it's unknown or
+            # too big, produce instead a write_barrier_from_array.
+            LARGE = 130
+            length = self.known_lengths.get(v_base, LARGE)
+            if length >= LARGE:
+                # unknown or too big: produce a write_barrier_from_array
+                args = [v_base, v_index, v_value]
+                self.newops.append(
+                    ResOperation(rop.COND_CALL_GC_WB_ARRAY, args, None,
+                                 descr=write_barrier_descr))
+                return
+        # fall-back case: produce a write_barrier
+        self.gen_write_barrier(v_base, v_value)
+
+    def round_up_for_allocation(self, size):
+        if not self.gc_ll_descr.round_up:
+            return size
+        if self.gc_ll_descr.translate_support_code:
+            from pypy.rpython.lltypesystem import llarena
+            return llarena.round_up_for_allocation(
+                size, self.gc_ll_descr.minimal_size_in_nursery)
+        else:
+            # non-translated: do it manually
+            # assume that "self.gc_ll_descr.minimal_size_in_nursery" is 2 WORDs
+            size = max(size, 2 * WORD)
+            return (size + WORD-1) & ~(WORD-1)     # round up
diff --git a/pypy/jit/backend/llsupport/test/test_descr.py b/pypy/jit/backend/llsupport/test/test_descr.py
--- a/pypy/jit/backend/llsupport/test/test_descr.py
+++ b/pypy/jit/backend/llsupport/test/test_descr.py
@@ -1,4 +1,4 @@
-from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rpython.lltypesystem import lltype, rffi, rstr
 from pypy.jit.backend.llsupport.descr import *
 from pypy.jit.backend.llsupport import symbolic
 from pypy.rlib.objectmodel import Symbolic
@@ -53,18 +53,6 @@
                              ('z', lltype.Ptr(U)),
                              ('f', lltype.Float),
                              ('s', lltype.SingleFloat))
-    assert getFieldDescrClass(lltype.Ptr(T)) is GcPtrFieldDescr
-    assert getFieldDescrClass(lltype.Ptr(U)) is NonGcPtrFieldDescr
-    cls = getFieldDescrClass(lltype.Char)
-    assert cls != getFieldDescrClass(lltype.Signed)
-    assert cls == getFieldDescrClass(lltype.Char)
-    clsf = getFieldDescrClass(lltype.Float)
-    assert clsf != cls
-    assert clsf == getFieldDescrClass(lltype.Float)
-    clss = getFieldDescrClass(lltype.SingleFloat)
-    assert clss not in (cls, clsf)
-    assert clss == getFieldDescrClass(lltype.SingleFloat)
-    assert clss == getFieldDescrClass(rffi.UINT)    # for now
     #
     c0 = GcCache(False)
     c1 = GcCache(True)
@@ -77,11 +65,7 @@
         descr_z = get_field_descr(c2, S, 'z')
         descr_f = get_field_descr(c2, S, 'f')
         descr_s = get_field_descr(c2, S, 's')
-        assert descr_x.__class__ is cls
-        assert descr_y.__class__ is GcPtrFieldDescr
-        assert descr_z.__class__ is NonGcPtrFieldDescr
-        assert descr_f.__class__ is clsf
-        assert descr_s.__class__ is clss
+        assert isinstance(descr_x, FieldDescr)
         assert descr_x.name == 'S.x'
         assert descr_y.name == 'S.y'
         assert descr_z.name == 'S.z'
@@ -90,33 +74,27 @@
         if not tsc:
             assert descr_x.offset < descr_y.offset < descr_z.offset
             assert descr_x.sort_key() < descr_y.sort_key() < descr_z.sort_key()
-            assert descr_x.get_field_size(False) == rffi.sizeof(lltype.Char)
-            assert descr_y.get_field_size(False) == rffi.sizeof(lltype.Ptr(T))
-            assert descr_z.get_field_size(False) == rffi.sizeof(lltype.Ptr(U))
-            assert descr_f.get_field_size(False) == rffi.sizeof(lltype.Float)
-            assert descr_s.get_field_size(False) == rffi.sizeof(
-                                                            lltype.SingleFloat)
+            assert descr_x.field_size == rffi.sizeof(lltype.Char)
+            assert descr_y.field_size == rffi.sizeof(lltype.Ptr(T))
+            assert descr_z.field_size == rffi.sizeof(lltype.Ptr(U))
+            assert descr_f.field_size == rffi.sizeof(lltype.Float)
+            assert descr_s.field_size == rffi.sizeof(lltype.SingleFloat)
         else:
             assert isinstance(descr_x.offset, Symbolic)
             assert isinstance(descr_y.offset, Symbolic)
             assert isinstance(descr_z.offset, Symbolic)
             assert isinstance(descr_f.offset, Symbolic)
             assert isinstance(descr_s.offset, Symbolic)
-            assert isinstance(descr_x.get_field_size(True), Symbolic)
-            assert isinstance(descr_y.get_field_size(True), Symbolic)
-            assert isinstance(descr_z.get_field_size(True), Symbolic)
-            assert isinstance(descr_f.get_field_size(True), Symbolic)
-            assert isinstance(descr_s.get_field_size(True), Symbolic)
-        assert not descr_x.is_pointer_field()
-        assert     descr_y.is_pointer_field()
-        assert not descr_z.is_pointer_field()
-        assert not descr_f.is_pointer_field()
-        assert not descr_s.is_pointer_field()
-        assert not descr_x.is_float_field()
-        assert not descr_y.is_float_field()
-        assert not descr_z.is_float_field()
-        assert     descr_f.is_float_field()
-        assert not descr_s.is_float_field()
+            assert isinstance(descr_x.field_size, Symbolic)
+            assert isinstance(descr_y.field_size, Symbolic)
+            assert isinstance(descr_z.field_size, Symbolic)
+            assert isinstance(descr_f.field_size, Symbolic)
+            assert isinstance(descr_s.field_size, Symbolic)
+        assert descr_x.flag == FLAG_UNSIGNED
+        assert descr_y.flag == FLAG_POINTER
+        assert descr_z.flag == FLAG_UNSIGNED
+        assert descr_f.flag == FLAG_FLOAT
+        assert descr_s.flag == FLAG_UNSIGNED
 
 
 def test_get_field_descr_sign():
@@ -128,7 +106,8 @@
         for tsc in [False, True]:
             c2 = GcCache(tsc)
             descr_x = get_field_descr(c2, S, 'x')
-            assert descr_x.is_field_signed() == signed
+            assert descr_x.flag == {False: FLAG_UNSIGNED,
+                                    True:  FLAG_SIGNED  }[signed]
 
 def test_get_field_descr_longlong():
     if sys.maxint > 2147483647:
@@ -136,9 +115,8 @@
     c0 = GcCache(False)
     S = lltype.GcStruct('S', ('y', lltype.UnsignedLongLong))
     descr = get_field_descr(c0, S, 'y')
-    assert not descr.is_pointer_field()
-    assert descr.is_float_field()
-    assert descr.get_field_size(False) == 8
+    assert descr.flag == FLAG_FLOAT
+    assert descr.field_size == 8
 
 
 def test_get_array_descr():
@@ -149,19 +127,8 @@
     A3 = lltype.GcArray(lltype.Ptr(U))
     A4 = lltype.GcArray(lltype.Float)
     A5 = lltype.GcArray(lltype.Struct('x', ('v', lltype.Signed),
-                                      ('k', lltype.Signed)))
+                                           ('k', lltype.Signed)))
     A6 = lltype.GcArray(lltype.SingleFloat)
-    assert getArrayDescrClass(A2) is GcPtrArrayDescr
-    assert getArrayDescrClass(A3) is NonGcPtrArrayDescr
-    cls = getArrayDescrClass(A1)
-    assert cls != getArrayDescrClass(lltype.GcArray(lltype.Signed))
-    assert cls == getArrayDescrClass(lltype.GcArray(lltype.Char))
-    clsf = getArrayDescrClass(A4)
-    assert clsf != cls
-    assert clsf == getArrayDescrClass(lltype.GcArray(lltype.Float))
-    clss = getArrayDescrClass(A6)
-    assert clss not in (clsf, cls)
-    assert clss == getArrayDescrClass(lltype.GcArray(rffi.UINT))
     #
     c0 = GcCache(False)
     descr1 = get_array_descr(c0, A1)
@@ -170,82 +137,61 @@
     descr4 = get_array_descr(c0, A4)
     descr5 = get_array_descr(c0, A5)
     descr6 = get_array_descr(c0, A6)
-    assert descr1.__class__ is cls
-    assert descr2.__class__ is GcPtrArrayDescr
-    assert descr3.__class__ is NonGcPtrArrayDescr
-    assert descr4.__class__ is clsf
-    assert descr6.__class__ is clss
+    assert isinstance(descr1, ArrayDescr)
     assert descr1 == get_array_descr(c0, lltype.GcArray(lltype.Char))
-    assert not descr1.is_array_of_pointers()
-    assert     descr2.is_array_of_pointers()
-    assert not descr3.is_array_of_pointers()
-    assert not descr4.is_array_of_pointers()
-    assert not descr5.is_array_of_pointers()
-    assert not descr1.is_array_of_floats()
-    assert not descr2.is_array_of_floats()
-    assert not descr3.is_array_of_floats()
-    assert     descr4.is_array_of_floats()
-    assert not descr5.is_array_of_floats()
+    assert descr1.flag == FLAG_UNSIGNED
+    assert descr2.flag == FLAG_POINTER
+    assert descr3.flag == FLAG_UNSIGNED
+    assert descr4.flag == FLAG_FLOAT
+    assert descr5.flag == FLAG_STRUCT
+    assert descr6.flag == FLAG_UNSIGNED
     #
     def get_alignment(code):
         # Retrieve default alignment for the compiler/platform
         return struct.calcsize('l' + code) - struct.calcsize(code)
-    assert descr1.get_base_size(False) == get_alignment('c')
-    assert descr2.get_base_size(False) == get_alignment('p')
-    assert descr3.get_base_size(False) == get_alignment('p')
-    assert descr4.get_base_size(False) == get_alignment('d')
-    assert descr5.get_base_size(False) == get_alignment('f')
-    assert descr1.get_ofs_length(False) == 0
-    assert descr2.get_ofs_length(False) == 0
-    assert descr3.get_ofs_length(False) == 0
-    assert descr4.get_ofs_length(False) == 0
-    assert descr5.get_ofs_length(False) == 0
-    assert descr1.get_item_size(False) == rffi.sizeof(lltype.Char)
-    assert descr2.get_item_size(False) == rffi.sizeof(lltype.Ptr(T))
-    assert descr3.get_item_size(False) == rffi.sizeof(lltype.Ptr(U))
-    assert descr4.get_item_size(False) == rffi.sizeof(lltype.Float)
-    assert descr5.get_item_size(False) == rffi.sizeof(lltype.Signed) * 2
-    assert descr6.get_item_size(False) == rffi.sizeof(lltype.SingleFloat)
+    assert descr1.basesize == get_alignment('c')
+    assert descr2.basesize == get_alignment('p')
+    assert descr3.basesize == get_alignment('p')
+    assert descr4.basesize == get_alignment('d')
+    assert descr5.basesize == get_alignment('f')
+    assert descr1.lendescr.offset == 0
+    assert descr2.lendescr.offset == 0
+    assert descr3.lendescr.offset == 0
+    assert descr4.lendescr.offset == 0
+    assert descr5.lendescr.offset == 0
+    assert descr1.itemsize == rffi.sizeof(lltype.Char)
+    assert descr2.itemsize == rffi.sizeof(lltype.Ptr(T))
+    assert descr3.itemsize == rffi.sizeof(lltype.Ptr(U))
+    assert descr4.itemsize == rffi.sizeof(lltype.Float)
+    assert descr5.itemsize == rffi.sizeof(lltype.Signed) * 2
+    assert descr6.itemsize == rffi.sizeof(lltype.SingleFloat)
     #
-    assert isinstance(descr1.get_base_size(True), Symbolic)
-    assert isinstance(descr2.get_base_size(True), Symbolic)
-    assert isinstance(descr3.get_base_size(True), Symbolic)
-    assert isinstance(descr4.get_base_size(True), Symbolic)
-    assert isinstance(descr5.get_base_size(True), Symbolic)
-    assert isinstance(descr1.get_ofs_length(True), Symbolic)
-    assert isinstance(descr2.get_ofs_length(True), Symbolic)
-    assert isinstance(descr3.get_ofs_length(True), Symbolic)
-    assert isinstance(descr4.get_ofs_length(True), Symbolic)
-    assert isinstance(descr5.get_ofs_length(True), Symbolic)
-    assert isinstance(descr1.get_item_size(True), Symbolic)
-    assert isinstance(descr2.get_item_size(True), Symbolic)
-    assert isinstance(descr3.get_item_size(True), Symbolic)
-    assert isinstance(descr4.get_item_size(True), Symbolic)
-    assert isinstance(descr5.get_item_size(True), Symbolic)
     CA = rffi.CArray(lltype.Signed)
     descr = get_array_descr(c0, CA)
-    assert not descr.is_array_of_floats()
-    assert descr.get_base_size(False) == 0
-    assert descr.get_ofs_length(False) == -1
+    assert descr.flag == FLAG_SIGNED
+    assert descr.basesize == 0
+    assert descr.lendescr is None
     CA = rffi.CArray(lltype.Ptr(lltype.GcStruct('S')))
     descr = get_array_descr(c0, CA)
-    assert descr.is_array_of_pointers()
-    assert descr.get_base_size(False) == 0
-    assert descr.get_ofs_length(False) == -1
+    assert descr.flag == FLAG_POINTER
+    assert descr.basesize == 0
+    assert descr.lendescr is None
     CA = rffi.CArray(lltype.Ptr(lltype.Struct('S')))
     descr = get_array_descr(c0, CA)
-    assert descr.get_base_size(False) == 0
-    assert descr.get_ofs_length(False) == -1
+    assert descr.flag == FLAG_UNSIGNED
+    assert descr.basesize == 0
+    assert descr.lendescr is None
     CA = rffi.CArray(lltype.Float)
     descr = get_array_descr(c0, CA)
-    assert descr.is_array_of_floats()
-    assert descr.get_base_size(False) == 0
-    assert descr.get_ofs_length(False) == -1
+    assert descr.flag == FLAG_FLOAT
+    assert descr.basesize == 0
+    assert descr.lendescr is None
     CA = rffi.CArray(rffi.FLOAT)
     descr = get_array_descr(c0, CA)
-    assert not descr.is_array_of_floats()
-    assert descr.get_base_size(False) == 0
-    assert descr.get_ofs_length(False) == -1
+    assert descr.flag == FLAG_UNSIGNED
+    assert descr.basesize == 0
+    assert descr.itemsize == rffi.sizeof(lltype.SingleFloat)
+    assert descr.lendescr is None
 
 
 def test_get_array_descr_sign():
@@ -257,46 +203,55 @@
         for tsc in [False, True]:
             c2 = GcCache(tsc)
             arraydescr = get_array_descr(c2, A)
-            assert arraydescr.is_item_signed() == signed
+            assert arraydescr.flag == {False: FLAG_UNSIGNED,
+                                       True:  FLAG_SIGNED  }[signed]
         #
         RA = rffi.CArray(RESTYPE)
         for tsc in [False, True]:
             c2 = GcCache(tsc)
             arraydescr = get_array_descr(c2, RA)
-            assert arraydescr.is_item_signed() == signed
+            assert arraydescr.flag == {False: FLAG_UNSIGNED,
+                                       True:  FLAG_SIGNED  }[signed]
+
+
+def test_get_array_descr_str():
+    c0 = GcCache(False)
+    descr1 = get_array_descr(c0, rstr.STR)
+    assert descr1.itemsize == rffi.sizeof(lltype.Char)
+    assert descr1.flag == FLAG_UNSIGNED
 
 
 def test_get_call_descr_not_translated():
     c0 = GcCache(False)
     descr1 = get_call_descr(c0, [lltype.Char, lltype.Signed], lltype.Char)
-    assert descr1.get_result_size(False) == rffi.sizeof(lltype.Char)
-    assert descr1.get_return_type() == history.INT
+    assert descr1.get_result_size() == rffi.sizeof(lltype.Char)
+    assert descr1.get_result_type() == history.INT
     assert descr1.arg_classes == "ii"
     #
     T = lltype.GcStruct('T')
     descr2 = get_call_descr(c0, [lltype.Ptr(T)], lltype.Ptr(T))
-    assert descr2.get_result_size(False) == rffi.sizeof(lltype.Ptr(T))
-    assert descr2.get_return_type() == history.REF
+    assert descr2.get_result_size() == rffi.sizeof(lltype.Ptr(T))
+    assert descr2.get_result_type() == history.REF
     assert descr2.arg_classes == "r"
     #
     U = lltype.GcStruct('U', ('x', lltype.Signed))
     assert descr2 == get_call_descr(c0, [lltype.Ptr(U)], lltype.Ptr(U))
     #
     V = lltype.Struct('V', ('x', lltype.Signed))
-    assert (get_call_descr(c0, [], lltype.Ptr(V)).get_return_type() ==
+    assert (get_call_descr(c0, [], lltype.Ptr(V)).get_result_type() ==
             history.INT)
     #
-    assert (get_call_descr(c0, [], lltype.Void).get_return_type() ==
+    assert (get_call_descr(c0, [], lltype.Void).get_result_type() ==
             history.VOID)
     #
     descr4 = get_call_descr(c0, [lltype.Float, lltype.Float], lltype.Float)
-    assert descr4.get_result_size(False) == rffi.sizeof(lltype.Float)
-    assert descr4.get_return_type() == history.FLOAT
+    assert descr4.get_result_size() == rffi.sizeof(lltype.Float)
+    assert descr4.get_result_type() == history.FLOAT
     assert descr4.arg_classes == "ff"
     #
     descr5 = get_call_descr(c0, [lltype.SingleFloat], lltype.SingleFloat)
-    assert descr5.get_result_size(False) == rffi.sizeof(lltype.SingleFloat)
-    assert descr5.get_return_type() == "S"
+    assert descr5.get_result_size() == rffi.sizeof(lltype.SingleFloat)
+    assert descr5.get_result_type() == "S"
     assert descr5.arg_classes == "S"
 
 def test_get_call_descr_not_translated_longlong():
@@ -305,13 +260,13 @@
     c0 = GcCache(False)
     #
     descr5 = get_call_descr(c0, [lltype.SignedLongLong], lltype.Signed)
-    assert descr5.get_result_size(False) == 4
-    assert descr5.get_return_type() == history.INT
+    assert descr5.get_result_size() == 4
+    assert descr5.get_result_type() == history.INT
     assert descr5.arg_classes == "L"
     #
     descr6 = get_call_descr(c0, [lltype.Signed], lltype.SignedLongLong)
-    assert descr6.get_result_size(False) == 8
-    assert descr6.get_return_type() == "L"
+    assert descr6.get_result_size() == 8
+    assert descr6.get_result_type() == "L"
     assert descr6.arg_classes == "i"
 
 def test_get_call_descr_translated():
@@ -319,18 +274,18 @@
     T = lltype.GcStruct('T')
     U = lltype.GcStruct('U', ('x', lltype.Signed))
     descr3 = get_call_descr(c1, [lltype.Ptr(T)], lltype.Ptr(U))
-    assert isinstance(descr3.get_result_size(True), Symbolic)
-    assert descr3.get_return_type() == history.REF
+    assert isinstance(descr3.get_result_size(), Symbolic)
+    assert descr3.get_result_type() == history.REF
     assert descr3.arg_classes == "r"
     #
     descr4 = get_call_descr(c1, [lltype.Float, lltype.Float], lltype.Float)
-    assert isinstance(descr4.get_result_size(True), Symbolic)
-    assert descr4.get_return_type() == history.FLOAT
+    assert isinstance(descr4.get_result_size(), Symbolic)
+    assert descr4.get_result_type() == history.FLOAT
     assert descr4.arg_classes == "ff"
     #
     descr5 = get_call_descr(c1, [lltype.SingleFloat], lltype.SingleFloat)
-    assert isinstance(descr5.get_result_size(True), Symbolic)
-    assert descr5.get_return_type() == "S"
+    assert isinstance(descr5.get_result_size(), Symbolic)
+    assert descr5.get_result_type() == "S"
     assert descr5.arg_classes == "S"
 
 def test_call_descr_extra_info():
@@ -358,6 +313,10 @@
 
 
 def test_repr_of_descr():
+    def repr_of_descr(descr):
+        s = descr.repr_of_descr()
+        assert ',' not in s  # makes the life easier for pypy.tool.jitlogparser
+        return s
     c0 = GcCache(False)
     T = lltype.GcStruct('T')
     S = lltype.GcStruct('S', ('x', lltype.Char),
@@ -365,33 +324,34 @@
                              ('z', lltype.Ptr(T)))
     descr1 = get_size_descr(c0, S)
     s = symbolic.get_size(S, False)
-    assert descr1.repr_of_descr() == '<SizeDescr %d>' % s
+    assert repr_of_descr(descr1) == '<SizeDescr %d>' % s
     #
     descr2 = get_field_descr(c0, S, 'y')
     o, _ = symbolic.get_field_token(S, 'y', False)
-    assert descr2.repr_of_descr() == '<GcPtrFieldDescr S.y %d>' % o
+    assert repr_of_descr(descr2) == '<FieldP S.y %d>' % o
     #
     descr2i = get_field_descr(c0, S, 'x')
     o, _ = symbolic.get_field_token(S, 'x', False)
-    assert descr2i.repr_of_descr() == '<CharFieldDescr S.x %d>' % o
+    assert repr_of_descr(descr2i) == '<FieldU S.x %d>' % o
     #
     descr3 = get_array_descr(c0, lltype.GcArray(lltype.Ptr(S)))
-    assert descr3.repr_of_descr() == '<GcPtrArrayDescr>'
+    o = symbolic.get_size(lltype.Ptr(S), False)
+    assert repr_of_descr(descr3) == '<ArrayP %d>' % o
     #
     descr3i = get_array_descr(c0, lltype.GcArray(lltype.Char))
-    assert descr3i.repr_of_descr() == '<CharArrayDescr>'
+    assert repr_of_descr(descr3i) == '<ArrayU 1>'
     #
     descr4 = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Ptr(S))
-    assert 'GcPtrCallDescr' in descr4.repr_of_descr()
+    assert repr_of_descr(descr4) == '<Callr %d ir>' % o
     #
     descr4i = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Char)
-    assert 'CharCallDescr' in descr4i.repr_of_descr()
+    assert repr_of_descr(descr4i) == '<Calli 1 ir>'
     #
     descr4f = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Float)
-    assert 'FloatCallDescr' in descr4f.repr_of_descr()
+    assert repr_of_descr(descr4f) == '<Callf 8 ir>'
     #
     descr5f = get_call_descr(c0, [lltype.Char], lltype.SingleFloat)
-    assert 'SingleFloatCallDescr' in descr5f.repr_of_descr()
+    assert repr_of_descr(descr5f) == '<CallS 4 i>'
 
 def test_call_stubs_1():
     c0 = GcCache(False)
@@ -401,10 +361,10 @@
     def f(a, b):
         return 'c'
 
-    call_stub = descr1.call_stub
     fnptr = llhelper(lltype.Ptr(lltype.FuncType(ARGS, RES)), f)
 
-    res = call_stub(rffi.cast(lltype.Signed, fnptr), [1, 2], None, None)
+    res = descr1.call_stub_i(rffi.cast(lltype.Signed, fnptr),
+                             [1, 2], None, None)
     assert res == ord('c')
 
 def test_call_stubs_2():
@@ -421,8 +381,8 @@
     a = lltype.malloc(ARRAY, 3)
     opaquea = lltype.cast_opaque_ptr(llmemory.GCREF, a)
     a[0] = 1
-    res = descr2.call_stub(rffi.cast(lltype.Signed, fnptr),
-                           [], [opaquea], [longlong.getfloatstorage(3.5)])
+    res = descr2.call_stub_f(rffi.cast(lltype.Signed, fnptr),
+                             [], [opaquea], [longlong.getfloatstorage(3.5)])
     assert longlong.getrealfloat(res) == 4.5
 
 def test_call_stubs_single_float():
@@ -445,6 +405,22 @@
     a = intmask(singlefloat2uint(r_singlefloat(-10.0)))
     b = intmask(singlefloat2uint(r_singlefloat(3.0)))
     c = intmask(singlefloat2uint(r_singlefloat(2.0)))
-    res = descr2.call_stub(rffi.cast(lltype.Signed, fnptr),
-                           [a, b, c], [], [])
+    res = descr2.call_stub_i(rffi.cast(lltype.Signed, fnptr),
+                             [a, b, c], [], [])
     assert float(uint2singlefloat(rffi.r_uint(res))) == -11.5
+
+def test_field_arraylen_descr():
+    c0 = GcCache(True)
+    A1 = lltype.GcArray(lltype.Signed)
+    fielddescr = get_field_arraylen_descr(c0, A1)
+    assert isinstance(fielddescr, FieldDescr)
+    ofs = fielddescr.offset
+    assert repr(ofs) == '< ArrayLengthOffset <GcArray of Signed > >'
+    #
+    fielddescr = get_field_arraylen_descr(c0, rstr.STR)
+    ofs = fielddescr.offset
+    assert repr(ofs) == ("< <FieldOffset <GcStruct rpy_string { hash, chars }>"
+                         " 'chars'> + < ArrayLengthOffset"
+                         " <Array of Char > > >")
+    # caching:
+    assert fielddescr is get_field_arraylen_descr(c0, rstr.STR)
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,5 +1,6 @@
 from pypy.rlib.libffi import types
 from pypy.jit.codewriter.longlong import is_64_bit
+from pypy.jit.backend.llsupport.descr import *
 from pypy.jit.backend.llsupport.ffisupport import *
 
 
@@ -15,7 +16,9 @@
     args = [types.sint, types.pointer]
     descr = get_call_descr_dynamic(FakeCPU(), args, types.sint, None,
                                    ffi_flags=42)
-    assert isinstance(descr, DynamicIntCallDescr)
+    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
 
@@ -24,18 +27,20 @@
     assert descr is None    # missing floats
     descr = get_call_descr_dynamic(FakeCPU(supports_floats=True),
                                    args, types.void, None, ffi_flags=43)
-    assert isinstance(descr, VoidCallDescr)
+    assert descr.result_type == 'v'
+    assert descr.result_flag == FLAG_VOID
     assert descr.arg_classes == 'ifi'
     assert descr.get_ffi_flags() == 43
 
     descr = get_call_descr_dynamic(FakeCPU(), [], types.sint8, None, 42)
-    assert isinstance(descr, DynamicIntCallDescr)
-    assert descr.get_result_size(False) == 1
+    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)
-    assert isinstance(descr, DynamicIntCallDescr)
-    assert descr.get_result_size(False) == 1
+    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:
@@ -44,7 +49,9 @@
         assert descr is None   # missing longlongs
         descr = get_call_descr_dynamic(FakeCPU(supports_longlong=True),
                                        [], types.slonglong, None, ffi_flags=43)
-        assert isinstance(descr, LongLongCallDescr)
+        assert isinstance(descr, CallDescr)
+        assert descr.result_flag == FLAG_FLOAT
+        assert descr.result_type == 'L'
         assert descr.get_ffi_flags() == 43
     else:
         assert types.slonglong is types.slong
@@ -53,6 +60,6 @@
     assert descr is None   # missing singlefloats
     descr = get_call_descr_dynamic(FakeCPU(supports_singlefloats=True),
                                    [], types.float, None, ffi_flags=44)
-    SingleFloatCallDescr = getCallDescrClass(rffi.FLOAT)
-    assert isinstance(descr, SingleFloatCallDescr)
+    assert descr.result_flag == FLAG_UNSIGNED
+    assert descr.result_type == 'S'
     assert descr.get_ffi_flags() == 44
diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py
--- a/pypy/jit/backend/llsupport/test/test_gc.py
+++ b/pypy/jit/backend/llsupport/test/test_gc.py
@@ -6,6 +6,7 @@
 from pypy.jit.backend.llsupport.gc import *
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.metainterp.gc import get_description
+from pypy.jit.metainterp.history import BoxPtr, BoxInt, ConstPtr
 from pypy.jit.metainterp.resoperation import get_deep_immutable_oplist
 from pypy.jit.tool.oparser import parse
 from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
@@ -15,12 +16,12 @@
     gc_ll_descr = GcLLDescr_boehm(None, None, None)
     #
     record = []
-    prev_funcptr_for_new = gc_ll_descr.funcptr_for_new
-    def my_funcptr_for_new(size):
-        p = prev_funcptr_for_new(size)
+    prev_malloc_fn_ptr = gc_ll_descr.malloc_fn_ptr
+    def my_malloc_fn_ptr(size):
+        p = prev_malloc_fn_ptr(size)
         record.append((size, p))
         return p
-    gc_ll_descr.funcptr_for_new = my_funcptr_for_new
+    gc_ll_descr.malloc_fn_ptr = my_malloc_fn_ptr
     #
     # ---------- gc_malloc ----------
     S = lltype.GcStruct('S', ('x', lltype.Signed))
@@ -32,8 +33,8 @@
     A = lltype.GcArray(lltype.Signed)
     arraydescr = get_array_descr(gc_ll_descr, A)
     p = gc_ll_descr.gc_malloc_array(arraydescr, 10)
-    assert record == [(arraydescr.get_base_size(False) +
-                       10 * arraydescr.get_item_size(False), p)]
+    assert record == [(arraydescr.basesize +
+                       10 * arraydescr.itemsize, p)]
     del record[:]
     # ---------- gc_malloc_str ----------
     p = gc_ll_descr.gc_malloc_str(10)
@@ -246,24 +247,28 @@
     def __init__(self):
         self.record = []
 
+    def _malloc(self, type_id, size):
+        tid = llop.combine_ushort(lltype.Signed, type_id, 0)
+        x = llmemory.raw_malloc(self.gcheaderbuilder.size_gc_header + size)
+        x += self.gcheaderbuilder.size_gc_header
+        return x, tid
+
     def do_malloc_fixedsize_clear(self, RESTYPE, type_id, size,
                                   has_finalizer, has_light_finalizer,
                                   contains_weakptr):
         assert not contains_weakptr
-        assert not has_finalizer           # in these tests
-        assert not has_light_finalizer     # in these tests
-        p = llmemory.raw_malloc(size)
+        assert not has_finalizer
+        assert not has_light_finalizer
+        p, tid = self._malloc(type_id, size)
         p = llmemory.cast_adr_to_ptr(p, RESTYPE)
-        tid = llop.combine_ushort(lltype.Signed, type_id, 0)
         self.record.append(("fixedsize", repr(size), tid, p))
         return p
 
     def do_malloc_varsize_clear(self, RESTYPE, type_id, length, size,
                                 itemsize, offset_to_length):
-        p = llmemory.raw_malloc(size + itemsize * length)
+        p, tid = self._malloc(type_id, size + itemsize * length)
         (p + offset_to_length).signed[0] = length
         p = llmemory.cast_adr_to_ptr(p, RESTYPE)
-        tid = llop.combine_ushort(lltype.Signed, type_id, 0)
         self.record.append(("varsize", tid, length,
                             repr(size), repr(itemsize),
                             repr(offset_to_length), p))
@@ -322,43 +327,40 @@
         gc_ll_descr = GcLLDescr_framework(gcdescr, FakeTranslator(), None,
                                           llop1)
         gc_ll_descr.initialize()
+        llop1.gcheaderbuilder = gc_ll_descr.gcheaderbuilder
         self.llop1 = llop1
         self.gc_ll_descr = gc_ll_descr
         self.fake_cpu = FakeCPU()
 
-    def test_args_for_new(self):
-        S = lltype.GcStruct('S', ('x', lltype.Signed))
-        sizedescr = get_size_descr(self.gc_ll_descr, S)
-        args = self.gc_ll_descr.args_for_new(sizedescr)
-        for x in args:
-            assert lltype.typeOf(x) == lltype.Signed
-        A = lltype.GcArray(lltype.Signed)
-        arraydescr = get_array_descr(self.gc_ll_descr, A)
-        args = self.gc_ll_descr.args_for_new(sizedescr)
-        for x in args:
-            assert lltype.typeOf(x) == lltype.Signed
+##    def test_args_for_new(self):
+##        S = lltype.GcStruct('S', ('x', lltype.Signed))
+##        sizedescr = get_size_descr(self.gc_ll_descr, S)
+##        args = self.gc_ll_descr.args_for_new(sizedescr)
+##        for x in args:
+##            assert lltype.typeOf(x) == lltype.Signed
+##        A = lltype.GcArray(lltype.Signed)
+##        arraydescr = get_array_descr(self.gc_ll_descr, A)
+##        args = self.gc_ll_descr.args_for_new(sizedescr)
+##        for x in args:
+##            assert lltype.typeOf(x) == lltype.Signed
 
     def test_gc_malloc(self):
         S = lltype.GcStruct('S', ('x', lltype.Signed))
         sizedescr = get_size_descr(self.gc_ll_descr, S)
         p = self.gc_ll_descr.gc_malloc(sizedescr)
-        assert self.llop1.record == [("fixedsize",
-                                      repr(sizedescr.size),
+        assert lltype.typeOf(p) == llmemory.GCREF
+        assert self.llop1.record == [("fixedsize", repr(sizedescr.size),
                                       sizedescr.tid, p)]
-        assert repr(self.gc_ll_descr.args_for_new(sizedescr)) == repr(
-            [sizedescr.size, sizedescr.tid])
 
     def test_gc_malloc_array(self):
         A = lltype.GcArray(lltype.Signed)
         arraydescr = get_array_descr(self.gc_ll_descr, A)
         p = self.gc_ll_descr.gc_malloc_array(arraydescr, 10)
         assert self.llop1.record == [("varsize", arraydescr.tid, 10,
-                                      repr(arraydescr.get_base_size(True)),
-                                      repr(arraydescr.get_item_size(True)),
-                                      repr(arraydescr.get_ofs_length(True)),
+                                      repr(arraydescr.basesize),
+                                      repr(arraydescr.itemsize),
+                                      repr(arraydescr.lendescr.offset),
                                       p)]
-        assert repr(self.gc_ll_descr.args_for_new_array(arraydescr)) == repr(
-            [arraydescr.get_item_size(True), arraydescr.tid])
 
     def test_gc_malloc_str(self):
         p = self.gc_ll_descr.gc_malloc_str(10)
@@ -404,10 +406,11 @@
         gc_ll_descr = self.gc_ll_descr
         llop1 = self.llop1
         #
-        newops = []
+        rewriter = GcRewriterAssembler(gc_ll_descr, None)
+        newops = rewriter.newops
         v_base = BoxPtr()
         v_value = BoxPtr()
-        gc_ll_descr._gen_write_barrier(newops, v_base, v_value)
+        rewriter.gen_write_barrier(v_base, v_value)
         assert llop1.record == []
         assert len(newops) == 1
         assert newops[0].getopnum() == rop.COND_CALL_GC_WB
@@ -427,8 +430,7 @@
         operations = gc_ll_descr.rewrite_assembler(None, operations, [])
         assert len(operations) == 0
 
-    def test_rewrite_assembler_1(self):
-        # check recording of ConstPtrs
+    def test_record_constptrs(self):
         class MyFakeCPU(object):
             def cast_adr_to_int(self, adr):
                 assert adr == "some fake address"
@@ -455,211 +457,6 @@
         assert operations2 == operations
         assert gcrefs == [s_gcref]
 
-    def test_rewrite_assembler_2(self):
-        # check write barriers before SETFIELD_GC
-        v_base = BoxPtr()
-        v_value = BoxPtr()
-        field_descr = AbstractDescr()
-        operations = [
-            ResOperation(rop.SETFIELD_GC, [v_base, v_value], None,
-                         descr=field_descr),
-            ]
-        gc_ll_descr = self.gc_ll_descr
-        operations = get_deep_immutable_oplist(operations)
-        operations = gc_ll_descr.rewrite_assembler(self.fake_cpu, operations,
-                                                   [])
-        assert len(operations) == 2
-        #
-        assert operations[0].getopnum() == rop.COND_CALL_GC_WB
-        assert operations[0].getarg(0) == v_base
-        assert operations[0].getarg(1) == v_value
-        assert operations[0].result is None
-        #
-        assert operations[1].getopnum() == rop.SETFIELD_RAW
-        assert operations[1].getarg(0) == v_base
-        assert operations[1].getarg(1) == v_value
-        assert operations[1].getdescr() == field_descr
-
-    def test_rewrite_assembler_3(self):
-        # check write barriers before SETARRAYITEM_GC
-        for v_new_length in (None, ConstInt(5), ConstInt(5000), BoxInt()):
-            v_base = BoxPtr()
-            v_index = BoxInt()
-            v_value = BoxPtr()
-            array_descr = AbstractDescr()
-            operations = [
-                ResOperation(rop.SETARRAYITEM_GC, [v_base, v_index, v_value],
-                             None, descr=array_descr),
-                ]
-            if v_new_length is not None:
-                operations.insert(0, ResOperation(rop.NEW_ARRAY,
-                                                  [v_new_length], v_base,
-                                                  descr=array_descr))
-                # we need to insert another, unrelated NEW_ARRAY here
-                # to prevent the initialization_store optimization
-                operations.insert(1, ResOperation(rop.NEW_ARRAY,
-                                                  [ConstInt(12)], BoxPtr(),
-                                                  descr=array_descr))
-            gc_ll_descr = self.gc_ll_descr
-            operations = get_deep_immutable_oplist(operations)
-            operations = gc_ll_descr.rewrite_assembler(self.fake_cpu,
-                                                       operations, [])
-            if v_new_length is not None:
-                assert operations[0].getopnum() == rop.NEW_ARRAY
-                assert operations[1].getopnum() == rop.NEW_ARRAY
-                del operations[:2]
-            assert len(operations) == 2
-            #
-            assert operations[0].getopnum() == rop.COND_CALL_GC_WB
-            assert operations[0].getarg(0) == v_base
-            assert operations[0].getarg(1) == v_value
-            assert operations[0].result is None
-            #
-            assert operations[1].getopnum() == rop.SETARRAYITEM_RAW
-            assert operations[1].getarg(0) == v_base
-            assert operations[1].getarg(1) == v_index
-            assert operations[1].getarg(2) == v_value
-            assert operations[1].getdescr() == array_descr
-
-    def test_rewrite_assembler_4(self):
-        # check write barriers before SETARRAYITEM_GC,
-        # if we have actually a write_barrier_from_array.
-        self.llop1._have_wb_from_array = True
-        for v_new_length in (None, ConstInt(5), ConstInt(5000), BoxInt()):
-            v_base = BoxPtr()
-            v_index = BoxInt()
-            v_value = BoxPtr()
-            array_descr = AbstractDescr()
-            operations = [
-                ResOperation(rop.SETARRAYITEM_GC, [v_base, v_index, v_value],
-                             None, descr=array_descr),
-                ]
-            if v_new_length is not None:
-                operations.insert(0, ResOperation(rop.NEW_ARRAY,
-                                                  [v_new_length], v_base,
-                                                  descr=array_descr))
-                # we need to insert another, unrelated NEW_ARRAY here
-                # to prevent the initialization_store optimization
-                operations.insert(1, ResOperation(rop.NEW_ARRAY,
-                                                  [ConstInt(12)], BoxPtr(),
-                                                  descr=array_descr))
-            gc_ll_descr = self.gc_ll_descr
-            operations = get_deep_immutable_oplist(operations)
-            operations = gc_ll_descr.rewrite_assembler(self.fake_cpu,
-                                                       operations, [])
-            if v_new_length is not None:
-                assert operations[0].getopnum() == rop.NEW_ARRAY
-                assert operations[1].getopnum() == rop.NEW_ARRAY
-                del operations[:2]
-            assert len(operations) == 2
-            #
-            if isinstance(v_new_length, ConstInt) and v_new_length.value < 130:
-                assert operations[0].getopnum() == rop.COND_CALL_GC_WB
-                assert operations[0].getarg(0) == v_base
-                assert operations[0].getarg(1) == v_value
-            else:
-                assert operations[0].getopnum() == rop.COND_CALL_GC_WB_ARRAY
-                assert operations[0].getarg(0) == v_base
-                assert operations[0].getarg(1) == v_index
-                assert operations[0].getarg(2) == v_value
-            assert operations[0].result is None
-            #
-            assert operations[1].getopnum() == rop.SETARRAYITEM_RAW
-            assert operations[1].getarg(0) == v_base
-            assert operations[1].getarg(1) == v_index
-            assert operations[1].getarg(2) == v_value
-            assert operations[1].getdescr() == array_descr
-
-    def test_rewrite_assembler_5(self):
-        S = lltype.GcStruct('S')
-        A = lltype.GcArray(lltype.Struct('A', ('x', lltype.Ptr(S))))
-        interiordescr = get_interiorfield_descr(self.gc_ll_descr, A,
-                                                A.OF, 'x')
-        wbdescr = self.gc_ll_descr.write_barrier_descr
-        ops = parse("""
-        [p1, p2]
-        setinteriorfield_gc(p1, 0, p2, descr=interiordescr)
-        jump(p1, p2)
-        """, namespace=locals())
-        expected = parse(""" 
-        [p1, p2]
-        cond_call_gc_wb(p1, p2, descr=wbdescr)
-        setinteriorfield_raw(p1, 0, p2, descr=interiordescr)
-        jump(p1, p2)
-        """, namespace=locals())
-        operations = get_deep_immutable_oplist(ops.operations)
-        operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu,
-                                                        operations, [])
-        equaloplists(operations, expected.operations)
-
-    def test_rewrite_assembler_initialization_store(self):
-        S = lltype.GcStruct('S', ('parent', OBJECT),
-                            ('x', lltype.Signed))
-        s_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
-        xdescr = get_field_descr(self.gc_ll_descr, S, 'x')
-        ops = parse("""
-        [p1]
-        p0 = new_with_vtable(ConstClass(s_vtable))
-        setfield_gc(p0, p1, descr=xdescr)
-        jump()
-        """, namespace=locals())
-        expected = parse("""
-        [p1]
-        p0 = new_with_vtable(ConstClass(s_vtable))
-        # no write barrier
-        setfield_gc(p0, p1, descr=xdescr)
-        jump()
-        """, namespace=locals())
-        operations = get_deep_immutable_oplist(ops.operations)
-        operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu,
-                                                        operations, [])
-        equaloplists(operations, expected.operations)
-
-    def test_rewrite_assembler_initialization_store_2(self):
-        S = lltype.GcStruct('S', ('parent', OBJECT),
-                            ('x', lltype.Signed))
-        s_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
-        wbdescr = self.gc_ll_descr.write_barrier_descr
-        xdescr = get_field_descr(self.gc_ll_descr, S, 'x')
-        ops = parse("""
-        [p1]
-        p0 = new_with_vtable(ConstClass(s_vtable))
-        p3 = new_with_vtable(ConstClass(s_vtable))
-        setfield_gc(p0, p1, descr=xdescr)
-        jump()
-        """, namespace=locals())
-        expected = parse("""
-        [p1]
-        p0 = new_with_vtable(ConstClass(s_vtable))
-        p3 = new_with_vtable(ConstClass(s_vtable))
-        cond_call_gc_wb(p0, p1, descr=wbdescr)
-        setfield_raw(p0, p1, descr=xdescr)
-        jump()
-        """, namespace=locals())
-        operations = get_deep_immutable_oplist(ops.operations)
-        operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu,
-                                                        operations, [])
-        equaloplists(operations, expected.operations)
-
-    def test_rewrite_assembler_initialization_store_3(self):
-        A = lltype.GcArray(lltype.Ptr(lltype.GcStruct('S')))
-        arraydescr = get_array_descr(self.gc_ll_descr, A)
-        ops = parse("""
-        [p1]
-        p0 = new_array(3, descr=arraydescr)
-        setarrayitem_gc(p0, 0, p1, descr=arraydescr)
-        jump()
-        """, namespace=locals())
-        expected = parse("""
-        [p1]
-        p0 = new_array(3, descr=arraydescr)
-        setarrayitem_gc(p0, 0, p1, descr=arraydescr)
-        jump()
-        """, namespace=locals())
-        operations = get_deep_immutable_oplist(ops.operations)
-        operations = self.gc_ll_descr.rewrite_assembler(self.fake_cpu,
-                                                        operations, [])
-        equaloplists(operations, expected.operations)
 
 class TestFrameworkMiniMark(TestFramework):
     gc = 'minimark'
diff --git a/pypy/jit/backend/llsupport/test/test_rewrite.py b/pypy/jit/backend/llsupport/test/test_rewrite.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/backend/llsupport/test/test_rewrite.py
@@ -0,0 +1,668 @@
+from pypy.jit.backend.llsupport.descr import *
+from pypy.jit.backend.llsupport.gc import *
+from pypy.jit.metainterp.gc import get_description
+from pypy.jit.tool.oparser import parse
+from pypy.jit.metainterp.optimizeopt.util import equaloplists
+from pypy.jit.codewriter.heaptracker import register_known_gctype
+
+
+class Evaluator(object):
+    def __init__(self, scope):
+        self.scope = scope
+    def __getitem__(self, key):
+        return eval(key, self.scope)
+
+
+class RewriteTests(object):
+    def check_rewrite(self, frm_operations, to_operations, **namespace):
+        S = lltype.GcStruct('S', ('x', lltype.Signed),
+                                 ('y', lltype.Signed))
+        sdescr = get_size_descr(self.gc_ll_descr, S)
+        sdescr.tid = 1234
+        #
+        T = lltype.GcStruct('T', ('y', lltype.Signed),
+                                 ('z', lltype.Ptr(S)),
+                                 ('t', lltype.Signed))
+        tdescr = get_size_descr(self.gc_ll_descr, T)
+        tdescr.tid = 5678
+        tzdescr = get_field_descr(self.gc_ll_descr, T, 'z')
+        #
+        A = lltype.GcArray(lltype.Signed)
+        adescr = get_array_descr(self.gc_ll_descr, A)
+        adescr.tid = 4321
+        alendescr = adescr.lendescr
+        #
+        B = lltype.GcArray(lltype.Char)
+        bdescr = get_array_descr(self.gc_ll_descr, B)
+        bdescr.tid = 8765
+        blendescr = bdescr.lendescr
+        #
+        C = lltype.GcArray(lltype.Ptr(S))
+        cdescr = get_array_descr(self.gc_ll_descr, C)
+        cdescr.tid = 8111
+        clendescr = cdescr.lendescr
+        #
+        E = lltype.GcStruct('Empty')
+        edescr = get_size_descr(self.gc_ll_descr, E)
+        edescr.tid = 9000
+        #
+        vtable_descr = self.gc_ll_descr.fielddescr_vtable
+        O = lltype.GcStruct('O', ('parent', rclass.OBJECT),
+                                 ('x', lltype.Signed))
+        o_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
+        register_known_gctype(self.cpu, o_vtable, O)
+        #
+        tiddescr = self.gc_ll_descr.fielddescr_tid
+        wbdescr = self.gc_ll_descr.write_barrier_descr
+        WORD = globals()['WORD']
+        #
+        strdescr     = self.gc_ll_descr.str_descr
+        unicodedescr = self.gc_ll_descr.unicode_descr
+        strlendescr     = strdescr.lendescr
+        unicodelendescr = unicodedescr.lendescr
+        #
+        namespace.update(locals())
+        #
+        for funcname in self.gc_ll_descr._generated_functions:
+            namespace[funcname] = self.gc_ll_descr.get_malloc_fn(funcname)
+            namespace[funcname + '_descr'] = getattr(self.gc_ll_descr,
+                                                     '%s_descr' % funcname)
+        #
+        ops = parse(frm_operations, namespace=namespace)
+        expected = parse(to_operations % Evaluator(namespace),
+                         namespace=namespace)
+        operations = self.gc_ll_descr.rewrite_assembler(self.cpu,
+                                                        ops.operations,
+                                                        [])
+        equaloplists(operations, expected.operations)
+
+
+class TestBoehm(RewriteTests):
+    def setup_method(self, meth):
+        class FakeCPU(object):
+            def sizeof(self, STRUCT):
+                return SizeDescrWithVTable(102)
+        self.cpu = FakeCPU()
+        self.gc_ll_descr = GcLLDescr_boehm(None, None, None)
+
+    def test_new(self):
+        self.check_rewrite("""
+            []
+            p0 = new(descr=sdescr)
+            jump()
+        """, """
+            [p1]
+            p0 = call_malloc_gc(ConstClass(malloc_fixedsize), %(sdescr.size)d,\
+                                descr=malloc_fixedsize_descr)
+            jump()
+        """)
+
+    def test_no_collapsing(self):
+        self.check_rewrite("""
+            []
+            p0 = new(descr=sdescr)
+            p1 = new(descr=sdescr)
+            jump()
+        """, """
+            []
+            p0 = call_malloc_gc(ConstClass(malloc_fixedsize), %(sdescr.size)d,\
+                                descr=malloc_fixedsize_descr)
+            p1 = call_malloc_gc(ConstClass(malloc_fixedsize), %(sdescr.size)d,\
+                                descr=malloc_fixedsize_descr)
+            jump()
+        """)
+
+    def test_new_array_fixed(self):
+        self.check_rewrite("""
+            []
+            p0 = new_array(10, descr=adescr)
+            jump()
+        """, """
+            []
+            p0 = call_malloc_gc(ConstClass(malloc_fixedsize), \
+                                %(adescr.basesize + 10 * adescr.itemsize)d, \
+                                descr=malloc_fixedsize_descr)
+            setfield_gc(p0, 10, descr=alendescr)
+            jump()
+        """)
+
+    def test_new_array_variable(self):
+        self.check_rewrite("""
+            [i1]
+            p0 = new_array(i1, descr=adescr)
+            jump()
+        """, """
+            [i1]
+            p0 = call_malloc_gc(ConstClass(malloc_array),   \
+                                %(adescr.basesize)d,        \
+                                i1,                         \
+                                %(adescr.itemsize)d,        \
+                                %(adescr.lendescr.offset)d, \
+                                descr=malloc_array_descr)
+            jump()
+        """)
+
+    def test_new_with_vtable(self):
+        self.check_rewrite("""
+            []
+            p0 = new_with_vtable(ConstClass(o_vtable))
+            jump()
+        """, """
+            [p1]
+            p0 = call_malloc_gc(ConstClass(malloc_fixedsize), 102, \
+                                descr=malloc_fixedsize_descr)
+            setfield_gc(p0, ConstClass(o_vtable), descr=vtable_descr)
+            jump()
+        """)
+
+    def test_newstr(self):
+        self.check_rewrite("""
+            [i1]
+            p0 = newstr(i1)
+            jump()
+        """, """
+            [i1]
+            p0 = call_malloc_gc(ConstClass(malloc_array), \
+                                %(strdescr.basesize)d,    \
+                                i1,                       \
+                                %(strdescr.itemsize)d,    \
+                                %(strlendescr.offset)d,   \
+                                descr=malloc_array_descr)
+            jump()
+        """)
+
+    def test_newunicode(self):
+        self.check_rewrite("""
+            [i1]
+            p0 = newunicode(10)
+            jump()
+        """, """
+            [i1]
+            p0 = call_malloc_gc(ConstClass(malloc_fixedsize),   \
+                                %(unicodedescr.basesize +       \
+                                  10 * unicodedescr.itemsize)d, \
+                                descr=malloc_fixedsize_descr)
+            setfield_gc(p0, 10, descr=unicodelendescr)
+            jump()
+        """)
+
+
+class TestFramework(RewriteTests):
+    def setup_method(self, meth):
+        class config_(object):
+            class translation(object):
+                gc = 'hybrid'
+                gcrootfinder = 'asmgcc'
+                gctransformer = 'framework'
+                gcremovetypeptr = False
+        gcdescr = get_description(config_)
+        self.gc_ll_descr = GcLLDescr_framework(gcdescr, None, None, None,
+                                               really_not_translated=True)
+        self.gc_ll_descr.write_barrier_descr.has_write_barrier_from_array = (
+            lambda cpu: True)
+        #
+        class FakeCPU(object):
+            def sizeof(self, STRUCT):
+                descr = SizeDescrWithVTable(102)
+                descr.tid = 9315
+                return descr
+        self.cpu = FakeCPU()
+
+    def test_rewrite_assembler_new_to_malloc(self):
+        self.check_rewrite("""
+            [p1]
+            p0 = new(descr=sdescr)
+            jump()
+        """, """
+            [p1]
+            p0 = call_malloc_nursery(%(sdescr.size)d)
+            setfield_gc(p0, 1234, descr=tiddescr)
+            jump()
+        """)
+
+    def test_rewrite_assembler_new3_to_malloc(self):
+        self.check_rewrite("""
+            []
+            p0 = new(descr=sdescr)
+            p1 = new(descr=tdescr)
+            p2 = new(descr=sdescr)
+            jump()
+        """, """
+            []
+            p0 = call_malloc_nursery(   \
+                               %(sdescr.size + tdescr.size + sdescr.size)d)
+            setfield_gc(p0, 1234, descr=tiddescr)
+            p1 = int_add(p0, %(sdescr.size)d)
+            setfield_gc(p1, 5678, descr=tiddescr)
+            p2 = int_add(p1, %(tdescr.size)d)
+            setfield_gc(p2, 1234, descr=tiddescr)
+            jump()
+        """)
+
+    def test_rewrite_assembler_new_array_fixed_to_malloc(self):
+        self.check_rewrite("""
+            []
+            p0 = new_array(10, descr=adescr)
+            jump()
+        """, """
+            []
+            p0 = call_malloc_nursery(    \
+                                %(adescr.basesize + 10 * adescr.itemsize)d)
+            setfield_gc(p0, 4321, descr=tiddescr)
+            setfield_gc(p0, 10, descr=alendescr)
+            jump()
+        """)
+
+    def test_rewrite_assembler_new_and_new_array_fixed_to_malloc(self):
+        self.check_rewrite("""
+            []
+            p0 = new(descr=sdescr)
+            p1 = new_array(10, descr=adescr)
+            jump()
+        """, """
+            []
+            p0 = call_malloc_nursery(                                  \
+                                %(sdescr.size +                        \
+                                  adescr.basesize + 10 * adescr.itemsize)d)
+            setfield_gc(p0, 1234, descr=tiddescr)
+            p1 = int_add(p0, %(sdescr.size)d)
+            setfield_gc(p1, 4321, descr=tiddescr)
+            setfield_gc(p1, 10, descr=alendescr)
+            jump()
+        """)
+
+    def test_rewrite_assembler_round_up(self):
+        self.check_rewrite("""
+            []
+            p0 = new_array(6, descr=bdescr)
+            jump()
+        """, """
+            []
+            p0 = call_malloc_nursery(%(bdescr.basesize + 8)d)
+            setfield_gc(p0, 8765, descr=tiddescr)
+            setfield_gc(p0, 6, descr=blendescr)
+            jump()
+        """)
+
+    def test_rewrite_assembler_round_up_always(self):
+        self.check_rewrite("""
+            []
+            p0 = new_array(5, descr=bdescr)
+            p1 = new_array(5, descr=bdescr)
+            p2 = new_array(5, descr=bdescr)
+            p3 = new_array(5, descr=bdescr)
+            jump()
+        """, """
+            []
+            p0 = call_malloc_nursery(%(4 * (bdescr.basesize + 8))d)
+            setfield_gc(p0, 8765, descr=tiddescr)
+            setfield_gc(p0, 5, descr=blendescr)
+            p1 = int_add(p0, %(bdescr.basesize + 8)d)
+            setfield_gc(p1, 8765, descr=tiddescr)
+            setfield_gc(p1, 5, descr=blendescr)
+            p2 = int_add(p1, %(bdescr.basesize + 8)d)
+            setfield_gc(p2, 8765, descr=tiddescr)
+            setfield_gc(p2, 5, descr=blendescr)
+            p3 = int_add(p2, %(bdescr.basesize + 8)d)
+            setfield_gc(p3, 8765, descr=tiddescr)
+            setfield_gc(p3, 5, descr=blendescr)
+            jump()
+        """)
+
+    def test_rewrite_assembler_minimal_size(self):
+        self.check_rewrite("""
+            []
+            p0 = new(descr=edescr)
+            p1 = new(descr=edescr)
+            jump()
+        """, """
+            []
+            p0 = call_malloc_nursery(%(4*WORD)d)
+            setfield_gc(p0, 9000, descr=tiddescr)
+            p1 = int_add(p0, %(2*WORD)d)
+            setfield_gc(p1, 9000, descr=tiddescr)
+            jump()
+        """)
+
+    def test_rewrite_assembler_variable_size(self):
+        self.check_rewrite("""
+            [i0]
+            p0 = new_array(i0, descr=bdescr)
+            jump(i0)
+        """, """
+            [i0]
+            p0 = call_malloc_gc(ConstClass(malloc_array), 1,  \
+                                %(bdescr.tid)d, i0,           \
+                                descr=malloc_array_descr)
+            jump(i0)
+        """)
+
+    def test_rewrite_assembler_nonstandard_array(self):
+        # a non-standard array is a bit hard to get; e.g. GcArray(Float)
+        # is like that on Win32, but not on Linux.  Build one manually...
+        NONSTD = lltype.GcArray(lltype.Float)
+        nonstd_descr = get_array_descr(self.gc_ll_descr, NONSTD)
+        nonstd_descr.tid = 6464
+        nonstd_descr.basesize = 64      # <= hacked
+        nonstd_descr.itemsize = 8
+        nonstd_descr_gcref = 123
+        self.check_rewrite("""
+            [i0]
+            p0 = new_array(i0, descr=nonstd_descr)
+            jump(i0)
+        """, """
+            [i0]
+            p0 = call_malloc_gc(ConstClass(malloc_array_nonstandard), \
+                                64, 8,                                \
+                                %(nonstd_descr.lendescr.offset)d,     \
+                                6464, i0,                             \
+                                descr=malloc_array_nonstandard_descr)
+            jump(i0)
+        """, nonstd_descr=nonstd_descr)
+
+    def test_rewrite_assembler_maximal_size_1(self):
+        self.gc_ll_descr.max_size_of_young_obj = 100
+        self.check_rewrite("""
+            []
+            p0 = new_array(103, descr=bdescr)
+            jump()
+        """, """
+            []
+            p0 = call_malloc_gc(ConstClass(malloc_fixedsize), \
+                                %(bdescr.basesize + 104)d,    \
+                                descr=malloc_fixedsize_descr)
+            setfield_gc(p0, 8765, descr=tiddescr)
+            setfield_gc(p0, 103, descr=blendescr)
+            jump()
+        """)
+
+    def test_rewrite_assembler_maximal_size_2(self):
+        self.gc_ll_descr.max_size_of_young_obj = 300
+        self.check_rewrite("""
+            []
+            p0 = new_array(101, descr=bdescr)
+            p1 = new_array(102, descr=bdescr)  # two new_arrays can be combined
+            p2 = new_array(103, descr=bdescr)  # but not all three
+            jump()
+        """, """
+            []
+            p0 = call_malloc_nursery(    \
+                              %(2 * (bdescr.basesize + 104))d)
+            setfield_gc(p0, 8765, descr=tiddescr)
+            setfield_gc(p0, 101, descr=blendescr)
+            p1 = int_add(p0, %(bdescr.basesize + 104)d)
+            setfield_gc(p1, 8765, descr=tiddescr)
+            setfield_gc(p1, 102, descr=blendescr)
+            p2 = call_malloc_nursery(    \
+                              %(bdescr.basesize + 104)d)
+            setfield_gc(p2, 8765, descr=tiddescr)
+            setfield_gc(p2, 103, descr=blendescr)
+            jump()
+        """)
+
+    def test_rewrite_assembler_huge_size(self):
+        # "huge" is defined as "larger than 0xffffff bytes, or 16MB"
+        self.check_rewrite("""
+            []
+            p0 = new_array(20000000, descr=bdescr)
+            jump()
+        """, """
+            []
+            p0 = call_malloc_gc(ConstClass(malloc_array), 1, \
+                                %(bdescr.tid)d, 20000000,    \
+                                descr=malloc_array_descr)
+            jump()
+        """)
+
+    def test_new_with_vtable(self):
+        self.check_rewrite("""
+            []
+            p0 = new_with_vtable(ConstClass(o_vtable))
+            jump()
+        """, """
+            [p1]
+            p0 = call_malloc_nursery(104)      # rounded up
+            setfield_gc(p0, 9315, descr=tiddescr)
+            setfield_gc(p0, ConstClass(o_vtable), descr=vtable_descr)
+            jump()
+        """)
+
+    def test_new_with_vtable_too_big(self):
+        self.gc_ll_descr.max_size_of_young_obj = 100
+        self.check_rewrite("""
+            []
+            p0 = new_with_vtable(ConstClass(o_vtable))
+            jump()
+        """, """
+            [p1]
+            p0 = call_malloc_gc(ConstClass(malloc_fixedsize), 104, \
+                                descr=malloc_fixedsize_descr)
+            setfield_gc(p0, 9315, descr=tiddescr)
+            setfield_gc(p0, ConstClass(o_vtable), descr=vtable_descr)
+            jump()
+        """)
+
+    def test_rewrite_assembler_newstr_newunicode(self):
+        self.check_rewrite("""
+            [i2]
+            p0 = newstr(14)
+            p1 = newunicode(10)
+            p2 = newunicode(i2)
+            p3 = newstr(i2)
+            jump()
+        """, """
+            [i2]
+            p0 = call_malloc_nursery(                                \
+                      %(strdescr.basesize + 16 * strdescr.itemsize + \
+                        unicodedescr.basesize + 10 * unicodedescr.itemsize)d)
+            setfield_gc(p0, %(strdescr.tid)d, descr=tiddescr)
+            setfield_gc(p0, 14, descr=strlendescr)
+            p1 = int_add(p0, %(strdescr.basesize + 16 * strdescr.itemsize)d)
+            setfield_gc(p1, %(unicodedescr.tid)d, descr=tiddescr)
+            setfield_gc(p1, 10, descr=unicodelendescr)
+            p2 = call_malloc_gc(ConstClass(malloc_unicode), i2, \
+                                descr=malloc_unicode_descr)
+            p3 = call_malloc_gc(ConstClass(malloc_str), i2, \
+                                descr=malloc_str_descr)
+            jump()
+        """)
+
+    def test_write_barrier_before_setfield_gc(self):
+        self.check_rewrite("""
+            [p1, p2]
+            setfield_gc(p1, p2, descr=tzdescr)
+            jump()
+        """, """
+            [p1, p2]
+            cond_call_gc_wb(p1, p2, descr=wbdescr)
+            setfield_raw(p1, p2, descr=tzdescr)
+            jump()
+        """)
+
+    def test_write_barrier_before_array_without_from_array(self):
+        self.gc_ll_descr.write_barrier_descr.has_write_barrier_from_array = (
+            lambda cpu: False)
+        self.check_rewrite("""
+            [p1, i2, p3]
+            setarrayitem_gc(p1, i2, p3, descr=cdescr)
+            jump()
+        """, """
+            [p1, i2, p3]
+            cond_call_gc_wb(p1, p3, descr=wbdescr)
+            setarrayitem_raw(p1, i2, p3, descr=cdescr)
+            jump()
+        """)
+
+    def test_write_barrier_before_short_array(self):
+        self.gc_ll_descr.max_size_of_young_obj = 2000
+        self.check_rewrite("""
+            [i2, p3]
+            p1 = new_array(129, descr=cdescr)
+            call(123456)
+            setarrayitem_gc(p1, i2, p3, descr=cdescr)
+            jump()
+        """, """
+            [i2, p3]
+            p1 = call_malloc_nursery(    \
+                                %(cdescr.basesize + 129 * cdescr.itemsize)d)
+            setfield_gc(p1, 8111, descr=tiddescr)
+            setfield_gc(p1, 129, descr=clendescr)
+            call(123456)
+            cond_call_gc_wb(p1, p3, descr=wbdescr)
+            setarrayitem_raw(p1, i2, p3, descr=cdescr)
+            jump()
+        """)
+
+    def test_write_barrier_before_long_array(self):
+        # the limit of "being too long" is fixed, arbitrarily, at 130
+        self.gc_ll_descr.max_size_of_young_obj = 2000
+        self.check_rewrite("""
+            [i2, p3]
+            p1 = new_array(130, descr=cdescr)
+            call(123456)
+            setarrayitem_gc(p1, i2, p3, descr=cdescr)
+            jump()
+        """, """
+            [i2, p3]
+            p1 = call_malloc_nursery(    \
+                                %(cdescr.basesize + 130 * cdescr.itemsize)d)
+            setfield_gc(p1, 8111, descr=tiddescr)
+            setfield_gc(p1, 130, descr=clendescr)
+            call(123456)
+            cond_call_gc_wb_array(p1, i2, p3, descr=wbdescr)
+            setarrayitem_raw(p1, i2, p3, descr=cdescr)
+            jump()
+        """)
+
+    def test_write_barrier_before_unknown_array(self):
+        self.check_rewrite("""
+            [p1, i2, p3]
+            setarrayitem_gc(p1, i2, p3, descr=cdescr)
+            jump()
+        """, """
+            [p1, i2, p3]
+            cond_call_gc_wb_array(p1, i2, p3, descr=wbdescr)
+            setarrayitem_raw(p1, i2, p3, descr=cdescr)
+            jump()
+        """)
+
+    def test_label_makes_size_unknown(self):
+        self.check_rewrite("""
+            [i2, p3]
+            p1 = new_array(5, descr=cdescr)
+            label(p1, i2, p3)
+            setarrayitem_gc(p1, i2, p3, descr=cdescr)
+            jump()
+        """, """
+            [i2, p3]
+            p1 = call_malloc_nursery(    \
+                                %(cdescr.basesize + 5 * cdescr.itemsize)d)
+            setfield_gc(p1, 8111, descr=tiddescr)
+            setfield_gc(p1, 5, descr=clendescr)
+            label(p1, i2, p3)
+            cond_call_gc_wb_array(p1, i2, p3, descr=wbdescr)
+            setarrayitem_raw(p1, i2, p3, descr=cdescr)
+            jump()
+        """)
+
+    def test_write_barrier_before_setinteriorfield_gc(self):
+        S1 = lltype.GcStruct('S1')
+        INTERIOR = lltype.GcArray(('z', lltype.Ptr(S1)))
+        interiordescr = get_array_descr(self.gc_ll_descr, INTERIOR)
+        interiordescr.tid = 1291
+        interiorlendescr = interiordescr.lendescr
+        interiorzdescr = get_interiorfield_descr(self.gc_ll_descr,
+                                                 INTERIOR, 'z')
+        self.check_rewrite("""
+            [p1, p2]
+            setinteriorfield_gc(p1, 0, p2, descr=interiorzdescr)
+            jump(p1, p2)
+        """, """
+            [p1, p2]
+            cond_call_gc_wb(p1, p2, descr=wbdescr)
+            setinteriorfield_raw(p1, 0, p2, descr=interiorzdescr)
+            jump(p1, p2)
+        """, interiorzdescr=interiorzdescr)
+
+    def test_initialization_store(self):
+        self.check_rewrite("""
+            [p1]
+            p0 = new(descr=tdescr)
+            setfield_gc(p0, p1, descr=tzdescr)
+            jump()
+        """, """
+            [p1]
+            p0 = call_malloc_nursery(%(tdescr.size)d)
+            setfield_gc(p0, 5678, descr=tiddescr)
+            setfield_gc(p0, p1, descr=tzdescr)
+            jump()
+        """)
+
+    def test_initialization_store_2(self):
+        self.check_rewrite("""
+            []
+            p0 = new(descr=tdescr)
+            p1 = new(descr=sdescr)
+            setfield_gc(p0, p1, descr=tzdescr)
+            jump()
+        """, """
+            []
+            p0 = call_malloc_nursery(%(tdescr.size + sdescr.size)d)
+            setfield_gc(p0, 5678, descr=tiddescr)
+            p1 = int_add(p0, %(tdescr.size)d)
+            setfield_gc(p1, 1234, descr=tiddescr)
+            # <<<no cond_call_gc_wb here>>>
+            setfield_gc(p0, p1, descr=tzdescr)
+            jump()
+        """)
+
+    def test_initialization_store_array(self):
+        self.check_rewrite("""
+            [p1, i2]
+            p0 = new_array(5, descr=cdescr)
+            setarrayitem_gc(p0, i2, p1, descr=cdescr)
+            jump()
+        """, """
+            [p1, i2]
+            p0 = call_malloc_nursery(    \
+                                %(cdescr.basesize + 5 * cdescr.itemsize)d)
+            setfield_gc(p0, 8111, descr=tiddescr)
+            setfield_gc(p0, 5, descr=clendescr)
+            setarrayitem_gc(p0, i2, p1, descr=cdescr)
+            jump()
+        """)
+
+    def test_non_initialization_store(self):
+        self.check_rewrite("""
+            [i0]
+            p0 = new(descr=tdescr)
+            p1 = newstr(i0)
+            setfield_gc(p0, p1, descr=tzdescr)
+            jump()
+        """, """
+            [i0]
+            p0 = call_malloc_nursery(%(tdescr.size)d)
+            setfield_gc(p0, 5678, descr=tiddescr)
+            p1 = call_malloc_gc(ConstClass(malloc_str), i0, \
+                                descr=malloc_str_descr)
+            cond_call_gc_wb(p0, p1, descr=wbdescr)
+            setfield_raw(p0, p1, descr=tzdescr)
+            jump()
+        """)
+
+    def test_non_initialization_store_label(self):
+        self.check_rewrite("""
+            [p1]
+            p0 = new(descr=tdescr)
+            label(p0, p1)
+            setfield_gc(p0, p1, descr=tzdescr)
+            jump()
+        """, """
+            [p1]
+            p0 = call_malloc_nursery(%(tdescr.size)d)
+            setfield_gc(p0, 5678, descr=tiddescr)
+            label(p0, p1)
+            cond_call_gc_wb(p0, p1, descr=wbdescr)
+            setfield_raw(p0, p1, descr=tzdescr)
+            jump()
+        """)
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
@@ -2930,6 +2930,8 @@
         # overflowing value:
         fail = self.cpu.execute_token(looptoken, sys.maxint // 4 + 1)
         assert fail.identifier == excdescr.identifier
+        exc = self.cpu.grab_exc_value()
+        assert exc == "memoryerror!"
 
     def test_compile_loop_with_target(self):
         i0 = BoxInt()
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
@@ -70,10 +70,6 @@
         self.cpu = cpu
         self.verbose = False
         self.rtyper = cpu.rtyper
-        self.malloc_func_addr = 0
-        self.malloc_array_func_addr = 0
-        self.malloc_str_func_addr = 0
-        self.malloc_unicode_func_addr = 0
         self.fail_boxes_int = values_array(lltype.Signed, failargs_limit)
         self.fail_boxes_ptr = values_array(llmemory.GCREF, failargs_limit)
         self.fail_boxes_float = values_array(longlong.FLOATSTORAGE,
@@ -108,20 +104,6 @@
         # the address of the function called by 'new'
         gc_ll_descr = self.cpu.gc_ll_descr
         gc_ll_descr.initialize()
-        ll_new = gc_ll_descr.get_funcptr_for_new()
-        self.malloc_func_addr = rffi.cast(lltype.Signed, ll_new)
-        if gc_ll_descr.get_funcptr_for_newarray is not None:
-            ll_new_array = gc_ll_descr.get_funcptr_for_newarray()
-            self.malloc_array_func_addr = rffi.cast(lltype.Signed,
-                                                    ll_new_array)
-        if gc_ll_descr.get_funcptr_for_newstr is not None:
-            ll_new_str = gc_ll_descr.get_funcptr_for_newstr()
-            self.malloc_str_func_addr = rffi.cast(lltype.Signed,
-                                                  ll_new_str)
-        if gc_ll_descr.get_funcptr_for_newunicode is not None:
-            ll_new_unicode = gc_ll_descr.get_funcptr_for_newunicode()
-            self.malloc_unicode_func_addr = rffi.cast(lltype.Signed,
-                                                      ll_new_unicode)
         self.memcpy_addr = self.cpu.cast_ptr_to_int(support.memcpy_fn)
         self._build_failure_recovery(False)
         self._build_failure_recovery(True)
@@ -275,7 +257,8 @@
         #
         self.mc = codebuf.MachineCodeBlockWrapper()
         # call on_leave_jitted_save_exc()
-        addr = self.cpu.get_on_leave_jitted_int(save_exception=True)
+        addr = self.cpu.get_on_leave_jitted_int(save_exception=True,
+                                                default_to_memoryerror=True)
         self.mc.CALL(imm(addr))
         self.mc.MOV_ri(eax.value, self.cpu.propagate_exception_v)
         self._call_footer()
@@ -865,8 +848,8 @@
         high_part = rffi.cast(rffi.CArrayPtr(rffi.INT), from_loc.value)[1]
         low_part  = intmask(low_part)
         high_part = intmask(high_part)
-        self.mc.MOV_bi(to_loc.value,     low_part)
-        self.mc.MOV_bi(to_loc.value + 4, high_part)
+        self.mc.MOV32_bi(to_loc.value,     low_part)
+        self.mc.MOV32_bi(to_loc.value + 4, high_part)
 
     def regalloc_perform(self, op, arglocs, resloc):
         genop_list[op.getopnum()](self, op, arglocs, resloc)
@@ -1357,46 +1340,10 @@
         self.mc.SHR_ri(resloc.value, 7)
         self.mc.AND_ri(resloc.value, 1)
 
-    def genop_new_with_vtable(self, op, arglocs, result_loc):
-        assert result_loc is eax
-        loc_vtable = arglocs[-1]
-        assert isinstance(loc_vtable, ImmedLoc)
-        arglocs = arglocs[:-1]
-        self.call(self.malloc_func_addr, arglocs, eax)
-        self.propagate_memoryerror_if_eax_is_null()
-        self.set_vtable(eax, loc_vtable)
+    # ----------
 
-    def set_vtable(self, loc, loc_vtable):
-        if self.cpu.vtable_offset is not None:
-            assert isinstance(loc, RegLoc)
-            assert isinstance(loc_vtable, ImmedLoc)
-            self.mc.MOV(mem(loc, self.cpu.vtable_offset), loc_vtable)
-
-    def set_new_array_length(self, loc, ofs_length, loc_num_elem):
-        assert isinstance(loc, RegLoc)
-        assert isinstance(loc_num_elem, ImmedLoc)
-        self.mc.MOV(mem(loc, ofs_length), loc_num_elem)
-
-    # XXX genop_new is abused for all varsized mallocs with Boehm, for now
-    # (instead of genop_new_array, genop_newstr, genop_newunicode)
-    def genop_new(self, op, arglocs, result_loc):
-        assert result_loc is eax
-        self.call(self.malloc_func_addr, arglocs, eax)
-        self.propagate_memoryerror_if_eax_is_null()
-
-    def genop_new_array(self, op, arglocs, result_loc):
-        assert result_loc is eax
-        self.call(self.malloc_array_func_addr, arglocs, eax)
-        self.propagate_memoryerror_if_eax_is_null()
-
-    def genop_newstr(self, op, arglocs, result_loc):
-        assert result_loc is eax
-        self.call(self.malloc_str_func_addr, arglocs, eax)
-        self.propagate_memoryerror_if_eax_is_null()
-
-    def genop_newunicode(self, op, arglocs, result_loc):
-        assert result_loc is eax
-        self.call(self.malloc_unicode_func_addr, arglocs, eax)
+    def genop_call_malloc_gc(self, op, arglocs, result_loc):
+        self.genop_call(op, arglocs, result_loc)
         self.propagate_memoryerror_if_eax_is_null()
 
     def propagate_memoryerror_if_eax_is_null(self):
@@ -2065,6 +2012,8 @@
         self._genop_call(op, arglocs, resloc, force_index)
 
     def _genop_call(self, op, arglocs, resloc, force_index):
+        from pypy.jit.backend.llsupport.descr import CallDescr
+
         sizeloc = arglocs[0]
         assert isinstance(sizeloc, ImmedLoc)
         size = sizeloc.value
@@ -2079,13 +2028,16 @@
         else:
             tmp = eax
 
+        descr = op.getdescr()
+        assert isinstance(descr, CallDescr)
+
         self._emit_call(force_index, x, arglocs, 3, tmp=tmp,
-                        argtypes=op.getdescr().get_arg_types(),
-                        callconv=op.getdescr().get_call_conv())
+                        argtypes=descr.get_arg_types(),
+                        callconv=descr.get_call_conv())
 
         if IS_X86_32 and isinstance(resloc, StackLoc) and resloc.type == FLOAT:
             # a float or a long long return
-            if op.getdescr().get_return_type() == 'L':
+            if descr.get_result_type() == 'L':
                 self.mc.MOV_br(resloc.value, eax.value)      # long long
                 self.mc.MOV_br(resloc.value + 4, edx.value)
                 # XXX should ideally not move the result on the stack,
@@ -2094,7 +2046,7 @@
                 #     can just be always a stack location
             else:
                 self.mc.FSTPL_b(resloc.value)   # float return
-        elif op.getdescr().get_return_type() == 'S':
+        elif descr.get_result_type() == 'S':
             # singlefloat return
             assert resloc is eax
             if IS_X86_32:
@@ -2292,9 +2244,9 @@
         #
         # Reset the vable token --- XXX really too much special logic here:-(
         if jd.index_of_virtualizable >= 0:
-            from pypy.jit.backend.llsupport.descr import BaseFieldDescr
+            from pypy.jit.backend.llsupport.descr import FieldDescr
             fielddescr = jd.vable_token_descr
-            assert isinstance(fielddescr, BaseFieldDescr)
+            assert isinstance(fielddescr, FieldDescr)
             ofs = fielddescr.offset
             self.mc.MOV(eax, arglocs[1])
             self.mc.MOV_mi((eax.value, ofs), 0)
@@ -2497,9 +2449,8 @@
         else:
             self.mc.JMP(imm(target))
 
-    def malloc_cond(self, nursery_free_adr, nursery_top_adr, size, tid):
-        size = max(size, self.cpu.gc_ll_descr.minimal_size_in_nursery)
-        size = (size + WORD-1) & ~(WORD-1)     # round up
+    def malloc_cond(self, nursery_free_adr, nursery_top_adr, size):
+        assert size & (WORD-1) == 0     # must be correctly aligned
         self.mc.MOV(eax, heap(nursery_free_adr))
         self.mc.LEA_rm(edx.value, (eax.value, size))
         self.mc.CMP(edx, heap(nursery_top_adr))
@@ -2535,9 +2486,6 @@
         offset = self.mc.get_relative_pos() - jmp_adr
         assert 0 < offset <= 127
         self.mc.overwrite(jmp_adr-1, chr(offset))
-        # on 64-bits, 'tid' is a value that fits in 31 bits
-        assert rx86.fits_in_32bits(tid)
-        self.mc.MOV_mi((eax.value, 0), tid)
         self.mc.MOV(heap(nursery_free_adr), edx)
 
 genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST
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
@@ -16,8 +16,8 @@
 from pypy.jit.codewriter import heaptracker, longlong
 from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.jit.metainterp.resoperation import rop
-from pypy.jit.backend.llsupport.descr import BaseFieldDescr, BaseArrayDescr
-from pypy.jit.backend.llsupport.descr import BaseCallDescr, BaseSizeDescr
+from pypy.jit.backend.llsupport.descr import FieldDescr, ArrayDescr
+from pypy.jit.backend.llsupport.descr import CallDescr, SizeDescr
 from pypy.jit.backend.llsupport.descr import InteriorFieldDescr
 from pypy.jit.backend.llsupport.regalloc import FrameManager, RegisterManager,\
      TempBox
@@ -870,9 +870,9 @@
 
     def _consider_call(self, op, guard_not_forced_op=None):
         calldescr = op.getdescr()
-        assert isinstance(calldescr, BaseCallDescr)
+        assert isinstance(calldescr, CallDescr)
         assert len(calldescr.arg_classes) == op.numargs() - 1
-        size = calldescr.get_result_size(self.translate_support_code)
+        size = calldescr.get_result_size()
         sign = calldescr.is_result_signed()
         if sign:
             sign_loc = imm1
@@ -917,12 +917,15 @@
 
     consider_call_release_gil = consider_call_may_force
 
+    def consider_call_malloc_gc(self, op):
+        self._consider_call(op)
+
     def consider_call_assembler(self, op, guard_op):
         descr = op.getdescr()
         assert isinstance(descr, JitCellToken)
         jd = descr.outermost_jitdriver_sd
         assert jd is not None
-        size = jd.portal_calldescr.get_result_size(self.translate_support_code)
+        size = jd.portal_calldescr.get_result_size()
         vable_index = jd.index_of_virtualizable
         if vable_index >= 0:
             self.rm._sync_var(op.getarg(vable_index))
@@ -957,21 +960,10 @@
 
     consider_cond_call_gc_wb_array = consider_cond_call_gc_wb
 
-    def fastpath_malloc_fixedsize(self, op, descr):
-        assert isinstance(descr, BaseSizeDescr)
-        self._do_fastpath_malloc(op, descr.size, descr.tid)
-
-    def fastpath_malloc_varsize(self, op, arraydescr, num_elem):
-        assert isinstance(arraydescr, BaseArrayDescr)
-        ofs_length = arraydescr.get_ofs_length(self.translate_support_code)
-        basesize = arraydescr.get_base_size(self.translate_support_code)
-        itemsize = arraydescr.get_item_size(self.translate_support_code)
-        size = basesize + itemsize * num_elem
-        self._do_fastpath_malloc(op, size, arraydescr.tid)
-        self.assembler.set_new_array_length(eax, ofs_length, imm(num_elem))
-
-    def _do_fastpath_malloc(self, op, size, tid):
-        gc_ll_descr = self.assembler.cpu.gc_ll_descr
+    def consider_call_malloc_nursery(self, op):
+        size_box = op.getarg(0)
+        assert isinstance(size_box, ConstInt)
+        size = size_box.getint()
         self.rm.force_allocate_reg(op.result, selected_reg=eax)
         #
         # We need edx as a temporary, but otherwise don't save any more
@@ -980,86 +972,39 @@
         self.rm.force_allocate_reg(tmp_box, selected_reg=edx)
         self.rm.possibly_free_var(tmp_box)
         #
+        gc_ll_descr = self.assembler.cpu.gc_ll_descr
         self.assembler.malloc_cond(
             gc_ll_descr.get_nursery_free_addr(),
             gc_ll_descr.get_nursery_top_addr(),
-            size, tid,
-            )
-
-    def consider_new(self, op):
-        gc_ll_descr = self.assembler.cpu.gc_ll_descr
-        if gc_ll_descr.can_inline_malloc(op.getdescr()):
-            self.fastpath_malloc_fixedsize(op, op.getdescr())
-        else:
-            args = gc_ll_descr.args_for_new(op.getdescr())
-            arglocs = [imm(x) for x in args]
-            return self._call(op, arglocs)
-
-    def consider_new_with_vtable(self, op):
-        classint = op.getarg(0).getint()
-        descrsize = heaptracker.vtable2descr(self.assembler.cpu, classint)
-        if self.assembler.cpu.gc_ll_descr.can_inline_malloc(descrsize):
-            self.fastpath_malloc_fixedsize(op, descrsize)
-            self.assembler.set_vtable(eax, imm(classint))
-            # result of fastpath malloc is in eax
-        else:
-            args = self.assembler.cpu.gc_ll_descr.args_for_new(descrsize)
-            arglocs = [imm(x) for x in args]
-            arglocs.append(self.loc(op.getarg(0)))
-            return self._call(op, arglocs)
-
-    def consider_newstr(self, op):
-        loc = self.loc(op.getarg(0))
-        return self._call(op, [loc])
-
-    def consider_newunicode(self, op):
-        loc = self.loc(op.getarg(0))
-        return self._call(op, [loc])
-
-    def consider_new_array(self, op):
-        gc_ll_descr = self.assembler.cpu.gc_ll_descr
-        box_num_elem = op.getarg(0)
-        if isinstance(box_num_elem, ConstInt):
-            num_elem = box_num_elem.value
-            if gc_ll_descr.can_inline_malloc_varsize(op.getdescr(),
-                                                     num_elem):
-                self.fastpath_malloc_varsize(op, op.getdescr(), num_elem)
-                return
-        args = self.assembler.cpu.gc_ll_descr.args_for_new_array(
-            op.getdescr())
-        arglocs = [imm(x) for x in args]
-        arglocs.append(self.loc(box_num_elem))
-        self._call(op, arglocs)
+            size)
 
     def _unpack_arraydescr(self, arraydescr):
-        assert isinstance(arraydescr, BaseArrayDescr)
-        ofs_length = arraydescr.get_ofs_length(self.translate_support_code)
-        ofs = arraydescr.get_base_size(self.translate_support_code)
-        size = arraydescr.get_item_size(self.translate_support_code)
-        ptr = arraydescr.is_array_of_pointers()
+        assert isinstance(arraydescr, ArrayDescr)
+        ofs = arraydescr.basesize
+        size = arraydescr.itemsize
         sign = arraydescr.is_item_signed()
-        return size, ofs, ofs_length, ptr, sign
+        return size, ofs, sign
 
     def _unpack_fielddescr(self, fielddescr):
-        assert isinstance(fielddescr, BaseFieldDescr)
+        assert isinstance(fielddescr, FieldDescr)
         ofs = fielddescr.offset
-        size = fielddescr.get_field_size(self.translate_support_code)
-        ptr = fielddescr.is_pointer_field()
+        size = fielddescr.field_size
         sign = fielddescr.is_field_signed()
-        return imm(ofs), imm(size), ptr, sign
+        return imm(ofs), imm(size), sign
+    _unpack_fielddescr._always_inline_ = True
 
     def _unpack_interiorfielddescr(self, descr):
         assert isinstance(descr, InteriorFieldDescr)
         arraydescr = descr.arraydescr
-        ofs = arraydescr.get_base_size(self.translate_support_code)
-        itemsize = arraydescr.get_item_size(self.translate_support_code)
-        fieldsize = descr.fielddescr.get_field_size(self.translate_support_code)
+        ofs = arraydescr.basesize
+        itemsize = arraydescr.itemsize
+        fieldsize = descr.fielddescr.field_size
         sign = descr.fielddescr.is_field_signed()
         ofs += descr.fielddescr.offset
         return imm(ofs), imm(itemsize), imm(fieldsize), sign
 
     def consider_setfield_gc(self, op):
-        ofs_loc, size_loc, _, _ = self._unpack_fielddescr(op.getdescr())
+        ofs_loc, size_loc, _ = self._unpack_fielddescr(op.getdescr())
         assert isinstance(size_loc, ImmedLoc)
         if size_loc.value == 1:
             need_lower_byte = True
@@ -1117,7 +1062,7 @@
     consider_unicodesetitem = consider_strsetitem
 
     def consider_setarrayitem_gc(self, op):
-        itemsize, ofs, _, _, _ = self._unpack_arraydescr(op.getdescr())
+        itemsize, ofs, _ = self._unpack_arraydescr(op.getdescr())
         args = op.getarglist()
         base_loc  = self.rm.make_sure_var_in_reg(op.getarg(0), args)
         if itemsize == 1:
@@ -1134,7 +1079,7 @@
     consider_setarrayitem_raw = consider_setarrayitem_gc
 
     def consider_getfield_gc(self, op):
-        ofs_loc, size_loc, _, sign = self._unpack_fielddescr(op.getdescr())
+        ofs_loc, size_loc, sign = self._unpack_fielddescr(op.getdescr())
         args = op.getarglist()
         base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args)
         self.rm.possibly_free_vars(args)
@@ -1150,7 +1095,7 @@
     consider_getfield_gc_pure = consider_getfield_gc
 
     def consider_getarrayitem_gc(self, op):
-        itemsize, ofs, _, _, sign = self._unpack_arraydescr(op.getdescr())
+        itemsize, ofs, sign = self._unpack_arraydescr(op.getdescr())
         args = op.getarglist()
         base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args)
         ofs_loc = self.rm.make_sure_var_in_reg(op.getarg(1), args)
@@ -1229,8 +1174,8 @@
 
     def consider_arraylen_gc(self, op):
         arraydescr = op.getdescr()
-        assert isinstance(arraydescr, BaseArrayDescr)
-        ofs = arraydescr.get_ofs_length(self.translate_support_code)
+        assert isinstance(arraydescr, ArrayDescr)
+        ofs = arraydescr.lendescr.offset
         args = op.getarglist()
         base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args)
         self.rm.possibly_free_vars_for_op(op)
diff --git a/pypy/jit/backend/x86/test/test_gc_integration.py b/pypy/jit/backend/x86/test/test_gc_integration.py
--- a/pypy/jit/backend/x86/test/test_gc_integration.py
+++ b/pypy/jit/backend/x86/test/test_gc_integration.py
@@ -8,7 +8,7 @@
 from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.jit.codewriter import heaptracker
 from pypy.jit.codewriter.effectinfo import EffectInfo
-from pypy.jit.backend.llsupport.descr import GcCache
+from pypy.jit.backend.llsupport.descr import GcCache, FieldDescr, FLAG_SIGNED
 from pypy.jit.backend.llsupport.gc import GcLLDescription
 from pypy.jit.backend.detect_cpu import getcpuclass
 from pypy.jit.backend.x86.regalloc import RegAlloc
@@ -17,7 +17,7 @@
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rpython.lltypesystem import rclass, rstr
-from pypy.jit.backend.llsupport.gc import GcLLDescr_framework, GcPtrFieldDescr
+from pypy.jit.backend.llsupport.gc import GcLLDescr_framework
 
 from pypy.jit.backend.x86.test.test_regalloc import MockAssembler
 from pypy.jit.backend.x86.test.test_regalloc import BaseTestRegalloc
@@ -41,20 +41,15 @@
         return ['compressed'] + shape[1:]
 
 class MockGcDescr(GcCache):
-    def get_funcptr_for_new(self):
-        return 123
-    get_funcptr_for_newarray = get_funcptr_for_new
-    get_funcptr_for_newstr = get_funcptr_for_new
-    get_funcptr_for_newunicode = get_funcptr_for_new
     get_malloc_slowpath_addr = None
-
+    write_barrier_descr = None
     moving_gc = True
     gcrootmap = MockGcRootMap()
 
     def initialize(self):
         pass
 
-    record_constptrs = GcLLDescr_framework.record_constptrs.im_func
+    _record_constptrs = GcLLDescr_framework._record_constptrs.im_func
     rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func
 
 class TestRegallocDirectGcIntegration(object):
@@ -170,42 +165,32 @@
         '''
         self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0, 0], run=False)
 
+NOT_INITIALIZED = chr(0xdd)
+
 class GCDescrFastpathMalloc(GcLLDescription):
     gcrootmap = None
-    expected_malloc_slowpath_size = WORD*2
+    write_barrier_descr = None
 
     def __init__(self):
-        GcCache.__init__(self, False)
+        GcLLDescription.__init__(self, None)
         # create a nursery
-        NTP = rffi.CArray(lltype.Signed)
-        self.nursery = lltype.malloc(NTP, 16, flavor='raw')
-        self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 3,
+        NTP = rffi.CArray(lltype.Char)
+        self.nursery = lltype.malloc(NTP, 64, flavor='raw')
+        for i in range(64):
+            self.nursery[i] = NOT_INITIALIZED
+        self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 2,
                                    flavor='raw')
         self.addrs[0] = rffi.cast(lltype.Signed, self.nursery)
-        self.addrs[1] = self.addrs[0] + 16*WORD
-        self.addrs[2] = 0
-        # 16 WORDs
+        self.addrs[1] = self.addrs[0] + 64
+        self.calls = []
         def malloc_slowpath(size):
-            assert size == self.expected_malloc_slowpath_size
+            self.calls.append(size)
+            # reset the nursery
             nadr = rffi.cast(lltype.Signed, self.nursery)
             self.addrs[0] = nadr + size
-            self.addrs[2] += 1
             return nadr
-        self.malloc_slowpath = malloc_slowpath
-        self.MALLOC_SLOWPATH = lltype.FuncType([lltype.Signed],
-                                               lltype.Signed)
-        self._counter = 123000
-
-    def can_inline_malloc(self, descr):
-        return True
-
-    def get_funcptr_for_new(self):
-        return 42
-#        return llhelper(lltype.Ptr(self.NEW_TP), self.new)
-
-    def init_size_descr(self, S, descr):
-        descr.tid = self._counter
-        self._counter += 1
+        self.generate_function('malloc_nursery', malloc_slowpath,
+                               [lltype.Signed], lltype.Signed)
 
     def get_nursery_free_addr(self):
         return rffi.cast(lltype.Signed, self.addrs)
@@ -214,204 +199,61 @@
         return rffi.cast(lltype.Signed, self.addrs) + WORD
 
     def get_malloc_slowpath_addr(self):
-        fptr = llhelper(lltype.Ptr(self.MALLOC_SLOWPATH), self.malloc_slowpath)
-        return rffi.cast(lltype.Signed, fptr)
+        return self.get_malloc_fn_addr('malloc_nursery')
 
-    get_funcptr_for_newarray = None
-    get_funcptr_for_newstr = None
-    get_funcptr_for_newunicode = None
+    def check_nothing_in_nursery(self):
+        # CALL_MALLOC_NURSERY should not write anything in the nursery
+        for i in range(64):
+            assert self.nursery[i] == NOT_INITIALIZED
 
 class TestMallocFastpath(BaseTestRegalloc):
 
     def setup_method(self, method):
         cpu = CPU(None, None)
-        cpu.vtable_offset = WORD
         cpu.gc_ll_descr = GCDescrFastpathMalloc()
         cpu.setup_once()
+        self.cpu = cpu
 
-        # hack: specify 'tid' explicitly, because this test is not running
-        # with the gc transformer
-        NODE = lltype.GcStruct('node', ('tid', lltype.Signed),
-                                       ('value', lltype.Signed))
-        nodedescr = cpu.sizeof(NODE)
-        valuedescr = cpu.fielddescrof(NODE, 'value')
-
-        self.cpu = cpu
-        self.nodedescr = nodedescr
-        vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
-        vtable_int = cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(vtable))
-        NODE2 = lltype.GcStruct('node2',
-                                  ('parent', rclass.OBJECT),
-                                  ('tid', lltype.Signed),
-                                  ('vtable', lltype.Ptr(rclass.OBJECT_VTABLE)))
-        descrsize = cpu.sizeof(NODE2)
-        heaptracker.register_known_gctype(cpu, vtable, NODE2)
-        self.descrsize = descrsize
-        self.vtable_int = vtable_int
-
-        self.namespace = locals().copy()
-        
     def test_malloc_fastpath(self):
         ops = '''
-        [i0]
-        p0 = new(descr=nodedescr)
-        setfield_gc(p0, i0, descr=valuedescr)
-        finish(p0)
+        []
+        p0 = call_malloc_nursery(16)
+        p1 = call_malloc_nursery(32)
+        p2 = call_malloc_nursery(16)
+        finish(p0, p1, p2)
         '''
-        self.interpret(ops, [42])
-        # check the nursery
+        self.interpret(ops, [])
+        # check the returned pointers
         gc_ll_descr = self.cpu.gc_ll_descr
-        assert gc_ll_descr.nursery[0] == self.nodedescr.tid
-        assert gc_ll_descr.nursery[1] == 42
         nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
-        assert gc_ll_descr.addrs[0] == nurs_adr + (WORD*2)
-        assert gc_ll_descr.addrs[2] == 0   # slowpath never called
+        ref = self.cpu.get_latest_value_ref
+        assert rffi.cast(lltype.Signed, ref(0)) == nurs_adr + 0
+        assert rffi.cast(lltype.Signed, ref(1)) == nurs_adr + 16
+        assert rffi.cast(lltype.Signed, ref(2)) == nurs_adr + 48
+        # check the nursery content and state
+        gc_ll_descr.check_nothing_in_nursery()
+        assert gc_ll_descr.addrs[0] == nurs_adr + 64
+        # slowpath never called
+        assert gc_ll_descr.calls == []
 
     def test_malloc_slowpath(self):
         ops = '''
         []
-        p0 = new(descr=nodedescr)
-        p1 = new(descr=nodedescr)
-        p2 = new(descr=nodedescr)
-        p3 = new(descr=nodedescr)
-        p4 = new(descr=nodedescr)
-        p5 = new(descr=nodedescr)
-        p6 = new(descr=nodedescr)
-        p7 = new(descr=nodedescr)
-        p8 = new(descr=nodedescr)
-        finish(p0, p1, p2, p3, p4, p5, p6, p7, p8)
+        p0 = call_malloc_nursery(16)
+        p1 = call_malloc_nursery(32)
+        p2 = call_malloc_nursery(24)     # overflow
+        finish(p0, p1, p2)
         '''
         self.interpret(ops, [])
+        # check the returned pointers
+        gc_ll_descr = self.cpu.gc_ll_descr
+        nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
+        ref = self.cpu.get_latest_value_ref
+        assert rffi.cast(lltype.Signed, ref(0)) == nurs_adr + 0
+        assert rffi.cast(lltype.Signed, ref(1)) == nurs_adr + 16
+        assert rffi.cast(lltype.Signed, ref(2)) == nurs_adr + 0
+        # check the nursery content and state
+        gc_ll_descr.check_nothing_in_nursery()
+        assert gc_ll_descr.addrs[0] == nurs_adr + 24
         # this should call slow path once
-        gc_ll_descr = self.cpu.gc_ll_descr
-        nadr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
-        assert gc_ll_descr.addrs[0] == nadr + (WORD*2)
-        assert gc_ll_descr.addrs[2] == 1   # slowpath called once
-
-    def test_new_with_vtable(self):
-        ops = '''
-        [i0, i1]
-        p0 = new_with_vtable(ConstClass(vtable))
-        guard_class(p0, ConstClass(vtable)) [i0]
-        finish(i1)
-        '''
-        self.interpret(ops, [0, 1])
-        assert self.getint(0) == 1
-        gc_ll_descr = self.cpu.gc_ll_descr
-        assert gc_ll_descr.nursery[0] == self.descrsize.tid
-        assert gc_ll_descr.nursery[1] == self.vtable_int
-        nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
-        assert gc_ll_descr.addrs[0] == nurs_adr + (WORD*3)
-        assert gc_ll_descr.addrs[2] == 0   # slowpath never called
-
-
-class Seen(Exception):
-    pass
-
-class GCDescrFastpathMallocVarsize(GCDescrFastpathMalloc):
-    def can_inline_malloc_varsize(self, arraydescr, num_elem):
-        return num_elem < 5
-    def get_funcptr_for_newarray(self):
-        return 52
-    def init_array_descr(self, A, descr):
-        descr.tid = self._counter
-        self._counter += 1
-    def args_for_new_array(self, descr):
-        raise Seen("args_for_new_array")
-
-class TestMallocVarsizeFastpath(BaseTestRegalloc):
-    def setup_method(self, method):
-        cpu = CPU(None, None)
-        cpu.vtable_offset = WORD
-        cpu.gc_ll_descr = GCDescrFastpathMallocVarsize()
-        cpu.setup_once()
-        self.cpu = cpu
-
-        ARRAY = lltype.GcArray(lltype.Signed)
-        arraydescr = cpu.arraydescrof(ARRAY)
-        self.arraydescr = arraydescr
-        ARRAYCHAR = lltype.GcArray(lltype.Char)
-        arraychardescr = cpu.arraydescrof(ARRAYCHAR)
-
-        self.namespace = locals().copy()
-
-    def test_malloc_varsize_fastpath(self):
-        # Hack.  Running the GcLLDescr_framework without really having
-        # a complete GC means that we end up with both the tid and the
-        # length being at offset 0.  In this case, so the length overwrites
-        # the tid.  This is of course only the case in this test class.
-        ops = '''
-        []
-        p0 = new_array(4, descr=arraydescr)
-        setarrayitem_gc(p0, 0, 142, descr=arraydescr)
-        setarrayitem_gc(p0, 3, 143, descr=arraydescr)
-        finish(p0)
-        '''
-        self.interpret(ops, [])
-        # check the nursery
-        gc_ll_descr = self.cpu.gc_ll_descr
-        assert gc_ll_descr.nursery[0] == 4
-        assert gc_ll_descr.nursery[1] == 142
-        assert gc_ll_descr.nursery[4] == 143
-        nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
-        assert gc_ll_descr.addrs[0] == nurs_adr + (WORD*5)
-        assert gc_ll_descr.addrs[2] == 0   # slowpath never called
-
-    def test_malloc_varsize_slowpath(self):
-        ops = '''
-        []
-        p0 = new_array(4, descr=arraydescr)
-        setarrayitem_gc(p0, 0, 420, descr=arraydescr)
-        setarrayitem_gc(p0, 3, 430, descr=arraydescr)
-        p1 = new_array(4, descr=arraydescr)
-        setarrayitem_gc(p1, 0, 421, descr=arraydescr)
-        setarrayitem_gc(p1, 3, 431, descr=arraydescr)
-        p2 = new_array(4, descr=arraydescr)
-        setarrayitem_gc(p2, 0, 422, descr=arraydescr)
-        setarrayitem_gc(p2, 3, 432, descr=arraydescr)
-        p3 = new_array(4, descr=arraydescr)
-        setarrayitem_gc(p3, 0, 423, descr=arraydescr)
-        setarrayitem_gc(p3, 3, 433, descr=arraydescr)
-        finish(p0, p1, p2, p3)
-        '''
-        gc_ll_descr = self.cpu.gc_ll_descr
-        gc_ll_descr.expected_malloc_slowpath_size = 5*WORD
-        self.interpret(ops, [])
-        assert gc_ll_descr.addrs[2] == 1   # slowpath called once
-
-    def test_malloc_varsize_too_big(self):
-        ops = '''
-        []
-        p0 = new_array(5, descr=arraydescr)
-        finish(p0)
-        '''
-        py.test.raises(Seen, self.interpret, ops, [])
-
-    def test_malloc_varsize_variable(self):
-        ops = '''
-        [i0]
-        p0 = new_array(i0, descr=arraydescr)
-        finish(p0)
-        '''
-        py.test.raises(Seen, self.interpret, ops, [])
-
-    def test_malloc_array_of_char(self):
-        # check that fastpath_malloc_varsize() respects the alignment
-        # of the pointer in the nursery
-        ops = '''
-        []
-        p1 = new_array(1, descr=arraychardescr)
-        p2 = new_array(2, descr=arraychardescr)
-        p3 = new_array(3, descr=arraychardescr)
-        p4 = new_array(4, descr=arraychardescr)
-        finish(p1, p2, p3, p4)
-        '''
-        self.interpret(ops, [])
-        p1 = self.getptr(0, llmemory.GCREF)
-        p2 = self.getptr(1, llmemory.GCREF)
-        p3 = self.getptr(2, llmemory.GCREF)
-        p4 = self.getptr(3, llmemory.GCREF)
-        assert p1._obj.intval & (WORD-1) == 0    # aligned
-        assert p2._obj.intval & (WORD-1) == 0    # aligned
-        assert p3._obj.intval & (WORD-1) == 0    # aligned
-        assert p4._obj.intval & (WORD-1) == 0    # aligned
+        assert gc_ll_descr.calls == [24]
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
@@ -69,6 +69,7 @@
         return ctypes.cast(res.value._obj.intval, ctypes.POINTER(item_tp))
 
     def test_allocations(self):
+        py.test.skip("rewrite or kill")
         from pypy.rpython.lltypesystem import rstr
 
         allocs = [None]
diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py
--- a/pypy/jit/backend/x86/test/test_zrpy_gc.py
+++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py
@@ -69,16 +69,17 @@
 def get_functions_to_patch():
     from pypy.jit.backend.llsupport import gc
     #
-    can_inline_malloc1 = gc.GcLLDescr_framework.can_inline_malloc
-    def can_inline_malloc2(*args):
+    can_use_nursery_malloc1 = gc.GcLLDescr_framework.can_use_nursery_malloc
+    def can_use_nursery_malloc2(*args):
         try:
             if os.environ['PYPY_NO_INLINE_MALLOC']:
                 return False
         except KeyError:
             pass
-        return can_inline_malloc1(*args)
+        return can_use_nursery_malloc1(*args)
     #
-    return {(gc.GcLLDescr_framework, 'can_inline_malloc'): can_inline_malloc2}
+    return {(gc.GcLLDescr_framework, 'can_use_nursery_malloc'):
+                can_use_nursery_malloc2}
 
 def compile(f, gc, enable_opts='', **kwds):
     from pypy.annotation.listdef import s_list_of_strings
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
@@ -46,7 +46,7 @@
     # get the function address as an integer
     func = argboxes[0].getint()
     # do the call using the correct function from the cpu
-    rettype = descr.get_return_type()
+    rettype = descr.get_result_type()
     if rettype == INT or rettype == 'S':       # *S*ingle float
         try:
             result = cpu.bh_call_i(func, descr, args_i, args_r, args_f)
@@ -344,6 +344,8 @@
                          rop.SETINTERIORFIELD_RAW,
                          rop.CALL_RELEASE_GIL,
                          rop.QUASIIMMUT_FIELD,
+                         rop.CALL_MALLOC_GC,
+                         rop.CALL_MALLOC_NURSERY,
                          rop.LABEL,
                          ):      # list of opcodes never executed by pyjitpl
                 continue
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
@@ -142,59 +142,6 @@
     def repr_of_descr(self):
         return '%r' % (self,)
 
-    def get_arg_types(self):
-        """ Implement in call descr.
-        Must return a string of INT, REF and FLOAT ('i', 'r', 'f').
-        """
-        raise NotImplementedError
-
-    def get_return_type(self):
-        """ Implement in call descr.
-        Must return INT, REF, FLOAT, or 'v' for void.
-        On 32-bit (hack) it can also be 'L' for longlongs.
-        Additionally it can be 'S' for singlefloats.
-        """
-        raise NotImplementedError
-
-    def get_extra_info(self):
-        """ Implement in call descr
-        """
-        raise NotImplementedError
-
-    def is_array_of_pointers(self):
-        """ Implement for array descr
-        """
-        raise NotImplementedError
-
-    def is_array_of_floats(self):
-        """ Implement for array descr
-        """
-        raise NotImplementedError
-
-    def is_array_of_structs(self):
-        """ Implement for array descr
-        """
-        raise NotImplementedError
-
-    def is_pointer_field(self):
-        """ Implement for field descr
-        """
-        raise NotImplementedError
-
-    def is_float_field(self):
-        """ Implement for field descr
-        """
-        raise NotImplementedError
-
-    def as_vtable_size_descr(self):
-        """ Implement for size descr representing objects with vtables.
-        Returns self.  (it's an annotation hack)
-        """
-        raise NotImplementedError
-
-    def count_fields_if_immutable(self):
-        return -1
-
     def _clone_if_mutable(self):
         return self
     def clone_if_mutable(self):
diff --git a/pypy/jit/metainterp/memmgr.py b/pypy/jit/metainterp/memmgr.py
--- a/pypy/jit/metainterp/memmgr.py
+++ b/pypy/jit/metainterp/memmgr.py
@@ -1,5 +1,5 @@
 import math
-from pypy.rlib.rarithmetic import r_int64, r_uint
+from pypy.rlib.rarithmetic import r_int64
 from pypy.rlib.debug import debug_start, debug_print, debug_stop
 from pypy.rlib.objectmodel import we_are_translated
 
@@ -21,7 +21,6 @@
 #
 
 class MemoryManager(object):
-    NO_NEXT_CHECK = r_int64(2 ** 63 - 1)
 
     def __init__(self):
         self.check_frequency = -1
@@ -37,13 +36,12 @@
         # According to my estimates it's about 5e9 years given 1000 loops
         # per second
         self.current_generation = r_int64(1)
-        self.next_check = self.NO_NEXT_CHECK
+        self.next_check = r_int64(-1)
         self.alive_loops = {}
-        self._cleanup_jitcell_dicts = lambda: None
 
     def set_max_age(self, max_age, check_frequency=0):
         if max_age <= 0:
-            self.next_check = self.NO_NEXT_CHECK
+            self.next_check = r_int64(-1)
         else:
             self.max_age = max_age
             if check_frequency <= 0:
@@ -51,11 +49,10 @@
             self.check_frequency = check_frequency
             self.next_check = self.current_generation + 1
 
-    def next_generation(self, do_cleanups_now=True):
+    def next_generation(self):
         self.current_generation += 1
-        if do_cleanups_now and self.current_generation >= self.next_check:
+        if self.current_generation == self.next_check:
             self._kill_old_loops_now()
-            self._cleanup_jitcell_dicts()
             self.next_check = self.current_generation + self.check_frequency
 
     def keep_loop_alive(self, looptoken):
@@ -84,22 +81,3 @@
             # a single one is not enough for all tests :-(
             rgc.collect(); rgc.collect(); rgc.collect()
         debug_stop("jit-mem-collect")
-
-    def get_current_generation_uint(self):
-        """Return the current generation, possibly truncated to a uint.
-        To use only as an approximation for decaying counters."""
-        return r_uint(self.current_generation)
-
-    def record_jitcell_dict(self, callback):
-        """NOT_RPYTHON.  The given jitcell_dict is a dict that needs
-        occasional clean-ups of old cells.  A cell is old if it never
-        reached the threshold, and its counter decayed to a tiny value."""
-        # note that the various jitcell_dicts have different RPython types,
-        # so we have to make a different function for each one.  These
-        # functions are chained to each other: each calls the previous one.
-        def cleanup_dict():
-            callback()
-            cleanup_previous()
-        #
-        cleanup_previous = self._cleanup_jitcell_dicts
-        self._cleanup_jitcell_dicts = cleanup_dict
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_multilabel.py
@@ -1,3 +1,4 @@
+from __future__ import with_statement
 from pypy.jit.metainterp.optimizeopt.test.test_util import (
     LLtypeMixin, BaseTest, Storage, _sortboxes, FakeDescrWithSnapshot)
 from pypy.jit.metainterp.history import TreeLoop, JitCellToken, TargetToken
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
@@ -508,6 +508,8 @@
     #'OOSEND',                     # ootype operation
     #'OOSEND_PURE',                # ootype operation
     'CALL_PURE/*d',             # removed before it's passed to the backend
+    'CALL_MALLOC_GC/*d',      # like CALL, but NULL => propagate MemoryError
+    'CALL_MALLOC_NURSERY/1',  # nursery malloc, const number of bytes, zeroed
     '_CALL_LAST',
     '_CANRAISE_LAST', # ----- end of can_raise operations -----
 
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
@@ -2910,27 +2910,6 @@
         res = self.meta_interp(f, [32])
         assert res == f(32)
 
-    def test_decay_counters(self):
-        myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
-        def f(m, n):
-            while n > 0:
-                myjitdriver.jit_merge_point(m=m, n=n)
-                n += m
-                n -= m
-                n -= 1
-        def main():
-            f(5, 7)      # run 7x with m=5           counter[m=5] = 7
-            f(15, 10)    # compiles one loop         counter[m=5] = 3  (automatic decay)
-            f(5, 5)      # run 5x times with m=5     counter[m=5] = 8
-        #
-        self.meta_interp(main, [], decay_halflife=1,
-                         function_threshold=0, threshold=9, trace_eagerness=99)
-        self.check_trace_count(1)
-        #
-        self.meta_interp(main, [], decay_halflife=1,
-                         function_threshold=0, threshold=8, trace_eagerness=99)
-        self.check_trace_count(2)
-
 
 class TestOOtype(BasicTests, OOJitMixin):
 
diff --git a/pypy/jit/metainterp/test/test_executor.py b/pypy/jit/metainterp/test/test_executor.py
--- a/pypy/jit/metainterp/test/test_executor.py
+++ b/pypy/jit/metainterp/test/test_executor.py
@@ -18,7 +18,7 @@
     pass
 
 class FakeCallDescr(FakeDescr):
-    def get_return_type(self):
+    def get_result_type(self):
         return history.FLOAT
 
 class FakeFieldDescr(FakeDescr):
diff --git a/pypy/jit/metainterp/test/test_warmstate.py b/pypy/jit/metainterp/test/test_warmstate.py
--- a/pypy/jit/metainterp/test/test_warmstate.py
+++ b/pypy/jit/metainterp/test/test_warmstate.py
@@ -1,4 +1,3 @@
-import math
 from pypy.rpython.test.test_llinterp import interpret
 from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi
 from pypy.rpython.ootypesystem import ootype
@@ -9,7 +8,7 @@
 from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr
 from pypy.jit.metainterp.history import ConstInt, ConstFloat, ConstPtr
 from pypy.jit.codewriter import longlong
-from pypy.rlib.rarithmetic import r_singlefloat, r_uint
+from pypy.rlib.rarithmetic import r_singlefloat
 
 def boxfloat(x):
     return BoxFloat(longlong.getfloatstorage(x))
@@ -277,76 +276,51 @@
     res = state.can_never_inline(5, 42.5)
     assert res is True
 
-def test_decay_counters():
-    cell = JitCell(r_uint(5))
-    cell.counter = 100
-    cell.adjust_counter(r_uint(5), math.log(0.9))
-    assert cell.counter == 100
-    cell.adjust_counter(r_uint(6), math.log(0.9))
-    assert cell.counter == 90
-    cell.adjust_counter(r_uint(9), math.log(0.9))
-    assert cell.counter == int(90 * (0.9**3))
-
 def test_cleanup_jitcell_dict():
-    from pypy.jit.metainterp.memmgr import MemoryManager
-    class FakeWarmRunnerDesc:
-        memory_manager = MemoryManager()
-        class cpu:
-            pass
     class FakeJitDriverSD:
         _green_args_spec = [lltype.Signed]
     #
     # Test creating tons of jitcells that remain at 0
-    warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
+    warmstate = WarmEnterState(None, FakeJitDriverSD())
     get_jitcell = warmstate._make_jitcell_getter_default()
     cell1 = get_jitcell(True, -1)
     assert len(warmstate._jitcell_dict) == 1
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 1
     #
     for i in range(1, 20005):
         get_jitcell(True, i)     # should trigger a clean-up at 20001
         assert len(warmstate._jitcell_dict) == (i % 20000) + 1
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 2
     #
     # Same test, with one jitcell that has a counter of BASE instead of 0
-    warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
-    warmstate.set_param_decay_halflife(2)
-    warmstate.set_param_threshold(5)
-    warmstate.set_param_function_threshold(0)
+    warmstate = WarmEnterState(None, FakeJitDriverSD())
     get_jitcell = warmstate._make_jitcell_getter_default()
     cell2 = get_jitcell(True, -2)
-    cell2.counter = BASE = warmstate.increment_threshold * 3
+    cell2.counter = BASE = warmstate.THRESHOLD_LIMIT // 2    # 50%
     #
     for i in range(0, 20005):
         get_jitcell(True, i)
         assert len(warmstate._jitcell_dict) == (i % 19999) + 2
     #
     assert cell2 in warmstate._jitcell_dict.values()
-    assert cell2.counter == int(BASE * math.sqrt(0.5))   # decayed once
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 3
+    assert cell2.counter == int(BASE * 0.92)   # decayed once
     #
-    # Same test, with jitcells that are compiled and free by the memmgr
-    warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
+    # Same test, with jitcells that are compiled and freed by the memmgr
+    warmstate = WarmEnterState(None, FakeJitDriverSD())
     get_jitcell = warmstate._make_jitcell_getter_default()
     get_jitcell(True, -1)
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 3
     #
     for i in range(1, 20005):
         cell = get_jitcell(True, i)
         cell.counter = -1
         cell.wref_procedure_token = None    # or a dead weakref, equivalently
         assert len(warmstate._jitcell_dict) == (i % 20000) + 1
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 4
     #
     # Same test, with counter == -2 (rare case, kept alive)
-    warmstate = WarmEnterState(FakeWarmRunnerDesc(), FakeJitDriverSD())
+    warmstate = WarmEnterState(None, FakeJitDriverSD())
     get_jitcell = warmstate._make_jitcell_getter_default()
     cell = get_jitcell(True, -1)
     cell.counter = -2
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 4
     #
     for i in range(1, 20005):
         cell = get_jitcell(True, i)
         cell.counter = -2
         assert len(warmstate._jitcell_dict) == i + 1
-    assert FakeWarmRunnerDesc.memory_manager.current_generation == 5
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
@@ -64,11 +64,9 @@
 
 def jittify_and_run(interp, graph, args, repeat=1, graph_and_interp_only=False,
                     backendopt=False, trace_limit=sys.maxint,
-                    threshold=3, trace_eagerness=2,
                     inline=False, loop_longevity=0, retrace_limit=5,
-                    function_threshold=4, decay_halflife=0,
-                    enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15,
-                    **kwds):
+                    function_threshold=4,
+                    enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15, **kwds):
     from pypy.config.config import ConfigError
     translator = interp.typer.annotator.translator
     try:
@@ -85,16 +83,15 @@
         pass
     warmrunnerdesc = WarmRunnerDesc(translator, backendopt=backendopt, **kwds)
     for jd in warmrunnerdesc.jitdrivers_sd:
-        jd.warmstate.set_param_threshold(threshold)
+        jd.warmstate.set_param_threshold(3)          # for tests
         jd.warmstate.set_param_function_threshold(function_threshold)
-        jd.warmstate.set_param_trace_eagerness(trace_eagerness)
+        jd.warmstate.set_param_trace_eagerness(2)    # for tests
         jd.warmstate.set_param_trace_limit(trace_limit)
         jd.warmstate.set_param_inlining(inline)
         jd.warmstate.set_param_loop_longevity(loop_longevity)
         jd.warmstate.set_param_retrace_limit(retrace_limit)
         jd.warmstate.set_param_max_retrace_guards(max_retrace_guards)
         jd.warmstate.set_param_enable_opts(enable_opts)
-        jd.warmstate.set_param_decay_halflife(decay_halflife)
     warmrunnerdesc.finish()
     if graph_and_interp_only:
         return interp, graph
diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py
--- a/pypy/jit/metainterp/warmstate.py
+++ b/pypy/jit/metainterp/warmstate.py
@@ -1,10 +1,10 @@
-import sys, weakref, math
+import sys, weakref
 from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rffi
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.annlowlevel import hlstr, cast_base_ptr_to_instance
 from pypy.rpython.annlowlevel import cast_object_to_ptr
 from pypy.rlib.objectmodel import specialize, we_are_translated, r_dict
-from pypy.rlib.rarithmetic import intmask, r_uint
+from pypy.rlib.rarithmetic import intmask
 from pypy.rlib.nonconst import NonConstant
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.jit import PARAMETERS
@@ -151,27 +151,9 @@
     #     counter == -2: tracing is currently going on for this cell
     counter = 0
     dont_trace_here = False
+    extra_delay = chr(0)
     wref_procedure_token = None
 
-    def __init__(self, generation):
-        # The stored 'counter' value follows an exponential decay model.
-        # Conceptually after every generation, it decays by getting
-        # multiplied by a constant <= 1.0.  In practice, decaying occurs
-        # lazily: the following field records the latest seen generation
-        # number, and adjustment is done by adjust_counter() when needed.
-        self.latest_generation_seen = generation
-
-    def adjust_counter(self, generation, log_decay_factor):
-        if generation != self.latest_generation_seen:
-            # The latest_generation_seen is older than the current generation.
-            # Adjust by multiplying self.counter N times by decay_factor, i.e.
-            # by decay_factor ** N, which is equal to exp(log(decay_factor)*N).
-            assert self.counter >= 0
-            N = generation - self.latest_generation_seen
-            factor = math.exp(log_decay_factor * N)
-            self.counter = int(self.counter * factor)
-            self.latest_generation_seen = generation
-
     def get_procedure_token(self):
         if self.wref_procedure_token is not None:
             token = self.wref_procedure_token()
@@ -231,17 +213,6 @@
     def set_param_inlining(self, value):
         self.inlining = value
 
-    def set_param_decay_halflife(self, value):
-        # Use 0 or -1 to mean "no decay".  Initialize the internal variable
-        # 'log_decay_factor'.  It is choosen such that by multiplying the
-        # counter on loops by 'exp(log_decay_factor)' (<= 1.0) every
-        # generation, then the counter will be divided by two after 'value'
-        # generations have passed.
-        if value <= 0:
-            self.log_decay_factor = 0.0    # log(1.0)
-        else:
-            self.log_decay_factor = math.log(0.5) / value
-
     def set_param_enable_opts(self, value):
         from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT, ALL_OPTS_NAMES
 
@@ -311,11 +282,6 @@
         confirm_enter_jit = self.confirm_enter_jit
         range_red_args = unrolling_iterable(
             range(num_green_args, num_green_args + jitdriver_sd.num_red_args))
-        memmgr = self.warmrunnerdesc.memory_manager
-        if memmgr is not None:
-            get_current_generation = memmgr.get_current_generation_uint
-        else:
-            get_current_generation = lambda: r_uint(0)
         # get a new specialized copy of the method
         ARGS = []
         for kind in jitdriver_sd.red_args_types:
@@ -350,6 +316,36 @@
             #
             assert 0, "should have raised"
 
+        def bound_reached(cell, *args):
+            # bound reached, but we do a last check: if it is the first
+            # time we reach the bound, or if another loop or bridge was
+            # compiled since the last time we reached it, then decrease
+            # the counter by a few percents instead.  It should avoid
+            # sudden bursts of JIT-compilation, and also corner cases
+            # where we suddenly compile more than one loop because all
+            # counters reach the bound at the same time, but where
+            # compiling all but the first one is pointless.
+            curgen = warmrunnerdesc.memory_manager.current_generation
+            curgen = chr(intmask(curgen) & 0xFF)    # only use 8 bits
+            if we_are_translated() and curgen != cell.extra_delay:
+                cell.counter = int(self.THRESHOLD_LIMIT * 0.98)
+                cell.extra_delay = curgen
+                return
+            #
+            if not confirm_enter_jit(*args):
+                cell.counter = 0
+                return
+            # start tracing
+            from pypy.jit.metainterp.pyjitpl import MetaInterp
+            metainterp = MetaInterp(metainterp_sd, jitdriver_sd)
+            # set counter to -2, to mean "tracing in effect"
+            cell.counter = -2
+            try:
+                metainterp.compile_and_run_once(jitdriver_sd, *args)
+            finally:
+                if cell.counter == -2:
+                    cell.counter = 0
+
         def maybe_compile_and_run(threshold, *args):
             """Entry point to the JIT.  Called at the point with the
             can_enter_jit() hint.
@@ -360,25 +356,13 @@
 
             if cell.counter >= 0:
                 # update the profiling counter
-                cell.adjust_counter(get_current_generation(),
-                                    self.log_decay_factor)
                 n = cell.counter + threshold
                 if n <= self.THRESHOLD_LIMIT:       # bound not reached
                     cell.counter = n
                     return
-                if not confirm_enter_jit(*args):
-                    cell.counter = 0
+                else:
+                    bound_reached(cell, *args)
                     return
-                # bound reached; start tracing
-                from pypy.jit.metainterp.pyjitpl import MetaInterp
-                metainterp = MetaInterp(metainterp_sd, jitdriver_sd)
-                # set counter to -2, to mean "tracing in effect"
-                cell.counter = -2
-                try:
-                    metainterp.compile_and_run_once(jitdriver_sd, *args)
-                finally:
-                    if cell.counter == -2:
-                        cell.counter = 0
             else:
                 if cell.counter != -1:
                     assert cell.counter == -2
@@ -454,15 +438,6 @@
         #
         return jit_getter
 
-    def _new_jitcell(self):
-        warmrunnerdesc = self.warmrunnerdesc
-        if (warmrunnerdesc is not None and
-                warmrunnerdesc.memory_manager is not None):
-            gen = warmrunnerdesc.memory_manager.get_current_generation_uint()
-        else:
-            gen = r_uint(0)
-        return JitCell(gen)
-
     def _make_jitcell_getter_default(self):
         "NOT_RPYTHON"
         jitdriver_sd = self.jitdriver_sd
@@ -492,44 +467,32 @@
         except AttributeError:
             pass
         #
-        memmgr = self.warmrunnerdesc and self.warmrunnerdesc.memory_manager
-        if memmgr:
-            def _cleanup_dict():
-                minimum = sys.maxint
-                if self.increment_threshold > 0:
-                    minimum = min(minimum, self.increment_threshold)
-                if self.increment_function_threshold > 0:
-                    minimum = min(minimum, self.increment_function_threshold)
-                currentgen = memmgr.get_current_generation_uint()
-                killme = []
-                for key, cell in jitcell_dict.iteritems():
-                    if cell.counter >= 0:
-                        cell.adjust_counter(currentgen, self.log_decay_factor)
-                        if cell.counter < minimum:
-                            killme.append(key)
-                    elif (cell.counter == -1
-                          and cell.get_procedure_token() is None):
+        def _cleanup_dict():
+            minimum = self.THRESHOLD_LIMIT // 20     # minimum 5%
+            killme = []
+            for key, cell in jitcell_dict.iteritems():
+                if cell.counter >= 0:
+                    cell.counter = int(cell.counter * 0.92)
+                    if cell.counter < minimum:
                         killme.append(key)
-                for key in killme:
-                    del jitcell_dict[key]
-            #
-            def _maybe_cleanup_dict():
-                # If no tracing goes on at all because the jitcells are
-                # each time for new greenargs, the dictionary grows forever.
-                # So every one in a (rare) while, we decide to force an
-                # artificial next_generation() and _cleanup_dict().
-                self._trigger_automatic_cleanup += 1
-                if self._trigger_automatic_cleanup > 20000:
-                    self._trigger_automatic_cleanup = 0
-                    memmgr.next_generation(do_cleanups_now=False)
-                    _cleanup_dict()
-            #
-            self._trigger_automatic_cleanup = 0
-            self._jitcell_dict = jitcell_dict       # for tests
-            memmgr.record_jitcell_dict(_cleanup_dict)
-        else:
-            def _maybe_cleanup_dict():
-                pass
+                elif (cell.counter == -1
+                      and cell.get_procedure_token() is None):
+                    killme.append(key)
+            for key in killme:
+                del jitcell_dict[key]
+        #
+        def _maybe_cleanup_dict():
+            # Once in a while, rarely, when too many entries have
+            # been put in the jitdict_dict, we do a cleanup phase:
+            # we decay all counters and kill entries with a too
+            # low counter.
+            self._trigger_automatic_cleanup += 1
+            if self._trigger_automatic_cleanup > 20000:
+                self._trigger_automatic_cleanup = 0
+                _cleanup_dict()
+        #
+        self._trigger_automatic_cleanup = 0
+        self._jitcell_dict = jitcell_dict       # for tests
         #
         def get_jitcell(build, *greenargs):
             try:
@@ -538,7 +501,7 @@
                 if not build:
                     return None
                 _maybe_cleanup_dict()
-                cell = self._new_jitcell()
+                cell = JitCell()
                 jitcell_dict[greenargs] = cell
             return cell
         return get_jitcell
@@ -549,7 +512,7 @@
         get_jitcell_at_ptr = self.jitdriver_sd._get_jitcell_at_ptr
         set_jitcell_at_ptr = self.jitdriver_sd._set_jitcell_at_ptr
         lltohlhack = {}
-        # note that there is no equivalent of record_jitcell_dict()
+        # note that there is no equivalent of _maybe_cleanup_dict()
         # in the case of custom getters.  We assume that the interpreter
         # stores the JitCells on some objects that can go away by GC,
         # like the PyCode objects in PyPy.
@@ -574,7 +537,7 @@
             if not build:
                 return cell
             if cell is None:
-                cell = self._new_jitcell()
+                cell = JitCell()
                 # <hacks>
                 if we_are_translated():
                     cellref = cast_object_to_ptr(BASEJITCELL, cell)
diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py
--- a/pypy/module/_weakref/interp__weakref.py
+++ b/pypy/module/_weakref/interp__weakref.py
@@ -329,11 +329,16 @@
 special_ops = {'repr': True, 'userdel': True, 'hash': True}
 
 for opname, _, arity, special_methods in ObjSpace.MethodTable:
-    if opname in special_ops:
+    if opname in special_ops or not special_methods:
         continue
     nonspaceargs =  ", ".join(["w_obj%s" % i for i in range(arity)])
     code = "def func(space, %s):\n    '''%s'''\n" % (nonspaceargs, opname)
-    for i in range(arity):
+    assert arity >= len(special_methods)
+    forcing_count = len(special_methods)
+    if opname.startswith('inplace_'):
+        assert arity == 2
+        forcing_count = arity
+    for i in range(forcing_count):
         code += "    w_obj%s = force(space, w_obj%s)\n" % (i, i)
     code += "    return space.%s(%s)" % (opname, nonspaceargs)
     exec py.code.Source(code).compile()
diff --git a/pypy/module/_weakref/test/test_weakref.py b/pypy/module/_weakref/test/test_weakref.py
--- a/pypy/module/_weakref/test/test_weakref.py
+++ b/pypy/module/_weakref/test/test_weakref.py
@@ -466,3 +466,44 @@
         # No exception should be raised here
         gc.collect()
 
+    def test_add(self):
+        import _weakref
+        class A(object):
+            def __add__(self, other):
+                return other
+        a1 = A()
+        a2 = A()
+        p1 = _weakref.proxy(a1)
+        p2 = _weakref.proxy(a2)
+        a3 = p1 + p2
+        assert a3 is a2
+
+    def test_inplace_add(self):
+        import _weakref
+        class A(object):
+            def __add__(self, other):
+                return other
+        a1 = A()
+        a2 = A()
+        p1 = _weakref.proxy(a1)
+        p2 = _weakref.proxy(a2)
+        p1 += p2
+        assert p1 is a2
+
+    def test_setattr(self):
+        import _weakref
+        class A(object):
+            def __setitem__(self, key, value):
+                self.setkey = key
+                self.setvalue = value
+        a1 = A()
+        a2 = A()
+        p1 = _weakref.proxy(a1)
+        p2 = _weakref.proxy(a2)
+        p1[p2] = 42
+        assert a1.setkey is p2
+        assert a1.setvalue == 42
+        #
+        p1[42] = p2
+        assert a1.setkey == 42
+        assert a1.setvalue is p2
diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py
--- a/pypy/module/micronumpy/app_numpy.py
+++ b/pypy/module/micronumpy/app_numpy.py
@@ -53,7 +53,6 @@
     i = start
     for j in range(arr.size):
         arr[j] = i
-        j += 1
         i += step
     return arr
 
diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py
--- a/pypy/module/pypyjit/test_pypy_c/model.py
+++ b/pypy/module/pypyjit/test_pypy_c/model.py
@@ -311,7 +311,7 @@
         # to repeat it every time
         ticker_check = """
             guard_not_invalidated?
-            ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+            ticker0 = getfield_raw(ticker_address, descr=<FieldS pypysig_long_struct.c_value .*>)
             ticker_cond0 = int_lt(ticker0, 0)
             guard_false(ticker_cond0, descr=...)
         """
@@ -320,9 +320,9 @@
         # this is the ticker check generated if we have threads
         thread_ticker_check = """
             guard_not_invalidated?
-            ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+            ticker0 = getfield_raw(ticker_address, descr=<FieldS pypysig_long_struct.c_value .*>)
             ticker1 = int_sub(ticker0, _)
-            setfield_raw(ticker_address, ticker1, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+            setfield_raw(ticker_address, ticker1, descr=<FieldS pypysig_long_struct.c_value .*>)
             ticker_cond0 = int_lt(ticker1, 0)
             guard_false(ticker_cond0, descr=...)
         """
@@ -330,7 +330,7 @@
         #
         # this is the ticker check generated in PyFrame.handle_operation_error
         exc_ticker_check = """
-            ticker2 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+            ticker2 = getfield_raw(ticker_address, descr=<FieldS pypysig_long_struct.c_value .*>)
             ticker_cond1 = int_lt(ticker2, 0)
             guard_false(ticker_cond1, descr=...)
         """
@@ -451,7 +451,6 @@
         try:
             self.match_loop(expected_ops, ignore_ops)
         except InvalidMatch, e:
-            #raise # uncomment this and use py.test --pdb for better debugging
             print '@' * 40
             print "Loops don't match"
             print "================="
@@ -464,7 +463,7 @@
             print
             print "Expected:"
             print format(expected_src)
-            return False
+            raise     # always propagate the exception in case of mismatch
         else:
             return True
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
@@ -7,8 +7,9 @@
 from pypy.tool.udir import udir
 from pypy.tool import logparser
 from pypy.jit.tool.jitoutput import parse_prof
-from pypy.module.pypyjit.test_pypy_c.model import Log, find_ids_range, find_ids, \
-    TraceWithIds, OpMatcher
+from pypy.module.pypyjit.test_pypy_c.model import (Log, find_ids_range,
+                                                   find_ids, TraceWithIds,
+                                                   OpMatcher, InvalidMatch)
 
 class BaseTestPyPyC(object):
     def setup_class(cls):
@@ -115,13 +116,18 @@
         assert opcodes_names == ['LOAD_FAST', 'LOAD_CONST', 'BINARY_ADD', 'STORE_FAST']
 
 
-class TestOpMatcher(object):
+class TestOpMatcher_(object):
 
     def match(self, src1, src2, **kwds):
         from pypy.tool.jitlogparser.parser import SimpleParser
         loop = SimpleParser.parse_from_input(src1)
         matcher = OpMatcher(loop.operations)
-        return matcher.match(src2, **kwds)
+        try:
+            res = matcher.match(src2, **kwds)
+            assert res is True
+            return True
+        except InvalidMatch:
+            return False
 
     def test_match_var(self):
         match_var = OpMatcher([]).match_var
@@ -447,7 +453,7 @@
             jump(p0, p1, p2, p3, i8, descr=...)
         """)
         #
-        assert not loop.match("""
+        py.test.raises(InvalidMatch, loop.match, """
             i6 = int_lt(i4, 1003)
             guard_true(i6)
             i8 = int_add(i5, 1) # variable mismatch
@@ -492,9 +498,8 @@
             guard_no_exception(descr=...)
         """)
         #
-        assert not loop.match_by_id('ntohs', """
+        py.test.raises(InvalidMatch, loop.match_by_id, 'ntohs', """
             guard_not_invalidated(descr=...)
             p12 = call(ConstClass(foobar), 1, descr=...)
             guard_no_exception(descr=...)
         """)
-        
diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
@@ -35,7 +35,7 @@
             guard_not_invalidated(descr=...)
             i17 = force_token()
             setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>)
-            f21 = call_release_gil(%s, 2.000000, 3.000000, descr=<FloatCallDescr>)
+            f21 = call_release_gil(%s, 2.000000, 3.000000, descr=<Callf 8 ff EF=6>)
             guard_not_forced(descr=...)
             guard_no_exception(descr=...)
         """ % pow_addr)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py
--- a/pypy/module/pypyjit/test_pypy_c/test_array.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_array.py
@@ -42,7 +42,7 @@
             guard_not_invalidated(descr=...)
             i13 = int_lt(i7, i9)
             guard_true(i13, descr=...)
-            i15 = getarrayitem_raw(i10, i7, descr=<.*ArrayNoLengthDescr>)
+            i15 = getarrayitem_raw(i10, i7, descr=<ArrayS .>)
             i16 = int_add_ovf(i8, i15)
             guard_no_overflow(descr=...)
             i18 = int_add(i7, 1)
@@ -72,17 +72,17 @@
             guard_true(i13, descr=...)
             guard_not_invalidated(descr=...)
         # the bound check guard on img has been killed (thanks to the asserts)
-            i14 = getarrayitem_raw(i10, i8, descr=<.*ArrayNoLengthDescr>)
+            i14 = getarrayitem_raw(i10, i8, descr=<ArrayS .>)
             i15 = int_add_ovf(i9, i14)
             guard_no_overflow(descr=...)
             i17 = int_sub(i8, 640)
         # the bound check guard on intimg has been killed (thanks to the asserts)
-            i18 = getarrayitem_raw(i11, i17, descr=<.*ArrayNoLengthDescr>)
+            i18 = getarrayitem_raw(i11, i17, descr=<ArrayS .>)
             i19 = int_add_ovf(i18, i15)
             guard_no_overflow(descr=...)
         # on 64bit, there is a guard checking that i19 actually fits into 32bit
             ...
-            setarrayitem_raw(i11, i8, _, descr=<.*ArrayNoLengthDescr>)
+            setarrayitem_raw(i11, i8, _, descr=<ArrayS .>)
             i28 = int_add(i8, 1)
             --TICK--
             jump(p0, p1, p2, p3, p4, p5, p6, i28, i15, p9, i10, i11, descr=...)
@@ -107,10 +107,10 @@
             guard_true(i10, descr=...)
             i11 = int_lt(i6, i7)
             guard_true(i11, descr=...)
-            f13 = getarrayitem_raw(i8, i6, descr=<FloatArrayNoLengthDescr>)
+            f13 = getarrayitem_raw(i8, i6, descr=<ArrayF 8>)
             f15 = float_add(f13, 20.500000)
-            setarrayitem_raw(i8, i6, f15, descr=<FloatArrayNoLengthDescr>)
-            f16 = getarrayitem_raw(i8, i6, descr=<FloatArrayNoLengthDescr>)
+            setarrayitem_raw(i8, i6, f15, descr=<ArrayF 8>)
+            f16 = getarrayitem_raw(i8, i6, descr=<ArrayF 8>)
             i18 = float_eq(f16, 42.000000)
             guard_true(i18, descr=...)
             i20 = int_add(i6, 1)
@@ -132,28 +132,24 @@
         log = self.run(main, [])
         assert log.result == 321
         loop, = log.loops_by_filename(self.filepath)
-        if sys.maxint == 2147483647:
-            arraydescr = 'UnsignedArrayNoLengthDescr'
-        else:
-            arraydescr = 'UINTArrayNoLengthDescr'
         assert loop.match("""
             i10 = int_lt(i6, 1000)
             guard_true(i10, descr=...)
             i11 = int_lt(i6, i7)
             guard_true(i11, descr=...)
-            i13 = getarrayitem_raw(i8, i6, descr=<%s>)
+            i13 = getarrayitem_raw(i8, i6, descr=<Array. 4>)
             f14 = cast_singlefloat_to_float(i13)
             f16 = float_add(f14, 20.500000)
             i17 = cast_float_to_singlefloat(f16)
-            setarrayitem_raw(i8, i6,i17, descr=<%s>)
-            i18 = getarrayitem_raw(i8, i6, descr=<%s>)
+            setarrayitem_raw(i8, i6,i17, descr=<Array. 4>)
+            i18 = getarrayitem_raw(i8, i6, descr=<Array. 4>)
             f19 = cast_singlefloat_to_float(i18)
             i21 = float_eq(f19, 42.000000)
             guard_true(i21, descr=...)
             i23 = int_add(i6, 1)
             --TICK--
             jump(..., descr=...)
-        """ % (arraydescr, arraydescr, arraydescr))
+        """)
 
 
     def test_zeropadded(self):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -75,12 +75,12 @@
         assert log.opnames(ops) == []
         #
         assert entry_bridge.match_by_id('call', """
-            p38 = call(ConstClass(getexecutioncontext), descr=<GcPtrCallDescr>)
-            p39 = getfield_gc(p38, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
+            p38 = call(ConstClass(getexecutioncontext), descr=<Callr . EF=1>)
+            p39 = getfield_gc(p38, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
             i40 = force_token()
-            p41 = getfield_gc(p38, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
+            p41 = getfield_gc(p38, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
             guard_isnull(p41, descr=...)
-            i42 = getfield_gc(p38, descr=<NonGcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
+            i42 = getfield_gc(p38, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
             i43 = int_is_zero(i42)
             guard_true(i43, descr=...)
             i50 = force_token()
@@ -192,7 +192,7 @@
         assert log.result == 1000
         loop, = log.loops_by_id('call')
         assert loop.match_by_id('call', """
-            p14 = getarrayitem_gc_pure(p8, i9, descr=<GcPtrArrayDescr>)
+            p14 = getarrayitem_gc_pure(p8, i9, descr=<ArrayP .>)
             i14 = force_token()
             i16 = force_token()
         """)
@@ -336,15 +336,15 @@
         loop, = log.loops_by_filename(self.filepath)
         # the int strategy is used here
         assert loop.match_by_id('append', """
-            i13 = getfield_gc(p8, descr=<SignedFieldDescr list.length .*>)
+            i13 = getfield_gc(p8, descr=<FieldS list.length .*>)
             i15 = int_add(i13, 1)
             # Will be killed by the backend
-            p15 = getfield_gc(p8, descr=<GcPtrFieldDescr list.items .*>)
-            i17 = arraylen_gc(p15, descr=<SignedArrayDescr>)
-            call(_, p8, i15, descr=<VoidCallDescr>) # this is a call to _ll_list_resize_ge_trampoline__...
+            p15 = getfield_gc(p8, descr=<FieldP list.items .*>)
+            i17 = arraylen_gc(p15, descr=<ArrayS .>)
+            call(_, p8, i15, descr=<Callv 0 ri EF=4>) # this is a call to _ll_list_resize_ge_trampoline__...
             guard_no_exception(descr=...)
-            p17 = getfield_gc(p8, descr=<GcPtrFieldDescr list.items .*>)
-            setarrayitem_gc(p17, i13, i12, descr=<SignedArrayDescr>)
+            p17 = getfield_gc(p8, descr=<FieldP list.items .*>)
+            setarrayitem_gc(p17, i13, i12, descr=<ArrayS .>)
         """)
 
     def test_blockstack_virtualizable(self):
@@ -368,13 +368,13 @@
             ...
             i20 = force_token()
             p22 = new_with_vtable(19511408)
-            p24 = new_array(1, descr=<GcPtrArrayDescr>)
+            p24 = new_array(1, descr=<ArrayP .>)
             p26 = new_with_vtable(ConstClass(W_ListObject))
-            setfield_gc(p0, i20, descr=<SignedFieldDescr .*PyFrame.vable_token .*>)
-            setfield_gc(p26, ConstPtr(ptr22), descr=<GcPtrFieldDescr pypy.objspace.std.listobject.W_ListObject.inst_strategy .*>)
-            setarrayitem_gc(p24, 0, p26, descr=<GcPtrArrayDescr>)
-            setfield_gc(p22, p24, descr=<GcPtrFieldDescr .*Arguments.inst_arguments_w .*>)
-            p32 = call_may_force(11376960, p18, p22, descr=<GcPtrCallDescr>)
+            setfield_gc(p0, i20, descr=<FieldS .*PyFrame.vable_token .*>)
+            setfield_gc(p26, ConstPtr(ptr22), descr=<FieldP pypy.objspace.std.listobject.W_ListObject.inst_strategy .*>)
+            setarrayitem_gc(p24, 0, p26, descr=<ArrayP .>)
+            setfield_gc(p22, p24, descr=<FieldP .*Arguments.inst_arguments_w .*>)
+            p32 = call_may_force(11376960, p18, p22, descr=<Callr . rr EF=6>)
             ...
         """)
 
@@ -415,26 +415,26 @@
             guard_nonnull_class(p8, ConstClass(W_IntObject), descr=...)
             guard_value(i4, 0, descr=...)
             guard_value(p3, ConstPtr(ptr14), descr=...)
-            i15 = getfield_gc_pure(p8, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+            i15 = getfield_gc_pure(p8, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
             i17 = int_lt(i15, 5000)
             guard_true(i17, descr=...)
-            p18 = getfield_gc(p0, descr=<GcPtrFieldDescr pypy.interpreter.eval.Frame.inst_w_globals .*>)
+            p18 = getfield_gc(p0, descr=<FieldP pypy.interpreter.eval.Frame.inst_w_globals .*>)
             guard_value(p18, ConstPtr(ptr19), descr=...)
-            p20 = getfield_gc(p18, descr=<GcPtrFieldDescr pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_strategy .*>)
+            p20 = getfield_gc(p18, descr=<FieldP pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_strategy .*>)
             guard_value(p20, ConstPtr(ptr21), descr=...)
             guard_not_invalidated(descr=...)
             # most importantly, there is no getarrayitem_gc here
-            p23 = call(ConstClass(getexecutioncontext), descr=<GcPtrCallDescr>)
-            p24 = getfield_gc(p23, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
+            p23 = call(ConstClass(getexecutioncontext), descr=<Callr . EF=1>)
+            p24 = getfield_gc(p23, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
             i25 = force_token()
-            p26 = getfield_gc(p23, descr=<GcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
+            p26 = getfield_gc(p23, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
             guard_isnull(p26, descr=...)
-            i27 = getfield_gc(p23, descr=<NonGcPtrFieldDescr pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
+            i27 = getfield_gc(p23, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
             i28 = int_is_zero(i27)
             guard_true(i28, descr=...)
-            p30 = getfield_gc(ConstPtr(ptr29), descr=<GcPtrFieldDescr pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
+            p30 = getfield_gc(ConstPtr(ptr29), descr=<FieldP pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
             guard_nonnull_class(p30, ConstClass(W_IntObject), descr=...)
-            i32 = getfield_gc_pure(p30, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+            i32 = getfield_gc_pure(p30, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
             i33 = int_add_ovf(i15, i32)
             guard_no_overflow(descr=...)
             --TICK--
@@ -452,15 +452,15 @@
             """, [])
         loop, = log.loops_by_id('call')
         assert loop.match("""
-            i8 = getfield_gc_pure(p6, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+            i8 = getfield_gc_pure(p6, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
             i10 = int_lt(i8, 5000)
             guard_true(i10, descr=...)
             i11 = force_token()
             i13 = int_add(i8, 1)
             --TICK--
             p22 = new_with_vtable(ConstClass(W_IntObject))
-            setfield_gc(p22, i13, descr=<SignedFieldDescr pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
-            setfield_gc(p4, p22, descr=<GcPtrFieldDescr pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
+            setfield_gc(p22, i13, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+            setfield_gc(p4, p22, descr=<FieldP pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
             jump(p0, p1, p2, p3, p4, p7, p22, p7, descr=...)
         """)
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_containers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py
@@ -46,7 +46,7 @@
         assert loop.match_by_id("getitem", """
             i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...)
             ...
-            p33 = getinteriorfield_gc(p31, i26, descr=<InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>)
+            p33 = getinteriorfield_gc(p31, i26, descr=<InteriorFieldDescr <FieldP dictentry.value .*>>)
             ...
         """)
 
@@ -86,28 +86,28 @@
             i8 = int_lt(i5, i7)
             guard_true(i8, descr=...)
             guard_not_invalidated(descr=...)
-            p10 = call(ConstClass(ll_int_str), i5, descr=<GcPtrCallDescr>)
+            p10 = call(ConstClass(ll_int_str), i5, descr=<Callr . i EF=3>)
             guard_no_exception(descr=...)
-            i12 = call(ConstClass(ll_strhash), p10, descr=<SignedCallDescr>)
+            i12 = call(ConstClass(ll_strhash), p10, descr=<Calli . r EF=0>)
             p13 = new(descr=...)
-            p15 = new_array(8, descr=<dictentryArrayDescr>)
-            setfield_gc(p13, p15, descr=<GcPtrFieldDescr dicttable.entries .*>)
-            i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<SignedCallDescr>)
-            setfield_gc(p13, 16, descr=<SignedFieldDescr dicttable.resize_counter .*>)
+            p15 = new_array(8, descr=<ArrayX .*>)
+            setfield_gc(p13, p15, descr=<FieldP dicttable.entries .*>)
+            i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<Calli . rri EF=4>)
+            setfield_gc(p13, 16, descr=<FieldS dicttable.resize_counter .*>)
             guard_no_exception(descr=...)
             p20 = new_with_vtable(ConstClass(W_IntObject))
-            call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=<VoidCallDescr>)
-            setfield_gc(p20, i5, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
+            call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=<Callv 0 rrrii EF=4>)
+            setfield_gc(p20, i5, descr=<FieldS .*W_IntObject.inst_intval .*>)
             guard_no_exception(descr=...)
-            i23 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<SignedCallDescr>)
+            i23 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<Calli . rri EF=4>)
             guard_no_exception(descr=...)
             i26 = int_and(i23, .*)
             i27 = int_is_true(i26)
             guard_false(i27, descr=...)
-            p28 = getfield_gc(p13, descr=<GcPtrFieldDescr dicttable.entries .*>)
-            p29 = getinteriorfield_gc(p28, i23, descr=<InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>)
+            p28 = getfield_gc(p13, descr=<FieldP dicttable.entries .*>)
+            p29 = getinteriorfield_gc(p28, i23, descr=<InteriorFieldDescr <FieldP dictentry.value .*>>)
             guard_nonnull_class(p29, ConstClass(W_IntObject), descr=...)
-            i31 = getfield_gc_pure(p29, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
+            i31 = getfield_gc_pure(p29, descr=<FieldS .*W_IntObject.inst_intval .*>)
             i32 = int_sub_ovf(i31, i5)
             guard_no_overflow(descr=...)
             i34 = int_add_ovf(i32, 1)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py
--- a/pypy/module/pypyjit/test_pypy_c/test_generators.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py
@@ -17,24 +17,17 @@
             g()
 
         log = self.run(main, [500])
-        # XXX XXX this test fails so far because of a detail that
-        # changed with jit-simplify-backendintf.  We should try to
-        # think of a way to be more resistent against such details.
-        # The issue is that we now get one Tracing, then go back
-        # to the interpreter hoping to immediately run the JITted
-        # code; but instead, we Trace again, just because another
-        # counter was also about to reach its limit...
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match_by_id("generator", """
             i16 = force_token()
             p45 = new_with_vtable(ConstClass(W_IntObject))
-            setfield_gc(p45, i29, descr=<SignedFieldDescr .*>)
-            setarrayitem_gc(p8, 0, p45, descr=<GcPtrArrayDescr>)
-            i47 = arraylen_gc(p8, descr=<GcPtrArrayDescr>) # Should be removed by backend
+            setfield_gc(p45, i29, descr=<FieldS .*>)
+            setarrayitem_gc(p8, 0, p45, descr=<ArrayP .>)
+            i47 = arraylen_gc(p8, descr=<ArrayP .>) # Should be removed by backend
             jump(..., descr=...)
             """)
         assert loop.match_by_id("subtract", """
-            setfield_gc(p7, 35, descr=<.*last_instr .*>)      # XXX bad, kill me
+            setfield_gc(p7, 35, descr=<.*last_instr .*>)     # XXX bad, kill me
             i2 = int_sub_ovf(i1, 42)
             guard_no_overflow(descr=...)
             """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py
--- a/pypy/module/pypyjit/test_pypy_c/test_globals.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py
@@ -16,11 +16,11 @@
         assert log.result == 500
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match_by_id("loadglobal", """
-            p10 = getfield_gc(p0, descr=<GcPtrFieldDescr .*Frame.inst_w_globals .*>)
+            p10 = getfield_gc(p0, descr=<FieldP .*Frame.inst_w_globals .*>)
             guard_value(p10, ConstPtr(ptr11), descr=...)
-            p12 = getfield_gc(p10, descr=<GcPtrFieldDescr .*W_DictMultiObject.inst_strategy .*>)
+            p12 = getfield_gc(p10, descr=<FieldP .*W_DictMultiObject.inst_strategy .*>)
             guard_value(p12, ConstPtr(ptr13), descr=...)
             guard_not_invalidated(descr=...)
-            p19 = getfield_gc(ConstPtr(p17), descr=<GcPtrFieldDescr .*W_DictMultiObject.inst_strategy .*>)
+            p19 = getfield_gc(ConstPtr(p17), descr=<FieldP .*W_DictMultiObject.inst_strategy .*>)
             guard_value(p19, ConstPtr(ptr20), descr=...)
-        """)
\ No newline at end of file
+        """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py
--- a/pypy/module/pypyjit/test_pypy_c/test_instance.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py
@@ -125,8 +125,8 @@
             i12 = force_token()
             --TICK--
             p20 = new_with_vtable(ConstClass(W_IntObject))
-            setfield_gc(p20, i11, descr=<SignedFieldDescr.*W_IntObject.inst_intval .*>)
-            setfield_gc(ConstPtr(ptr21), p20, descr=<GcPtrFieldDescr .*TypeCell.inst_w_value .*>)
+            setfield_gc(p20, i11, descr=<FieldS.*W_IntObject.inst_intval .*>)
+            setfield_gc(ConstPtr(ptr21), p20, descr=<FieldP .*TypeCell.inst_w_value .*>)
             jump(p0, p1, p2, p3, p4, p20, p6, i7, p20, descr=...)
         """)
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py
--- a/pypy/module/pypyjit/test_pypy_c/test_math.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_math.py
@@ -23,8 +23,8 @@
             f1 = cast_int_to_float(i0)
             i3 = float_le(f1, 0)
             guard_false(i3, descr=...)
-            f2 = call(ConstClass(log), f1, descr=<FloatCallDescr>)
-            f3 = call(ConstClass(log10), f1, descr=<FloatCallDescr>)
+            f2 = call(ConstClass(log), f1, descr=<Callf . f EF=2>)
+            f3 = call(ConstClass(log10), f1, descr=<Callf . f EF=2>)
             f4 = float_sub(f2, f3)
             f5 = float_add(f0, f4)
             i4 = int_add(i0, 1)
@@ -52,8 +52,8 @@
             f1 = cast_int_to_float(i0)
             i6 = --ISINF--(f1)
             guard_false(i6, descr=...)
-            f2 = call(ConstClass(sin), f1, descr=<FloatCallDescr>)
-            f3 = call(ConstClass(cos), f1, descr=<FloatCallDescr>)
+            f2 = call(ConstClass(sin), f1, descr=<Callf . f EF=2>)
+            f3 = call(ConstClass(cos), f1, descr=<Callf . f EF=2>)
             f4 = float_sub(f2, f3)
             f5 = float_add(f0, f4)
             i7 = int_add(i0, f1)
@@ -84,7 +84,7 @@
             i4 = int_or(i2, i3)
             i5 = int_is_true(i4)
             guard_false(i5, descr=...)
-            f2 = call(ConstClass(fmod), f1, 2.0, descr=<FloatCallDescr>)
+            f2 = call(ConstClass(fmod), f1, 2.0, descr=<Callf . ff EF=2>)
             f3 = float_add(f0, f2)
             i6 = int_sub(i0, 1)
             --TICK--
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -46,7 +46,7 @@
                 r *= n
                 n -= 1
             return r
-        log = self.run(fact, [7], threshold=5)
+        log = self.run(fact, [7], threshold=4)
         assert log.result == 5040
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
@@ -204,18 +204,18 @@
         assert log.result == 1000000
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
-            i14 = getfield_gc(p12, descr=<SignedFieldDescr list.length .*>)
+            i14 = getfield_gc(p12, descr=<FieldS list.length .*>)
             i16 = uint_ge(i12, i14)
             guard_false(i16, descr=...)
-            p16 = getfield_gc(p12, descr=<GcPtrFieldDescr list.items .*>)
-            p17 = getarrayitem_gc(p16, i12, descr=<GcPtrArrayDescr>)
+            p16 = getfield_gc(p12, descr=<FieldP list.items .*>)
+            p17 = getarrayitem_gc(p16, i12, descr=<ArrayP .>)
             i19 = int_add(i12, 1)
-            setfield_gc(p9, i19, descr=<SignedFieldDescr .*W_AbstractSeqIterObject.inst_index .*>)
+            setfield_gc(p9, i19, descr=<FieldS .*W_AbstractSeqIterObject.inst_index .*>)
             guard_nonnull_class(p17, 146982464, descr=...)
-            i21 = getfield_gc(p17, descr=<SignedFieldDescr .*W_ArrayTypei.inst_len .*>)
+            i21 = getfield_gc(p17, descr=<FieldS .*W_ArrayTypei.inst_len .*>)
             i23 = int_lt(0, i21)
             guard_true(i23, descr=...)
-            i24 = getfield_gc(p17, descr=<NonGcPtrFieldDescr .*W_ArrayTypei.inst_buffer .*>)
+            i24 = getfield_gc(p17, descr=<FieldU .*W_ArrayTypei.inst_buffer .*>)
             i25 = getarrayitem_raw(i24, 0, descr=<.*>)
             i27 = int_lt(1, i21)
             guard_false(i27, descr=...)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py
--- a/pypy/module/pypyjit/test_pypy_c/test_string.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_string.py
@@ -1,6 +1,9 @@
 from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
 
 
+# XXX review the <Call> descrs to replace some EF=4 with EF=3 (elidable)
+
+
 class TestString(BaseTestPyPyC):
     def test_lookup_default_encoding(self):
         def main(n):
@@ -52,8 +55,8 @@
                 i += int(long(string.digits[i % len(string.digits)], 16))
             return i
 
-        log = self.run(main, [1000])
-        assert log.result == main(1000)
+        log = self.run(main, [1100])
+        assert log.result == main(1100)
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
             i11 = int_lt(i6, i7)
@@ -72,7 +75,7 @@
             i23 = strgetitem(p10, i19)
             p25 = newstr(1)
             strsetitem(p25, 0, i23)
-            p28 = call(ConstClass(strip_spaces), p25, descr=<GcPtrCallDescr>)
+            p28 = call(ConstClass(strip_spaces), p25, descr=<Callr . r EF=4>)
             guard_no_exception(descr=...)
             i29 = strlen(p28)
             i30 = int_is_true(i29)
@@ -88,9 +91,9 @@
             guard_false(i41, descr=...)
             i43 = int_eq(i39, 43)
             guard_false(i43, descr=...)
-            i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=<BoolCallDescr>)
+            i43 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr42), descr=<Calli 1 rr EF=0>)
             guard_false(i43, descr=...)
-            i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=<BoolCallDescr>)
+            i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=<Calli 1 rr EF=0>)
             guard_false(i46, descr=...)
             p51 = new_with_vtable(21136408)
             setfield_gc(p51, _, descr=...)    # 7 setfields, but the order is dict-order-dependent
@@ -100,9 +103,9 @@
             setfield_gc(p51, _, descr=...)
             setfield_gc(p51, _, descr=...)
             setfield_gc(p51, _, descr=...)
-            p55 = call(ConstClass(parse_digit_string), p51, descr=<GcPtrCallDescr>)
+            p55 = call(ConstClass(parse_digit_string), p51, descr=<Callr . r EF=4>)
             guard_no_exception(descr=...)
-            i57 = call(ConstClass(rbigint.toint), p55, descr=<SignedCallDescr>)
+            i57 = call(ConstClass(rbigint.toint), p55, descr=<Calli . r EF=3>)
             guard_no_exception(descr=...)
             i58 = int_add_ovf(i6, i57)
             guard_no_overflow(descr=...)
@@ -125,7 +128,7 @@
             i7 = int_gt(i4, 0)
             guard_true(i7, descr=...)
             guard_not_invalidated(descr=...)
-            p9 = call(ConstClass(ll_int2dec__Signed), i4, descr=<GcPtrCallDescr>)
+            p9 = call(ConstClass(ll_int2dec__Signed), i4, descr=<Callr . i EF=3>)
             guard_no_exception(descr=...)
             i10 = strlen(p9)
             i11 = int_is_true(i10)
@@ -149,7 +152,7 @@
             copystrcontent(p9, p21, 0, i25, i10)
             i33 = int_lt(i30, 23)
             guard_true(i33, descr=...)
-            p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=<GcPtrCallDescr>)
+            p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=<Callr . ri EF=4>)
             guard_no_exception(descr=...)
             i37 = strlen(p35)
             i38 = int_add_ovf(i5, i37)
@@ -192,6 +195,6 @@
             strsetitem(p35, 3, 104)
             strsetitem(p35, 4, 95)
             copystrcontent(p31, p35, 0, 5, i32)
-            i49 = call(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=<SignedCallDescr>)
-            guard_value(i49, 1, descr=<Guard8>)
+            i49 = call(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=<Calli [48] rr EF=0 OS=28>)
+            guard_value(i49, 1, descr=...)
             ''')
diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -524,11 +524,16 @@
             upper = maxsplit - 1
             assert upper >= 0
         first = False
-        for i in range(upper):
+        try:
+            for i in range(upper):
+                builder.append(by)
+                builder.append(input[i])
             builder.append(by)
-            builder.append(input[i])
-        builder.append(by)
-        builder.append_slice(input, upper, len(input))
+            builder.append_slice(input, upper, len(input))
+        except MemoryError:
+            raise OperationError(space.w_OverflowError,
+                space.wrap("replace string too long")
+            )
     else:
         start = 0
         sublen = len(sub)
diff --git a/pypy/objspace/std/test/test_stringobject.py b/pypy/objspace/std/test/test_stringobject.py
--- a/pypy/objspace/std/test/test_stringobject.py
+++ b/pypy/objspace/std/test/test_stringobject.py
@@ -737,13 +737,6 @@
         iterable = "hello"
         raises(TypeError, len, iter(iterable))
 
-    def test_overflow_replace(self):
-        import sys
-        if sys.maxint > 2**31-1:
-            skip("Wrong platform")
-        x = "A" * (2**16)
-        raises(OverflowError, x.replace, '', x)
-
 class AppTestPrebuilt(AppTestStringObject):
     def setup_class(cls):
         cls.space = gettestobjspace(**{"objspace.std.withprebuiltchar": True})
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -395,7 +395,6 @@
               'retrace_limit': 5,
               'max_retrace_guards': 15,
               'enable_opts': 'all',
-              'decay_halflife': 40,
               }
 unroll_parameters = unrolling_iterable(PARAMETERS.items())
 DEFAULT = object()
diff --git a/pypy/rlib/rstring.py b/pypy/rlib/rstring.py
--- a/pypy/rlib/rstring.py
+++ b/pypy/rlib/rstring.py
@@ -3,6 +3,7 @@
 
 from pypy.annotation.model import (SomeObject, SomeString, s_None, SomeChar,
     SomeInteger, SomeUnicodeCodePoint, SomeUnicodeString, SomePtr, SomePBC)
+from pypy.rlib.rarithmetic import ovfcheck
 from pypy.tool.pairtype import pair, pairtype
 from pypy.rpython.extregistry import ExtRegistryEntry
 
@@ -52,25 +53,37 @@
 class AbstractStringBuilder(object):
     def __init__(self, init_size=INIT_SIZE):
         self.l = []
+        self.size = 0
+
+    def _grow(self, size):
+        try:
+            self.size = ovfcheck(self.size + size)
+        except OverflowError:
+            raise MemoryError
 
     def append(self, s):
         assert isinstance(s, self.tp)
         self.l.append(s)
+        self._grow(len(s))
 
     def append_slice(self, s, start, end):
         assert isinstance(s, self.tp)
         assert 0 <= start <= end <= len(s)
-        self.l.append(s[start:end])
+        s = s[start:end]
+        self.l.append(s)
+        self._grow(len(s))
 
     def append_multiple_char(self, c, times):
         assert isinstance(c, self.tp)
         self.l.append(c * times)
+        self._grow(times)
 
     def append_charpsize(self, s, size):
         l = []
         for i in xrange(size):
             l.append(s[i])
         self.l.append(self.tp("").join(l))
+        self._grow(size)
 
     def build(self):
         return self.tp("").join(self.l)
diff --git a/pypy/rpython/lltypesystem/llarena.py b/pypy/rpython/lltypesystem/llarena.py
--- a/pypy/rpython/lltypesystem/llarena.py
+++ b/pypy/rpython/lltypesystem/llarena.py
@@ -374,6 +374,7 @@
     following an object.  For arenas containing heterogenous objects.
     If minsize is specified, it gives a minimum on the resulting size."""
     return _round_up_for_allocation(size, minsize)
+round_up_for_allocation._annenforceargs_ = [int, int]
 
 def _round_up_for_allocation(size, minsize):    # internal
     return RoundedUpForAllocation(size, minsize)
diff --git a/pypy/tool/jitlogparser/test/test_modulefinder.py b/pypy/tool/jitlogparser/test/test_modulefinder.py
--- a/pypy/tool/jitlogparser/test/test_modulefinder.py
+++ b/pypy/tool/jitlogparser/test/test_modulefinder.py
@@ -3,7 +3,7 @@
 import re, sys
 
 def setup_module(mod):
-    if sys.version_info[:2] != (2.6):
+    if sys.version_info[:2] != (2, 6):
         py.test.skip("Specific python 2.6 tests")
 
 def test_gather_code_py():


More information about the pypy-commit mailing list