Author: Armin Rigo <ar...@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)) + +@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)) + +@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)) - -@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)) - -@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 ---- _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit