[pypy-commit] pypy default: (fijal, arigo) merge optresult-unroll - this branch improves warmup by about

fijal noreply at buildbot.pypy.org
Tue Sep 8 15:11:53 CEST 2015


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: 
Changeset: r79543:3c45f447b1e3
Date: 2015-09-08 15:11 +0200
http://bitbucket.org/pypy/pypy/changeset/3c45f447b1e3/

Log:	(fijal, arigo) merge optresult-unroll - this branch improves warmup
	by about 20% by changing the underlaying structure of the
	ResOperations by killing Boxes. It also rewrites unrolling to
	something (hopefully) a bit saner

diff too long, truncating to 2000 out of 44326 lines

diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -341,8 +341,8 @@
 
     def jitpolicy(self, driver):
         from pypy.module.pypyjit.policy import PyPyJitPolicy
-        from pypy.module.pypyjit.hooks import pypy_hooks
-        return PyPyJitPolicy(pypy_hooks)
+        #from pypy.module.pypyjit.hooks import pypy_hooks
+        return PyPyJitPolicy()#pypy_hooks)
 
     def get_entry_point(self, config):
         from pypy.tool.lib_pypy import import_from_lib_pypy
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -111,7 +111,6 @@
                                      'interp_magic.mapdict_cache_counter')
         PYC_MAGIC = get_pyc_magic(self.space)
         self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC)
-        #
         try:
             from rpython.jit.backend import detect_cpu
             model = detect_cpu.autodetect()
@@ -121,7 +120,7 @@
                 raise
             else:
                 pass   # ok fine to ignore in this case
-        #
+        
         if self.space.config.translation.jit:
             features = detect_cpu.getcpufeatures(model)
             self.extra_interpdef('jit_backend_features',
diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py
--- a/pypy/module/pypyjit/__init__.py
+++ b/pypy/module/pypyjit/__init__.py
@@ -8,16 +8,16 @@
         'set_param':    'interp_jit.set_param',
         'residual_call': 'interp_jit.residual_call',
         'not_from_assembler': 'interp_jit.W_NotFromAssembler',
-        'set_compile_hook': 'interp_resop.set_compile_hook',
-        'set_optimize_hook': 'interp_resop.set_optimize_hook',
-        'set_abort_hook': 'interp_resop.set_abort_hook',
-        'get_stats_snapshot': 'interp_resop.get_stats_snapshot',
-        'enable_debug': 'interp_resop.enable_debug',
-        'disable_debug': 'interp_resop.disable_debug',
-        'ResOperation': 'interp_resop.WrappedOp',
-        'DebugMergePoint': 'interp_resop.DebugMergePoint',
-        'JitLoopInfo': 'interp_resop.W_JitLoopInfo',
-        'Box': 'interp_resop.WrappedBox',
+        #'set_compile_hook': 'interp_resop.set_compile_hook',
+        #'set_optimize_hook': 'interp_resop.set_optimize_hook',
+        #'set_abort_hook': 'interp_resop.set_abort_hook',
+        #'get_stats_snapshot': 'interp_resop.get_stats_snapshot',
+        #'enable_debug': 'interp_resop.enable_debug',
+        #'disable_debug': 'interp_resop.disable_debug',
+        #'ResOperation': 'interp_resop.WrappedOp',
+        #'DebugMergePoint': 'interp_resop.DebugMergePoint',
+        #'JitLoopInfo': 'interp_resop.W_JitLoopInfo',
+        #'Box': 'interp_resop.WrappedBox',
         'PARAMETER_DOCS': 'space.wrap(rpython.rlib.jit.PARAMETER_DOCS)',
     }
 
diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py
--- a/pypy/module/pypyjit/interp_resop.py
+++ b/pypy/module/pypyjit/interp_resop.py
@@ -8,7 +8,7 @@
 from rpython.rtyper.lltypesystem import lltype
 from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance, hlstr
 from rpython.rtyper.rclass import OBJECT
-from rpython.jit.metainterp.resoperation import rop
+#from rpython.jit.metainterp.resoperation import rop
 from rpython.rlib.nonconst import NonConstant
 from rpython.rlib import jit_hooks
 from rpython.rlib.jit import Counters
diff --git a/pypy/tool/pypyjit.py b/pypy/tool/pypyjit.py
--- a/pypy/tool/pypyjit.py
+++ b/pypy/tool/pypyjit.py
@@ -14,6 +14,9 @@
     print >> sys.stderr, __doc__
     sys.exit(2)
 
+import sys
+sys.setrecursionlimit(100000000)
+
 from pypy.objspace.std import Space
 from rpython.config.translationoption import set_opt_level
 from pypy.config.pypyoption import get_pypy_config, set_pypy_opt_level
@@ -22,6 +25,7 @@
 from rpython.rtyper.lltypesystem import lltype
 from pypy.interpreter.pycode import PyCode
 from rpython.translator.goal import unixcheckpoint
+import pypy.module.pypyjit.interp_jit
 
 config = get_pypy_config(translating=True)
 config.translation.backendopt.inline_threshold = 0.1
@@ -33,6 +37,8 @@
 config.objspace.usemodules.pypyjit = True
 config.objspace.usemodules.array = False
 config.objspace.usemodules._weakref = False
+config.objspace.usemodules.struct = True
+config.objspace.usemodules.time = True
 config.objspace.usemodules._sre = False
 config.objspace.usemodules._lsprof = False
 #
@@ -73,6 +79,7 @@
 read_code_ptr = llhelper(FPTR, read_code)
 
 def entry_point():
+    space.startup()
     from pypy.module.marshal.interp_marshal import loads
     code = loads(space, space.wrap(hlstr(read_code_ptr())))
     assert isinstance(code, PyCode)
diff --git a/pypy/tool/pypyjit_demo.py b/pypy/tool/pypyjit_demo.py
--- a/pypy/tool/pypyjit_demo.py
+++ b/pypy/tool/pypyjit_demo.py
@@ -1,8 +1,31 @@
-def f():
-    i = 0
-    while i < 1303:
-        i += 1
-    return i
 
+import time
+l = []
 
-f()
+for i in range(100):
+    print i
+    t0 = time.time()
+    exec """
+def k(a, b, c):
+    pass
+
+def g(a, b, c):
+    k(a, b + 1, c + 2)
+    k(a, b + 1, c + 2)
+    k(a, b + 1, c + 2)
+    k(a, b + 1, c + 2)
+    k(a, b + 1, c + 2)
+
+def f(i):
+    g(i, i + 1, i + 2)
+    g(i, i + 1, i + 2)
+    g(i, i + 1, i + 2)
+    g(i, i + 1, i + 2)
+    g(i, i + 1, i + 2)
+    g(i, i + 1, i + 2)
+for i in range(1000):
+    f(i)
+"""
+    l.append(time.time() - t0)
+
+print l
diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py
--- a/rpython/jit/backend/arm/assembler.py
+++ b/rpython/jit/backend/arm/assembler.py
@@ -708,7 +708,7 @@
         self.fixup_target_tokens(rawstart)
         self.update_frame_depth(frame_depth)
         if logger:
-            logger.log_bridge(inputargs, operations, "rewritten",
+            logger.log_bridge(inputargs, operations, "rewritten", faildescr,
                               ops_offset=ops_offset)
         self.teardown()
 
@@ -935,9 +935,9 @@
             op = operations[i]
             self.mc.mark_op(op)
             opnum = op.getopnum()
-            if op.has_no_side_effect() and op.result not in regalloc.longevity:
+            if op.has_no_side_effect() and op not in regalloc.longevity:
                 regalloc.possibly_free_vars_for_op(op)
-            elif not we_are_translated() and op.getopnum() == -124:
+            elif not we_are_translated() and op.getopnum() == -127:
                 regalloc.prepare_force_spill(op, fcond)
             else:
                 arglocs = regalloc_operations[opnum](regalloc, op, fcond)
@@ -947,8 +947,8 @@
                     assert fcond is not None
             if op.is_guard():
                 regalloc.possibly_free_vars(op.getfailargs())
-            if op.result:
-                regalloc.possibly_free_var(op.result)
+            if op.type != 'v':
+                regalloc.possibly_free_var(op)
             regalloc.possibly_free_vars_for_op(op)
             regalloc.free_temp_vars()
             regalloc._check_invariants()
diff --git a/rpython/jit/backend/arm/helper/assembler.py b/rpython/jit/backend/arm/helper/assembler.py
--- a/rpython/jit/backend/arm/helper/assembler.py
+++ b/rpython/jit/backend/arm/helper/assembler.py
@@ -2,7 +2,7 @@
 from rpython.jit.backend.arm import conditions as c
 from rpython.jit.backend.arm import registers as r
 from rpython.jit.backend.arm.codebuilder import InstrBuilder
-from rpython.jit.metainterp.history import ConstInt, BoxInt, FLOAT
+from rpython.jit.metainterp.history import FLOAT
 from rpython.rlib.rarithmetic import r_uint, r_longlong, intmask
 from rpython.jit.metainterp.resoperation import rop
 
@@ -50,7 +50,7 @@
     helper = getattr(InstrBuilder, opname)
     def f(self, op, arglocs, regalloc, fcond):
         assert fcond is not None
-        if op.result:
+        if op.type != 'v':
             regs = r.caller_resp[1:] + [r.ip]
         else:
             regs = r.caller_resp
diff --git a/rpython/jit/backend/arm/helper/regalloc.py b/rpython/jit/backend/arm/helper/regalloc.py
--- a/rpython/jit/backend/arm/helper/regalloc.py
+++ b/rpython/jit/backend/arm/helper/regalloc.py
@@ -1,14 +1,13 @@
 from rpython.jit.backend.arm import conditions as c
 from rpython.jit.backend.arm import registers as r
-from rpython.jit.metainterp.history import ConstInt, BoxInt, Box, FLOAT
-from rpython.jit.metainterp.history import ConstInt
+from rpython.jit.metainterp.history import Const, ConstInt, FLOAT
 from rpython.rlib.objectmodel import we_are_translated
 
 VMEM_imm_size=0x3FC
 default_imm_size=0xFF
 
 def check_imm_arg(arg, size=default_imm_size, allow_zero=True):
-    assert not isinstance(arg, ConstInt)
+    assert not isinstance(arg, Const)     # because it must be an int :-)
     if not we_are_translated():
         if not isinstance(arg, int):
             import pdb; pdb.set_trace()
@@ -44,7 +43,7 @@
             l1 = self.make_sure_var_in_reg(a1, boxes)
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.force_allocate_reg(op.result, boxes)
+        res = self.force_allocate_reg(op, boxes)
         return [l0, l1, res]
     if name:
         f.__name__ = name
@@ -54,7 +53,7 @@
     loc1 = self.make_sure_var_in_reg(op.getarg(0))
     self.possibly_free_vars_for_op(op)
     self.free_temp_vars()
-    res = self.force_allocate_reg(op.result)
+    res = self.force_allocate_reg(op)
     return [loc1, res]
 
 def prepare_two_regs_op(self, op, fcond):
@@ -62,7 +61,7 @@
     loc2 = self.make_sure_var_in_reg(op.getarg(1))
     self.possibly_free_vars_for_op(op)
     self.free_temp_vars()
-    res = self.force_allocate_reg(op.result)
+    res = self.force_allocate_reg(op)
     return [loc1, loc2, res]
 
 def prepare_float_cmp(self, op, fcond):
@@ -70,7 +69,7 @@
     loc2 = self.make_sure_var_in_reg(op.getarg(1))
     self.possibly_free_vars_for_op(op)
     self.free_temp_vars()
-    res = self.force_allocate_reg_or_cc(op.result)
+    res = self.force_allocate_reg_or_cc(op)
     return [loc1, loc2, res]
 
 def prepare_op_by_helper_call(name):
@@ -82,12 +81,12 @@
         arg2 = self.rm.make_sure_var_in_reg(a1, selected_reg=r.r1)
         assert arg1 == r.r0
         assert arg2 == r.r1
-        if isinstance(a0, Box) and self.stays_alive(a0):
+        if not isinstance(a0, Const) and self.stays_alive(a0):
             self.force_spill_var(a0)
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        self.after_call(op.result)
-        self.possibly_free_var(op.result)
+        self.after_call(op)
+        self.possibly_free_var(op)
         return []
     f.__name__ = name
     return f
@@ -106,14 +105,14 @@
 
     self.possibly_free_vars_for_op(op)
     self.free_temp_vars()
-    res = self.force_allocate_reg_or_cc(op.result)
+    res = self.force_allocate_reg_or_cc(op)
     return [l0, l1, res]
 
 def prepare_unary_cmp(self, op, fcond):
     assert fcond is not None
     a0 = op.getarg(0)
-    assert isinstance(a0, Box)
+    assert not isinstance(a0, Const)
     reg = self.make_sure_var_in_reg(a0)
     self.possibly_free_vars_for_op(op)
-    res = self.force_allocate_reg_or_cc(op.result)
+    res = self.force_allocate_reg_or_cc(op)
     return [reg, res]
diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -15,20 +15,21 @@
 from rpython.jit.backend.arm.helper.regalloc import VMEM_imm_size
 from rpython.jit.backend.arm.codebuilder import InstrBuilder, OverwritingBuilder
 from rpython.jit.backend.arm.jump import remap_frame_layout
-from rpython.jit.backend.arm.regalloc import TempBox
+from rpython.jit.backend.arm.regalloc import TempVar
 from rpython.jit.backend.arm.locations import imm, RawSPStackLocation
 from rpython.jit.backend.llsupport import symbolic
 from rpython.jit.backend.llsupport.gcmap import allocate_gcmap
 from rpython.jit.backend.llsupport.descr import InteriorFieldDescr
 from rpython.jit.backend.llsupport.assembler import GuardToken, BaseAssembler
 from rpython.jit.backend.llsupport.regalloc import get_scale
-from rpython.jit.metainterp.history import (Box, AbstractFailDescr, ConstInt,
+from rpython.jit.metainterp.history import (AbstractFailDescr, ConstInt,
                                             INT, FLOAT, REF)
 from rpython.jit.metainterp.history import TargetToken
 from rpython.jit.metainterp.resoperation import rop
 from rpython.rlib.objectmodel import we_are_translated
 from rpython.rtyper.lltypesystem import rstr, rffi, lltype
 from rpython.rtyper.annlowlevel import cast_instance_to_gcref
+from rpython.rtyper import rclass
 from rpython.jit.backend.arm import callbuilder
 from rpython.rlib.rarithmetic import r_uint
 
@@ -49,6 +50,8 @@
     def emit_op_int_add(self, op, arglocs, regalloc, fcond):
         return self.int_add_impl(op, arglocs, regalloc, fcond)
 
+    emit_op_nursery_ptr_increment = emit_op_int_add
+
     def int_add_impl(self, op, arglocs, regalloc, fcond, flags=False):
         l0, l1, res = arglocs
         if flags:
@@ -253,28 +256,105 @@
     def emit_op_guard_class(self, op, arglocs, regalloc, fcond):
         self._cmp_guard_class(op, arglocs, regalloc, fcond)
         self.guard_success_cc = c.EQ
-        self._emit_guard(op, arglocs[3:], save_exc=False)
+        self._emit_guard(op, arglocs[2:], save_exc=False)
         return fcond
 
     def emit_op_guard_nonnull_class(self, op, arglocs, regalloc, fcond):
         self.mc.CMP_ri(arglocs[0].value, 1)
         self._cmp_guard_class(op, arglocs, regalloc, c.HS)
         self.guard_success_cc = c.EQ
-        self._emit_guard(op, arglocs[3:], save_exc=False)
+        self._emit_guard(op, arglocs[2:], save_exc=False)
         return fcond
 
     def _cmp_guard_class(self, op, locs, regalloc, fcond):
-        offset = locs[2]
+        offset = self.cpu.vtable_offset
         if offset is not None:
-            self.mc.LDR_ri(r.ip.value, locs[0].value, offset.value, cond=fcond)
-            self.mc.CMP_rr(r.ip.value, locs[1].value, cond=fcond)
+            self.mc.LDR_ri(r.ip.value, locs[0].value, offset, cond=fcond)
+            self.mc.gen_load_int(r.lr.value, locs[1].value, cond=fcond)
+            self.mc.CMP_rr(r.ip.value, r.lr.value, cond=fcond)
         else:
-            typeid = locs[1]
-            self.mc.LDRH_ri(r.ip.value, locs[0].value, cond=fcond)
-            if typeid.is_imm():
-                self.mc.CMP_ri(r.ip.value, typeid.value, cond=fcond)
-            else:
-                self.mc.CMP_rr(r.ip.value, typeid.value, cond=fcond)
+            expected_typeid = (self.cpu.gc_ll_descr
+                    .get_typeid_from_classptr_if_gcremovetypeptr(locs[1].value))
+            self._cmp_guard_gc_type(locs[0], expected_typeid, fcond)
+
+    def _cmp_guard_gc_type(self, loc_ptr, expected_typeid, fcond=c.AL):
+        # Note that the typeid half-word is at offset 0 on a little-endian
+        # machine; it would be at offset 2 or 4 on a big-endian machine.
+        assert self.cpu.supports_guard_gc_type
+        self.mc.LDRH_ri(r.ip.value, loc_ptr.value, cond=fcond)
+        self.mc.gen_load_int(r.lr.value, expected_typeid, cond=fcond)
+        self.mc.CMP_rr(r.ip.value, r.lr.value, cond=fcond)
+
+    def emit_op_guard_gc_type(self, op, arglocs, regalloc, fcond):
+        self._cmp_guard_gc_type(arglocs[0], arglocs[1].value, fcond)
+        self.guard_success_cc = c.EQ
+        self._emit_guard(op, arglocs[2:], save_exc=False)
+        return fcond
+
+    def emit_op_guard_is_object(self, op, arglocs, regalloc, fcond):
+        assert self.cpu.supports_guard_gc_type
+        loc_object = arglocs[0]
+        # idea: read the typeid, fetch one byte of the field 'infobits' from
+        # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'.
+        self.mc.LDRH_ri(r.ip.value, loc_object.value)
+        #
+        base_type_info, shift_by, sizeof_ti = (
+            self.cpu.gc_ll_descr.get_translated_info_for_typeinfo())
+        infobits_offset, IS_OBJECT_FLAG = (
+            self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object())
+
+        self.mc.gen_load_int(r.lr.value, base_type_info + infobits_offset)
+        if shift_by > 0:
+            self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by)
+        self.mc.LDRB_rr(r.ip.value, r.ip.value, r.lr.value)
+        self.mc.TST_ri(r.ip.value, imm=(IS_OBJECT_FLAG & 0xff))
+        self.guard_success_cc = c.NE
+        self._emit_guard(op, arglocs[1:], save_exc=False)
+        return fcond
+
+    def emit_op_guard_subclass(self, op, arglocs, regalloc, fcond):
+        assert self.cpu.supports_guard_gc_type
+        loc_object = arglocs[0]
+        loc_check_against_class = arglocs[1]
+        offset = self.cpu.vtable_offset
+        offset2 = self.cpu.subclassrange_min_offset
+        if offset is not None:
+            # read this field to get the vtable pointer
+            self.mc.LDR_ri(r.ip.value, loc_object.value, offset)
+            # read the vtable's subclassrange_min field
+            self.mc.LDR_ri(r.ip.value, r.ip.value, offset2)
+        else:
+            # read the typeid
+            self.mc.LDRH_ri(r.ip.value, loc_object.value)
+            # read the vtable's subclassrange_min field, as a single
+            # step with the correct offset
+            base_type_info, shift_by, sizeof_ti = (
+                self.cpu.gc_ll_descr.get_translated_info_for_typeinfo())
+
+            self.mc.gen_load_int(r.lr.value,
+                                 base_type_info + sizeof_ti + offset2)
+            if shift_by > 0:
+                self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by)
+            self.mc.LDR_rr(r.ip.value, r.ip.value, r.lr.value)
+        # get the two bounds to check against
+        vtable_ptr = loc_check_against_class.getint()
+        vtable_ptr = rffi.cast(rclass.CLASSTYPE, vtable_ptr)
+        check_min = vtable_ptr.subclassrange_min
+        check_max = vtable_ptr.subclassrange_max
+        assert check_max > check_min
+        check_diff = check_max - check_min - 1
+        # check by doing the unsigned comparison (tmp - min) < (max - min)
+        self.mc.gen_load_int(r.lr.value, check_min)
+        self.mc.SUB_rr(r.ip.value, r.ip.value, r.lr.value)
+        if check_diff <= 0xff:
+            self.mc.CMP_ri(r.ip.value, check_diff)
+        else:
+            self.mc.gen_load_int(r.lr.value, check_diff)
+            self.mc.CMP_rr(r.ip.value, r.lr.value)
+        # the guard passes if we get a result of "below or equal"
+        self.guard_success_cc = c.LS
+        self._emit_guard(op, arglocs[2:], save_exc=False)
+        return fcond
 
     def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond):
         return self._emit_guard(op, locs, save_exc=False,
@@ -365,8 +445,12 @@
         self.gen_func_epilog()
         return fcond
 
-    def emit_op_call(self, op, arglocs, regalloc, fcond):
+    def _genop_call(self, op, arglocs, regalloc, fcond):
         return self._emit_call(op, arglocs, fcond=fcond)
+    emit_op_call_i = _genop_call
+    emit_op_call_r = _genop_call
+    emit_op_call_f = _genop_call
+    emit_op_call_n = _genop_call
 
     def _emit_call(self, op, arglocs, is_call_release_gil=False, fcond=c.AL):
         # args = [resloc, size, sign, args...]
@@ -396,14 +480,17 @@
             cb.emit()
         return fcond
 
-    def emit_op_same_as(self, op, arglocs, regalloc, fcond):
+    def _genop_same_as(self, op, arglocs, regalloc, fcond):
         argloc, resloc = arglocs
         if argloc is not resloc:
             self.mov_loc_loc(argloc, resloc)
         return fcond
 
-    emit_op_cast_ptr_to_int = emit_op_same_as
-    emit_op_cast_int_to_ptr = emit_op_same_as
+    emit_op_same_as_i = _genop_same_as
+    emit_op_same_as_r = _genop_same_as
+    emit_op_same_as_f = _genop_same_as
+    emit_op_cast_ptr_to_int = _genop_same_as
+    emit_op_cast_int_to_ptr = _genop_same_as
 
     def emit_op_guard_no_exception(self, op, arglocs, regalloc, fcond):
         loc = arglocs[0]
@@ -574,16 +661,23 @@
     emit_op_setfield_raw = emit_op_setfield_gc
     emit_op_zero_ptr_field = emit_op_setfield_gc
 
-    def emit_op_getfield_gc(self, op, arglocs, regalloc, fcond):
+    def _genop_getfield(self, op, arglocs, regalloc, fcond):
         base_loc, ofs, res, size = arglocs
         signed = op.getdescr().is_field_signed()
         scale = get_scale(size.value)
         self._load_from_mem(res, base_loc, ofs, imm(scale), signed, fcond)
         return fcond
 
-    emit_op_getfield_raw = emit_op_getfield_gc
-    emit_op_getfield_raw_pure = emit_op_getfield_gc
-    emit_op_getfield_gc_pure = emit_op_getfield_gc
+    emit_op_getfield_gc_i = _genop_getfield
+    emit_op_getfield_gc_r = _genop_getfield
+    emit_op_getfield_gc_f = _genop_getfield
+    emit_op_getfield_gc_pure_i = _genop_getfield
+    emit_op_getfield_gc_pure_r = _genop_getfield
+    emit_op_getfield_gc_pure_f = _genop_getfield
+    emit_op_getfield_raw_i = _genop_getfield
+    emit_op_getfield_raw_f = _genop_getfield
+    emit_op_getfield_raw_pure_i = _genop_getfield
+    emit_op_getfield_raw_pure_f = _genop_getfield
 
     def emit_op_increment_debug_counter(self, op, arglocs, regalloc, fcond):
         base_loc, value_loc = arglocs
@@ -592,7 +686,7 @@
         self.mc.STR_ri(value_loc.value, base_loc.value, 0, cond=fcond)
         return fcond
 
-    def emit_op_getinteriorfield_gc(self, op, arglocs, regalloc, fcond):
+    def _genop_getinteriorfield(self, op, arglocs, regalloc, fcond):
         (base_loc, index_loc, res_loc,
             ofs_loc, ofs, itemsize, fieldsize) = arglocs
         scale = get_scale(fieldsize.value)
@@ -613,6 +707,10 @@
                                 imm(scale), signed, fcond)
         return fcond
 
