Author: Remi Meier <[email protected]>
Branch: stmgc-c4
Changeset: r66017:406b5e69c06e
Date: 2013-08-08 16:14 +0200
http://bitbucket.org/pypy/pypy/changeset/406b5e69c06e/
Log: first test for stm_read_barrier fastpath
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
@@ -845,7 +845,8 @@
rst = self._get_root_stack_top_addr()
if rx86.fits_in_32bits(rst):
- if gcrootmap.is_stm:
+ if gcrootmap.is_stm and we_are_translated():
+ # during testing, it will be an absolute address
stmtlocal.tl_segment_prefix(mc)
mc.MOV_rj(ebx.value, rst) # MOV ebx, [rootstacktop]
else:
@@ -861,7 +862,8 @@
self.mc.ADD_ri(ebx.value, WORD)
if rx86.fits_in_32bits(rst):
- if gcrootmap.is_stm:
+ if gcrootmap.is_stm and we_are_translated():
+ # during testing, it will be an absolute address
stmtlocal.tl_segment_prefix(self.mc)
self.mc.MOV_jr(rst, ebx.value) # MOV [rootstacktop], ebx
else:
@@ -875,7 +877,8 @@
rst = self._get_root_stack_top_addr()
if rx86.fits_in_32bits(rst):
- if gcrootmap.is_stm:
+ if gcrootmap.is_stm and we_are_translated():
+ # during testing, it will be an absolute address
stmtlocal.tl_segment_prefix(self.mc)
self.mc.SUB_ji8(rst, WORD) # SUB [rootstacktop], WORD
else:
@@ -1192,7 +1195,8 @@
gcrootmap = self.cpu.gc_ll_descr.gcrootmap
rst = gcrootmap.get_root_stack_top_addr()
- if gcrootmap.is_stm:
+ if gcrootmap.is_stm and we_are_translated():
+ # during testing, we return an absolute address
rst = rst - stmtlocal.threadlocal_base()
assert rx86.fits_in_32bits(rst)
return rst
@@ -1203,7 +1207,8 @@
if gcrootmap and gcrootmap.is_shadow_stack:
rst = self._get_root_stack_top_addr()
- if gcrootmap.is_stm:
+ if gcrootmap.is_stm and we_are_translated():
+ # during testing, it will be an absolute address
stmtlocal.tl_segment_prefix(mc)
mc.MOV(ecx, heap(rst))
mc.MOV(ebp, mem(ecx, -WORD))
@@ -2267,16 +2272,17 @@
# OK: flags already set
if j_ok1:
offset = mc.get_relative_pos() - j_ok1
+ assert 0 <= offset <= 127
mc.overwrite(j_ok1 - 1, chr(offset))
if j_ok2:
offset = mc.get_relative_pos() - j_ok2
+ assert 0 <= offset <= 127
mc.overwrite(j_ok2 - 1, chr(offset))
if j_ok3:
offset = mc.get_relative_pos() - j_ok3
+ assert 0 <= offset <= 127
mc.overwrite(j_ok3 - 1, chr(offset))
-
-
def _get_stm_private_rev_num_addr(self):
assert self.cpu.gc_ll_descr.stm
rn = rstm.get_adr_of_private_rev_num()
@@ -2294,9 +2300,9 @@
def _stm_barrier_fastpath(self, mc, descr, arglocs, is_frame=False,
align_stack=False):
assert self.cpu.gc_ll_descr.stm
- from rpython.jit.backend.llsupport.gc import (
- STMBarrierDescr, STMReadBarrierDescr, STMWriteBarrierDescr)
- assert isinstance(descr, STMBarrierDescr)
+ #from rpython.jit.backend.llsupport.gc import (
+ # STMBarrierDescr, STMReadBarrierDescr, STMWriteBarrierDescr)
+ #assert isinstance(descr, STMBarrierDescr)
assert descr.returns_modified_object
loc_base = arglocs[0]
assert isinstance(loc_base, RegLoc)
@@ -2321,14 +2327,20 @@
jnz_location = 0
# compare h_revision with stm_private_rev_num (XXX: may be slow)
rn = self._get_stm_private_rev_num_addr()
- stmtlocal.tl_segment_prefix(mc)
- mc.MOV_rj(X86_64_SCRATCH_REG.value, rn)
+ if we_are_translated():
+ # during tests, _get_stm_private_rev_num_addr returns
+ # an absolute address, not a tl-offset
+ stmtlocal.tl_segment_prefix(mc)
+ mc.MOV_rj(X86_64_SCRATCH_REG.value, rn)
+ else: # testing:
+ mc.MOV(X86_64_SCRATCH_REG, heap(rn))
+
if loc_base == ebp:
mc.CMP_rb(X86_64_SCRATCH_REG.value, StmGC.H_REVISION)
else:
mc.CMP(X86_64_SCRATCH_REG, mem(loc_base, StmGC.H_REVISION))
#
- if isinstance(descr, STMReadBarrierDescr):
+ if descr.stmcat == 'P2R':#isinstance(descr, STMReadBarrierDescr):
# jump to end if h_rev==priv_rev
mc.J_il8(rx86.Conditions['Z'], 0) # patched below
jz_location = mc.get_relative_pos()
@@ -2338,21 +2350,29 @@
jnz_location = mc.get_relative_pos()
# FXCACHE_AT(obj) != obj
- if isinstance(descr, STMReadBarrierDescr):
+ if descr.stmcat == 'P2R':#isinstance(descr, STMReadBarrierDescr):
# calculate: temp = obj & FX_MASK
assert StmGC.FX_MASK == 65535
assert not is_frame
mc.MOVZX16(X86_64_SCRATCH_REG, loc_base)
# calculate: rbc + temp == obj
rbc = self._get_stm_read_barrier_cache_addr()
- stmtlocal.tl_segment_prefix(mc)
- mc.ADD_rj(X86_64_SCRATCH_REG.value, rbc)
+ if we_are_translated():
+ # during tests, _get_stm_rbca returns
+ # an absolute address, not a tl-offset
+ stmtlocal.tl_segment_prefix(mc)
+ mc.ADD_rj(X86_64_SCRATCH_REG.value, rbc)
+ else: # testing:
+ mc.PUSH_r(eax.value)
+ mc.MOV(eax, heap(rbc))
+ mc.ADD(X86_64_SCRATCH_REG, eax)
+ mc.POP_r(eax.value)
mc.CMP_rm(loc_base.value, (X86_64_SCRATCH_REG.value, 0))
mc.J_il8(rx86.Conditions['Z'], 0) # patched below
jz_location2 = mc.get_relative_pos()
# obj->h_tid & GCFLAG_WRITE_BARRIER) != 0
- if isinstance(descr, STMWriteBarrierDescr):
+ if descr.stmcat == 'P2W':#isinstance(descr, STMWriteBarrierDescr):
assert IS_X86_64 and (StmGC.GCFLAG_WRITE_BARRIER >> 32) > 0
assert (StmGC.GCFLAG_WRITE_BARRIER >> 40) == 0
off = 4
@@ -2398,7 +2418,7 @@
offset = mc.get_relative_pos() - jz_location
assert 0 < offset <= 127
mc.overwrite(jz_location - 1, chr(offset))
- if isinstance(descr, STMReadBarrierDescr):
+ if descr.stmcat == 'P2R':#isinstance(descr, STMReadBarrierDescr):
offset = mc.get_relative_pos() - jz_location2
assert 0 < offset <= 127
mc.overwrite(jz_location2 - 1, chr(offset))
diff --git a/rpython/jit/backend/x86/test/test_stm_integration.py
b/rpython/jit/backend/x86/test/test_stm_integration.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/x86/test/test_stm_integration.py
@@ -0,0 +1,209 @@
+import py
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr
+from rpython.jit.metainterp.history import ResOperation, TargetToken,\
+ JitCellToken
+from rpython.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt,
+ ConstPtr, Box,
+ BasicFailDescr, BasicFinalDescr)
+from rpython.jit.backend.detect_cpu import getcpuclass
+from rpython.jit.backend.x86.arch import WORD
+from rpython.jit.backend.x86.rx86 import fits_in_32bits
+from rpython.jit.backend.llsupport import symbolic
+from rpython.jit.metainterp.resoperation import rop
+from rpython.jit.metainterp.executor import execute
+from rpython.jit.backend.test.runner_test import LLtypeBackendTest
+from rpython.jit.tool.oparser import parse
+from rpython.rtyper.annlowlevel import llhelper, llhelper_args
+from rpython.jit.backend.llsupport.gc import (
+ GcRootMap_stm, BarrierDescr)
+from rpython.jit.backend.llsupport.test.test_gc_integration import (
+ GCDescrShadowstackDirect, BaseTestRegalloc)
+from rpython.jit.backend.llsupport import jitframe
+import ctypes
+
+CPU = getcpuclass()
+
+class MockSTMRootMap(object):
+ is_shadow_stack = True
+ is_stm = 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 FakeSTMBarrier(BarrierDescr):
+ def __init__(self, gc_ll_descr, stmcat, func):
+ BarrierDescr.__init__(self, gc_ll_descr)
+ self.stmcat = stmcat
+ self.returns_modified_object = True
+ self.B_FUNCPTR_MOD = lltype.Ptr(lltype.FuncType(
+ [llmemory.Address], llmemory.Address))
+ self.write_barrier_fn = llhelper(self.B_FUNCPTR_MOD, func)
+ def get_barrier_funcptr(self, returns_modified_object):
+ assert returns_modified_object
+ return self.write_barrier_fn
+ def get_barrier_fn(self, cpu, returns_modified_object):
+ assert returns_modified_object
+ return self.write_barrier_fn
+
+# ____________________________________________________________
+
+
+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',
+ ('h_tid', lltype.Signed),
+ ('h_revision', lltype.Signed),
+ ('h_original', lltype.Signed),
+ ('jf_frame_info', lltype.Ptr(jitframe.JITFRAMEINFO)),
+ ('jf_descr', llmemory.GCREF),
+ ('jf_force_descr', llmemory.GCREF),
+ ('jf_extra_stack_depth', lltype.Signed),
+ ('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 FakeGCHeaderBuilder:
+ size_gc_header = WORD
+
+
+class GCDescrStm(GCDescrShadowstackDirect):
+ def __init__(self):
+ GCDescrShadowstackDirect.__init__(self)
+ self.gcrootmap = MockSTMRootMap()
+ self.gcheaderbuilder = FakeGCHeaderBuilder()
+ self.write_barrier_descr = None
+ self.llop1 = None
+ self.rb_called_on = []
+ self.wb_called_on = []
+ self.stm = True
+
+ def read_barrier(obj):
+ self.rb_called_on.append(obj)
+ return obj
+ def write_barrier(obj):
+ self.wb_called_on.append(obj)
+ return obj
+
+ self.P2Rdescr = FakeSTMBarrier(self, 'P2R', read_barrier)
+ self.P2Wdescr = FakeSTMBarrier(self, 'P2W', write_barrier)
+
+ self.do_write_barrier = None
+ self.get_nursery_top_addr = None
+ self.get_nursery_free_addr = None
+
+ def malloc_str(length):
+ assert False
+ self.generate_function('malloc_str', malloc_str,
+ [lltype.Signed])
+ def malloc_unicode(length):
+ assert False
+ self.generate_function('malloc_unicode', malloc_unicode,
+ [lltype.Signed])
+ def inevitable():
+ pass
+ self.generate_function('stm_try_inevitable',
+ inevitable, [],
+ RESULT=lltype.Void)
+ def ptr_eq(x, y): return x == y
+ def ptr_ne(x, y): return x != y
+ self.generate_function('stm_ptr_eq', ptr_eq, [llmemory.GCREF] * 2,
+ RESULT=lltype.Bool)
+ self.generate_function('stm_ptr_ne', ptr_ne, [llmemory.GCREF] * 2,
+ RESULT=lltype.Bool)
+
+ def get_malloc_slowpath_addr(self):
+ return None
+
+
+class TestGcStm(BaseTestRegalloc):
+ def get_priv_rev_num(self):
+ return rffi.cast(lltype.Signed, self.priv_rev_num)
+
+ def get_read_cache(self):
+ return rffi.cast(lltype.Signed, self.read_cache_adr)
+
+ def setup_method(self, meth):
+ cpu = CPU(None, None)
+ cpu.gc_ll_descr = GCDescrStm()
+ self.p2wd = cpu.gc_ll_descr.P2Wdescr
+ self.p2rd = cpu.gc_ll_descr.P2Rdescr
+
+ TP = rffi.CArray(lltype.Signed)
+ self.priv_rev_num = lltype.malloc(TP, 1, flavor='raw')
+ self.read_cache = lltype.malloc(TP, n=65536 / WORD, flavor='raw')
+ self.read_cache_adr = lltype.malloc(TP, 1, flavor='raw')
+ self.read_cache_adr[0] = rffi.cast(lltype.Signed, self.read_cache)
+
+ cpu.assembler._get_stm_private_rev_num_addr = self.get_priv_rev_num
+ cpu.assembler._get_stm_read_barrier_cache_addr = self.get_read_cache
+
+ S = lltype.GcForwardReference()
+ S.become(lltype.GcStruct(
+ 'S', ('h_tid', lltype.Signed),
+ ('h_revision', lltype.Signed),
+ ('h_original', lltype.Signed)))
+ cpu.gc_ll_descr.fielddescr_tid = None # not needed
+ # = cpu.fielddescrof(S, 'h_tid')
+ self.S = S
+ self.cpu = cpu
+
+ def teardown_method(self, meth):
+ rffi.aroundstate._cleanup_()
+
+ def assert_in_read_barrier(self, *args):
+ rb_called_on = self.cpu.gc_ll_descr.rb_called_on
+ for i, ref in enumerate(args):
+ assert rffi.cast_ptr_to_adr(ref) == rb_called_on[i]
+ def assert_not_in_read_barrier(self, *args):
+ rb_called_on = self.cpu.gc_ll_descr.rb_called_on
+ for ref in args:
+ assert not rffi.cast_ptr_to_adr(ref) in rb_called_on
+
+ def test_read_barrier_fastpath(self):
+ cpu = self.cpu
+ cpu.setup_once()
+ PRIV_REV = 3
+ self.priv_rev_num[0] = PRIV_REV
+ for rev in [PRIV_REV, PRIV_REV+1]:
+ s = lltype.malloc(self.S)
+ sgcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
+ s.h_tid = 0
+ s.h_revision = rev
+ p0 = BoxPtr()
+ operations = [
+ ResOperation(rop.COND_CALL_STM_B, [p0,], None,
+ descr=self.p2rd),
+ ResOperation(rop.FINISH, [p0], None, descr=BasicFinalDescr(0)),
+ ]
+ inputargs = [p0]
+ looptoken = JitCellToken()
+ cpu.compile_loop(inputargs, operations, looptoken)
+ self.cpu.execute_token(looptoken, sgcref)
+ if rev == PRIV_REV:
+ # fastpath
+ self.assert_not_in_read_barrier(sgcref)
+ else:
+ self.assert_in_read_barrier(sgcref)
+
+
+
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit