Commits

Maciej Fijalkowski committed 22ade1f Merge

merge

Comments (0)

Files changed (12)

rpython/jit/backend/arm/assembler.py

                                            clt.allgcrefs)
 
         loop_head = self.mc.get_relative_pos()
-        looptoken._arm_loop_code = loop_head
+        looptoken._ll_loop_code = loop_head
         #
         frame_depth_no_fixed_size = self._assemble(regalloc, inputargs, operations)
         self.update_frame_depth(frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE)
 
     def fixup_target_tokens(self, rawstart):
         for targettoken in self.target_tokens_currently_compiling:
-            targettoken._arm_loop_code += rawstart
+            targettoken._ll_loop_code += rawstart
         self.target_tokens_currently_compiling = None
 
     def _patch_stackadjust(self, adr, allocated_depth):

rpython/jit/backend/arm/opassembler.py

         # stack locations both before and after the jump.
         #
         target_token = op.getdescr()
-        target = target_token._arm_loop_code
+        target = target_token._ll_loop_code
         assert isinstance(target_token, TargetToken)
         assert fcond == c.AL
         my_nbargs = self.current_clt._debug_nbargs

rpython/jit/backend/arm/regalloc.py

 from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr
 
 
-# xxx hack: set a default value for TargetToken._arm_loop_code.  If 0, we know
+# xxx hack: set a default value for TargetToken._ll_loop_code.  If 0, we know
 # that it is a LABEL that was not compiled yet.
-TargetToken._arm_loop_code = 0
+TargetToken._ll_loop_code = 0
 
 class TempInt(TempBox):
     type = INT
         self.final_jump_op = op
         descr = op.getdescr()
         assert isinstance(descr, TargetToken)
-        if descr._arm_loop_code != 0:
+        if descr._ll_loop_code != 0:
             # if the target LABEL was already compiled, i.e. if it belongs
             # to some already-compiled piece of code
             self._compute_hint_frame_locations_from_descr(descr)
                 self.frame_manager.mark_as_free(arg)
         #
         descr._arm_arglocs = arglocs
-        descr._arm_loop_code = self.assembler.mc.currpos()
+        descr._ll_loop_code = self.assembler.mc.currpos()
         descr._arm_clt = self.assembler.current_clt
         self.assembler.target_tokens_currently_compiling[descr] = None
         self.possibly_free_vars_for_op(op)

rpython/jit/backend/arm/test/test_regalloc.py

     fdescr3 = BasicFailDescr(3)
 
     def setup_method(self, meth):
-        self.targettoken._arm_loop_code = 0
-        self.targettoken2._arm_loop_code = 0
+        self.targettoken._ll_loop_code = 0
+        self.targettoken2._ll_loop_code = 0
 
     def f1(x):
         return x + 1

rpython/jit/backend/llsupport/test/test_gc_integration.py

+
+""" Tests for register allocation for common constructs
+"""
+
+from rpython.jit.metainterp.history import TargetToken, BasicFinalDescr,\
+     JitCellToken, BasicFailDescr, AbstractDescr
+from rpython.jit.backend.llsupport.gc import GcLLDescription, GcLLDescr_boehm,\
+     GcLLDescr_framework, GcCache, JitFrameDescrs
+from rpython.jit.backend.detect_cpu import getcpuclass
+from rpython.jit.backend.llsupport.symbolic import WORD
+from rpython.jit.backend.llsupport import jitframe
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
+from rpython.rtyper.annlowlevel import llhelper, llhelper_args
+
+from rpython.jit.backend.llsupport.test.test_regalloc_integration import BaseTestRegalloc
+from rpython.jit.codewriter.effectinfo import EffectInfo
+from rpython.rlib.objectmodel import invoke_around_extcall
+
+CPU = getcpuclass()
+
+class TestRegallocGcIntegration(BaseTestRegalloc):
+    
+    cpu = CPU(None, None)
+    cpu.gc_ll_descr = GcLLDescr_boehm(None, None, None)
+    cpu.setup_once()
+    
+    S = lltype.GcForwardReference()
+    S.become(lltype.GcStruct('S', ('field', lltype.Ptr(S)),
+                             ('int', lltype.Signed)))
+
+    fielddescr = cpu.fielddescrof(S, 'field')
+
+    struct_ptr = lltype.malloc(S)
+    struct_ref = lltype.cast_opaque_ptr(llmemory.GCREF, struct_ptr)
+    child_ptr = lltype.nullptr(S)
+    struct_ptr.field = child_ptr
+
+
+    intdescr = cpu.fielddescrof(S, 'int')
+    ptr0 = struct_ref
+
+    targettoken = TargetToken()
+    targettoken2 = TargetToken()
+
+    namespace = locals().copy()
+
+    def test_basic(self):
+        ops = '''
+        [p0]
+        p1 = getfield_gc(p0, descr=fielddescr)
+        finish(p1)
+        '''
+        self.interpret(ops, [self.struct_ptr])
+        assert not self.getptr(0, lltype.Ptr(self.S))
+
+    def test_guard(self):
+        ops = '''
+        [i0, p0, i1, p1]
+        p3 = getfield_gc(p0, descr=fielddescr)
+        guard_true(i0) [p0, i1, p1, p3]
+        '''
+        s1 = lltype.malloc(self.S)
+        s2 = lltype.malloc(self.S)
+        s1.field = s2
+        self.interpret(ops, [0, s1, 1, s2])
+        frame = lltype.cast_opaque_ptr(jitframe.JITFRAMEPTR, self.deadframe)
+        # p0 and p3 should be in registers, p1 not so much
+        assert self.getptr(0, lltype.Ptr(self.S)) == s1
+        # this is a fairly CPU specific check
+        assert len(frame.jf_gcmap) == 1
+        # the gcmap should contain three things, p0, p1 and p3
+        # p3 stays in a register
+        # while p0 and p1 are on the frame
+        if self.cpu.IS_64_BIT:
+            nos = [11, 12, 31]
+        else:
+            nos = [4, 5, 25]
+        assert frame.jf_gcmap[0] == ((1 << nos[0]) | (1 << nos[1]) |
+                                     (1 << nos[2]))
+        assert frame.jf_frame[nos[0]]
+        assert frame.jf_frame[nos[1]]
+        assert frame.jf_frame[nos[2]]
+
+    def test_rewrite_constptr(self):
+        ops = '''
+        []
+        p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr)
+        finish(p1)
+        '''
+        self.interpret(ops, [])
+        assert not self.getptr(0, lltype.Ptr(self.S))
+
+    def test_bug_0(self):
+        ops = '''
+        [i0, i1, i2, i3, i4, i5, i6, i7, i8]
+        label(i0, i1, i2, i3, i4, i5, i6, i7, i8, descr=targettoken)
+        guard_value(i2, 1) [i2, i3, i4, i5, i6, i7, i0, i1, i8]
+        guard_class(i4, 138998336) [i4, i5, i6, i7, i0, i1, i8]
+        i11 = getfield_gc(i4, descr=intdescr)
+        guard_nonnull(i11) [i4, i5, i6, i7, i0, i1, i11, i8]
+        i13 = getfield_gc(i11, descr=intdescr)
+        guard_isnull(i13) [i4, i5, i6, i7, i0, i1, i11, i8]
+        i15 = getfield_gc(i4, descr=intdescr)
+        i17 = int_lt(i15, 0)
+        guard_false(i17) [i4, i5, i6, i7, i0, i1, i11, i15, i8]
+        i18 = getfield_gc(i11, descr=intdescr)
+        i19 = int_ge(i15, i18)
+        guard_false(i19) [i4, i5, i6, i7, i0, i1, i11, i15, i8]
+        i20 = int_lt(i15, 0)
+        guard_false(i20) [i4, i5, i6, i7, i0, i1, i11, i15, i8]
+        i21 = getfield_gc(i11, descr=intdescr)
+        i22 = getfield_gc(i11, descr=intdescr)
+        i23 = int_mul(i15, i22)
+        i24 = int_add(i21, i23)
+        i25 = getfield_gc(i4, descr=intdescr)
+        i27 = int_add(i25, 1)
+        setfield_gc(i4, i27, descr=intdescr)
+        i29 = getfield_raw(144839744, descr=intdescr)
+        i31 = int_and(i29, -2141192192)
+        i32 = int_is_true(i31)
+        guard_false(i32) [i4, i6, i7, i0, i1, i24]
+        i33 = getfield_gc(i0, descr=intdescr)
+        guard_value(i33, ConstPtr(ptr0)) [i4, i6, i7, i0, i1, i33, i24]
+        jump(i0, i1, 1, 17, i4, ConstPtr(ptr0), i6, i7, i24, descr=targettoken)
+        '''
+        self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0, 0], run=False)
+
+NOT_INITIALIZED = chr(0xdd)
+
+class GCDescrFastpathMalloc(GcLLDescription):
+    gcrootmap = None
+    passes_frame = True
+    write_barrier_descr = None
+
+    def __init__(self, callback):
+        GcLLDescription.__init__(self, None)
+        # create a nursery
+        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] + 64
+        self.calls = []
+        def malloc_slowpath(size, frame):
+            if callback is not None:
+                callback(frame)
+            if self.gcrootmap is not None:   # hook
+                self.gcrootmap.hook_malloc_slowpath()
+            self.calls.append(size)
+            # reset the nursery
+            nadr = rffi.cast(lltype.Signed, self.nursery)
+            self.addrs[0] = nadr + size
+            return nadr
+        self.generate_function('malloc_nursery', malloc_slowpath,
+                               [lltype.Signed, jitframe.JITFRAMEPTR],
+                               lltype.Signed)
+
+    def get_nursery_free_addr(self):
+        return rffi.cast(lltype.Signed, self.addrs)
+
+    def get_nursery_top_addr(self):
+        return rffi.cast(lltype.Signed, self.addrs) + WORD
+
+    def get_malloc_slowpath_addr(self):
+        return self.get_malloc_fn_addr('malloc_nursery')
+
+    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 teardown_method(self, method):
+        lltype.free(self.cpu.gc_ll_descr.addrs, flavor='raw')
+        lltype.free(self.cpu.gc_ll_descr.nursery, flavor='raw')
+
+    def getcpu(self, callback):
+        cpu = CPU(None, None)
+        cpu.gc_ll_descr = GCDescrFastpathMalloc(callback)
+        cpu.setup_once()
+        return cpu
+
+    def test_malloc_fastpath(self):
+        self.cpu = self.getcpu(None)
+        ops = '''
+        [i0]
+        p0 = call_malloc_nursery(16)
+        p1 = call_malloc_nursery(32)
+        p2 = call_malloc_nursery(16)
+        guard_true(i0) [p0, p1, p2]
+        '''
+        self.interpret(ops, [0])
+        # check the returned pointers
+        gc_ll_descr = self.cpu.gc_ll_descr
+        nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
+        ref = lambda n: self.cpu.get_ref_value(self.deadframe, n)
+        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_nursery_varsize_small(self):
+        self.cpu = self.getcpu(None)
+        ops = '''
+        [i0, i1, i2]
+        p0 = call_malloc_nursery_varsize_small(i0)
+        p1 = call_malloc_nursery_varsize_small(i1)
+        p2 = call_malloc_nursery_varsize_small(i2)
+        guard_true(i0) [p0, p1, p2]
+        ''' 
+        self.interpret(ops, [16, 32, 16])
+        # check the returned pointers
+        gc_ll_descr = self.cpu.gc_ll_descr
+        nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
+        ref = lambda n: self.cpu.get_ref_value(self.deadframe, n)
+        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):
+        def check(frame):
+            assert len(frame.jf_gcmap) == 1
+            if self.cpu.IS_64_BIT:
+                assert frame.jf_gcmap[0] == (1<<29) | (1 << 30)
+            else:
+                assert frame.jf_gcmap[0] == (1<<24) | (1 << 23)
+        
+        self.cpu = self.getcpu(check)
+        ops = '''
+        [i0]
+        p0 = call_malloc_nursery(16)
+        p1 = call_malloc_nursery(32)
+        p2 = call_malloc_nursery(24)     # overflow
+        guard_true(i0) [p0, p1, p2]
+        '''
+        self.interpret(ops, [0])
+        # check the returned pointers
+        gc_ll_descr = self.cpu.gc_ll_descr
+        nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
+        ref = lambda n: self.cpu.get_ref_value(self.deadframe, n)
+        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
+        assert gc_ll_descr.calls == [24]
+
+    def test_save_regs_around_malloc(self):
+        def check(frame):
+            x = frame.jf_gcmap
+            if self.cpu.IS_64_BIT:
+                assert len(x) == 1
+                assert (bin(x[0]).count('1') ==
+                        '0b1111100000000000000001111111011110'.count('1'))
+            else:
+                assert len(x) == 2
+                s = bin(x[0]).count('1') + bin(x[1]).count('1')
+                assert s == 16
+            # all but two registers + some stuff on stack
+        
+        self.cpu = self.getcpu(check)
+        S1 = lltype.GcStruct('S1')
+        S2 = lltype.GcStruct('S2', ('s0', lltype.Ptr(S1)),
+                                   ('s1', lltype.Ptr(S1)),
+                                   ('s2', lltype.Ptr(S1)),
+                                   ('s3', lltype.Ptr(S1)),
+                                   ('s4', lltype.Ptr(S1)),
+                                   ('s5', lltype.Ptr(S1)),
+                                   ('s6', lltype.Ptr(S1)),
+                                   ('s7', lltype.Ptr(S1)),
+                                   ('s8', lltype.Ptr(S1)),
+                                   ('s9', lltype.Ptr(S1)),
+                                   ('s10', lltype.Ptr(S1)),
+                                   ('s11', lltype.Ptr(S1)),
+                                   ('s12', lltype.Ptr(S1)),
+                                   ('s13', lltype.Ptr(S1)),
+                                   ('s14', lltype.Ptr(S1)),
+                                   ('s15', lltype.Ptr(S1)))
+        cpu = self.cpu
+        self.namespace = self.namespace.copy()
+        for i in range(16):
+            self.namespace['ds%i' % i] = cpu.fielddescrof(S2, 's%d' % i)
+        ops = '''
+        [i0, p0]
+        p1 = getfield_gc(p0, descr=ds0)
+        p2 = getfield_gc(p0, descr=ds1)
+        p3 = getfield_gc(p0, descr=ds2)
+        p4 = getfield_gc(p0, descr=ds3)
+        p5 = getfield_gc(p0, descr=ds4)
+        p6 = getfield_gc(p0, descr=ds5)
+        p7 = getfield_gc(p0, descr=ds6)
+        p8 = getfield_gc(p0, descr=ds7)
+        p9 = getfield_gc(p0, descr=ds8)
+        p10 = getfield_gc(p0, descr=ds9)
+        p11 = getfield_gc(p0, descr=ds10)
+        p12 = getfield_gc(p0, descr=ds11)
+        p13 = getfield_gc(p0, descr=ds12)
+        p14 = getfield_gc(p0, descr=ds13)
+        p15 = getfield_gc(p0, descr=ds14)
+        p16 = getfield_gc(p0, descr=ds15)
+        #
+        # now all registers are in use
+        p17 = call_malloc_nursery(40)
+        p18 = call_malloc_nursery(40)     # overflow
+        #
+        guard_true(i0) [p1, p2, p3, p4, p5, p6, \
+            p7, p8, p9, p10, p11, p12, p13, p14, p15, p16]
+        '''
+        s2 = lltype.malloc(S2)
+        for i in range(16):
+            setattr(s2, 's%d' % i, lltype.malloc(S1))
+        s2ref = lltype.cast_opaque_ptr(llmemory.GCREF, s2)
+        #
+        self.interpret(ops, [0, s2ref])
+        gc_ll_descr = cpu.gc_ll_descr
+        gc_ll_descr.check_nothing_in_nursery()
+        assert gc_ll_descr.calls == [40]
+        # check the returned pointers
+        for i in range(16):
+            s1ref = self.cpu.get_ref_value(self.deadframe, i)
+            s1 = lltype.cast_opaque_ptr(lltype.Ptr(S1), s1ref)
+            assert s1 == getattr(s2, 's%d' % i)
+
+class MockShadowStackRootMap(object):
+    is_shadow_stack = True
+    
+    def __init__(self):
+        TP = rffi.CArray(lltype.Signed)
+        self.stack = lltype.malloc(TP, 10, flavor='raw')
+        self.stack_addr = lltype.malloc(TP, 1,
+                                        flavor='raw')
+        self.stack_addr[0] = rffi.cast(lltype.Signed, self.stack)
+
+    def __del__(self):
+        lltype.free(self.stack_addr, flavor='raw')        
+        lltype.free(self.stack, flavor='raw')
+
+    def register_asm_addr(self, start, mark):
+        pass
+
+    def get_root_stack_top_addr(self):
+        return rffi.cast(lltype.Signed, self.stack_addr)
+
+class WriteBarrierDescr(AbstractDescr):
+    jit_wb_cards_set = 0
+    jit_wb_if_flag_singlebyte = 1
+    
+    def __init__(self, gc_ll_descr):
+        def write_barrier(frame):
+            gc_ll_descr.write_barrier_on_frame_called = frame
+
+        self.write_barrier_fn = llhelper_args(write_barrier,
+                                              [lltype.Signed], lltype.Void)
+
+    def get_write_barrier_fn(self, cpu):
+        return self.write_barrier_fn
+
+# a copy of JITFRAM that has 'hdr' field for tests
+
+def jitframe_allocate(frame_info):
+    frame = lltype.malloc(JITFRAME, frame_info.jfi_frame_depth, zero=True)
+    frame.jf_frame_info = frame_info
+    return frame
+
+JITFRAME = lltype.GcStruct(
+    'JITFRAME',
+    ('hdr', lltype.Signed),
+    ('jf_frame_info', lltype.Ptr(jitframe.JITFRAMEINFO)),
+    ('jf_descr', llmemory.GCREF),
+    ('jf_force_descr', llmemory.GCREF),
+    ('jf_guard_exc', llmemory.GCREF),
+    ('jf_gcmap', lltype.Ptr(jitframe.GCMAP)),
+    ('jf_gc_trace_state', lltype.Signed),
+    ('jf_frame', lltype.Array(lltype.Signed)),
+    adtmeths = {
+        'allocate': jitframe_allocate,
+    },
+)
+
+JITFRAMEPTR = lltype.Ptr(JITFRAME)
+
+class GCDescrShadowstackDirect(GcLLDescr_framework):
+    layoutbuilder = None
+
+    class GCClass:
+        JIT_WB_IF_FLAG = 0
+
+    def __init__(self):
+        GcCache.__init__(self, False, None)
+        self._generated_functions = []
+        self.gcrootmap = MockShadowStackRootMap()
+        self.write_barrier_descr = WriteBarrierDescr(self)
+        self.nursery_ptrs = lltype.malloc(rffi.CArray(lltype.Signed), 2,
+                                          flavor='raw')
+        self._initialize_for_tests()
+        self.frames = []
+
+        def malloc_slowpath(size):
+            self._collect()
+            res = self.nursery_ptrs[0]
+            self.nursery_ptrs[0] += size
+            return res
+
+        self.malloc_slowpath_fnptr = llhelper_args(malloc_slowpath,
+                                                   [lltype.Signed],
+                                                   lltype.Signed)
+        self.all_nurseries = []
+
+    def init_nursery(self, nursery_size=None):
+        if nursery_size is None:
+            nursery_size = self.nursery_size
+        else:
+            self.nursery_size = nursery_size
+        self.nursery = lltype.malloc(rffi.CArray(lltype.Char), nursery_size,
+                                     flavor='raw', zero=True,
+                                     track_allocation=False)
+        self.nursery_ptrs[0] = rffi.cast(lltype.Signed, self.nursery)
+        self.nursery_ptrs[1] = self.nursery_ptrs[0] + nursery_size
+        self.nursery_addr = rffi.cast(lltype.Signed, self.nursery_ptrs)
+        self.all_nurseries.append(self.nursery)
+        if hasattr(self, 'collections'):
+            self.collections.reverse()
+
+    def _collect(self):
+        gcmap = unpack_gcmap(self.frames[-1])
+        col = self.collections.pop()
+        frame = self.frames[-1].jf_frame
+        start = rffi.cast(lltype.Signed, self.nursery)
+        assert len(gcmap) == len(col)
+        pos = [frame[item] for item in gcmap]
+        pos.sort()
+        for i in range(len(gcmap)):
+            assert col[i] + start == pos[i]
+        self.frames[-1].hdr |= 1
+        self.init_nursery()
+
+    def malloc_jitframe(self, frame_info):
+        """ Allocate a new frame, overwritten by tests
+        """
+        frame = JITFRAME.allocate(frame_info)
+        self.frames.append(frame)
+        return frame
+
+    def getframedescrs(self, cpu):
+        descrs = JitFrameDescrs()
+        descrs.arraydescr = cpu.arraydescrof(JITFRAME)
+        for name in ['jf_descr', 'jf_guard_exc', 'jf_force_descr',
+                     'jf_frame_info', 'jf_gcmap']:
+            setattr(descrs, name, cpu.fielddescrof(JITFRAME, name))
+        descrs.jfi_frame_depth = cpu.fielddescrof(jitframe.JITFRAMEINFO,
+                                                  'jfi_frame_depth')
+        descrs.jfi_frame_size = cpu.fielddescrof(jitframe.JITFRAMEINFO,
+                                                  'jfi_frame_size')
+        return descrs
+
+    def do_write_barrier(self, gcref_struct, gcref_newptr):
+        pass
+
+    def get_malloc_slowpath_addr(self):
+        return self.malloc_slowpath_fnptr
+
+    def get_nursery_free_addr(self):
+        return self.nursery_addr
+
+    def get_nursery_top_addr(self):
+        return self.nursery_addr + rffi.sizeof(lltype.Signed)
+
+    def __del__(self):
+        for nursery in self.all_nurseries:
+            lltype.free(nursery, flavor='raw', track_allocation=False)
+        lltype.free(self.nursery_ptrs, flavor='raw')
+    
+def unpack_gcmap(frame):
+    res = []
+    val = 0
+    for i in range(len(frame.jf_gcmap)):
+        item = frame.jf_gcmap[i]
+        while item != 0:
+            if item & 1:
+                res.append(val)
+            val += 1
+            item >>= 1
+    return res
+
+class TestGcShadowstackDirect(BaseTestRegalloc):
+
+    def setup_method(self, meth):
+        cpu = CPU(None, None)
+        cpu.gc_ll_descr = GCDescrShadowstackDirect()
+        wbd = cpu.gc_ll_descr.write_barrier_descr
+        wbd.jit_wb_if_flag_byteofs = 0 # directly into 'hdr' field
+        S = lltype.GcForwardReference()
+        S.become(lltype.GcStruct('S',
+                                 ('hdr', lltype.Signed),
+                                 ('x', lltype.Ptr(S))))
+        cpu.gc_ll_descr.fielddescr_tid = cpu.fielddescrof(S, 'hdr')
+        self.S = S
+        self.cpu = cpu
+
+    def test_shadowstack_call(self):
+        cpu = self.cpu
+        cpu.gc_ll_descr.init_nursery(100)
+        cpu.setup_once() 
+        S = self.S
+        frames = []
+        
+        def check(i):
+            assert cpu.gc_ll_descr.gcrootmap.stack[0] == i
+            frame = rffi.cast(JITFRAMEPTR, i)
+            assert len(frame.jf_frame) == self.cpu.JITFRAME_FIXED_SIZE + 4
+            # we "collect"
+            frames.append(frame)
+            new_frame = JITFRAME.allocate(frame.jf_frame_info)
+            gcmap = unpack_gcmap(frame)
+            if self.cpu.IS_64_BIT:
+                assert gcmap == [28, 29, 30]
+            else:
+                assert gcmap == [22, 23, 24]
+            for item, s in zip(gcmap, new_items):
+                new_frame.jf_frame[item] = rffi.cast(lltype.Signed, s)
+            assert cpu.gc_ll_descr.gcrootmap.stack[0] == rffi.cast(lltype.Signed, frame)
+            cpu.gc_ll_descr.gcrootmap.stack[0] = rffi.cast(lltype.Signed, new_frame)
+            frames.append(new_frame)
+
+        def check2(i):
+            assert cpu.gc_ll_descr.gcrootmap.stack[0] == i
+            frame = rffi.cast(JITFRAMEPTR, i)
+            assert frame == frames[1]
+            assert frame != frames[0]
+
+        CHECK = lltype.FuncType([lltype.Signed], lltype.Void)
+        checkptr = llhelper(lltype.Ptr(CHECK), check)
+        check2ptr = llhelper(lltype.Ptr(CHECK), check2)
+        checkdescr = cpu.calldescrof(CHECK, CHECK.ARGS, CHECK.RESULT,
+                                          EffectInfo.MOST_GENERAL)
+
+        loop = self.parse("""
+        [p0, p1, p2]
+        pf = force_token() # this is the frame
+        call(ConstClass(check_adr), pf, descr=checkdescr) # this can collect
+        p3 = getfield_gc(p0, descr=fielddescr)
+        pf2 = force_token()
+        call(ConstClass(check2_adr), pf2, descr=checkdescr)
+        guard_nonnull(p3, descr=faildescr) [p0, p1, p2, p3]
+        p4 = getfield_gc(p0, descr=fielddescr)
+        finish(p4, descr=finaldescr)
+        """, namespace={'finaldescr': BasicFinalDescr(),
+                        'faildescr': BasicFailDescr(),
+                        'check_adr': checkptr, 'check2_adr': check2ptr,
+                        'checkdescr': checkdescr,
+                        'fielddescr': cpu.fielddescrof(S, 'x')})
+        token = JitCellToken()
+        cpu.compile_loop(loop.inputargs, loop.operations, token)
+        p0 = lltype.malloc(S, zero=True)
+        p1 = lltype.malloc(S)
+        p2 = lltype.malloc(S)
+        new_items = [lltype.malloc(S), lltype.malloc(S), lltype.malloc(S)]
+        new_items[0].x = new_items[2]
+        frame = cpu.execute_token(token, p0, p1, p2)
+        frame = lltype.cast_opaque_ptr(JITFRAMEPTR, frame)
+        gcmap = unpack_gcmap(lltype.cast_opaque_ptr(JITFRAMEPTR, frame))
+        assert len(gcmap) == 1
+        assert gcmap[0] < self.cpu.JITFRAME_FIXED_SIZE
+        item = rffi.cast(lltype.Ptr(S), frame.jf_frame[gcmap[0]])
+        assert item == new_items[2]
+
+    def test_malloc_1(self):
+        cpu = self.cpu
+        sizeof = cpu.sizeof(self.S)
+        sizeof.tid = 0
+        size = sizeof.size
+        loop = self.parse("""
+        []
+        p0 = call_malloc_nursery(%d)
+        p1 = call_malloc_nursery(%d)
+        p2 = call_malloc_nursery(%d) # this overflows
+        guard_nonnull(p2, descr=faildescr) [p0, p1, p2]
+        finish(p2, descr=finaldescr)
+        """ % (size, size, size), namespace={'sizedescr': sizeof,
+                        'finaldescr': BasicFinalDescr(),
+                        'faildescr': BasicFailDescr()})
+        token = JitCellToken()
+        cpu.gc_ll_descr.collections = [[0, sizeof.size]]
+        cpu.gc_ll_descr.init_nursery(2 * sizeof.size)
+        cpu.setup_once()
+        cpu.compile_loop(loop.inputargs, loop.operations, token)
+        frame = cpu.execute_token(token)
+        # now we should be able to track everything from the frame
+        frame = lltype.cast_opaque_ptr(JITFRAMEPTR, frame)
+        thing = frame.jf_frame[unpack_gcmap(frame)[0]]
+        assert thing == rffi.cast(lltype.Signed, cpu.gc_ll_descr.nursery)
+        assert cpu.gc_ll_descr.nursery_ptrs[0] == thing + sizeof.size
+        assert rffi.cast(JITFRAMEPTR, cpu.gc_ll_descr.write_barrier_on_frame_called) == frame
+
+    def test_call_release_gil(self):
+        # note that we can't test floats here because when untranslated
+        # people actually wreck xmm registers
+        cpu = self.cpu
+        l = []
+
+        def before():
+            l.append("before")
+
+        def after():
+            l.append("after")
+
+        invoke_around_extcall(before, after)
+
+        def f(x):
+            assert x == 1
+            return 2
+        
+        FUNC = lltype.FuncType([lltype.Signed], lltype.Signed)
+        fptr = llhelper(lltype.Ptr(FUNC), f)
+        calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+                                    EffectInfo.MOST_GENERAL)        
+        loop = self.parse("""
+        [i0]
+        i1 = call_release_gil(ConstClass(fptr), i0, descr=calldescr)
+        guard_not_forced(descr=faildescr) []
+        finish(i1, descr=finaldescr)
+        """, namespace={'fptr': fptr, 'calldescr':calldescr,
+                        'faildescr': BasicFailDescr(),
+                        'finaldescr': BasicFinalDescr()})
+        token = JitCellToken()
+        cpu.gc_ll_descr.init_nursery(100)
+        cpu.setup_once()
+        cpu.compile_loop(loop.inputargs, loop.operations, token)
+        frame = cpu.execute_token(token, 1)
+        frame = rffi.cast(JITFRAMEPTR, frame)
+        assert frame.jf_frame[0] == 2
+        assert l == ['before', 'after']

rpython/jit/backend/llsupport/test/test_regalloc_integration.py

+
+""" Tests for register allocation for common constructs
+"""
+
+import py
+from rpython.jit.metainterp.history import BoxInt, ConstInt,\
+     BoxPtr, ConstPtr, BasicFailDescr, JitCellToken, TargetToken
+from rpython.jit.metainterp.resoperation import rop, ResOperation
+from rpython.jit.backend.llsupport.descr import GcCache
+from rpython.jit.backend.detect_cpu import getcpuclass
+from rpython.jit.backend.llsupport.regalloc import is_comparison_or_ovf_op
+from rpython.jit.tool.oparser import parse
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
+from rpython.rtyper.annlowlevel import llhelper
+from rpython.rtyper.lltypesystem import rclass, rstr
+from rpython.jit.codewriter import longlong
+from rpython.jit.codewriter.effectinfo import EffectInfo
+
+def test_is_comparison_or_ovf_op():
+    assert not is_comparison_or_ovf_op(rop.INT_ADD)
+    assert is_comparison_or_ovf_op(rop.INT_ADD_OVF)
+    assert is_comparison_or_ovf_op(rop.INT_EQ)
+
+
+def get_zero_division_error(self):
+    # for tests, a random emulated ll_inst will do
+    ll_inst = lltype.malloc(rclass.OBJECT)
+    ll_inst.typeptr = lltype.malloc(rclass.OBJECT_VTABLE,
+                                    immortal=True)
+    _zer_error_vtable = llmemory.cast_ptr_to_adr(ll_inst.typeptr)
+    zer_vtable = self.cast_adr_to_int(_zer_error_vtable)
+    zer_inst = lltype.cast_opaque_ptr(llmemory.GCREF, ll_inst)
+    return zer_vtable, zer_inst
+
+
+CPU = getcpuclass()
+class BaseTestRegalloc(object):
+    cpu = CPU(None, None)
+    cpu.setup_once()
+
+    def raising_func(i):
+        if i:
+            raise LLException(zero_division_error,
+                              zero_division_value)
+    FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void))
+    raising_fptr = llhelper(FPTR, raising_func)
+    zero_division_tp, zero_division_value = get_zero_division_error(cpu)
+    zd_addr = cpu.cast_int_to_adr(zero_division_tp)
+    zero_division_error = llmemory.cast_adr_to_ptr(zd_addr,
+                                            lltype.Ptr(rclass.OBJECT_VTABLE))
+    raising_calldescr = cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT,
+                                        EffectInfo.MOST_GENERAL)
+
+    targettoken = TargetToken()
+    targettoken2 = TargetToken()
+    fdescr1 = BasicFailDescr(1)
+    fdescr2 = BasicFailDescr(2)
+    fdescr3 = BasicFailDescr(3)
+
+    def setup_method(self, meth):
+        self.targettoken._ll_loop_code = 0
+        self.targettoken2._ll_loop_code = 0
+
+    def f1(x):
+        return x+1
+
+    def f2(x, y):
+        return x*y
+
+    def f10(*args):
+        assert len(args) == 10
+        return sum(args)
+
+    F1PTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed))
+    F2PTR = lltype.Ptr(lltype.FuncType([lltype.Signed]*2, lltype.Signed))
+    F10PTR = lltype.Ptr(lltype.FuncType([lltype.Signed]*10, lltype.Signed))
+    f1ptr = llhelper(F1PTR, f1)
+    f2ptr = llhelper(F2PTR, f2)
+    f10ptr = llhelper(F10PTR, f10)
+
+    f1_calldescr = cpu.calldescrof(F1PTR.TO, F1PTR.TO.ARGS, F1PTR.TO.RESULT,
+                                   EffectInfo.MOST_GENERAL)
+    f2_calldescr = cpu.calldescrof(F2PTR.TO, F2PTR.TO.ARGS, F2PTR.TO.RESULT,
+                                   EffectInfo.MOST_GENERAL)
+    f10_calldescr= cpu.calldescrof(F10PTR.TO, F10PTR.TO.ARGS, F10PTR.TO.RESULT,
+                                   EffectInfo.MOST_GENERAL)
+
+    namespace = locals().copy()
+    type_system = 'lltype'
+
+    def parse(self, s, boxkinds=None, namespace=None):
+        return parse(s, self.cpu, namespace or self.namespace,
+                     type_system=self.type_system,
+                     boxkinds=boxkinds)
+
+    def interpret(self, ops, args, run=True):
+        loop = self.parse(ops)
+        looptoken = JitCellToken()
+        self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+        arguments = []
+        for arg in args:
+            if isinstance(arg, int):
+                arguments.append(arg)
+            elif isinstance(arg, float):
+                arg = longlong.getfloatstorage(arg)
+                arguments.append(arg)
+            else:
+                assert isinstance(lltype.typeOf(arg), lltype.Ptr)
+                llgcref = lltype.cast_opaque_ptr(llmemory.GCREF, arg)
+                arguments.append(llgcref)
+        loop._jitcelltoken = looptoken
+        if run:
+            self.deadframe = self.cpu.execute_token(looptoken, *arguments)
+        return loop
+
+    def prepare_loop(self, ops):
+        loop = self.parse(ops)
+        regalloc = self.cpu.build_regalloc()
+        regalloc.prepare_loop(loop.inputargs, loop.operations,
+                              loop.original_jitcell_token, [])
+        return regalloc
+
+    def getint(self, index):
+        return self.cpu.get_int_value(self.deadframe, index)
+
+    def getfloat(self, index):
+        return self.cpu.get_float_value(self.deadframe, index)
+
+    def getints(self, end):
+        return [self.cpu.get_int_value(self.deadframe, index) for
+                index in range(0, end)]
+
+    def getfloats(self, end):
+        return [longlong.getrealfloat(
+                    self.cpu.get_float_value(self.deadframe, index))
+                for index in range(0, end)]
+
+    def getptr(self, index, T):
+        gcref = self.cpu.get_ref_value(self.deadframe, index)
+        return lltype.cast_opaque_ptr(T, gcref)
+
+    def attach_bridge(self, ops, loop, guard_op_index, **kwds):
+        guard_op = loop.operations[guard_op_index]
+        assert guard_op.is_guard()
+        bridge = self.parse(ops, **kwds)
+        assert ([box.type for box in bridge.inputargs] ==
+                [box.type for box in guard_op.getfailargs()])
+        faildescr = guard_op.getdescr()
+        self.cpu.compile_bridge(faildescr, bridge.inputargs, bridge.operations,
+                                loop._jitcelltoken)
+        return bridge
+
+    def run(self, loop, *arguments):
+        self.deadframe = self.cpu.execute_token(loop._jitcelltoken, *arguments)
+        return self.cpu.get_latest_descr(self.deadframe)
+
+class TestRegallocSimple(BaseTestRegalloc):
+    def test_simple_loop(self):
+        ops = '''
+        [i0]
+        label(i0, descr=targettoken)
+        i1 = int_add(i0, 1)
+        i2 = int_lt(i1, 20)
+        guard_true(i2) [i1]
+        jump(i1, descr=targettoken)
+        '''
+        self.interpret(ops, [0])
+        assert self.getint(0) == 20
+
+    def test_two_loops_and_a_bridge(self):
+        ops = '''
+        [i0, i1, i2, i3]
+        label(i0, i1, i2, i3, descr=targettoken)
+        i4 = int_add(i0, 1)
+        i5 = int_lt(i4, 20)
+        guard_true(i5) [i4, i1, i2, i3]
+        jump(i4, i1, i2, i3, descr=targettoken)
+        '''
+        loop = self.interpret(ops, [0, 0, 0, 0])
+        ops2 = '''
+        [i5, i6, i7, i8]
+        label(i5, descr=targettoken2)
+        i1 = int_add(i5, 1)
+        i3 = int_add(i1, 1)
+        i4 = int_add(i3, 1)
+        i2 = int_lt(i4, 30)
+        guard_true(i2) [i4]
+        jump(i4, descr=targettoken2)
+        '''
+        loop2 = self.interpret(ops2, [0, 0, 0, 0])
+        bridge_ops = '''
+        [i4]
+        jump(i4, i4, i4, i4, descr=targettoken)
+        '''
+        bridge = self.attach_bridge(bridge_ops, loop2, 5)
+        self.run(loop2, 0, 0, 0, 0)
+        assert self.getint(0) == 31
+        assert self.getint(1) == 30
+        assert self.getint(2) == 30
+        assert self.getint(3) == 30
+
+    def test_pointer_arg(self):
+        ops = '''
+        [i0, p0]
+        label(i0, p0, descr=targettoken)
+        i1 = int_add(i0, 1)
+        i2 = int_lt(i1, 10)
+        guard_true(i2) [p0]
+        jump(i1, p0, descr=targettoken)
+        '''
+        S = lltype.GcStruct('S')
+        ptr = lltype.malloc(S)
+        self.interpret(ops, [0, ptr])
+        assert self.getptr(0, lltype.Ptr(S)) == ptr
+
+    def test_exception_bridge_no_exception(self):
+        ops = '''
+        [i0]
+        i1 = same_as(1)
+        call(ConstClass(raising_fptr), i0, descr=raising_calldescr)
+        guard_exception(ConstClass(zero_division_error)) [i1]
+        finish(0)
+        '''
+        bridge_ops = '''
+        [i3]
+        i2 = same_as(2)
+        guard_no_exception() [i2]
+        finish(1)
+        '''
+        loop = self.interpret(ops, [0])
+        assert self.getint(0) == 1
+        bridge = self.attach_bridge(bridge_ops, loop, 2)
+        self.run(loop, 0)
+        assert self.getint(0) == 1
+
+    def test_inputarg_unused(self):
+        ops = '''
+        [i0]
+        finish(1)
+        '''
+        self.interpret(ops, [0])
+        # assert did not explode
+
+    def test_nested_guards(self):
+        ops = '''
+        [i0, i1]
+        guard_true(i0) [i0, i1]
+        finish(4)
+        '''
+        bridge_ops = '''
+        [i0, i1]
+        guard_true(i0) [i0, i1]
+        finish(3)
+        '''
+        loop = self.interpret(ops, [0, 10])
+        assert self.getint(0) == 0
+        assert self.getint(1) == 10
+        bridge = self.attach_bridge(bridge_ops, loop, 0)
+        self.run(loop, 0, 10)
+        assert self.getint(0) == 0
+        assert self.getint(1) == 10
+
+    def test_nested_unused_arg(self):
+        ops = '''
+        [i0, i1]
+        guard_true(i0) [i0, i1]
+        finish(1)
+        '''
+        loop = self.interpret(ops, [0, 1])
+        assert self.getint(0) == 0
+        bridge_ops = '''
+        [i0, i1]
+        finish(2)
+        '''
+        self.attach_bridge(bridge_ops, loop, 0)
+        self.run(loop, 0, 1)
+
+    def test_spill_for_constant(self):
+        ops = '''
+        [i0, i1, i2, i3]
+        label(i0, i1, i2, i3, descr=targettoken)
+        i4 = int_add(3, i1)
+        i5 = int_lt(i4, 30)
+        guard_true(i5) [i0, i4, i2, i3]
+        jump(1, i4, 3, 4, descr=targettoken)
+        '''
+        self.interpret(ops, [0, 0, 0, 0])
+        assert self.getints(4) == [1, 30, 3, 4]
+
+    def test_spill_for_constant_lshift(self):
+        ops = '''
+        [i0, i2, i1, i3]
+        label(i0, i2, i1, i3, descr=targettoken)
+        i4 = int_lshift(1, i1)
+        i5 = int_add(1, i1)
+        i6 = int_lt(i5, 30)
+        guard_true(i6) [i4, i5, i2, i3]
+        jump(i4, 3, i5, 4, descr=targettoken)
+        '''
+        self.interpret(ops, [0, 0, 0, 0])
+        assert self.getints(4) == [1<<29, 30, 3, 4]
+        ops = '''
+        [i0, i1, i2, i3]
+        label(i0, i1, i2, i3, descr=targettoken)
+        i4 = int_lshift(1, i1)
+        i5 = int_add(1, i1)
+        i6 = int_lt(i5, 30)
+        guard_true(i6) [i4, i5, i2, i3]
+        jump(i4, i5, 3, 4, descr=targettoken)
+        '''
+        self.interpret(ops, [0, 0, 0, 0])
+        assert self.getints(4) == [1<<29, 30, 3, 4]
+        ops = '''
+        [i0, i3, i1, i2]
+        label(i0, i3, i1, i2, descr=targettoken)
+        i4 = int_lshift(1, i1)
+        i5 = int_add(1, i1)
+        i6 = int_lt(i5, 30)
+        guard_true(i6) [i4, i5, i2, i3]
+        jump(i4, 4, i5, 3, descr=targettoken)
+        '''
+        self.interpret(ops, [0, 0, 0, 0])
+        assert self.getints(4) == [1<<29, 30, 3, 4]
+
+    def test_result_selected_reg_via_neg(self):
+        ops = '''
+        [i0, i1, i2, i3]
+        label(i0, i1, i2, i3, descr=targettoken)
+        i6 = int_neg(i2)
+        i7 = int_add(1, i1)
+        i4 = int_lt(i7, 10)
+        guard_true(i4) [i0, i6, i7]
+        jump(1, i7, i2, i6, descr=targettoken)
+        '''
+        self.interpret(ops, [0, 0, 3, 0])
+        assert self.getints(3) == [1, -3, 10]
+        
+    def test_compare_memory_result_survives(self):
+        ops = '''
+        [i0, i1, i2, i3]
+        label(i0, i1, i2, i3, descr=targettoken)
+        i4 = int_lt(i0, i1)
+        i5 = int_add(i3, 1)
+        i6 = int_lt(i5, 30)
+        guard_true(i6) [i4]
+        jump(i0, i1, i4, i5, descr=targettoken)
+        '''
+        self.interpret(ops, [0, 10, 0, 0])
+        assert self.getint(0) == 1
+
+    def test_jump_different_args(self):
+        ops = '''
+        [i0, i15, i16, i18, i1, i2, i3]
+        label(i0, i15, i16, i18, i1, i2, i3, descr=targettoken)
+        i4 = int_add(i3, 1)
+        i5 = int_lt(i4, 20)
+        guard_true(i5) [i2, i1]
+        jump(i0, i18, i15, i16, i2, i1, i4, descr=targettoken)
+        '''
+        self.interpret(ops, [0, 1, 2, 3, 0, 0, 0])
+
+    def test_op_result_unused(self):
+        ops = '''
+        [i0, i1]
+        i2 = int_add(i0, i1)
+        finish(0)
+        '''
+        self.interpret(ops, [0, 0])
+
+    def test_guard_value_two_boxes(self):
+        ops = '''
+        [i0, i1, i2, i3, i4, i5, i6, i7]
+        guard_value(i6, i1) [i0, i2, i3, i4, i5, i6]
+        finish(i0)
+        '''
+        self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0])
+        assert self.getint(0) == 0
+
+    def test_bug_wrong_stack_adj(self):
+        ops = '''
+        [i0, i1, i2, i3, i4, i5, i6, i7, i8]
+        i9 = same_as(0)
+        guard_true(i0) [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8]
+        finish(1)
+        '''
+        loop = self.interpret(ops, [0, 1, 2, 3, 4, 5, 6, 7, 8])
+        assert self.getint(0) == 0
+        bridge_ops = '''
+        [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8]
+        call(ConstClass(raising_fptr), 0, descr=raising_calldescr)
+        guard_true(i9) [i0, i1, i2, i3, i4, i5, i6, i7, i8]
+        finish()
+        '''
+        self.attach_bridge(bridge_ops, loop, 1)
+        self.run(loop, 0, 1, 2, 3, 4, 5, 6, 7, 8)
+        assert self.getints(9) == range(9)
+
+    def test_loopargs(self):
+        ops = """
+        [i0, i1, i2, i3]
+        i4 = int_add(i0, i1)
+        jump(i4, i1, i2, i3)
+        """
+        regalloc = self.prepare_loop(ops)
+        # we pass stuff on the frame
+        assert len(regalloc.rm.reg_bindings) == 0
+        assert len(regalloc.fm.bindings) == 4
+
+
+class TestRegallocCompOps(BaseTestRegalloc):
+    
+    def test_cmp_op_0(self):
+        ops = '''
+        [i0, i3]
+        i1 = same_as(1)
+        i2 = int_lt(i0, 100)
+        guard_true(i3) [i1, i2]
+        i4 = int_neg(i2)
+        finish(0)
+        '''
+        self.interpret(ops, [0, 1])
+        assert self.getint(0) == 0
+
+class TestRegallocMoreRegisters(BaseTestRegalloc):
+
+    cpu = BaseTestRegalloc.cpu
+    targettoken = TargetToken()
+
+    S = lltype.GcStruct('S', ('field', lltype.Char))
+    fielddescr = cpu.fielddescrof(S, 'field')
+
+    A = lltype.GcArray(lltype.Char)
+    arraydescr = cpu.arraydescrof(A)
+
+    namespace = locals().copy()
+
+    def test_int_is_true(self):
+        ops = '''
+        [i0, i1, i2, i3, i4, i5, i6, i7]
+        i10 = int_is_true(i0)
+        i11 = int_is_true(i1)
+        i12 = int_is_true(i2)
+        i13 = int_is_true(i3)
+        i14 = int_is_true(i4)
+        i15 = int_is_true(i5)
+        i16 = int_is_true(i6)
+        i17 = int_is_true(i7)
+        guard_true(i0) [i10, i11, i12, i13, i14, i15, i16, i17]
+        finish()
+        '''
+        self.interpret(ops, [0, 42, 12, 0, 13, 0, 0, 3333])
+        assert self.getints(8) == [0, 1, 1, 0, 1, 0, 0, 1]
+
+    def test_comparison_ops(self):
+        ops = '''
+        [i0, i1, i2, i3, i4, i5, i6]
+        i10 = int_lt(i0, i1)
+        i11 = int_le(i2, i3)
+        i12 = int_ge(i4, i5)
+        i13 = int_eq(i5, i6)
+        i14 = int_gt(i6, i2)
+        i15 = int_ne(i2, i6)
+        guard_true(i0) [i10, i11, i12, i13, i14, i15]
+        finish()
+        '''
+        self.interpret(ops, [0, 1, 2, 3, 4, 5, 6])
+        assert self.getints(6) == [1, 1, 0, 0, 1, 1]
+
+    def test_strsetitem(self):
+        ops = '''
+        [p0, i]
+        strsetitem(p0, 1, i)
+        finish()
+        '''
+        llstr  = rstr.mallocstr(10)
+        self.interpret(ops, [llstr, ord('a')])
+        assert llstr.chars[1] == 'a'
+
+    def test_setfield_char(self):
+        ops = '''
+        [p0, i]
+        setfield_gc(p0, i, descr=fielddescr)
+        finish()
+        '''
+        s = lltype.malloc(self.S)
+        self.interpret(ops, [s, ord('a')])
+        assert s.field == 'a'
+
+    def test_setarrayitem_gc(self):
+        ops = '''
+        [p0, i]
+        setarrayitem_gc(p0, 1, i, descr=arraydescr)
+        finish()
+        '''
+        s = lltype.malloc(self.A, 3)
+        self.interpret(ops, [s, ord('a')])
+        assert s[1] == 'a'
+
+    def test_division_optimized(self):
+        ops = '''
+        [i7, i6]
+        label(i7, i6, descr=targettoken)
+        i18 = int_floordiv(i7, i6)
+        i19 = int_xor(i7, i6)
+        i21 = int_lt(i19, 0)
+        i22 = int_mod(i7, i6)
+        i23 = int_is_true(i22)
+        i24 = int_eq(i6, 4)
+        guard_false(i24) [i18]
+        jump(i18, i6, descr=targettoken)
+        '''
+        self.interpret(ops, [10, 4])
+        assert self.getint(0) == 2
+        # FIXME: Verify that i19 - i23 are removed
+
+class TestRegallocFloats(BaseTestRegalloc):
+    def test_float_add(self):
+        ops = '''
+        [f0, f1]
+        f2 = float_add(f0, f1)
+        i0 = same_as(0)
+        guard_true(i0) [f2, f0, f1]
+        finish()
+        '''
+        self.interpret(ops, [3.0, 1.5])
+        assert self.getfloats(3) == [4.5, 3.0, 1.5]
+
+    def test_float_adds_stack(self):
+        ops = '''
+        [f0, f1, f2, f3, f4, f5, f6, f7, f8]
+        f9 = float_add(f0, f1)
+        f10 = float_add(f8, 3.5)
+        i0 = same_as(0)
+        guard_true(i0) [f9, f10, f2, f3, f4, f5, f6, f7, f8]
+        finish()
+        '''
+        self.interpret(ops, [0.1, .2, .3, .4, .5, .6, .7, .8, .9])
+        assert self.getfloats(9) == [.1+.2, .9+3.5, .3, .4, .5, .6, .7, .8, .9]
+
+    def test_lt_const(self):
+        ops = '''
+        [f0]
+        i1 = float_lt(3.5, f0)
+        finish(i1)
+        '''
+        self.interpret(ops, [0.1])
+        assert self.getint(0) == 0
+
+    def test_bug_float_is_true_stack(self):
+        # NB. float_is_true no longer exists.  Unsure if keeping this test
+        # makes sense any more.
+        ops = '''
+        [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9]
+        i0 = float_ne(f0, 0.0)
+        i1 = float_ne(f1, 0.0)
+        i2 = float_ne(f2, 0.0)
+        i3 = float_ne(f3, 0.0)
+        i4 = float_ne(f4, 0.0)
+        i5 = float_ne(f5, 0.0)
+        i6 = float_ne(f6, 0.0)
+        i7 = float_ne(f7, 0.0)
+        i8 = float_ne(f8, 0.0)
+        i9 = float_ne(f9, 0.0)
+        guard_true(i0) [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9]
+        finish()
+        '''
+        loop = self.interpret(ops, [0.0, .1, .2, .3, .4, .5, .6, .7, .8, .9])
+        assert self.getints(9) == [0, 1, 1, 1, 1, 1, 1, 1, 1]
+
+class TestRegAllocCallAndStackDepth(BaseTestRegalloc):
+    def setup_class(cls):
+        py.test.skip("skip for now, not sure what do we do")
+    
+    def expected_frame_depth(self, num_call_args, num_pushed_input_args=0):
+        # Assumes the arguments are all non-float
+        if not self.cpu.IS_64_BIT:
+            extra_esp = num_call_args
+            return extra_esp
+        elif self.cpu.IS_64_BIT:
+            # 'num_pushed_input_args' is for X86_64 only
+            extra_esp = max(num_call_args - 6, 0)
+            return num_pushed_input_args + extra_esp
+
+    def test_one_call(self):
+        ops = '''
+        [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i9b]
+        i10 = call(ConstClass(f1ptr), i0, descr=f1_calldescr)
+        guard_false(i10) [i10, i1, i2, i3, i4, i5, i6, i7, i8, i9, i9b]
+        '''
+        loop = self.interpret(ops, [4, 7, 9, 9 ,9, 9, 9, 9, 9, 9, 8])
+        assert self.getints(11) == [5, 7, 9, 9, 9, 9, 9, 9, 9, 9, 8]
+        clt = loop._jitcelltoken.compiled_loop_token
+        assert clt.frame_depth == self.expected_frame_depth(1, 5)
+
+    def test_one_call_reverse(self):
+        ops = '''
+        [i1, i2, i3, i4, i5, i6, i7, i8, i9, i9b, i0]
+        i10 = call(ConstClass(f1ptr), i0, descr=f1_calldescr)
+        guard_false(i10) [i10, i1, i2, i3, i4, i5, i6, i7, i8, i9, i9b]
+        '''
+        loop = self.interpret(ops, [7, 9, 9 ,9, 9, 9, 9, 9, 9, 8, 4])
+        assert self.getints(11) == [5, 7, 9, 9, 9, 9, 9, 9, 9, 9, 8]
+        clt = loop._jitcelltoken.compiled_loop_token
+        assert clt.frame_depth == self.expected_frame_depth(1, 6)
+
+    def test_two_calls(self):
+        ops = '''
+        [i0, i1,  i2, i3, i4, i5, i6, i7, i8, i9]
+        i10 = call(ConstClass(f1ptr), i0, descr=f1_calldescr)
+        i11 = call(ConstClass(f2ptr), i10, i1, descr=f2_calldescr)        
+        guard_false(i5) [i11, i1,  i2, i3, i4, i5, i6, i7, i8, i9]
+        '''
+        loop = self.interpret(ops, [4, 7, 9, 9 ,9, 9, 9, 9, 9, 9])
+        assert self.getints(10) == [5*7, 7, 9, 9, 9, 9, 9, 9, 9, 9]
+        clt = loop._jitcelltoken.compiled_loop_token
+        assert clt.frame_depth == self.expected_frame_depth(2, 5)
+
+    def test_call_many_arguments(self):
+        # NB: The first and last arguments in the call are constants. This
+        # is primarily for x86-64, to ensure that loading a constant to an
+        # argument register or to the stack works correctly
+        ops = '''
+        [i0, i1, i2, i3, i4, i5, i6, i7]
+        i8 = call(ConstClass(f10ptr), 1, i0, i1, i2, i3, i4, i5, i6, i7, 10, descr=f10_calldescr)
+        finish(i8)
+        '''
+        loop = self.interpret(ops, [2, 3, 4, 5, 6, 7, 8, 9])
+        assert self.getint(0) == 55
+        clt = loop._jitcelltoken.compiled_loop_token
+        assert clt.frame_depth == self.expected_frame_depth(10)
+
+    def test_bridge_calls_1(self):
+        ops = '''
+        [i0, i1]
+        i2 = call(ConstClass(f1ptr), i0, descr=f1_calldescr)
+        guard_value(i2, 0, descr=fdescr1) [i2, i0, i1]
+        guard_false(i1) [i1]
+        '''
+        loop = self.interpret(ops, [4, 7])
+        assert self.getint(0) == 5
+        clt = loop._jitcelltoken.compiled_loop_token
+        orgdepth = clt.frame_depth
+        assert orgdepth == self.expected_frame_depth(1, 2)
+
+        ops = '''
+        [i2, i0, i1]
+        i3 = call(ConstClass(f2ptr), i2, i1, descr=f2_calldescr)        
+        guard_false(i0, descr=fdescr2) [i3, i0]
+        '''
+        bridge = self.attach_bridge(ops, loop, -2)
+
+        assert clt.frame_depth == max(orgdepth, self.expected_frame_depth(2, 2))
+        assert loop.operations[-2].getdescr()._x86_bridge_frame_depth == \
+            self.expected_frame_depth(2, 2)
+
+        self.run(loop, 4, 7)
+        assert self.getint(0) == 5*7
+
+    def test_bridge_calls_2(self):
+        ops = '''
+        [i0, i1]
+        i2 = call(ConstClass(f2ptr), i0, i1, descr=f2_calldescr)
+        guard_value(i2, 0, descr=fdescr1) [i2]
+        guard_false(i2) [i2]
+        '''
+        loop = self.interpret(ops, [4, 7])
+        assert self.getint(0) == 4*7
+        clt = loop._jitcelltoken.compiled_loop_token
+        orgdepth = clt.frame_depth
+        assert orgdepth == self.expected_frame_depth(2)
+
+        ops = '''
+        [i2]
+        i3 = call(ConstClass(f1ptr), i2, descr=f1_calldescr)        
+        guard_false(i3, descr=fdescr2) [i3]
+        '''
+        bridge = self.attach_bridge(ops, loop, -2)
+
+        assert clt.frame_depth == max(orgdepth, self.expected_frame_depth(1))
+        assert loop.operations[-2].getdescr()._x86_bridge_frame_depth == \
+            self.expected_frame_depth(1)
+
+        self.run(loop, 4, 7)
+        assert self.getint(0) == 29
+

rpython/jit/backend/x86/assembler.py

     def assemble_loop(self, loopname, inputargs, operations, looptoken, log):
         '''adds the following attributes to looptoken:
                _ll_function_addr    (address of the generated func, as an int)
-               _x86_loop_code       (debug: addr of the start of the ResOps)
+               _ll_loop_code       (debug: addr of the start of the ResOps)
                _x86_fullsize        (debug: full size including failure)
                _x86_debug_checksum
         '''
         full_size = self.mc.get_relative_pos()
         #
         rawstart = self.materialize_loop(looptoken)
-        looptoken._x86_loop_code = looppos + rawstart
+        looptoken._ll_loop_code = looppos + rawstart
         debug_start("jit-backend-addr")
         debug_print("Loop %d (%s) has address %x to %x (bootstrap %x)" % (
             looptoken.number, loopname,
 
     def fixup_target_tokens(self, rawstart):
         for targettoken in self.target_tokens_currently_compiling:
-            targettoken._x86_loop_code += rawstart
+            targettoken._ll_loop_code += rawstart
         self.target_tokens_currently_compiling = None
 
     def _append_debugging_code(self, operations, tp, number, token):
                                 expected_size=expected_size)
 
     def closing_jump(self, target_token):
-        target = target_token._x86_loop_code
+        target = target_token._ll_loop_code
         if target_token in self.target_tokens_currently_compiling:
             curpos = self.mc.get_relative_pos() + 5
             self.mc.JMP_l(target - curpos)

rpython/jit/backend/x86/regalloc.py

         self.final_jump_op = op
         descr = op.getdescr()
         assert isinstance(descr, TargetToken)
-        if descr._x86_loop_code != 0:
+        if descr._ll_loop_code != 0:
             # if the target LABEL was already compiled, i.e. if it belongs
             # to some already-compiled piece of code
             self._compute_hint_frame_locations_from_descr(descr)
         self.flush_loop()
         #
         descr._x86_arglocs = arglocs
-        descr._x86_loop_code = self.assembler.mc.get_relative_pos()
+        descr._ll_loop_code = self.assembler.mc.get_relative_pos()
         descr._x86_clt = self.assembler.current_clt
         self.assembler.target_tokens_currently_compiling[descr] = None
         self.possibly_free_vars_for_op(op)
     os.write(2, '[x86/regalloc] %s\n' % msg)
     raise NotImplementedError(msg)
 
-# xxx hack: set a default value for TargetToken._x86_loop_code.
+# xxx hack: set a default value for TargetToken._ll_loop_code.
 # If 0, we know that it is a LABEL that was not compiled yet.
-TargetToken._x86_loop_code = 0
+TargetToken._ll_loop_code = 0

rpython/jit/backend/x86/runner.py

     def setup(self):
         self.assembler = Assembler386(self, self.translate_support_code)
 
+    def build_regalloc(self):
+	''' for tests'''
+	from rpython.jit.backend.x86.regalloc import RegAlloc
+	assert self.assembler is not None
+	return RegAlloc(self.assembler, False)
+
     def setup_once(self):
         self.profile_agent.startup()
         self.assembler.setup_once()

rpython/jit/backend/x86/test/test_gc_integration.py

-
-""" Tests for register allocation for common constructs
-"""
-
-from rpython.jit.metainterp.history import TargetToken, BasicFinalDescr,\
-     JitCellToken, BasicFailDescr, AbstractDescr
-from rpython.jit.backend.llsupport.gc import GcLLDescription, GcLLDescr_boehm,\
-     GcLLDescr_framework, GcCache, JitFrameDescrs
-from rpython.jit.backend.detect_cpu import getcpuclass
-from rpython.jit.backend.x86.arch import WORD, JITFRAME_FIXED_SIZE, IS_X86_64
-from rpython.jit.backend.llsupport import jitframe
-from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
-from rpython.rtyper.annlowlevel import llhelper, llhelper_args
-
-from rpython.jit.backend.x86.test.test_regalloc import BaseTestRegalloc
-from rpython.jit.codewriter.effectinfo import EffectInfo
-from rpython.rlib.objectmodel import invoke_around_extcall
-
-CPU = getcpuclass()
-
-class TestRegallocGcIntegration(BaseTestRegalloc):
-    
-    cpu = CPU(None, None)
-    cpu.gc_ll_descr = GcLLDescr_boehm(None, None, None)
-    cpu.setup_once()
-    
-    S = lltype.GcForwardReference()
-    S.become(lltype.GcStruct('S', ('field', lltype.Ptr(S)),
-                             ('int', lltype.Signed)))
-
-    fielddescr = cpu.fielddescrof(S, 'field')
-
-    struct_ptr = lltype.malloc(S)
-    struct_ref = lltype.cast_opaque_ptr(llmemory.GCREF, struct_ptr)
-    child_ptr = lltype.nullptr(S)
-    struct_ptr.field = child_ptr
-
-
-    intdescr = cpu.fielddescrof(S, 'int')
-    ptr0 = struct_ref
-
-    targettoken = TargetToken()
-    targettoken2 = TargetToken()
-
-    namespace = locals().copy()
-
-    def test_basic(self):
-        ops = '''
-        [p0]
-        p1 = getfield_gc(p0, descr=fielddescr)
-        finish(p1)
-        '''
-        self.interpret(ops, [self.struct_ptr])
-        assert not self.getptr(0, lltype.Ptr(self.S))
-
-    def test_guard(self):
-        ops = '''
-        [i0, p0, i1, p1]
-        p3 = getfield_gc(p0, descr=fielddescr)
-        guard_true(i0) [p0, i1, p1, p3]
-        '''
-        s1 = lltype.malloc(self.S)
-        s2 = lltype.malloc(self.S)
-        s1.field = s2
-        self.interpret(ops, [0, s1, 1, s2])
-        frame = lltype.cast_opaque_ptr(jitframe.JITFRAMEPTR, self.deadframe)
-        # p0 and p3 should be in registers, p1 not so much
-        assert self.getptr(0, lltype.Ptr(self.S)) == s1
-        # this is a fairly CPU specific check
-        assert len(frame.jf_gcmap) == 1
-        # the gcmap should contain three things, p0, p1 and p3
-        # p3 stays in a register
-        # while p0 and p1 are on the frame
-        if IS_X86_64:
-            nos = [11, 12, 31]
-        else:
-            nos = [4, 5, 25]
-        assert frame.jf_gcmap[0] == ((1 << nos[0]) | (1 << nos[1]) |
-                                     (1 << nos[2]))
-        assert frame.jf_frame[nos[0]]
-        assert frame.jf_frame[nos[1]]
-        assert frame.jf_frame[nos[2]]
-
-    def test_rewrite_constptr(self):
-        ops = '''
-        []
-        p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr)
-        finish(p1)
-        '''
-        self.interpret(ops, [])
-        assert not self.getptr(0, lltype.Ptr(self.S))
-
-    def test_bug_0(self):
-        ops = '''
-        [i0, i1, i2, i3, i4, i5, i6, i7, i8]
-        label(i0, i1, i2, i3, i4, i5, i6, i7, i8, descr=targettoken)
-        guard_value(i2, 1) [i2, i3, i4, i5, i6, i7, i0, i1, i8]
-        guard_class(i4, 138998336) [i4, i5, i6, i7, i0, i1, i8]
-        i11 = getfield_gc(i4, descr=intdescr)
-        guard_nonnull(i11) [i4, i5, i6, i7, i0, i1, i11, i8]
-        i13 = getfield_gc(i11, descr=intdescr)
-        guard_isnull(i13) [i4, i5, i6, i7, i0, i1, i11, i8]
-        i15 = getfield_gc(i4, descr=intdescr)
-        i17 = int_lt(i15, 0)
-        guard_false(i17) [i4, i5, i6, i7, i0, i1, i11, i15, i8]
-        i18 = getfield_gc(i11, descr=intdescr)
-        i19 = int_ge(i15, i18)
-        guard_false(i19) [i4, i5, i6, i7, i0, i1, i11, i15, i8]
-        i20 = int_lt(i15, 0)
-        guard_false(i20) [i4, i5, i6, i7, i0, i1, i11, i15, i8]
-        i21 = getfield_gc(i11, descr=intdescr)
-        i22 = getfield_gc(i11, descr=intdescr)
-        i23 = int_mul(i15, i22)
-        i24 = int_add(i21, i23)
-        i25 = getfield_gc(i4, descr=intdescr)
-        i27 = int_add(i25, 1)
-        setfield_gc(i4, i27, descr=intdescr)
-        i29 = getfield_raw(144839744, descr=intdescr)
-        i31 = int_and(i29, -2141192192)
-        i32 = int_is_true(i31)
-        guard_false(i32) [i4, i6, i7, i0, i1, i24]
-        i33 = getfield_gc(i0, descr=intdescr)
-        guard_value(i33, ConstPtr(ptr0)) [i4, i6, i7, i0, i1, i33, i24]
-        jump(i0, i1, 1, 17, i4, ConstPtr(ptr0), i6, i7, i24, descr=targettoken)
-        '''
-        self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0, 0], run=False)
-
-NOT_INITIALIZED = chr(0xdd)
-
-class GCDescrFastpathMalloc(GcLLDescription):
-    gcrootmap = None
-    passes_frame = True
-    write_barrier_descr = None
-
-    def __init__(self, callback):
-        GcLLDescription.__init__(self, None)
-        # create a nursery
-        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] + 64
-        self.calls = []
-        def malloc_slowpath(size, frame):
-            if callback is not None:
-                callback(frame)
-            if self.gcrootmap is not None:   # hook
-                self.gcrootmap.hook_malloc_slowpath()
-            self.calls.append(size)
-            # reset the nursery
-            nadr = rffi.cast(lltype.Signed, self.nursery)
-            self.addrs[0] = nadr + size
-            return nadr
-        self.generate_function('malloc_nursery', malloc_slowpath,
-                               [lltype.Signed, jitframe.JITFRAMEPTR],
-                               lltype.Signed)
-
-    def get_nursery_free_addr(self):
-        return rffi.cast(lltype.Signed, self.addrs)
-
-    def get_nursery_top_addr(self):
-        return rffi.cast(lltype.Signed, self.addrs) + WORD
-
-    def get_malloc_slowpath_addr(self):
-        return self.get_malloc_fn_addr('malloc_nursery')
-
-    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 teardown_method(self, method):
-        lltype.free(self.cpu.gc_ll_descr.addrs, flavor='raw')
-        lltype.free(self.cpu.gc_ll_descr.nursery, flavor='raw')
-
-    def getcpu(self, callback):
-        cpu = CPU(None, None)
-        cpu.gc_ll_descr = GCDescrFastpathMalloc(callback)
-        cpu.setup_once()
-        return cpu
-
-    def test_malloc_fastpath(self):
-        self.cpu = self.getcpu(None)
-        ops = '''
-        [i0]
-        p0 = call_malloc_nursery(16)
-        p1 = call_malloc_nursery(32)
-        p2 = call_malloc_nursery(16)
-        guard_true(i0) [p0, p1, p2]
-        '''
-        self.interpret(ops, [0])
-        # check the returned pointers
-        gc_ll_descr = self.cpu.gc_ll_descr
-        nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
-        ref = lambda n: self.cpu.get_ref_value(self.deadframe, n)
-        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_nursery_varsize_small(self):
-        self.cpu = self.getcpu(None)
-        ops = '''
-        [i0, i1, i2]
-        p0 = call_malloc_nursery_varsize_small(i0)
-        p1 = call_malloc_nursery_varsize_small(i1)
-        p2 = call_malloc_nursery_varsize_small(i2)
-        guard_true(i0) [p0, p1, p2]
-        ''' 
-        self.interpret(ops, [16, 32, 16])
-        # check the returned pointers
-        gc_ll_descr = self.cpu.gc_ll_descr
-        nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
-        ref = lambda n: self.cpu.get_ref_value(self.deadframe, n)
-        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):
-        def check(frame):
-            assert len(frame.jf_gcmap) == 1
-            if IS_X86_64:
-                assert frame.jf_gcmap[0] == (1<<29) | (1 << 30)
-            else:
-                assert frame.jf_gcmap[0] == (1<<24) | (1 << 23)
-        
-        self.cpu = self.getcpu(check)
-        ops = '''
-        [i0]
-        p0 = call_malloc_nursery(16)
-        p1 = call_malloc_nursery(32)
-        p2 = call_malloc_nursery(24)     # overflow
-        guard_true(i0) [p0, p1, p2]
-        '''
-        self.interpret(ops, [0])
-        # check the returned pointers
-        gc_ll_descr = self.cpu.gc_ll_descr
-        nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
-        ref = lambda n: self.cpu.get_ref_value(self.deadframe, n)
-        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
-        assert gc_ll_descr.calls == [24]
-
-    def test_save_regs_around_malloc(self):
-        def check(frame):
-            x = frame.jf_gcmap
-            if IS_X86_64:
-                assert len(x) == 1
-                assert (bin(x[0]).count('1') ==
-                        '0b1111100000000000000001111111011110'.count('1'))
-            else:
-                assert len(x) == 2
-                s = bin(x[0]).count('1') + bin(x[1]).count('1')
-                assert s == 16
-            # all but two registers + some stuff on stack
-        
-        self.cpu = self.getcpu(check)
-        S1 = lltype.GcStruct('S1')
-        S2 = lltype.GcStruct('S2', ('s0', lltype.Ptr(S1)),
-                                   ('s1', lltype.Ptr(S1)),
-                                   ('s2', lltype.Ptr(S1)),
-                                   ('s3', lltype.Ptr(S1)),
-                                   ('s4', lltype.Ptr(S1)),
-                                   ('s5', lltype.Ptr(S1)),
-                                   ('s6', lltype.Ptr(S1)),
-                                   ('s7', lltype.Ptr(S1)),
-                                   ('s8', lltype.Ptr(S1)),
-                                   ('s9', lltype.Ptr(S1)),
-                                   ('s10', lltype.Ptr(S1)),
-                                   ('s11', lltype.Ptr(S1)),
-                                   ('s12', lltype.Ptr(S1)),
-                                   ('s13', lltype.Ptr(S1)),
-                                   ('s14', lltype.Ptr(S1)),
-                                   ('s15', lltype.Ptr(S1)))
-        cpu = self.cpu
-        self.namespace = self.namespace.copy()
-        for i in range(16):
-            self.namespace['ds%i' % i] = cpu.fielddescrof(S2, 's%d' % i)
-        ops = '''
-        [i0, p0]
-        p1 = getfield_gc(p0, descr=ds0)
-        p2 = getfield_gc(p0, descr=ds1)
-        p3 = getfield_gc(p0, descr=ds2)
-        p4 = getfield_gc(p0, descr=ds3)
-        p5 = getfield_gc(p0, descr=ds4)
-        p6 = getfield_gc(p0, descr=ds5)
-        p7 = getfield_gc(p0, descr=ds6)
-        p8 = getfield_gc(p0, descr=ds7)
-        p9 = getfield_gc(p0, descr=ds8)
-        p10 = getfield_gc(p0, descr=ds9)
-        p11 = getfield_gc(p0, descr=ds10)
-        p12 = getfield_gc(p0, descr=ds11)
-        p13 = getfield_gc(p0, descr=ds12)
-        p14 = getfield_gc(p0, descr=ds13)
-        p15 = getfield_gc(p0, descr=ds14)
-        p16 = getfield_gc(p0, descr=ds15)
-        #
-        # now all registers are in use
-        p17 = call_malloc_nursery(40)
-        p18 = call_malloc_nursery(40)     # overflow
-        #
-        guard_true(i0) [p1, p2, p3, p4, p5, p6, \
-            p7, p8, p9, p10, p11, p12, p13, p14, p15, p16]
-        '''
-        s2 = lltype.malloc(S2)
-        for i in range(16):
-            setattr(s2, 's%d' % i, lltype.malloc(S1))
-        s2ref = lltype.cast_opaque_ptr(llmemory.GCREF, s2)
-        #
-        self.interpret(ops, [0, s2ref])
-        gc_ll_descr = cpu.gc_ll_descr
-        gc_ll_descr.check_nothing_in_nursery()
-        assert gc_ll_descr.calls == [40]
-        # check the returned pointers
-        for i in range(16):
-            s1ref = self.cpu.get_ref_value(self.deadframe, i)
-            s1 = lltype.cast_opaque_ptr(lltype.Ptr(S1), s1ref)
-            assert s1 == getattr(s2, 's%d' % i)
-
-class MockShadowStackRootMap(object):
-    is_shadow_stack = True
-    
-    def __init__(self):