+    emit_op_getinteriorfield_gc_i = _genop_getinteriorfield
+    emit_op_getinteriorfield_gc_r = _genop_getinteriorfield
+    emit_op_getinteriorfield_gc_f = _genop_getinteriorfield
+
     def emit_op_setinteriorfield_gc(self, op, arglocs, regalloc, fcond):
         (base_loc, index_loc, value_loc,
             ofs_loc, ofs, itemsize, fieldsize) = arglocs
@@ -697,12 +795,13 @@
         self._write_to_mem(value_loc, base_loc, ofs_loc, scale, fcond)
         return fcond
 
-    def emit_op_getarrayitem_gc(self, op, arglocs, regalloc, fcond):
+    def _genop_getarrayitem(self, op, arglocs, regalloc, fcond):
         res_loc, base_loc, ofs_loc, scale, ofs = arglocs
         assert ofs_loc.is_core_reg()
         signed = op.getdescr().is_item_signed()
 
         # scale the offset as required
+        # XXX we should try to encode the scale inside the "shift" part of LDR
         if scale.value > 0:
             self.mc.LSL_ri(r.ip.value, ofs_loc.value, scale.value)
             ofs_loc = r.ip
@@ -714,6 +813,17 @@
         self._load_from_mem(res_loc, base_loc, ofs_loc, scale, signed, fcond)
         return fcond
 
+    emit_op_getarrayitem_gc_i = _genop_getarrayitem
+    emit_op_getarrayitem_gc_r = _genop_getarrayitem
+    emit_op_getarrayitem_gc_f = _genop_getarrayitem
+    emit_op_getarrayitem_gc_pure_i = _genop_getarrayitem
+    emit_op_getarrayitem_gc_pure_r = _genop_getarrayitem
+    emit_op_getarrayitem_gc_pure_f = _genop_getarrayitem
+    emit_op_getarrayitem_raw_i = _genop_getarrayitem
+    emit_op_getarrayitem_raw_f = _genop_getarrayitem
+    emit_op_getarrayitem_raw_pure_i = _genop_getarrayitem
+    emit_op_getarrayitem_raw_pure_f = _genop_getarrayitem
+
     def _load_from_mem(self, res_loc, base_loc, ofs_loc, scale,
                                             signed=False, fcond=c.AL):
         if scale.value == 3:
@@ -771,10 +881,7 @@
         else:
             assert 0
 
-    emit_op_getarrayitem_raw = emit_op_getarrayitem_gc
-    emit_op_getarrayitem_gc_pure = emit_op_getarrayitem_gc
-
-    def emit_op_raw_load(self, op, arglocs, regalloc, fcond):
+    def _genop_raw_load(self, op, arglocs, regalloc, fcond):
         res_loc, base_loc, ofs_loc, scale, ofs = arglocs
         assert ofs_loc.is_core_reg()
         # no base offset
@@ -783,6 +890,9 @@
         self._load_from_mem(res_loc, base_loc, ofs_loc, scale, signed, fcond)
         return fcond
 
+    emit_op_raw_load_i = _genop_raw_load
+    emit_op_raw_load_f = _genop_raw_load
+
     def emit_op_strlen(self, op, arglocs, regalloc, fcond):
         l0, l1, res = arglocs
         if l1.is_imm():
@@ -833,7 +943,7 @@
         base_loc = regalloc.rm.make_sure_var_in_reg(args[0], args)
         ofs_loc = regalloc.rm.make_sure_var_in_reg(args[2], args)
         assert args[0] is not args[1]    # forbidden case of aliasing
-        srcaddr_box = TempBox()
+        srcaddr_box = TempVar()
         forbidden_vars = [args[1], args[3], args[4], srcaddr_box]
         srcaddr_loc = regalloc.rm.force_allocate_reg(srcaddr_box, forbidden_vars)
         self._gen_address_inside_string(base_loc, ofs_loc, srcaddr_loc,
@@ -842,7 +952,7 @@
         base_loc = regalloc.rm.make_sure_var_in_reg(args[1], forbidden_vars)
         ofs_loc = regalloc.rm.make_sure_var_in_reg(args[3], forbidden_vars)
         forbidden_vars = [args[4], srcaddr_box]
-        dstaddr_box = TempBox()
+        dstaddr_box = TempVar()
         dstaddr_loc = regalloc.rm.force_allocate_reg(dstaddr_box, forbidden_vars)
         self._gen_address_inside_string(base_loc, ofs_loc, dstaddr_loc,
                                         is_unicode=is_unicode)
@@ -851,7 +961,7 @@
         length_loc = regalloc.loc(length_box)
         if is_unicode:
             forbidden_vars = [srcaddr_box, dstaddr_box]
-            bytes_box = TempBox()
+            bytes_box = TempVar()
             bytes_loc = regalloc.rm.force_allocate_reg(bytes_box, forbidden_vars)
             scale = self._get_unicode_item_scale()
             if not length_loc.is_core_reg():
@@ -952,7 +1062,7 @@
     def imm(self, v):
         return imm(v)
 
-    def emit_op_call_assembler(self, op, arglocs, regalloc, fcond):
+    def _genop_call_assembler(self, op, arglocs, regalloc, fcond):
         if len(arglocs) == 4:
             [argloc, vloc, result_loc, tmploc] = arglocs
         else:
@@ -961,6 +1071,10 @@
         self._store_force_index(self._find_nearby_operation(+1))
         self.call_assembler(op, argloc, vloc, result_loc, tmploc)
         return fcond
+    emit_op_call_assembler_i = _genop_call_assembler
+    emit_op_call_assembler_r = _genop_call_assembler
+    emit_op_call_assembler_f = _genop_call_assembler
+    emit_op_call_assembler_n = _genop_call_assembler
 
     def _call_assembler_emit_call(self, addr, argloc, resloc):
         ofs = self.saved_threadlocal_addr
@@ -991,9 +1105,9 @@
         return pos
 
     def _call_assembler_load_result(self, op, result_loc):
-        if op.result is not None:
+        if op.type != 'v':
             # load the return value from (tmploc, 0)
-            kind = op.result.type
+            kind = op.type
             descr = self.cpu.getarraydescr_for_frame(kind)
             if kind == FLOAT:
                 ofs = self.cpu.unpack_arraydescr(descr)
@@ -1041,15 +1155,23 @@
         self._emit_guard(op, arglocs, save_exc=True, is_guard_not_forced=True)
         return fcond
 
-    def emit_op_call_may_force(self, op, arglocs, regalloc, fcond):
+    def _genop_call_may_force(self, op, arglocs, regalloc, fcond):
         self._store_force_index(self._find_nearby_operation(+1))
         self._emit_call(op, arglocs, fcond=fcond)
         return fcond
+    emit_op_call_may_force_i = _genop_call_may_force
+    emit_op_call_may_force_r = _genop_call_may_force
+    emit_op_call_may_force_f = _genop_call_may_force
+    emit_op_call_may_force_n = _genop_call_may_force
 
-    def emit_op_call_release_gil(self, op, arglocs, regalloc, fcond):
+    def _genop_call_release_gil(self, op, arglocs, regalloc, fcond):
         self._store_force_index(self._find_nearby_operation(+1))
         self._emit_call(op, arglocs, is_call_release_gil=True)
         return fcond
+    emit_op_call_release_gil_i = _genop_call_release_gil
+    emit_op_call_release_gil_r = _genop_call_release_gil
+    emit_op_call_release_gil_f = _genop_call_release_gil
+    emit_op_call_release_gil_n = _genop_call_release_gil
 
     def _store_force_index(self, guard_op):
         assert (guard_op.getopnum() == rop.GUARD_NOT_FORCED or
@@ -1065,7 +1187,7 @@
         return regalloc.operations[regalloc.rm.position + delta]
 
     def emit_op_call_malloc_gc(self, op, arglocs, regalloc, fcond):
-        self.emit_op_call(op, arglocs, regalloc, fcond)
+        self._emit_call(op, arglocs, fcond=fcond)
         self.propagate_memoryerror_if_r0_is_null()
         self._alignment_check()
         return fcond
@@ -1183,7 +1305,7 @@
         # address that we will pass as first argument to memset().
         # It can be in the same register as either one, but not in
         # args[2], because we're still needing the latter.
-        dstaddr_box = TempBox()
+        dstaddr_box = TempVar()
         dstaddr_loc = regalloc.rm.force_allocate_reg(dstaddr_box, [args[2]])
         if startindex >= 0:    # a constant
             ofs = baseofs + startindex * itemsize
@@ -1239,7 +1361,7 @@
                     # we need a register that is different from dstaddr_loc,
                     # but which can be identical to length_loc (as usual,
                     # only if the length_box is not used by future operations)
-                    bytes_box = TempBox()
+                    bytes_box = TempVar()
                     bytes_loc = regalloc.rm.force_allocate_reg(bytes_box,
                                                                [dstaddr_box])
                     self.mc.gen_load_int(r.ip.value, itemsize)
diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -2,7 +2,7 @@
 from rpython.rlib import rgc
 from rpython.rlib.debug import debug_print, debug_start, debug_stop
 from rpython.jit.backend.llsupport.regalloc import FrameManager, \
-        RegisterManager, TempBox, compute_vars_longevity, BaseRegalloc, \
+        RegisterManager, TempVar, compute_vars_longevity, BaseRegalloc, \
         get_scale
 from rpython.jit.backend.arm import registers as r
 from rpython.jit.backend.arm import conditions as c
@@ -24,8 +24,7 @@
 from rpython.jit.backend.arm.arch import WORD, JITFRAME_FIXED_SIZE
 from rpython.jit.codewriter import longlong
 from rpython.jit.metainterp.history import (Const, ConstInt, ConstFloat,
-                                            ConstPtr, BoxInt,
-                                            Box, BoxPtr,
+                                            ConstPtr,
                                             INT, REF, FLOAT)
 from rpython.jit.metainterp.history import TargetToken
 from rpython.jit.metainterp.resoperation import rop
@@ -46,21 +45,21 @@
 # that it is a LABEL that was not compiled yet.
 TargetToken._ll_loop_code = 0
 
-class TempInt(TempBox):
+class TempInt(TempVar):
     type = INT
 
     def __repr__(self):
         return "<TempInt at %s>" % (id(self),)
 
 
-class TempPtr(TempBox):
+class TempPtr(TempVar):
     type = REF
 
     def __repr__(self):
         return "<TempPtr at %s>" % (id(self),)
 
 
-class TempFloat(TempBox):
+class TempFloat(TempVar):
     type = FLOAT
 
     def __repr__(self):
@@ -225,6 +224,8 @@
             return self.rm.call_result_location(v)
 
     def after_call(self, v):
+        if v.type == 'v':
+            return
         if v.type == FLOAT:
             return self.vfprm.after_call(v)
         else:
@@ -434,9 +435,11 @@
         locs = self._prepare_op_int_add(op, fcond)
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.force_allocate_reg(op.result)
+        res = self.force_allocate_reg(op)
         return locs + [res]
 
+    prepare_op_nursery_ptr_increment = prepare_op_int_add
+
     def _prepare_op_int_sub(self, op, fcond):
         a0, a1 = boxes = op.getarglist()
         imm_a0 = check_imm_box(a0)
@@ -456,7 +459,7 @@
         locs = self._prepare_op_int_sub(op, fcond)
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.force_allocate_reg(op.result)
+        res = self.force_allocate_reg(op)
         return locs + [res]
 
     def prepare_op_int_mul(self, op, fcond):
@@ -468,19 +471,19 @@
 
         self.possibly_free_vars(boxes)
         self.possibly_free_vars_for_op(op)
-        res = self.force_allocate_reg(op.result)
-        self.possibly_free_var(op.result)
+        res = self.force_allocate_reg(op)
+        self.possibly_free_var(op)
         return [reg1, reg2, res]
 
     def prepare_op_int_force_ge_zero(self, op, fcond):
         argloc = self.make_sure_var_in_reg(op.getarg(0))
-        resloc = self.force_allocate_reg(op.result, [op.getarg(0)])
+        resloc = self.force_allocate_reg(op, [op.getarg(0)])
         return [argloc, resloc]
 
     def prepare_op_int_signext(self, op, fcond):
         argloc = self.make_sure_var_in_reg(op.getarg(0))
         numbytes = op.getarg(1).getint()
-        resloc = self.force_allocate_reg(op.result)
+        resloc = self.force_allocate_reg(op)
         return [argloc, imm(numbytes), resloc]
 
     prepare_op_int_floordiv = prepare_op_by_helper_call('int_floordiv')
@@ -523,7 +526,7 @@
     prepare_op_int_neg = prepare_unary_op
     prepare_op_int_invert = prepare_unary_op
 
-    def prepare_op_call(self, op, fcond):
+    def _prepare_op_call(self, op, fcond):
         calldescr = op.getdescr()
         assert calldescr is not None
         effectinfo = calldescr.get_extra_info()
@@ -554,6 +557,11 @@
             #    ...
         return self._prepare_call(op)
 
+    prepare_op_call_i = _prepare_op_call
+    prepare_op_call_r = _prepare_op_call
+    prepare_op_call_f = _prepare_op_call
+    prepare_op_call_n = _prepare_op_call
+
     def _prepare_call(self, op, force_store=[], save_all_regs=False,
                       first_arg_index=1):
         args = [None] * (op.numargs() + 3)
@@ -584,9 +592,7 @@
             if gcrootmap and gcrootmap.is_shadow_stack:
                 save_all_regs = 2
         self.rm.before_call(force_store, save_all_regs=save_all_regs)
-        resloc = None
-        if op.result:
-            resloc = self.after_call(op.result)
+        resloc = self.after_call(op)
         return resloc
 
     def prepare_op_call_malloc_gc(self, op, fcond):
@@ -598,12 +604,12 @@
         loc1 = self.make_sure_var_in_reg(op.getarg(2))
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.vfprm.force_allocate_reg(op.result)
+        res = self.vfprm.force_allocate_reg(op)
         return [loc0, loc1, res]
 
     def _prepare_llong_to_int(self, op, fcond):
         loc0 = self.make_sure_var_in_reg(op.getarg(1))
-        res = self.force_allocate_reg(op.result)
+        res = self.force_allocate_reg(op)
         return [loc0, res]
 
     def _prepare_threadlocalref_get(self, op, fcond):
@@ -611,7 +617,7 @@
         calldescr = op.getdescr()
         size_loc = imm(calldescr.get_result_size())
         sign_loc = imm(calldescr.is_result_signed())
-        res_loc = self.force_allocate_reg(op.result)
+        res_loc = self.force_allocate_reg(op)
         return [ofs_loc, size_loc, sign_loc, res_loc]
 
     def _prepare_guard(self, op, args=None):
@@ -669,7 +675,6 @@
             l1 = self.make_sure_var_in_reg(a1, boxes)
         else:
             l1 = self.convert_to_imm(a1)
-        assert op.result is None
         arglocs = self._prepare_guard(op, [l0, l1])
         self.possibly_free_vars(op.getarglist())
         self.possibly_free_vars(op.getfailargs())
@@ -689,9 +694,9 @@
         arg0 = ConstInt(rffi.cast(lltype.Signed, op.getarg(0).getint()))
         loc = self.make_sure_var_in_reg(arg0)
         loc1 = self.get_scratch_reg(INT, boxes)
-        if op.result in self.longevity:
-            resloc = self.force_allocate_reg(op.result, boxes)
-            self.possibly_free_var(op.result)
+        if op in self.longevity:
+            resloc = self.force_allocate_reg(op, boxes)
+            self.possibly_free_var(op)
         else:
             resloc = None
         pos_exc_value = imm(self.cpu.pos_exc_value())
@@ -706,55 +711,20 @@
         return arglocs
 
     def prepare_op_guard_class(self, op, fcond):
-        return self._prepare_guard_class(op, fcond)
-
-    prepare_op_guard_nonnull_class = prepare_op_guard_class
-
-    def _prepare_guard_class(self, op, fcond):
-        assert isinstance(op.getarg(0), Box)
+        assert not isinstance(op.getarg(0), Const)
         boxes = op.getarglist()
 
         x = self.make_sure_var_in_reg(boxes[0], boxes)
-        y_val = rffi.cast(lltype.Signed, op.getarg(1).getint())
+        y_val = rffi.cast(lltype.Signed, boxes[1].getint())
+        return self._prepare_guard(op, [x, imm(y_val)])
 
-        arglocs = [x, None, None]
+    prepare_op_guard_nonnull_class = prepare_op_guard_class
+    prepare_op_guard_gc_type = prepare_op_guard_class
+    prepare_op_guard_subclass = prepare_op_guard_class
 
-        offset = self.cpu.vtable_offset
-        if offset is not None:
-            y = self.get_scratch_reg(INT, forbidden_vars=boxes)
-            self.assembler.load(y, imm(y_val))
-
-            assert check_imm_arg(offset)
-            offset_loc = imm(offset)
-
-            arglocs[1] = y
-            arglocs[2] = offset_loc
-        else:
-            # XXX hard-coded assumption: to go from an object to its class
-            # we use the following algorithm:
-            #   - read the typeid from mem(locs[0]), i.e. at offset 0
-            #   - keep the lower 16 bits read there
-            #   - multiply by 4 and use it as an offset in type_info_group
-            #   - add 16 bytes, to go past the TYPE_INFO structure
-            classptr = y_val
-            # here, we have to go back from 'classptr' to the value expected
-            # from reading the 16 bits in the object header
-            from rpython.memory.gctypelayout import GCData
-            sizeof_ti = rffi.sizeof(GCData.TYPE_INFO)
-            type_info_group = llop.gc_get_type_info_group(llmemory.Address)
-            type_info_group = rffi.cast(lltype.Signed, type_info_group)
-            expected_typeid = classptr - sizeof_ti - type_info_group
-            expected_typeid >>= 2
-            if check_imm_arg(expected_typeid):
-                arglocs[1] = imm(expected_typeid)
-            else:
-                y = self.get_scratch_reg(INT, forbidden_vars=boxes)
-                self.assembler.load(y, imm(expected_typeid))
-                arglocs[1] = y
-
-        return self._prepare_guard(op, arglocs)
-
-        return arglocs
+    def prepare_op_guard_is_object(self, op, fcond):
+        loc_object = self.make_sure_var_in_reg(op.getarg(0))
+        return self._prepare_guard(op, [loc_object])
 
     def compute_hint_frame_locations(self, operations):
         # optimization only: fill in the 'hint_frame_locations' dictionary
@@ -782,7 +752,7 @@
         assert len(arglocs) == jump_op.numargs()
         for i in range(jump_op.numargs()):
             box = jump_op.getarg(i)
-            if isinstance(box, Box):
+            if not isinstance(box, Const):
                 loc = arglocs[i]
                 if loc is not None and loc.is_stack():
                     self.frame_manager.hint_frame_pos[box] = (
@@ -847,7 +817,7 @@
         ofs = op.getarg(1).getint()
         return self._prepare_op_setfield([a0, ConstInt(0)], ofs, WORD)
 
-    def prepare_op_getfield_gc(self, op, fcond):
+    def _prepare_op_getfield(self, op, fcond):
         a0 = op.getarg(0)
         ofs, size, sign = unpack_fielddescr(op.getdescr())
         base_loc = self.make_sure_var_in_reg(a0)
@@ -860,12 +830,19 @@
             self.assembler.load(ofs_loc, immofs)
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.force_allocate_reg(op.result)
+        res = self.force_allocate_reg(op)
         return [base_loc, ofs_loc, res, imm(size)]
 
-    prepare_op_getfield_raw = prepare_op_getfield_gc
-    prepare_op_getfield_raw_pure = prepare_op_getfield_gc
-    prepare_op_getfield_gc_pure = prepare_op_getfield_gc
+    prepare_op_getfield_gc_i = _prepare_op_getfield
+    prepare_op_getfield_gc_r = _prepare_op_getfield
+    prepare_op_getfield_gc_f = _prepare_op_getfield
+    prepare_op_getfield_raw_i = _prepare_op_getfield
+    prepare_op_getfield_raw_f = _prepare_op_getfield
+    prepare_op_getfield_raw_pure_i = _prepare_op_getfield
+    prepare_op_getfield_raw_pure_f = _prepare_op_getfield
+    prepare_op_getfield_gc_pure_i = _prepare_op_getfield
+    prepare_op_getfield_gc_pure_r = _prepare_op_getfield
+    prepare_op_getfield_gc_pure_f = _prepare_op_getfield
 
     def prepare_op_increment_debug_counter(self, op, fcond):
         boxes = op.getarglist()
@@ -875,7 +852,7 @@
         self.free_temp_vars()
         return [base_loc, value_loc]
 
-    def prepare_op_getinteriorfield_gc(self, op, fcond):
+    def _prepare_op_getinteriorfield(self, op, fcond):
         t = unpack_interiorfielddescr(op.getdescr())
         ofs, itemsize, fieldsize, sign = t
         args = op.getarglist()
@@ -890,10 +867,14 @@
             self.assembler.load(ofs_loc, immofs)
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        result_loc = self.force_allocate_reg(op.result)
+        result_loc = self.force_allocate_reg(op)
         return [base_loc, index_loc, result_loc, ofs_loc, imm(ofs),
                                     imm(itemsize), imm(fieldsize)]
 
+    prepare_op_getinteriorfield_gc_i = _prepare_op_getinteriorfield
+    prepare_op_getinteriorfield_gc_r = _prepare_op_getinteriorfield
+    prepare_op_getinteriorfield_gc_f = _prepare_op_getinteriorfield
+
     def prepare_op_setinteriorfield_gc(self, op, fcond):
         t = unpack_interiorfielddescr(op.getdescr())
         ofs, itemsize, fieldsize, sign = t
@@ -920,7 +901,7 @@
         base_loc = self.make_sure_var_in_reg(arg)
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.force_allocate_reg(op.result)
+        res = self.force_allocate_reg(op)
         return [res, base_loc, imm(ofs)]
 
     def prepare_op_setarrayitem_gc(self, op, fcond):
@@ -935,7 +916,7 @@
     prepare_op_setarrayitem_raw = prepare_op_setarrayitem_gc
     prepare_op_raw_store = prepare_op_setarrayitem_gc
 
-    def prepare_op_getarrayitem_gc(self, op, fcond):
+    def _prepare_op_getarrayitem(self, op, fcond):
         boxes = op.getarglist()
         size, ofs, _ = unpack_arraydescr(op.getdescr())
         scale = get_scale(size)
@@ -943,14 +924,22 @@
         ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes)
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.force_allocate_reg(op.result)
+        res = self.force_allocate_reg(op)
         assert check_imm_arg(ofs)
         return [res, base_loc, ofs_loc, imm(scale), imm(ofs)]
 
-    prepare_op_getarrayitem_raw = prepare_op_getarrayitem_gc
-    prepare_op_getarrayitem_raw_pure = prepare_op_getarrayitem_gc
-    prepare_op_getarrayitem_gc_pure = prepare_op_getarrayitem_gc
-    prepare_op_raw_load = prepare_op_getarrayitem_gc
+    prepare_op_getarrayitem_gc_i = _prepare_op_getarrayitem
+    prepare_op_getarrayitem_gc_r = _prepare_op_getarrayitem
+    prepare_op_getarrayitem_gc_f = _prepare_op_getarrayitem
+    prepare_op_getarrayitem_raw_i = _prepare_op_getarrayitem
+    prepare_op_getarrayitem_raw_f = _prepare_op_getarrayitem
+    prepare_op_getarrayitem_raw_pure_i = _prepare_op_getarrayitem
+    prepare_op_getarrayitem_raw_pure_f = _prepare_op_getarrayitem
+    prepare_op_getarrayitem_gc_pure_i = _prepare_op_getarrayitem
+    prepare_op_getarrayitem_gc_pure_r = _prepare_op_getarrayitem
+    prepare_op_getarrayitem_gc_pure_f = _prepare_op_getarrayitem
+    prepare_op_raw_load_i = _prepare_op_getarrayitem
+    prepare_op_raw_load_f = _prepare_op_getarrayitem
 
     def prepare_op_strlen(self, op, fcond):
         args = op.getarglist()
@@ -967,8 +956,8 @@
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
 
-        res = self.force_allocate_reg(op.result)
-        self.possibly_free_var(op.result)
+        res = self.force_allocate_reg(op)
+        self.possibly_free_var(op)
         return [l0, l1, res]
 
     def prepare_op_strgetitem(self, op, fcond):
@@ -984,7 +973,7 @@
 
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.force_allocate_reg(op.result)
+        res = self.force_allocate_reg(op)
 
         basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
                                          self.cpu.translate_support_code)
@@ -1018,7 +1007,7 @@
 
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.force_allocate_reg(op.result)
+        res = self.force_allocate_reg(op)
         return [l0, l1, res]
 
     def prepare_op_unicodegetitem(self, op, fcond):
@@ -1028,7 +1017,7 @@
 
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.force_allocate_reg(op.result)
+        res = self.force_allocate_reg(op)
 
         basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
                                          self.cpu.translate_support_code)
