[pypy-commit] pypy guard-compatible: in-progress
arigo
pypy.commits at gmail.com
Sun May 22 07:42:25 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: guard-compatible
Changeset: r84570:69e54b3e516d
Date: 2016-05-22 13:42 +0200
http://bitbucket.org/pypy/pypy/changeset/69e54b3e516d/
Log: in-progress
diff --git a/rpython/jit/backend/x86/guard_compat.py b/rpython/jit/backend/x86/guard_compat.py
--- a/rpython/jit/backend/x86/guard_compat.py
+++ b/rpython/jit/backend/x86/guard_compat.py
@@ -1,14 +1,13 @@
from rpython.rlib import rgc
-from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.objectmodel import specialize
from rpython.rlib.rarithmetic import r_uint
-from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.jit.backend.x86.arch import WORD, IS_X86_32, IS_X86_64
-from rpython.jit.backend.x86 import rx86, codebuf, valgrind
-from rpython.jit.backend.x86.regloc import X86_64_SCRATCH_REG, imm, eax, edx
-from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
-from rpython.jit.backend.llsupport.jitframe import GCMAP
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
+from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rtyper.annlowlevel import cast_instance_to_gcref
+from rpython.rtyper.annlowlevel import cast_gcref_to_instance
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+from rpython.jit.backend.llsupport import jitframe
from rpython.jit.metainterp.compile import GuardCompatibleDescr
-from rpython.jit.metainterp.history import BasicFailDescr
#
@@ -154,17 +153,75 @@
# ____________________________________________________________
-PAIR = lltype.Struct('PAIR', ('gcref', llmemory.GCREF,
- 'asmaddr', lltype.Signed))
+PAIR = lltype.Struct('PAIR', ('gcref', llmemory.GCREF),
+ ('asmaddr', lltype.Signed))
BACKEND_CHOICES = lltype.GcStruct('BACKEND_CHOICES',
('bc_gcmap', lltype.Ptr(jitframe.GCMAP)),
('bc_faildescr', llmemory.GCREF),
('bc_most_recent', PAIR),
('bc_list', lltype.Array(PAIR)))
+ at specialize.memo()
+def getofs(name):
+ return llmemory.offsetof(BACKEND_CHOICES, name)
+BCLISTLENGTHOFS = llmemory.arraylengthoffset(BACKEND_CHOICES.bc_list)
+BCLISTITEMSOFS = llmemory.itemoffsetof(BACKEND_CHOICES.bc_list, 0)
+PAIRSIZE = llmemory.sizeof(PAIR)
+
+def _real_number(ofs): # hack
+ return rffi.cast(lltype.Signed, rffi.cast(lltype.Unsigned, ofs))
+
+def bchoices_pair(gc, pair_addr, callback, arg):
+ gcref_addr = pair_addr + llmemory.offsetof(PAIR, 'gcref')
+ old = gcref_addr.unsigned[0]
+ if old != r_uint(-1):
+ gc._trace_callback(callback, arg, gcref_addr)
+ new = gcref_addr.unsigned[0]
+ return old != new
+
+def bchoices_trace(gc, obj_addr, callback, arg):
+ gc._trace_callback(callback, arg, obj_addr + getofs('bc_faildescr'))
+ bchoices_pair(gc, obj_addr + getofs('bc_most_recent'), callback, arg)
+ length = (obj_addr + getofs('bc_list') + BCLISTLENGTHOFS).signed[0]
+ array_addr = obj_addr + getofs('bc_list') + BCLISTITEMSOFS
+ item_addr = array_addr
+ i = 0
+ changes = False
+ while i < length:
+ changes |= bchoices_pair(gc, item_addr, callback, arg)
+ item_addr += PAIRSIZE
+ if changes:
+ pairs_quicksort(array_addr, length)
+lambda_bchoices_trace = lambda: bchoices_trace
+
+eci = ExternalCompilationInfo(separate_module_sources=["""
+
+static int _pairs_compare(const void *p1, const void *p2)
+{
+ if (*(Unsigned *const *)p1 < *(Unsigned *const *)p2)
+ return -1;
+ else if (*(Unsigned *const *)p1 == *(Unsigned *const *)p2)
+ return 0;
+ else
+ return 1;
+}
+RPY_EXTERN
+void pypy_pairs_quicksort(void *base_addr, Signed length)
+{
+ qsort(base_addr, length, 2 * sizeof(void *), _pairs_compare);
+}
+"""])
+pairs_quicksort = rffi.llexternal('pypy_pairs_quicksort',
+ [llmemory.Address, lltype.Signed],
+ lltype.Void,
+ sandboxsafe=True,
+ _nowrapper=True,
+ compilation_info=eci)
+
def invoke_find_compatible(bchoices, new_gcref):
descr = bchoices.bc_faildescr
+ descr = cast_gcref_to_instance(GuardCompatibleDescr, descr)
try:
result = descr.find_compatible(cpu, new_gcref)
if result == 0:
@@ -181,10 +238,17 @@
return descr._backend_failure_recovery
def add_in_tree(bchoices, new_gcref, new_asmaddr):
+ rgc.register_custom_trace_hook(BACKEND_CHOICES, lambda_bchoices_trace)
length = len(bchoices.bc_list)
- if bchoices.bc_list[length - 1] != -1:
+ #
+ gcref_base = lltype.cast_opaque_ptr(llmemory.GCREF, bchoices)
+ ofs = getofs('bc_list') + BCLISTITEMSOFS
+ ofs += (length - 1) * llmemory.sizeof(PAIR)
+ ofs = _real_number(ofs)
+ if llop.raw_load(lltype.Unsigned, gcref_base, ofs) != r_uint(-1):
# reallocate
- new_bchoices = lltype.malloc(BACKEND_CHOICES, length * 2 + 1)
+ new_bchoices = lltype.malloc(BACKEND_CHOICES, length * 2 + 1, zero=True)
+ # --- no GC below: it would mess up the order of bc_list ---
new_bchoices.bc_gcmap = bchoices.bc_gcmap
new_bchoices.bc_faildescr = bchoices.bc_faildescr
new_bchoices.bc_most_recent.gcref = bchoices.bc_most_recent.gcref
@@ -195,20 +259,56 @@
new_bchoices.bc_list[i].asmaddr = bchoices.bc_list[i].asmaddr
i += 1
# fill the new pairs with the invalid gcref value -1
- length *= 2
- gcref_base = lltype.cast_opaque_ptr(llmemory.GCREF, new_bchoices)
+ length = len(new_bchoices.bc_list)
ofs = (llmemory.offsetof(BACKEND_CHOICES, 'bc_list') +
- llmemory.itemoffsetof(BACKEND_CHOICES.bc_list))
+ llmemory.itemoffsetof(BACKEND_CHOICES.bc_list) +
+ i * llmemory.sizeof(PAIR))
while i < length:
- llop.raw_store(lltype.Void, gcref_base, ofs, r_uint(-1))
+ invalidate_pair(new_bchoices, ofs)
ofs += llmemory.sizeof(PAIR)
i += 1
+ bchoices = new_bchoices
#
bchoices.bc_list[length - 1].gcref = new_gcref
- bchoices.bc_list[length - 1].asmaddr = new_addr
- quicksort(bchoices)
+ bchoices.bc_list[length - 1].asmaddr = new_asmaddr
+ # --- no GC above ---
+ addr = llmemory.cast_ptr_to_adr(bchoices)
+ addr += getofs('bc_list') + BCLISTITEMSOFS
+ pairs_quicksort(addr, length)
return bchoices
+def initial_bchoices(guard_compat_descr, initial_gcref, gcmap):
+ bchoices = lltype.malloc(BACKEND_CHOICES, 1)
+ bchoices.bc_gcmap = gcmap
+ bchoices.bc_faildescr = cast_instance_to_gcref(guard_compat_descr)
+ bchoices.bc_most_recent.gcref = initial_gcref
+ # bchoices.bc_most_recent.asmaddr: later
+ bchoices.bc_list[0].gcref = initial_gcref
+ # bchoices.bc_list[0].asmaddr: later
+ return bchoices
+
+def finish_guard_compatible_descr(guard_compat_descr,
+ choices_addr, # points to bchoices in the GC table
+ sequel_label, # "sequel:" label above
+ failure_recovery): # failure recovery address
+ guard_compat_descr._backend_choices_addr = choices_addr
+ guard_compat_descr._backend_sequel_label = sequel_label
+ guard_compat_descr._backend_failure_recovery = failure_recovery
+ bchoices = rffi.cast(lltype.Ptr(BACKEND_CHOICES), choices_addr[0])
+ assert len(bchoices.bc_list) == 1
+ assert bchoices.bc_faildescr == cast_instance_to_gcref(guard_compat_descr)
+ bchoices.bc_most_recent.asmaddr = sequel_label
+ bchoices.bc_list[0].asmaddr = sequel_label
+
+def invalidate_pair(bchoices, pair_ofs):
+ gcref_base = lltype.cast_opaque_ptr(llmemory.GCREF, bchoices)
+ llop.raw_store(lltype.Void, gcref_base, _real_number(pair_ofs), r_uint(-1))
+ llop.raw_store(lltype.Void, gcref_base, _real_number(pair_ofs), r_uint(-1))
+
+def invalidate_cache(bchoices):
+ """Write -1 inside bchoices.bc_most_recent.gcref."""
+ ofs = llmemory.offsetof(BACKEND_CHOICES, 'bc_most_recent')
+ invalidate_pair(bchoices, ofs)
diff --git a/rpython/jit/backend/x86/test/test_guard_compat.py b/rpython/jit/backend/x86/test/test_guard_compat.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/x86/test/test_guard_compat.py
@@ -0,0 +1,64 @@
+from rpython.jit.backend.x86.guard_compat import *
+
+
+def test_invalidate_cache():
+ b = lltype.malloc(BACKEND_CHOICES, 4)
+ invalidate_cache(b)
+ x = b.bc_most_recent.gcref
+ assert rffi.cast(lltype.Unsigned, x) == r_uint(-1)
+
+def check_bclist(bchoices, expected):
+ assert len(bchoices.bc_list) == len(expected)
+ for i in range(len(bchoices.bc_list)):
+ pair = bchoices.bc_list[i]
+ if lltype.typeOf(expected[i][0]) == llmemory.GCREF:
+ assert pair.gcref == expected[i][0]
+ else:
+ assert rffi.cast(lltype.Signed, pair.gcref) == expected[i][0]
+ assert pair.asmaddr == expected[i][1]
+
+def test_add_in_tree():
+ b = lltype.malloc(BACKEND_CHOICES, 3, zero=True) # 3 * null
+ check_bclist(b, [
+ (0, 0), # null
+ (0, 0), # null
+ (0, 0), # null
+ ])
+ new_gcref = rffi.cast(llmemory.GCREF, 717344)
+ new_asmaddr = 1234567
+ b2 = add_in_tree(b, new_gcref, new_asmaddr)
+ check_bclist(b2, [
+ (0, 0), # null
+ (0, 0), # null
+ (0, 0), # null
+ (new_gcref, new_asmaddr),
+ (-1, 0), # invalid
+ (-1, 0), # invalid
+ (-1, 0), # invalid
+ ])
+ new_gcref_2 = rffi.cast(llmemory.GCREF, 717000) # lower than before
+ new_asmaddr_2 = 2345678
+ b3 = add_in_tree(b2, new_gcref_2, new_asmaddr_2)
+ assert b3 == b2 # was still large enough
+ check_bclist(b2, [
+ (0, 0), # null
+ (0, 0), # null
+ (0, 0), # null
+ (new_gcref_2, new_asmaddr_2),
+ (new_gcref, new_asmaddr),
+ (-1, 0), # invalid
+ (-1, 0), # invalid
+ ])
+ new_gcref_3 = rffi.cast(llmemory.GCREF, 717984) # higher than before
+ new_asmaddr_3 = 3456789
+ b4 = add_in_tree(b3, new_gcref_3, new_asmaddr_3)
+ assert b4 == b2 # was still large enough
+ check_bclist(b2, [
+ (0, 0), # null
+ (0, 0), # null
+ (0, 0), # null
+ (new_gcref_2, new_asmaddr_2),
+ (new_gcref, new_asmaddr),
+ (new_gcref_3, new_asmaddr_3),
+ (-1, 0), # invalid
+ ])
diff --git a/rpython/jit/backend/x86/test/test_runner.py b/rpython/jit/backend/x86/test/test_runner.py
--- a/rpython/jit/backend/x86/test/test_runner.py
+++ b/rpython/jit/backend/x86/test/test_runner.py
@@ -13,7 +13,6 @@
from rpython.jit.backend.test.runner_test import LLtypeBackendTest
from rpython.jit.tool.oparser import parse
import ctypes
-from hypothesis import strategies, given
CPU = getcpuclass()
@@ -557,52 +556,6 @@
assert self.cpu.get_int_value(deadframe, 2) == 42
assert self.cpu.get_int_value(deadframe, 3) == 42
- @given(strategies.integers(min_value=0, max_value=2),
- strategies.integers(min_value=0, max_value=15),
- strategies.lists(strategies.integers()))
- def test_guard_compatible_extra(self, grow_position, update_asm, lst):
- from rpython.jit.backend.x86 import guard_compat
- saved = guard_compat.GROW_POSITION, guard_compat.UPDATE_ASM
- try:
- guard_compat.GROW_POSITION = grow_position
- guard_compat.UPDATE_ASM = update_asm
-
- t1_box, T1_box, d1 = self.alloc_instance(self.T)
- faildescr1 = BasicFailDescr(1)
- loop = parse("""
- [p0]
- guard_compatible(p0, ConstPtr(t1), descr=faildescr1) []
- finish(p0, descr=fdescr)
- """, namespace={'fdescr': BasicFinalDescr(2),
- 'faildescr1': faildescr1,
- 't1': t1_box._resref})
- looptoken = JitCellToken()
- self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
-
- def run(box):
- deadframe = self.cpu.execute_token(looptoken,
- box._resref)
- fail = self.cpu.get_latest_descr(deadframe)
- return fail.identifier
-
- choices = {0: t1_box}
-
- for operation in lst:
- if operation >= 0 or (-operation) in choices:
- if operation in choices:
- assert run(choices[operation]) == 2
- else:
- t2_box, T2_box, d2 = self.alloc_instance(self.T)
- assert run(t2_box) == 1
- else:
- t2_box, T2_box, d2 = self.alloc_instance(self.T)
- self.cpu.grow_guard_compatible_switch(
- looptoken.compiled_loop_token,
- faildescr1, t2_box._resref)
- choices[-operation] = t2_box
- finally:
- guard_compat.GROW_POSITION, guard_compat.UPDATE_ASM = saved
-
class TestDebuggingAssembler(object):
def setup_method(self, meth):
More information about the pypy-commit
mailing list