[pypy-commit] pypy jitframe-on-heap: merge
fijal
noreply at buildbot.pypy.org
Fri Feb 15 15:00:37 CET 2013
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: jitframe-on-heap
Changeset: r61264:22ade1f1b39c
Date: 2013-02-15 15:59 +0200
http://bitbucket.org/pypy/pypy/changeset/22ade1f1b39c/
Log: merge
diff too long, truncating to 2000 out of 2918 lines
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
@@ -602,7 +602,7 @@
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)
@@ -815,7 +815,7 @@
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):
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
@@ -306,7 +306,7 @@
# 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
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
@@ -34,9 +34,9 @@
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
@@ -725,7 +725,7 @@
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)
@@ -1082,7 +1082,7 @@
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)
diff --git a/rpython/jit/backend/arm/test/test_regalloc.py b/rpython/jit/backend/arm/test/test_regalloc.py
--- a/rpython/jit/backend/arm/test/test_regalloc.py
+++ b/rpython/jit/backend/arm/test/test_regalloc.py
@@ -121,8 +121,8 @@
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
diff --git a/rpython/jit/backend/llsupport/test/test_gc_integration.py b/rpython/jit/backend/llsupport/test/test_gc_integration.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/llsupport/test/test_gc_integration.py
@@ -0,0 +1,647 @@
+
+""" 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']
diff --git a/rpython/jit/backend/llsupport/test/test_regalloc_integration.py b/rpython/jit/backend/llsupport/test/test_regalloc_integration.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/llsupport/test/test_regalloc_integration.py
@@ -0,0 +1,685 @@
+
+""" 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
+
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -474,7 +474,7 @@
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
'''
@@ -516,7 +516,7 @@
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,
@@ -734,7 +734,7 @@
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):
@@ -2411,7 +2411,7 @@
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)
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -1177,7 +1177,7 @@
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)
@@ -1289,7 +1289,7 @@
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)
@@ -1355,6 +1355,6 @@
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
diff --git a/rpython/jit/backend/x86/runner.py b/rpython/jit/backend/x86/runner.py
--- a/rpython/jit/backend/x86/runner.py
+++ b/rpython/jit/backend/x86/runner.py
@@ -57,6 +57,12 @@
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()
diff --git a/rpython/jit/backend/x86/test/test_gc_integration.py b/rpython/jit/backend/x86/test/test_gc_integration.py
deleted file mode 100644
--- a/rpython/jit/backend/x86/test/test_gc_integration.py
+++ /dev/null
@@ -1,647 +0,0 @@
-
-""" 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):
- 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):
More information about the pypy-commit
mailing list