@@ -1047,7 +1036,7 @@
         return [value_loc, base_loc, ofs_loc,
             imm(scale), imm(basesize), imm(itemsize)]
 
-    def prepare_op_same_as(self, op, fcond):
+    def _prepare_op_same_as(self, op, fcond):
         arg = op.getarg(0)
         imm_arg = check_imm_box(arg)
         if imm_arg:
@@ -1056,18 +1045,21 @@
             argloc = self.make_sure_var_in_reg(arg)
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        resloc = self.force_allocate_reg(op.result)
+        resloc = self.force_allocate_reg(op)
         return [argloc, resloc]
 
-    prepare_op_cast_ptr_to_int = prepare_op_same_as
-    prepare_op_cast_int_to_ptr = prepare_op_same_as
+    prepare_op_cast_ptr_to_int = _prepare_op_same_as
+    prepare_op_cast_int_to_ptr = _prepare_op_same_as
+    prepare_op_same_as_i = _prepare_op_same_as
+    prepare_op_same_as_r = _prepare_op_same_as
+    prepare_op_same_as_f = _prepare_op_same_as
 
     def prepare_op_call_malloc_nursery(self, op, fcond):
         size_box = op.getarg(0)
         assert isinstance(size_box, ConstInt)
         size = size_box.getint()
 
-        self.rm.force_allocate_reg(op.result, selected_reg=r.r0)
+        self.rm.force_allocate_reg(op, selected_reg=r.r0)
         t = TempInt()
         self.rm.force_allocate_reg(t, selected_reg=r.r1)
 
@@ -1085,13 +1077,13 @@
 
     def prepare_op_call_malloc_nursery_varsize_frame(self, op, fcond):
         size_box = op.getarg(0)
-        assert isinstance(size_box, BoxInt) # we cannot have a const here!
+        assert not isinstance(size_box, ConstInt) # we cannot have a const here!
         # sizeloc must be in a register, but we can free it now
         # (we take care explicitly of conflicts with r0 or r1)
         sizeloc = self.rm.make_sure_var_in_reg(size_box)
         self.rm.possibly_free_var(size_box)
         #
-        self.rm.force_allocate_reg(op.result, selected_reg=r.r0)
+        self.rm.force_allocate_reg(op, selected_reg=r.r0)
         #
         t = TempInt()
         self.rm.force_allocate_reg(t, selected_reg=r.r1)
@@ -1115,11 +1107,11 @@
             # for boehm, this function should never be called
         arraydescr = op.getdescr()
         length_box = op.getarg(2)
-        assert isinstance(length_box, BoxInt) # we cannot have a const here!
+        assert not isinstance(length_box, Const) # we cannot have a const here!
         # the result will be in r0
-        self.rm.force_allocate_reg(op.result, selected_reg=r.r0)
+        self.rm.force_allocate_reg(op, selected_reg=r.r0)
         # we need r1 as a temporary
-        tmp_box = TempBox()
+        tmp_box = TempVar()
         self.rm.force_allocate_reg(tmp_box, selected_reg=r.r1)
         gcmap = self.get_gcmap([r.r0, r.r1]) # allocate the gcmap *before*
         self.rm.possibly_free_var(tmp_box)
@@ -1144,7 +1136,6 @@
     prepare_op_leave_portal_frame = void
 
     def prepare_op_cond_call_gc_wb(self, op, fcond):
-        assert op.result is None
         # we force all arguments in a reg because it will be needed anyway by
         # the following setfield_gc or setarrayitem_gc. It avoids loading it
         # twice from the memory.
@@ -1160,7 +1151,6 @@
     prepare_op_cond_call_gc_wb_array = prepare_op_cond_call_gc_wb
 
     def prepare_op_cond_call(self, op, fcond):
-        assert op.result is None
         assert 2 <= op.numargs() <= 4 + 2
         tmpreg = self.get_scratch_reg(INT, selected_reg=r.r4)
         v = op.getarg(1)
@@ -1178,8 +1168,7 @@
 
     def prepare_op_force_token(self, op, fcond):
         # XXX for now we return a regular reg
-        res_loc = self.force_allocate_reg(op.result)
-        self.possibly_free_var(op.result)
+        res_loc = self.force_allocate_reg(op)
         return [res_loc]
 
     def prepare_op_label(self, op, fcond):
@@ -1194,14 +1183,14 @@
         # of some guard
         position = self.rm.position
         for arg in inputargs:
-            assert isinstance(arg, Box)
+            assert not isinstance(arg, Const)
             if self.last_real_usage.get(arg, -1) <= position:
                 self.force_spill_var(arg)
 
         #
         for i in range(len(inputargs)):
             arg = inputargs[i]
-            assert isinstance(arg, Box)
+            assert not isinstance(arg, Const)
             loc = self.loc(arg)
             arglocs[i] = loc
             if loc.is_core_reg() or loc.is_vfp_reg():
@@ -1228,18 +1217,33 @@
         self.assembler.store_force_descr(op, fail_locs[1:], fail_locs[0].value)
         self.possibly_free_vars(op.getfailargs())
 
-    def prepare_op_call_may_force(self, op, fcond):
+    def _prepare_op_call_may_force(self, op, fcond):
         return self._prepare_call(op, save_all_regs=True)
 
-    def prepare_op_call_release_gil(self, op, fcond):
+    prepare_op_call_may_force_i = _prepare_op_call_may_force
+    prepare_op_call_may_force_r = _prepare_op_call_may_force
+    prepare_op_call_may_force_f = _prepare_op_call_may_force
+    prepare_op_call_may_force_n = _prepare_op_call_may_force
+
+    def _prepare_op_call_release_gil(self, op, fcond):
         return self._prepare_call(op, save_all_regs=True, first_arg_index=2)
 
-    def prepare_op_call_assembler(self, op, fcond):
+    prepare_op_call_release_gil_i = _prepare_op_call_release_gil
+    prepare_op_call_release_gil_r = _prepare_op_call_release_gil
+    prepare_op_call_release_gil_f = _prepare_op_call_release_gil
+    prepare_op_call_release_gil_n = _prepare_op_call_release_gil
+
+    def _prepare_op_call_assembler(self, op, fcond):
         locs = self.locs_for_call_assembler(op)
         tmploc = self.get_scratch_reg(INT, selected_reg=r.r0)
         resloc = self._call(op, locs + [tmploc], save_all_regs=True)
         return locs + [resloc, tmploc]
 
+    prepare_op_call_assembler_i = _prepare_op_call_assembler
+    prepare_op_call_assembler_r = _prepare_op_call_assembler
+    prepare_op_call_assembler_f = _prepare_op_call_assembler
+    prepare_op_call_assembler_n = _prepare_op_call_assembler
+
     def _prepare_args_for_new_op(self, new_args):
         gc_ll_descr = self.cpu.gc_ll_descr
         args = gc_ll_descr.args_for_new(new_args)
@@ -1269,18 +1273,17 @@
         loc = self.make_sure_var_in_reg(op.getarg(1))
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.vfprm.force_allocate_reg(op.result)
-        self.possibly_free_var(op.result)
+        res = self.vfprm.force_allocate_reg(op)
         return [loc, res]
 
     def prepare_op_cast_float_to_int(self, op, fcond):
         loc1 = self.make_sure_var_in_reg(op.getarg(0))
-        res = self.rm.force_allocate_reg(op.result)
+        res = self.rm.force_allocate_reg(op)
         return [loc1, res]
 
     def prepare_op_cast_int_to_float(self, op, fcond):
         loc1 = self.make_sure_var_in_reg(op.getarg(0))
-        res = self.vfprm.force_allocate_reg(op.result)
+        res = self.vfprm.force_allocate_reg(op)
         return [loc1, res]
 
     def prepare_force_spill(self, op, fcond):
@@ -1292,17 +1295,17 @@
 
     #def prepare_op_read_timestamp(self, op, fcond):
     #    loc = self.get_scratch_reg(INT)
-    #    res = self.vfprm.force_allocate_reg(op.result)
+    #    res = self.vfprm.force_allocate_reg(op)
     #    return [loc, res]
 
     def prepare_op_cast_float_to_singlefloat(self, op, fcond):
         loc1 = self.make_sure_var_in_reg(op.getarg(0))
-        res = self.force_allocate_reg(op.result)
+        res = self.force_allocate_reg(op)
         return [loc1, res]
 
     def prepare_op_cast_singlefloat_to_float(self, op, fcond):
         loc1 = self.make_sure_var_in_reg(op.getarg(0))
-        res = self.force_allocate_reg(op.result)
+        res = self.force_allocate_reg(op)
         return [loc1, res]
 
 
diff --git a/rpython/jit/backend/arm/test/test_runner.py b/rpython/jit/backend/arm/test/test_runner.py
--- a/rpython/jit/backend/arm/test/test_runner.py
+++ b/rpython/jit/backend/arm/test/test_runner.py
@@ -2,9 +2,9 @@
 from rpython.jit.backend.detect_cpu import getcpuclass
 from rpython.jit.backend.test.runner_test import LLtypeBackendTest,\
      boxfloat, constfloat
-from rpython.jit.metainterp.history import (BasicFailDescr, BasicFinalDescr,
-                                            BoxInt)
-from rpython.jit.metainterp.resoperation import ResOperation, rop
+from rpython.jit.metainterp.history import BasicFailDescr, BasicFinalDescr
+from rpython.jit.metainterp.resoperation import (ResOperation, rop,
+                                                 InputArgInt)
 from rpython.jit.tool.oparser import parse
 from rpython.rtyper.lltypesystem import lltype, llmemory
 from rpython.rtyper import rclass
@@ -52,30 +52,29 @@
 
     def test_result_is_spilled(self):
         cpu = self.cpu
-        inp = [BoxInt(i) for i in range(1, 15)]
-        out = [BoxInt(i) for i in range(1, 15)]
+        inp = [InputArgInt(i) for i in range(1, 15)]
         looptoken = JitCellToken()
         targettoken = TargetToken()
         operations = [
-            ResOperation(rop.LABEL, inp, None, descr=targettoken),
-            ResOperation(rop.INT_ADD, [inp[0], inp[1]], out[0]),
-            ResOperation(rop.INT_ADD, [inp[2], inp[3]], out[1]),
-            ResOperation(rop.INT_ADD, [inp[4], inp[5]], out[2]),
-            ResOperation(rop.INT_ADD, [inp[6], inp[7]], out[3]),
-            ResOperation(rop.INT_ADD, [inp[8], inp[9]], out[4]),
-            ResOperation(rop.INT_ADD, [inp[10], inp[11]], out[5]),
-            ResOperation(rop.INT_ADD, [inp[12], inp[13]], out[6]),
-            ResOperation(rop.INT_ADD, [inp[0], inp[1]], out[7]),
-            ResOperation(rop.INT_ADD, [inp[2], inp[3]], out[8]),
-            ResOperation(rop.INT_ADD, [inp[4], inp[5]], out[9]),
-            ResOperation(rop.INT_ADD, [inp[6], inp[7]], out[10]),
-            ResOperation(rop.INT_ADD, [inp[8], inp[9]], out[11]),
-            ResOperation(rop.INT_ADD, [inp[10], inp[11]], out[12]),
-            ResOperation(rop.INT_ADD, [inp[12], inp[13]], out[13]),
-            ResOperation(rop.GUARD_FALSE, [inp[1]], None, descr=BasicFailDescr(1)),
-            ResOperation(rop.FINISH, [inp[1]], None, descr=BasicFinalDescr(1)),
+            ResOperation(rop.LABEL, inp, descr=targettoken),
+            ResOperation(rop.INT_ADD, [inp[0], inp[1]]),
+            ResOperation(rop.INT_ADD, [inp[2], inp[3]]),
+            ResOperation(rop.INT_ADD, [inp[4], inp[5]]),
+            ResOperation(rop.INT_ADD, [inp[6], inp[7]]),
+            ResOperation(rop.INT_ADD, [inp[8], inp[9]]),
+            ResOperation(rop.INT_ADD, [inp[10], inp[11]]),
+            ResOperation(rop.INT_ADD, [inp[12], inp[13]]),
+            ResOperation(rop.INT_ADD, [inp[0], inp[1]]),
+            ResOperation(rop.INT_ADD, [inp[2], inp[3]]),
+            ResOperation(rop.INT_ADD, [inp[4], inp[5]]),
+            ResOperation(rop.INT_ADD, [inp[6], inp[7]]),
+            ResOperation(rop.INT_ADD, [inp[8], inp[9]]),
+            ResOperation(rop.INT_ADD, [inp[10], inp[11]]),
+            ResOperation(rop.INT_ADD, [inp[12], inp[13]]),
+            ResOperation(rop.GUARD_FALSE, [inp[1]], descr=BasicFailDescr(1)),
+            ResOperation(rop.FINISH, [inp[1]], descr=BasicFinalDescr(1)),
             ]
-        operations[-2].setfailargs(out)
+        operations[-2].setfailargs(operations[1:15])
         cpu.compile_loop(inp, operations, looptoken)
         args = [i for i in range(1, 15)]
         deadframe = self.cpu.execute_token(looptoken, *args)
@@ -104,7 +103,7 @@
         lt2.outermost_jitdriver_sd = FakeJitDriverSD()
         loop1 = parse('''
         [i0]
-        i1 = call_assembler(i0, descr=lt2)
+        i1 = call_assembler_i(i0, descr=lt2)
         guard_not_forced()[]
         finish(i1)
         ''', namespace=locals())
@@ -181,19 +180,19 @@
     def test_float_field(self):
         if not self.cpu.supports_floats:
             py.test.skip('requires floats')
+        t_box, T_box, _ = self.alloc_instance(self.TFloat)
         floatdescr = self.cpu.fielddescrof(self.SFloat, 'float')
-        t_box, T_box = self.alloc_instance(self.TFloat)
         self.execute_operation(rop.SETFIELD_GC, [t_box, boxfloat(3.4)],
                                'void', descr=floatdescr)
