[pypy-commit] pypy guard-compatible: Move 3/4th of guard_compat to llsupport
arigo
pypy.commits at gmail.com
Tue May 24 02:51:32 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: guard-compatible
Changeset: r84654:389d769796e8
Date: 2016-05-24 08:52 +0200
http://bitbucket.org/pypy/pypy/changeset/389d769796e8/
Log: Move 3/4th of guard_compat to llsupport
diff --git a/rpython/jit/backend/llsupport/guard_compat.py b/rpython/jit/backend/llsupport/guard_compat.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/llsupport/guard_compat.py
@@ -0,0 +1,228 @@
+from rpython.rlib import rgc
+from rpython.rlib.objectmodel import specialize, we_are_translated
+from rpython.rlib.rarithmetic import r_uint
+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.metainterp.compile import GuardCompatibleDescr
+from rpython.jit.backend.llsupport import jitframe
+
+
+# See ../x86/guard_compat.py for an explanation of the idea, based on
+# x86-64 code. Here, we have the generic data structures and algos.
+
+
+PAIR = lltype.Struct('PAIR', ('gcref', lltype.Unsigned), # a GC ref or -1
+ ('asmaddr', lltype.Signed))
+BACKEND_CHOICES = lltype.GcStruct('BACKEND_CHOICES',
+ ('bc_faildescr', llmemory.GCREF),
+ ('bc_gc_table_tracer', llmemory.GCREF),
+ ('bc_most_recent', PAIR),
+ ('bc_list', lltype.Array(PAIR)))
+
+def _getofs(name):
+ return llmemory.offsetof(BACKEND_CHOICES, name)
+BCFAILDESCR = _getofs('bc_faildescr')
+BCMOSTRECENT = _getofs('bc_most_recent')
+BCLIST = _getofs('bc_list')
+del _getofs
+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))
+
+ at specialize.arg(2)
+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 + BCFAILDESCR)
+ bchoices_pair(gc, obj_addr + BCMOSTRECENT, callback, arg)
+ length = (obj_addr + BCLIST + BCLISTLENGTHOFS).signed[0]
+ array_addr = obj_addr + BCLIST + BCLISTITEMSOFS
+ item_addr = array_addr
+ i = 0
+ changes = False
+ while i < length:
+ changes |= bchoices_pair(gc, item_addr, callback, arg)
+ item_addr += PAIRSIZE
+ i += 1
+ if changes:
+ pairs_quicksort(array_addr, length)
+lambda_bchoices_trace = lambda: bchoices_trace
+
+eci = ExternalCompilationInfo(post_include_bits=["""
+RPY_EXTERN void pypy_pairs_quicksort(void *base_addr, Signed length);
+"""], separate_module_sources=["""
+#include <stdlib.h>
+
+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 gcref_to_unsigned(gcref):
+ return rffi.cast(lltype.Unsigned, gcref)
+
+
+INVOKE_FIND_COMPATIBLE_FUNC = lltype.Ptr(lltype.FuncType(
+ [lltype.Ptr(BACKEND_CHOICES), llmemory.GCREF,
+ lltype.Ptr(jitframe.JITFRAME)],
+ lltype.Signed))
+
+ at specialize.memo()
+def make_invoke_find_compatible(cpu):
+ def invoke_find_compatible(bchoices, new_gcref, jitframe):
+ descr = bchoices.bc_faildescr
+ descr = cast_gcref_to_instance(GuardCompatibleDescr, descr)
+ try:
+ jitframe.jf_gcmap = descr._backend_gcmap
+ result = descr.find_compatible(cpu, new_gcref)
+ if result == 0:
+ result = descr._backend_failure_recovery
+ else:
+ if result == -1:
+ result = descr._backend_sequel_label
+ bchoices = add_in_tree(bchoices, new_gcref, result)
+ # ---no GC operation---
+ choices_addr = descr._backend_choices_addr # GC table
+ bchoices_int = rffi.cast(lltype.Signed, bchoices)
+ llop.raw_store(lltype.Void, choices_addr, 0, bchoices_int)
+ llop.gc_writebarrier(lltype.Void, bchoices.bc_gc_table_tracer)
+ # ---no GC operation end---
+ bchoices.bc_most_recent.gcref = gcref_to_unsigned(new_gcref)
+ bchoices.bc_most_recent.asmaddr = result
+ llop.gc_writebarrier(lltype.Void, bchoices)
+ except: # oops!
+ if not we_are_translated():
+ import sys, pdb
+ pdb.post_mortem(sys.exc_info()[2])
+ result = descr._backend_failure_recovery
+ jitframe.jf_gcmap = lltype.nullptr(lltype.typeOf(jitframe.jf_gcmap).TO)
+ return result
+ return invoke_find_compatible
+
+def add_in_tree(bchoices, new_gcref, new_asmaddr):
+ rgc.register_custom_trace_hook(BACKEND_CHOICES, lambda_bchoices_trace)
+ length = len(bchoices.bc_list)
+ #
+ gcref_base = lltype.cast_opaque_ptr(llmemory.GCREF, bchoices)
+ ofs = BCLIST + 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)
+ # --- no GC below: it would mess up the order of bc_list ---
+ new_bchoices.bc_faildescr = bchoices.bc_faildescr
+ new_bchoices.bc_gc_table_tracer = bchoices.bc_gc_table_tracer
+ new_bchoices.bc_most_recent.gcref = bchoices.bc_most_recent.gcref
+ new_bchoices.bc_most_recent.asmaddr = bchoices.bc_most_recent.asmaddr
+ i = 0
+ while i < length:
+ new_bchoices.bc_list[i].gcref = bchoices.bc_list[i].gcref
+ new_bchoices.bc_list[i].asmaddr = bchoices.bc_list[i].asmaddr
+ i += 1
+ # fill the new pairs with the invalid gcref value -1
+ length = len(new_bchoices.bc_list)
+ ofs = (llmemory.offsetof(BACKEND_CHOICES, 'bc_list') +
+ llmemory.itemoffsetof(BACKEND_CHOICES.bc_list) +
+ i * llmemory.sizeof(PAIR))
+ while i < length:
+ invalidate_pair(new_bchoices, ofs)
+ ofs += llmemory.sizeof(PAIR)
+ i += 1
+ bchoices = new_bchoices
+ #
+ bchoices.bc_list[length - 1].gcref = gcref_to_unsigned(new_gcref)
+ bchoices.bc_list[length - 1].asmaddr = new_asmaddr
+ llop.gc_writebarrier(lltype.Void, bchoices)
+ # --- no GC above ---
+ addr = llmemory.cast_ptr_to_adr(bchoices)
+ addr += BCLIST + BCLISTITEMSOFS
+ pairs_quicksort(addr, length)
+ return bchoices
+
+def initial_bchoices(guard_compat_descr, initial_gcref):
+ bchoices = lltype.malloc(BACKEND_CHOICES, 1)
+ bchoices.bc_faildescr = cast_instance_to_gcref(guard_compat_descr)
+ bchoices.bc_gc_table_tracer = lltype.nullptr(llmemory.GCREF.TO) # (*)
+ bchoices.bc_most_recent.gcref = gcref_to_unsigned(initial_gcref)
+ bchoices.bc_most_recent.asmaddr = -43 # (*)
+ bchoices.bc_list[0].gcref = gcref_to_unsigned(initial_gcref)
+ bchoices.bc_list[0].asmaddr = -43 # (*)
+ llop.gc_writebarrier(lltype.Void, bchoices)
+ # entries with (*) are fixed in patch_guard_compatible()
+ return bchoices
+
+def descr_to_bchoices(descr):
+ assert isinstance(descr, GuardCompatibleDescr)
+ # ---no GC operation---
+ bchoices = llop.raw_load(lltype.Signed, descr._backend_choices_addr, 0)
+ bchoices = rffi.cast(lltype.Ptr(BACKEND_CHOICES), bchoices)
+ # ---no GC operation end---
+ return bchoices
+
+def patch_guard_compatible(guard_token, rawstart, get_addr_in_gc_table,
+ gc_table_tracer):
+ # go to the address in the gctable, number 'bindex'
+ bindex = guard_token.guard_compat_bindex
+ choices_addr = get_addr_in_gc_table(bindex)
+ sequel_label = rawstart + guard_token.pos_jump_offset
+ failure_recovery = rawstart + guard_token.pos_recovery_stub
+ gcmap = guard_token.gcmap
+ # choices_addr: points to bchoices in the GC table
+ # sequel_label: "sequel:" label above
+ # failure_recovery: failure recovery address
+ guard_compat_descr = guard_token.faildescr
+ assert isinstance(guard_compat_descr, GuardCompatibleDescr)
+ guard_compat_descr._backend_choices_addr = choices_addr
+ guard_compat_descr._backend_sequel_label = sequel_label
+ guard_compat_descr._backend_failure_recovery = failure_recovery
+ guard_compat_descr._backend_gcmap = gcmap
+ #
+ bchoices = descr_to_bchoices(guard_compat_descr)
+ assert len(bchoices.bc_list) == 1
+ assert (cast_gcref_to_instance(GuardCompatibleDescr, bchoices.bc_faildescr)
+ is guard_compat_descr)
+ bchoices.bc_gc_table_tracer = lltype.cast_opaque_ptr(llmemory.GCREF,
+ gc_table_tracer)
+ 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))
+ ofs = pair_ofs + llmemory.sizeof(lltype.Unsigned)
+ llop.raw_store(lltype.Void, gcref_base, _real_number(ofs), -1)
+
+def invalidate_cache(faildescr):
+ """Write -1 inside bchoices.bc_most_recent.gcref."""
+ bchoices = descr_to_bchoices(faildescr)
+ invalidate_pair(bchoices, BCMOSTRECENT)
diff --git a/rpython/jit/backend/llsupport/rewrite.py b/rpython/jit/backend/llsupport/rewrite.py
--- a/rpython/jit/backend/llsupport/rewrite.py
+++ b/rpython/jit/backend/llsupport/rewrite.py
@@ -990,7 +990,7 @@
return load_op
def handle_guard_compatible(self, op):
- from rpython.jit.backend.x86 import guard_compat # XXX
+ from rpython.jit.backend.llsupport import guard_compat
c = op.getarg(1)
assert isinstance(c, ConstPtr)
descr = op.getdescr()
diff --git a/rpython/jit/backend/llsupport/test/test_guard_compat.py b/rpython/jit/backend/llsupport/test/test_guard_compat.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/llsupport/test/test_guard_compat.py
@@ -0,0 +1,61 @@
+from rpython.jit.backend.llsupport.guard_compat import *
+
+
+def test_invalidate_cache():
+ b = lltype.malloc(BACKEND_CHOICES, 4)
+ invalidate_pair(b, BCMOSTRECENT)
+ x = b.bc_most_recent.gcref
+ assert 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]
+ assert pair.gcref == rffi.cast(lltype.Unsigned, 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, -1), # invalid
+ (-1, -1), # invalid
+ (-1, -1), # 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, -1), # invalid
+ (-1, -1), # 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, -1), # invalid
+ ])
diff --git a/rpython/jit/backend/llsupport/test/test_rewrite.py b/rpython/jit/backend/llsupport/test/test_rewrite.py
--- a/rpython/jit/backend/llsupport/test/test_rewrite.py
+++ b/rpython/jit/backend/llsupport/test/test_rewrite.py
@@ -1414,3 +1414,22 @@
jump()
""")
assert len(self.gcrefs) == 2
+
+ def test_guard_compatible(self):
+ from rpython.jit.backend.llsupport import guard_compat
+ self.check_rewrite("""
+ [p0]
+ guard_compatible(p0, ConstPtr(myR1)) []
+ guard_compatible(p0, ConstPtr(myR1)) []
+ jump()
+ """, """
+ [p0]
+ guard_compatible(p0, 0) []
+ guard_compatible(p0, 2) [] # no sharing the number
+ jump()
+ """)
+ assert len(self.gcrefs) == 4
+ for i in [0, 2]:
+ # type-checking
+ x = self.gcrefs[i]
+ lltype.cast_opaque_ptr(lltype.Ptr(guard_compat.BACKEND_CHOICES), x)
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
@@ -736,6 +736,10 @@
if WORD == 8 and len(self.pending_memoryerror_trampoline_from) > 0:
self.error_trampoline_64 = self.generate_propagate_error_64()
+ def _get_addr_in_gc_table(self, index):
+ # return the address of the slot in the gctable, number 'index'
+ return self.gc_table_addr + index * WORD
+
def patch_pending_failure_recoveries(self, rawstart):
# after we wrote the assembler to raw memory, set up
# tok.faildescr.adr_jump_offset to contain the raw address of
@@ -747,7 +751,7 @@
tok.faildescr.adr_jump_offset = addr
if tok.guard_compatible():
guard_compat.patch_guard_compatible(tok, rawstart,
- self.gc_table_addr,
+ self._get_addr_in_gc_table,
self.gc_table_tracer)
continue
descr = tok.faildescr
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,18 +1,12 @@
-from rpython.rlib import rgc
-from rpython.rlib.objectmodel import specialize, we_are_translated
-from rpython.rlib.rarithmetic import r_uint
-from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
-from rpython.rtyper.lltypesystem.lloperation import llop
-from rpython.rtyper.annlowlevel import cast_instance_to_gcref, llhelper
-from rpython.rtyper.annlowlevel import cast_gcref_to_instance
-from rpython.translator.tool.cbuild import ExternalCompilationInfo
-from rpython.jit.metainterp.compile import GuardCompatibleDescr
-from rpython.jit.backend.llsupport import jitframe
+from rpython.rtyper.annlowlevel import llhelper
from rpython.jit.backend.x86 import rx86, codebuf, regloc
from rpython.jit.backend.x86.regalloc import gpr_reg_mgr_cls
from rpython.jit.backend.x86.arch import WORD, IS_X86_64, IS_X86_32
from rpython.jit.backend.x86.arch import DEFAULT_FRAME_BYTES
+from rpython.jit.backend.llsupport.guard_compat import *
+from rpython.jit.backend.llsupport.guard_compat import _real_number
+
#
# GUARD_COMPATIBLE(reg, const-ptr) produces the following assembler.
@@ -171,218 +165,8 @@
# ____________________________________________________________
-PAIR = lltype.Struct('PAIR', ('gcref', lltype.Unsigned), # a GC ref or -1
- ('asmaddr', lltype.Signed))
-BACKEND_CHOICES = lltype.GcStruct('BACKEND_CHOICES',
- ('bc_faildescr', llmemory.GCREF),
- ('bc_gc_table_tracer', llmemory.GCREF),
- ('bc_most_recent', PAIR),
- ('bc_list', lltype.Array(PAIR)))
-
-def _getofs(name):
- return llmemory.offsetof(BACKEND_CHOICES, name)
-BCFAILDESCR = _getofs('bc_faildescr')
-BCMOSTRECENT = _getofs('bc_most_recent')
-BCLIST = _getofs('bc_list')
-del _getofs
-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))
-
- at specialize.arg(2)
-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 + BCFAILDESCR)
- bchoices_pair(gc, obj_addr + BCMOSTRECENT, callback, arg)
- length = (obj_addr + BCLIST + BCLISTLENGTHOFS).signed[0]
- array_addr = obj_addr + BCLIST + BCLISTITEMSOFS
- item_addr = array_addr
- i = 0
- changes = False
- while i < length:
- changes |= bchoices_pair(gc, item_addr, callback, arg)
- item_addr += PAIRSIZE
- i += 1
- if changes:
- pairs_quicksort(array_addr, length)
-lambda_bchoices_trace = lambda: bchoices_trace
-
-eci = ExternalCompilationInfo(post_include_bits=["""
-RPY_EXTERN void pypy_pairs_quicksort(void *base_addr, Signed length);
-"""], separate_module_sources=["""
-#include <stdlib.h>
-
-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 gcref_to_unsigned(gcref):
- return rffi.cast(lltype.Unsigned, gcref)
-
-
-INVOKE_FIND_COMPATIBLE_FUNC = lltype.Ptr(lltype.FuncType(
- [lltype.Ptr(BACKEND_CHOICES), llmemory.GCREF,
- lltype.Ptr(jitframe.JITFRAME)],
- lltype.Signed))
-
- at specialize.memo()
-def make_invoke_find_compatible(cpu):
- def invoke_find_compatible(bchoices, new_gcref, jitframe):
- descr = bchoices.bc_faildescr
- descr = cast_gcref_to_instance(GuardCompatibleDescr, descr)
- try:
- jitframe.jf_gcmap = descr._backend_gcmap
- result = descr.find_compatible(cpu, new_gcref)
- if result == 0:
- result = descr._backend_failure_recovery
- else:
- if result == -1:
- result = descr._backend_sequel_label
- bchoices = add_in_tree(bchoices, new_gcref, result)
- # ---no GC operation---
- choices_addr = descr._backend_choices_addr # GC table
- bchoices_int = rffi.cast(lltype.Signed, bchoices)
- llop.raw_store(lltype.Void, choices_addr, 0, bchoices_int)
- llop.gc_writebarrier(lltype.Void, bchoices.bc_gc_table_tracer)
- # ---no GC operation end---
- bchoices.bc_most_recent.gcref = gcref_to_unsigned(new_gcref)
- bchoices.bc_most_recent.asmaddr = result
- llop.gc_writebarrier(lltype.Void, bchoices)
- except: # oops!
- if not we_are_translated():
- import sys, pdb
- pdb.post_mortem(sys.exc_info()[2])
- result = descr._backend_failure_recovery
- jitframe.jf_gcmap = lltype.nullptr(lltype.typeOf(jitframe.jf_gcmap).TO)
- return result
- return invoke_find_compatible
-
-def add_in_tree(bchoices, new_gcref, new_asmaddr):
- rgc.register_custom_trace_hook(BACKEND_CHOICES, lambda_bchoices_trace)
- length = len(bchoices.bc_list)
- #
- gcref_base = lltype.cast_opaque_ptr(llmemory.GCREF, bchoices)
- ofs = BCLIST + 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)
- # --- no GC below: it would mess up the order of bc_list ---
- new_bchoices.bc_faildescr = bchoices.bc_faildescr
- new_bchoices.bc_gc_table_tracer = bchoices.bc_gc_table_tracer
- new_bchoices.bc_most_recent.gcref = bchoices.bc_most_recent.gcref
- new_bchoices.bc_most_recent.asmaddr = bchoices.bc_most_recent.asmaddr
- i = 0
- while i < length:
- new_bchoices.bc_list[i].gcref = bchoices.bc_list[i].gcref
- new_bchoices.bc_list[i].asmaddr = bchoices.bc_list[i].asmaddr
- i += 1
- # fill the new pairs with the invalid gcref value -1
- length = len(new_bchoices.bc_list)
- ofs = (llmemory.offsetof(BACKEND_CHOICES, 'bc_list') +
- llmemory.itemoffsetof(BACKEND_CHOICES.bc_list) +
- i * llmemory.sizeof(PAIR))
- while i < length:
- invalidate_pair(new_bchoices, ofs)
- ofs += llmemory.sizeof(PAIR)
- i += 1
- bchoices = new_bchoices
- #
- bchoices.bc_list[length - 1].gcref = gcref_to_unsigned(new_gcref)
- bchoices.bc_list[length - 1].asmaddr = new_asmaddr
- llop.gc_writebarrier(lltype.Void, bchoices)
- # --- no GC above ---
- addr = llmemory.cast_ptr_to_adr(bchoices)
- addr += BCLIST + BCLISTITEMSOFS
- pairs_quicksort(addr, length)
- return bchoices
-
-def initial_bchoices(guard_compat_descr, initial_gcref):
- bchoices = lltype.malloc(BACKEND_CHOICES, 1)
- bchoices.bc_faildescr = cast_instance_to_gcref(guard_compat_descr)
- bchoices.bc_gc_table_tracer = lltype.nullptr(llmemory.GCREF.TO) # (*)
- bchoices.bc_most_recent.gcref = gcref_to_unsigned(initial_gcref)
- bchoices.bc_most_recent.asmaddr = -43 # (*)
- bchoices.bc_list[0].gcref = gcref_to_unsigned(initial_gcref)
- bchoices.bc_list[0].asmaddr = -43 # (*)
- llop.gc_writebarrier(lltype.Void, bchoices)
- # entries with (*) are fixed in patch_guard_compatible()
- return bchoices
-
-def descr_to_bchoices(descr):
- assert isinstance(descr, GuardCompatibleDescr)
- # ---no GC operation---
- bchoices = llop.raw_load(lltype.Signed, descr._backend_choices_addr, 0)
- bchoices = rffi.cast(lltype.Ptr(BACKEND_CHOICES), bchoices)
- # ---no GC operation end---
- return bchoices
-
-def patch_guard_compatible(guard_token, rawstart, gc_table_addr,
- gc_table_tracer):
- # go to the address in the gctable, number 'bindex'
- bindex = guard_token.guard_compat_bindex
- choices_addr = gc_table_addr + WORD * bindex
- sequel_label = rawstart + guard_token.pos_jump_offset
- failure_recovery = rawstart + guard_token.pos_recovery_stub
- gcmap = guard_token.gcmap
- # choices_addr: points to bchoices in the GC table
- # sequel_label: "sequel:" label above
- # failure_recovery: failure recovery address
- guard_compat_descr = guard_token.faildescr
- assert isinstance(guard_compat_descr, GuardCompatibleDescr)
- guard_compat_descr._backend_choices_addr = choices_addr
- guard_compat_descr._backend_sequel_label = sequel_label
- guard_compat_descr._backend_failure_recovery = failure_recovery
- guard_compat_descr._backend_gcmap = gcmap
- #
- bchoices = descr_to_bchoices(guard_compat_descr)
- assert len(bchoices.bc_list) == 1
- assert (cast_gcref_to_instance(GuardCompatibleDescr, bchoices.bc_faildescr)
- is guard_compat_descr)
- bchoices.bc_gc_table_tracer = lltype.cast_opaque_ptr(llmemory.GCREF,
- gc_table_tracer)
- 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))
- ofs = pair_ofs + llmemory.sizeof(lltype.Unsigned)
- llop.raw_store(lltype.Void, gcref_base, _real_number(ofs), -1)
-
-def invalidate_cache(faildescr):
- """Write -1 inside bchoices.bc_most_recent.gcref."""
- bchoices = descr_to_bchoices(faildescr)
- invalidate_pair(bchoices, BCMOSTRECENT)
+# A lot of the logic is not specific to the x86 backend and is
+# written in ../llsupport/guard_compat.py.
def _fix_forward_label(mc, jmp_location):
diff --git a/rpython/jit/backend/x86/test/test_compatible.py b/rpython/jit/backend/x86/test/test_compatible.py
--- a/rpython/jit/backend/x86/test/test_compatible.py
+++ b/rpython/jit/backend/x86/test/test_compatible.py
@@ -10,65 +10,6 @@
pass
-def test_invalidate_cache():
- b = lltype.malloc(BACKEND_CHOICES, 4)
- invalidate_pair(b, BCMOSTRECENT)
- x = b.bc_most_recent.gcref
- assert 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]
- assert pair.gcref == rffi.cast(lltype.Unsigned, 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, -1), # invalid
- (-1, -1), # invalid
- (-1, -1), # 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, -1), # invalid
- (-1, -1), # 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, -1), # invalid
- ])
-
def test_guard_compat():
cpu = CPU(rtyper=None, stats=FakeStats())
cpu.setup_once()
@@ -129,7 +70,8 @@
faildescr = guard_compat_descr
guard_token = FakeGuardToken()
- patch_guard_compatible(guard_token, rawstart, rawstart,
+ patch_guard_compatible(guard_token, rawstart,
+ lambda index: rawstart + index * WORD,
lltype.nullptr(llmemory.GCREF.TO))
# ---- ready ----
More information about the pypy-commit
mailing list