-        res = self.execute_operation(rop.GETFIELD_GC, [t_box],
+        res = self.execute_operation(rop.GETFIELD_GC_F, [t_box],
                                      'float', descr=floatdescr)
-        assert res.getfloat() == 3.4
+        assert longlong.getrealfloat(res) == 3.4
         #
         self.execute_operation(rop.SETFIELD_GC, [t_box, constfloat(-3.6)],
                                'void', descr=floatdescr)
-        res = self.execute_operation(rop.GETFIELD_GC, [t_box],
+        res = self.execute_operation(rop.GETFIELD_GC_F, [t_box],
                                      'float', descr=floatdescr)
-        assert res.getfloat() == -3.6
+        assert longlong.getrealfloat(res) == -3.6
 
     def test_compile_loop_many_int_args(self):
         for numargs in range(2, 30):
@@ -269,13 +268,13 @@
         targettoken = TargetToken()
         ops = """
         [i0, f3]
-        i2 = same_as(i0)    # but forced to be in a register
+        i2 = same_as_i(i0)    # but forced to be in a register
         force_spill(i2)
         force_spill(f3)
         f4 = float_add(f3, 5.0)
         label(f3, f4, descr=targettoken)
         force_spill(f3)
-        f5 = same_as(f3)    # but forced to be in a register
+        f5 = same_as_f(f3)    # but forced to be in a register
         finish(f5)
         """
         faildescr = BasicFailDescr(2)
@@ -284,8 +283,8 @@
         info = self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
         ops2 = """
         [i0, f1]
-        i1 = same_as(i0)
-        f2 = same_as(f1)
+        i1 = same_as_i(i0)
+        f2 = same_as_f(f1)
         f3 = float_add(f1, 10.0)
         force_spill(f3)
         force_spill(i1)
diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py
--- a/rpython/jit/backend/detect_cpu.py
+++ b/rpython/jit/backend/detect_cpu.py
@@ -122,11 +122,15 @@
 
 
 def getcpufeatures(backend_name="auto"):
-    """NOT_RPYTHON"""
-    cpucls = getcpuclass(backend_name)
-    return [attr[len('supports_'):] for attr in dir(cpucls)
-                            if attr.startswith('supports_')
-                                and getattr(cpucls, attr)]
+    if backend_name == "auto":
+        backend_name = autodetect()
+    return {
+        MODEL_X86: ['floats', 'singlefloats', 'longlong'],
+        MODEL_X86_NO_SSE2: ['longlong'],
+        MODEL_X86_64: ['floats', 'singlefloats'],
+        MODEL_ARM: ['floats', 'singlefloats', 'longlong'],
+        MODEL_PPC_64: [], # we don't even have PPC directory, so no
+    }[backend_name]
 
 if __name__ == '__main__':
     if len(sys.argv) > 1:
diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -16,6 +16,7 @@
 
 from rpython.rlib.clibffi import FFI_DEFAULT_ABI
 from rpython.rlib.rarithmetic import ovfcheck, r_uint, r_ulonglong
+from rpython.rlib.objectmodel import Symbolic
 
 class LLTrace(object):
     has_been_freed = False
@@ -25,7 +26,9 @@
         # We need to clone the list of operations because the
         # front-end will mutate them under our feet again.  We also
         # need to make sure things get freed.
-        def mapping(box, _cache={}):
+        _cache={}
+        
+        def mapping(box):
             if isinstance(box, Const) or box is None:
                 return box
             try:
@@ -46,8 +49,8 @@
                 newdescr = None
             newop = op.copy_and_change(op.getopnum(),
                                        map(mapping, op.getarglist()),
-                                       mapping(op.result),
                                        newdescr)
+            _cache[op] = newop
             if op.getfailargs() is not None:
                 newop.setfailargs(map(mapping, op.getfailargs()))
             self.operations.append(newop)
@@ -86,15 +89,45 @@
     def get_result_type(self):
         return getkind(self.RESULT)[0]
 
+    get_normalized_result_type = get_result_type
+
+class TypeIDSymbolic(Symbolic):
+    def __init__(self, STRUCT_OR_ARRAY):
+        self.STRUCT_OR_ARRAY = STRUCT_OR_ARRAY
+
+    def __eq__(self, other):
+        return self.STRUCT_OR_ARRAY is other.STRUCT_OR_ARRAY
+
+    def __ne__(self, other):
+        return not self == other
+
 class SizeDescr(AbstractDescr):
-    def __init__(self, S):
+    def __init__(self, S, vtable, runner):
+        assert not isinstance(vtable, bool)
         self.S = S
+        self._vtable = vtable
+        self._is_object = bool(vtable)
+        self._runner = runner
 
-    def as_vtable_size_descr(self):
-        return self
+    def get_all_fielddescrs(self):
+        return self.all_fielddescrs
 
-    def count_fields_if_immutable(self):
-        return heaptracker.count_fields_if_immutable(self.S)
+    def is_object(self):
+        return self._is_object
+
+    def get_vtable(self):
+        assert self._vtable is not None
+        if self._vtable is Ellipsis:
+            self._vtable = heaptracker.get_vtable_for_gcstruct(self._runner,
+                                                               self.S)
+        return heaptracker.adr2int(llmemory.cast_ptr_to_adr(self._vtable))
+
+    def is_immutable(self):
+        return heaptracker.is_immutable_struct(self.S)
+
+    def get_type_id(self):
+        assert isinstance(self.S, lltype.GcStruct)
+        return TypeIDSymbolic(self.S)     # integer-like symbolic
 
     def __repr__(self):
         return 'SizeDescr(%r)' % (self.S,)
@@ -104,10 +137,21 @@
         self.S = S
         self.fieldname = fieldname
         self.FIELD = getattr(S, fieldname)
+        self.index = heaptracker.get_fielddescr_index_in(S, fieldname)
+        self._is_pure = S._immutable_field(fieldname)
+
+    def is_always_pure(self):
+        return self._is_pure
+
+    def get_parent_descr(self):
+        return self.parent_descr
 
     def get_vinfo(self):
         return self.vinfo
 
+    def get_index(self):
+        return self.index
+
     def __repr__(self):
         return 'FieldDescr(%r, %r)' % (self.S, self.fieldname)
 
@@ -146,11 +190,20 @@
             rffi.cast(TYPE, -1) == -1)
 
 class ArrayDescr(AbstractDescr):
-    def __init__(self, A):
+    all_interiorfielddescrs = None
+    
+    def __init__(self, A, runner):
         self.A = self.OUTERA = A
+        self._is_pure = A._immutable_field(None)
         if isinstance(A, lltype.Struct):
             self.A = A._flds[A._arrayfld]
 
+    def is_always_pure(self):
+        return self._is_pure
+
+    def get_all_fielddescrs(self):
+        return self.all_interiorfielddescrs
+
     def __repr__(self):
         return 'ArrayDescr(%r)' % (self.OUTERA,)
 
@@ -184,12 +237,27 @@
         return intbounds.get_integer_max(
             not _is_signed_kind(self.A.OF), rffi.sizeof(self.A.OF))
 
+    def get_type_id(self):
+        assert isinstance(self.A, lltype.GcArray)
+        return TypeIDSymbolic(self.A)     # integer-like symbolic
+
 
 class InteriorFieldDescr(AbstractDescr):
-    def __init__(self, A, fieldname):
+    def __init__(self, A, fieldname, runner):
         self.A = A
         self.fieldname = fieldname
         self.FIELD = getattr(A.OF, fieldname)
+        self.arraydescr = runner.arraydescrof(A)
+        self.fielddescr = runner.fielddescrof(A.OF, fieldname)
+
+    def get_index(self):
+        return self.fielddescr.get_index()
+
+    def get_arraydescr(self):
+        return self.arraydescr
+
+    def get_field_descr(self):
+        return self.fielddescr
 
     def __repr__(self):
         return 'InteriorFieldDescr(%r, %r)' % (self.A, self.fieldname)
@@ -232,6 +300,7 @@
     supports_floats = True
     supports_longlong = r_uint is not r_ulonglong
     supports_singlefloats = True
+    supports_guard_gc_type = True
     translate_support_code = False
     is_llgraph = True
 
@@ -336,10 +405,10 @@
         values = []
         for box in frame.force_guard_op.getfailargs():
             if box is not None:
-                if box is not frame.current_op.result:
+                if box is not frame.current_op:
                     value = frame.env[box]
                 else:
-                    value = box.value    # 0 or 0.0 or NULL
+                    value = box.getvalue()    # 0 or 0.0 or NULL
             else:
                 value = None
             values.append(value)
@@ -367,14 +436,19 @@
             self.descrs[key] = descr
             return descr
 
-    def sizeof(self, S):
+    def sizeof(self, S, vtable=lltype.nullptr(rclass.OBJECT_VTABLE)):
         key = ('size', S)
         try:
-            return self.descrs[key]
+            descr = self.descrs[key]
         except KeyError:
-            descr = SizeDescr(S)
+            descr = SizeDescr(S, vtable, self)
             self.descrs[key] = descr
-            return descr
+            descr.all_fielddescrs = heaptracker.all_fielddescrs(self, S,
+                    get_field_descr=LLGraphCPU.fielddescrof)
+        if descr._is_object and vtable is not Ellipsis:
+            assert vtable
+            heaptracker.testing_gcstruct2vtable.setdefault(S, vtable)
+        return descr
 
     def fielddescrof(self, S, fieldname):
         key = ('field', S, fieldname)
@@ -383,6 +457,12 @@
         except KeyError:
             descr = FieldDescr(S, fieldname)
             self.descrs[key] = descr
+            if (isinstance(S, lltype.GcStruct) and
+                    heaptracker.has_gcstruct_a_vtable(S)):
+                vtable = Ellipsis
+            else:
+                vtable = None
+            descr.parent_descr = self.sizeof(S, vtable)
             if self.vinfo_for_tests is not None:
                 descr.vinfo = self.vinfo_for_tests
             return descr
@@ -392,8 +472,12 @@
         try:
             return self.descrs[key]
         except KeyError:
-            descr = ArrayDescr(A)
+            descr = ArrayDescr(A, self)
             self.descrs[key] = descr
+            if isinstance(A, lltype.Array) and isinstance(A.OF, lltype.Struct):
+                descrs = heaptracker.all_interiorfielddescrs(self,
+                        A, get_field_descr=LLGraphCPU.interiorfielddescrof)
+                descr.all_interiorfielddescrs = descrs
             return descr
 
     def interiorfielddescrof(self, A, fieldname):
@@ -401,7 +485,7 @@
         try:
             return self.descrs[key]
         except KeyError:
-            descr = InteriorFieldDescr(A, fieldname)
+            descr = InteriorFieldDescr(A, fieldname, self)
             self.descrs[key] = descr
             return descr
 
@@ -435,6 +519,22 @@
             self.descrs[key] = descr
             return descr
 
+    def check_is_object(self, gcptr):
+        """Check if the given, non-null gcptr refers to an rclass.OBJECT
+        or not at all (an unrelated GcStruct or a GcArray).  Only usable
+        in the llgraph backend, or after translation of a real backend."""
+        ptr = lltype.normalizeptr(gcptr._obj.container._as_ptr())
+        T = lltype.typeOf(ptr).TO
+        return heaptracker.has_gcstruct_a_vtable(T) or T is rclass.OBJECT
+
+    def get_actual_typeid(self, gcptr):
+        """Fetch the actual typeid of the given gcptr, as an integer.
+        Only usable in the llgraph backend, or after translation of a
+        real backend.  (Here in the llgraph backend, returns a
+        TypeIDSymbolic instead of a real integer.)"""
+        ptr = lltype.normalizeptr(gcptr._obj.container._as_ptr())
+        return TypeIDSymbolic(lltype.typeOf(ptr).TO)
+
     # ------------------------------------------------------------
 
     def maybe_on_top_of_llinterp(self, func, args, RESULT):
@@ -461,13 +561,17 @@
         p = support.cast_arg(lltype.Ptr(descr.S), p)
         return support.cast_result(descr.FIELD, getattr(p, descr.fieldname))
 
-    bh_getfield_gc_pure = bh_getfield_gc
+    bh_getfield_gc_pure_i = bh_getfield_gc
+    bh_getfield_gc_pure_r = bh_getfield_gc
+    bh_getfield_gc_pure_f = bh_getfield_gc
     bh_getfield_gc_i = bh_getfield_gc
     bh_getfield_gc_r = bh_getfield_gc
     bh_getfield_gc_f = bh_getfield_gc
 
     bh_getfield_raw = bh_getfield_gc
-    bh_getfield_raw_pure = bh_getfield_raw
+    bh_getfield_raw_pure_i = bh_getfield_raw
+    bh_getfield_raw_pure_r = bh_getfield_raw
+    bh_getfield_raw_pure_f = bh_getfield_raw
     bh_getfield_raw_i = bh_getfield_raw
     bh_getfield_raw_r = bh_getfield_raw
     bh_getfield_raw_f = bh_getfield_raw
@@ -495,13 +599,17 @@
         array = a._obj
         return support.cast_result(descr.A.OF, array.getitem(index))
 
-    bh_getarrayitem_gc_pure = bh_getarrayitem_gc
+    bh_getarrayitem_gc_pure_i = bh_getarrayitem_gc
+    bh_getarrayitem_gc_pure_r = bh_getarrayitem_gc
+    bh_getarrayitem_gc_pure_f = bh_getarrayitem_gc
     bh_getarrayitem_gc_i = bh_getarrayitem_gc
     bh_getarrayitem_gc_r = bh_getarrayitem_gc
     bh_getarrayitem_gc_f = bh_getarrayitem_gc
 
     bh_getarrayitem_raw = bh_getarrayitem_gc
-    bh_getarrayitem_raw_pure = bh_getarrayitem_raw
+    bh_getarrayitem_raw_pure_i = bh_getarrayitem_raw
+    bh_getarrayitem_raw_pure_r = bh_getarrayitem_raw
+    bh_getarrayitem_raw_pure_f = bh_getarrayitem_raw
     bh_getarrayitem_raw_i = bh_getarrayitem_raw
     bh_getarrayitem_raw_r = bh_getarrayitem_raw
     bh_getarrayitem_raw_f = bh_getarrayitem_raw
@@ -634,11 +742,11 @@
         return lltype.cast_opaque_ptr(llmemory.GCREF,
                                       lltype.malloc(sizedescr.S, zero=True))
 
-    def bh_new_with_vtable(self, vtable, descr):
+    def bh_new_with_vtable(self, descr):
         result = lltype.malloc(descr.S, zero=True)
         result_as_objptr = lltype.cast_pointer(rclass.OBJECTPTR, result)
         result_as_objptr.typeptr = support.cast_from_int(rclass.CLASSTYPE,
-                                                         vtable)
+                                                descr.get_vtable())
         return lltype.cast_opaque_ptr(llmemory.GCREF, result)
 
     def bh_new_array(self, length, arraydescr):
@@ -749,8 +857,8 @@
                     i = 0
                 self.do_renaming(targetargs, j.args)
                 continue
-            if op.result is not None:
-                self.setenv(op.result, resval)
+            if op.type != 'v':
+                self.setenv(op, resval)
             else:
                 assert resval is None
             i += 1
@@ -823,6 +931,32 @@
         self.execute_guard_nonnull(descr, arg)
         self.execute_guard_class(descr, arg, klass)
 
+    def execute_guard_gc_type(self, descr, arg, typeid):
+        assert isinstance(typeid, TypeIDSymbolic)
+        TYPE = arg._obj.container._TYPE
+        if TYPE != typeid.STRUCT_OR_ARRAY:
+            self.fail_guard(descr)
+
+    def execute_guard_is_object(self, descr, arg):
+        TYPE = arg._obj.container._TYPE
+        while TYPE is not rclass.OBJECT:
+            if not isinstance(TYPE, lltype.GcStruct):   # or TYPE is None
+                self.fail_guard(descr)
+                return
+            _, TYPE = TYPE._first_struct()
+
+    def execute_guard_subclass(self, descr, arg, klass):
+        value = lltype.cast_opaque_ptr(rclass.OBJECTPTR, arg)
+        expected_class = llmemory.cast_adr_to_ptr(
+            llmemory.cast_int_to_adr(klass),
+            rclass.CLASSTYPE)
+        if (expected_class.subclassrange_min
+                <= value.typeptr.subclassrange_min
+                <= expected_class.subclassrange_max):
+            pass
+        else:
+            self.fail_guard(descr)
+
     def execute_guard_no_exception(self, descr):
         if self.last_exception is not None:
             self.fail_guard(descr)
@@ -894,6 +1028,7 @@
     def execute_guard_overflow(self, descr):
         if not self.overflow_flag:
             self.fail_guard(descr)
+        return lltype.nullptr(llmemory.GCREF.TO) # I think it's fine....
 
     def execute_jump(self, descr, *args):
         raise Jump(descr._llgraph_target, args)
@@ -908,9 +1043,9 @@
         if not cond:
             return
         # cond_call can't have a return value
-        self.execute_call(calldescr, func, *args)
+        self.execute_call_n(calldescr, func, *args)
 
-    def execute_call(self, calldescr, func, *args):
+    def _execute_call(self, calldescr, func, *args):
         effectinfo = calldescr.get_extra_info()
         if effectinfo is not None and hasattr(effectinfo, 'oopspecindex'):
             oopspecindex = effectinfo.oopspecindex
@@ -926,16 +1061,25 @@
             res = _example_res[getkind(TP.RESULT)[0]]
         return res
 
-    def execute_call_may_force(self, calldescr, func, *args):
-        call_op = self.lltrace.operations[self.current_index]
+    execute_call_i = _execute_call
+    execute_call_r = _execute_call
+    execute_call_f = _execute_call
+    execute_call_n = _execute_call
+
+    def _execute_call_may_force(self, calldescr, func, *args):
         guard_op = self.lltrace.operations[self.current_index + 1]
         assert guard_op.getopnum() == rop.GUARD_NOT_FORCED
         self.force_guard_op = guard_op
-        res = self.execute_call(calldescr, func, *args)
+        res = self._execute_call(calldescr, func, *args)
         del self.force_guard_op
         return res
 
-    def execute_call_release_gil(self, descr, saveerr, func, *args):
+    execute_call_may_force_n = _execute_call_may_force
+    execute_call_may_force_r = _execute_call_may_force
+    execute_call_may_force_f = _execute_call_may_force
+    execute_call_may_force_i = _execute_call_may_force
+
+    def _execute_call_release_gil(self, descr, saveerr, func, *args):
         if hasattr(descr, '_original_func_'):
             func = descr._original_func_     # see pyjitpl.py
             # we want to call the function that does the aroundstate
@@ -960,61 +1104,74 @@
         del self.force_guard_op
         return support.cast_result(descr.RESULT, result)
 
-    def execute_call_assembler(self, descr, *args):
-        # XXX simplify the following a bit
-        #
-        # pframe = CALL_ASSEMBLER(args..., descr=looptoken)
-        # ==>
-        #     pframe = CALL looptoken.loopaddr(*args)
-        #     JUMP_IF_FAST_PATH @fastpath
-        #     res = CALL assembler_call_helper(pframe)
-        #     jmp @done
-        #   @fastpath:
-        #     res = GETFIELD(pframe, 'result')
-        #   @done:
-        #
-        call_op = self.lltrace.operations[self.current_index]
-        guard_op = self.lltrace.operations[self.current_index + 1]
-        assert guard_op.getopnum() == rop.GUARD_NOT_FORCED
-        self.force_guard_op = guard_op
-        pframe = self.cpu._execute_token(descr, *args)
-        del self.force_guard_op
-        #
-        jd = descr.outermost_jitdriver_sd
-        assert jd is not None, ("call_assembler(): the loop_token needs "
-                                "to have 'outermost_jitdriver_sd'")
-        if jd.index_of_virtualizable != -1:
-            vable = args[jd.index_of_virtualizable]
-        else:
-            vable = lltype.nullptr(llmemory.GCREF.TO)
-        #
-        # Emulate the fast path
-        #
-        faildescr = self.cpu.get_latest_descr(pframe)
-        if faildescr == self.cpu.done_with_this_frame_descr_int:
-            return self.cpu.get_int_value(pframe, 0)
-        elif faildescr == self.cpu.done_with_this_frame_descr_ref:
-            return self.cpu.get_ref_value(pframe, 0)
-        elif faildescr == self.cpu.done_with_this_frame_descr_float:
-            return self.cpu.get_float_value(pframe, 0)
-        elif faildescr == self.cpu.done_with_this_frame_descr_void:
-            return None
+    execute_call_release_gil_n = _execute_call_release_gil
+    execute_call_release_gil_i = _execute_call_release_gil
+    execute_call_release_gil_r = _execute_call_release_gil
+    execute_call_release_gil_f = _execute_call_release_gil
 
-        assembler_helper_ptr = jd.assembler_helper_adr.ptr  # fish
-        try:
-            result = assembler_helper_ptr(pframe, vable)
-        except LLException, lle:
-            assert self.last_exception is None, "exception left behind"
-            self.last_exception = lle
-            # fish op
-            op = self.current_op
-            return op.result and op.result.value
-        if isinstance(result, float):
-            result = support.cast_to_floatstorage(result)
-        return result
+    def _new_execute_call_assembler(def_val):
+        def _execute_call_assembler(self, descr, *args):
+            # XXX simplify the following a bit
+            #
+            # pframe = CALL_ASSEMBLER(args..., descr=looptoken)
+            # ==>
+            #     pframe = CALL looptoken.loopaddr(*args)
+            #     JUMP_IF_FAST_PATH @fastpath
+            #     res = CALL assembler_call_helper(pframe)
+            #     jmp @done
+            #   @fastpath:
+            #     res = GETFIELD(pframe, 'result')
+            #   @done:
+            #
+            call_op = self.lltrace.operations[self.current_index]
+            guard_op = self.lltrace.operations[self.current_index + 1]
+            assert guard_op.getopnum() == rop.GUARD_NOT_FORCED
+            self.force_guard_op = guard_op
+            pframe = self.cpu._execute_token(descr, *args)
+            del self.force_guard_op
+            #
+            jd = descr.outermost_jitdriver_sd
+            assert jd is not None, ("call_assembler(): the loop_token needs "
+                                    "to have 'outermost_jitdriver_sd'")
+            if jd.index_of_virtualizable != -1:
+                vable = args[jd.index_of_virtualizable]
+            else:
+                vable = lltype.nullptr(llmemory.GCREF.TO)
+            #
+            # Emulate the fast path
+            #
+            faildescr = self.cpu.get_latest_descr(pframe)
+            if faildescr == self.cpu.done_with_this_frame_descr_int:
+                return self.cpu.get_int_value(pframe, 0)
+            elif faildescr == self.cpu.done_with_this_frame_descr_ref:
+                return self.cpu.get_ref_value(pframe, 0)
+            elif faildescr == self.cpu.done_with_this_frame_descr_float:
+                return self.cpu.get_float_value(pframe, 0)
+            elif faildescr == self.cpu.done_with_this_frame_descr_void:
+                return None
 
-    def execute_same_as(self, _, x):
+            assembler_helper_ptr = jd.assembler_helper_adr.ptr  # fish
+            try:
+                result = assembler_helper_ptr(pframe, vable)
+            except LLException, lle:
+                assert self.last_exception is None, "exception left behind"
+                self.last_exception = lle
+                # fish op
+                result = def_val
+            if isinstance(result, float):
+                result = support.cast_to_floatstorage(result)
+            return result
+        return _execute_call_assembler
+
+    execute_call_assembler_i = _new_execute_call_assembler(0)
+    execute_call_assembler_r = _new_execute_call_assembler(lltype.nullptr(llmemory.GCREF.TO))
+    execute_call_assembler_f = _new_execute_call_assembler(0.0)
+    execute_call_assembler_n = _new_execute_call_assembler(None)
+
+    def execute_same_as_i(self, _, x):
         return x
+    execute_same_as_f = execute_same_as_i
+    execute_same_as_r = execute_same_as_i
 
     def execute_debug_merge_point(self, descr, *args):
         from rpython.jit.metainterp.warmspot import get_stats
@@ -1031,9 +1188,8 @@
     def execute_leave_portal_frame(self, descr, *args):
         pass
 
-    def execute_new_with_vtable(self, _, vtable):
-        descr = heaptracker.vtable2descr(self.cpu, vtable)
-        return self.cpu.bh_new_with_vtable(vtable, descr)
+    def execute_new_with_vtable(self, descr):
+        return self.cpu.bh_new_with_vtable(descr)
 
     def execute_force_token(self, _):
         return self
diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -3,7 +3,7 @@
 from rpython.jit.backend.llsupport.symbolic import WORD
 from rpython.jit.backend.llsupport.codemap import CodemapBuilder
 from rpython.jit.metainterp.history import (INT, REF, FLOAT, JitCellToken,
-    ConstInt, BoxInt, AbstractFailDescr)
+    ConstInt, AbstractFailDescr)
 from rpython.jit.metainterp.resoperation import ResOperation, rop
 from rpython.rlib import rgc
 from rpython.rlib.debug import (debug_start, debug_stop, have_debug_prints_for,
@@ -223,11 +223,11 @@
         self._call_assembler_emit_call(self.imm(descr._ll_function_addr),


More information about the pypy-commit mailing list