def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue, custom_eq_hash=None, force_non_null=False): self.rtyper = rtyper self.DICT = lltype.GcForwardReference() self.lowleveltype = lltype.Ptr(self.DICT) self.custom_eq_hash = custom_eq_hash is not None if not isinstance(key_repr, rmodel.Repr): # not computed yet, done by setup() assert callable(key_repr) self._key_repr_computer = key_repr else: self.external_key_repr, self.key_repr = self.pickkeyrepr(key_repr) if not isinstance(value_repr, rmodel.Repr): # not computed yet, done by setup() assert callable(value_repr) self._value_repr_computer = value_repr else: self.external_value_repr, self.value_repr = self.pickrepr( value_repr) self.dictkey = dictkey self.dictvalue = dictvalue self.dict_cache = {} self._custom_eq_hash_repr = custom_eq_hash self.force_non_null = force_non_null
def test_size_descr_stack_overflow_bug(): c0 = GcCache(False) S = lltype.GcForwardReference() P = lltype.Ptr(S) fields = [('x%d' % i, P) for i in range(1500)] S.become(lltype.GcStruct('S', *fields)) get_size_descr(c0, S)
def test_malloc_struct_of_ptr_struct(self): S3 = lltype.GcForwardReference() S3.become( lltype.GcStruct('S3', ('gcptr_struct', S), ('prev', lltype.Ptr(S)), ('next', lltype.Ptr(S)))) s3 = self.malloc(S3) assert s3.gcptr_struct.prev == lltype.nullptr(S) assert s3.gcptr_struct.next == lltype.nullptr(S)
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_recursive_structure(): F = lltype.GcForwardReference() S = lltype.GcStruct('abc', ('x', lltype.Ptr(F))) F.become(S) def f(): s1 = lltype.malloc(S) s2 = lltype.malloc(S) s1.x = s2 t, transformer = rtype_and_transform(f, [], RefcountingGCTransformer, check=False)
def get_shadowstackref(root_walker, gctransformer): if hasattr(gctransformer, '_SHADOWSTACKREF'): return gctransformer._SHADOWSTACKREF SHADOWSTACKREFPTR = lltype.Ptr(lltype.GcForwardReference()) SHADOWSTACKREF = lltype.GcStruct( 'ShadowStackRef', ('base', llmemory.Address), ('top', llmemory.Address), ('context', llmemory.Address), #('fullstack', lltype.Bool), rtti=True) SHADOWSTACKREFPTR.TO.become(SHADOWSTACKREF) def customtrace(gc, obj, callback, arg): obj = llmemory.cast_adr_to_ptr(obj, SHADOWSTACKREFPTR) addr = obj.top start = obj.base while addr != start: addr -= sizeofaddr gc._trace_callback(callback, arg, addr) gc = gctransformer.gcdata.gc assert not hasattr(gc, 'custom_trace_dispatcher') # ^^^ create_custom_trace_funcs() must not run before this gctransformer.translator.rtyper.custom_trace_funcs.append( (SHADOWSTACKREF, customtrace)) def shadowstack_destructor(shadowstackref): if root_walker.stacklet_support: from rpython.rlib import _rffi_stacklet as _c h = shadowstackref.context h = llmemory.cast_adr_to_ptr(h, _c.handle) shadowstackref.context = llmemory.NULL # base = shadowstackref.base shadowstackref.base = llmemory.NULL shadowstackref.top = llmemory.NULL llmemory.raw_free(base) # if root_walker.stacklet_support: if h: _c.destroy(h) destrptr = gctransformer.annotate_helper(shadowstack_destructor, [SHADOWSTACKREFPTR], lltype.Void) lltype.attachRuntimeTypeInfo(SHADOWSTACKREF, destrptr=destrptr) gctransformer._SHADOWSTACKREF = SHADOWSTACKREF return SHADOWSTACKREF
class TestConstPtr(BaseTestRegalloc): cpu = CPU(None, None) #cpu.gc_ll_descr = MockGcDescr(False) cpu.setup_once() S = lltype.GcForwardReference() fields = [('int%d' % i, lltype.Signed) for i in range(1050)] S.become(lltype.GcStruct('S', *fields)) fielddescr = cpu.fielddescrof(S, 'int1049') struct_ptr = lltype.malloc(S) struct_ref = lltype.cast_opaque_ptr(llmemory.GCREF, struct_ptr) ptr0 = struct_ref namespace = locals().copy() def test_finish_failargs_constptr(self): ops = ''' [i0] i1 = int_add(i0, 1) finish(ConstPtr(ptr0)) ''' loop = self.interpret(ops, [99]) ptr = self.getptr(0, lltype.Ptr(self.S)) assert self.struct_ptr == ptr def test_getfield_with_offset_gt_one_byte(self): self.struct_ptr.int1049 = 666 ops = ''' [p0] i0 = getfield_gc(p0, descr=fielddescr) finish(i0) ''' self.interpret(ops, [self.struct_ptr]) assert self.getint(0) == 666 def test_setfield_with_offset_gt_one_byte(self): ops = ''' [p0] setfield_gc(p0, 777, descr=fielddescr) finish() ''' self.interpret(ops, [self.struct_ptr]) assert self.struct_ptr.int1049 == 777
def define_compile_framework_call_assembler(self): S = lltype.GcForwardReference() S.become(lltype.GcStruct('S', ('s', lltype.Ptr(S)))) driver = JitDriver(greens=[], reds='auto', is_recursive=True) def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s0): driver.jit_merge_point() i = 0 prev_s = lltype.nullptr(S) while i < 100: s = lltype.malloc(S) s.s = prev_s prev_s = s i += 1 return n - 1, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s0 return None, f, None
def define_write_barrier_direct(cls): from rpython.rlib import rgc S = lltype.GcForwardReference() S.become( lltype.GcStruct('S', ('x', lltype.Signed), ('prev', lltype.Ptr(S)), ('next', lltype.Ptr(S)))) s0 = lltype.malloc(S, immortal=True) def f(): s = lltype.malloc(S) s.x = 42 llop.bare_setfield(lltype.Void, s0, void('next'), s) llop.gc_writebarrier(lltype.Void, llmemory.cast_ptr_to_adr(s0)) rgc.collect(0) return s0.next.x def cleanup(): s0.next = lltype.nullptr(S) return f, cleanup, None
def get_shadowstackref(root_walker, gctransformer): if hasattr(gctransformer, '_SHADOWSTACKREF'): return gctransformer._SHADOWSTACKREF SHADOWSTACKREFPTR = lltype.Ptr(lltype.GcForwardReference()) SHADOWSTACKREF = lltype.GcStruct('ShadowStackRef', ('base', llmemory.Address), ('top', llmemory.Address), rtti=True) SHADOWSTACKREFPTR.TO.become(SHADOWSTACKREF) def customtrace(gc, obj, callback, arg1, arg2): obj = llmemory.cast_adr_to_ptr(obj, SHADOWSTACKREFPTR) walk_stack_root(gc._trace_callback, callback, arg1, arg2, obj.base, obj.top, is_minor=False) # xxx optimize? gc = gctransformer.gcdata.gc assert not hasattr(gc, 'custom_trace_dispatcher') # ^^^ create_custom_trace_funcs() must not run before this gctransformer.translator.rtyper.custom_trace_funcs.append( (SHADOWSTACKREF, customtrace)) def shadowstack_destructor(shadowstackref): base = shadowstackref.base shadowstackref.base = llmemory.NULL shadowstackref.top = llmemory.NULL llmemory.raw_free(base) destrptr = gctransformer.annotate_helper(shadowstack_destructor, [SHADOWSTACKREFPTR], lltype.Void) lltype.attachRuntimeTypeInfo(SHADOWSTACKREF, destrptr=destrptr) gctransformer._SHADOWSTACKREF = SHADOWSTACKREF return SHADOWSTACKREF
class LLtypeMixin(object): node_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) node_vtable.name = rclass.alloc_array_name('node') node_vtable2 = lltype.malloc(OBJECT_VTABLE, immortal=True) node_vtable2.name = rclass.alloc_array_name('node2') node_vtable3 = lltype.malloc(OBJECT_VTABLE, immortal=True) node_vtable3.name = rclass.alloc_array_name('node3') node_vtable3.subclassrange_min = 3 node_vtable3.subclassrange_max = 3 cpu = runner.LLGraphCPU(None) NODE = lltype.GcForwardReference() S = lltype.GcForwardReference() NODE.become( lltype.GcStruct('NODE', ('parent', OBJECT), ('value', lltype.Signed), ('floatval', lltype.Float), ('charval', lltype.Char), ('nexttuple', lltype.Ptr(S)), ('next', lltype.Ptr(NODE)))) S.become( lltype.GcStruct('TUPLE', ('a', lltype.Signed), ('abis', lltype.Signed), ('b', lltype.Ptr(NODE)))) NODE2 = lltype.GcStruct('NODE2', ('parent', NODE), ('other', lltype.Ptr(NODE))) NODE3 = lltype.GcForwardReference() NODE3.become( lltype.GcStruct('NODE3', ('parent', OBJECT), ('value', lltype.Signed), ('next', lltype.Ptr(NODE3)), hints={'immutable': True})) big_fields = [('big' + i, lltype.Signed) for i in string.ascii_lowercase] BIG = lltype.GcForwardReference() BIG.become(lltype.GcStruct('BIG', *big_fields, hints={'immutable': True})) for field, _ in big_fields: locals()[field + 'descr'] = cpu.fielddescrof(BIG, field) node = lltype.malloc(NODE) node.value = 5 node.next = node node.parent.typeptr = node_vtable nodeaddr = lltype.cast_opaque_ptr(llmemory.GCREF, node) #nodebox = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, node)) node2 = lltype.malloc(NODE2) node2.parent.parent.typeptr = node_vtable2 node2addr = lltype.cast_opaque_ptr(llmemory.GCREF, node2) myptr = lltype.cast_opaque_ptr(llmemory.GCREF, node) mynodeb = lltype.malloc(NODE) myarray = lltype.cast_opaque_ptr( llmemory.GCREF, lltype.malloc(lltype.GcArray(lltype.Signed), 13, zero=True)) mynodeb.parent.typeptr = node_vtable myptrb = lltype.cast_opaque_ptr(llmemory.GCREF, mynodeb) myptr2 = lltype.malloc(NODE2) myptr2.parent.parent.typeptr = node_vtable2 myptr2 = lltype.cast_opaque_ptr(llmemory.GCREF, myptr2) nullptr = lltype.nullptr(llmemory.GCREF.TO) mynode3 = lltype.malloc(NODE3) mynode3.parent.typeptr = node_vtable3 mynode3.value = 7 mynode3.next = mynode3 myptr3 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode3) # a NODE2 mynode4 = lltype.malloc(NODE3) mynode4.parent.typeptr = node_vtable3 myptr4 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode4) # a NODE3 nodesize = cpu.sizeof(NODE, node_vtable) node_tid = nodesize.get_type_id() nodesize2 = cpu.sizeof(NODE2, node_vtable2) nodesize3 = cpu.sizeof(NODE3, node_vtable3) valuedescr = cpu.fielddescrof(NODE, 'value') floatdescr = cpu.fielddescrof(NODE, 'floatval') chardescr = cpu.fielddescrof(NODE, 'charval') nextdescr = cpu.fielddescrof(NODE, 'next') nexttupledescr = cpu.fielddescrof(NODE, 'nexttuple') otherdescr = cpu.fielddescrof(NODE2, 'other') valuedescr3 = cpu.fielddescrof(NODE3, 'value') nextdescr3 = cpu.fielddescrof(NODE3, 'next') assert valuedescr3.is_always_pure() assert nextdescr3.is_always_pure() accessor = FieldListAccessor() accessor.initialize(None, {'inst_field': IR_QUASIIMMUTABLE}) QUASI = lltype.GcStruct('QUASIIMMUT', ('inst_field', lltype.Signed), ('mutate_field', rclass.OBJECTPTR), hints={'immutable_fields': accessor}) quasisize = cpu.sizeof(QUASI, None) quasi = lltype.malloc(QUASI, immortal=True) quasi.inst_field = -4247 quasifielddescr = cpu.fielddescrof(QUASI, 'inst_field') quasiptr = lltype.cast_opaque_ptr(llmemory.GCREF, quasi) quasiimmutdescr = QuasiImmutDescr(cpu, quasiptr, quasifielddescr, cpu.fielddescrof(QUASI, 'mutate_field')) NODEOBJ = lltype.GcStruct('NODEOBJ', ('parent', OBJECT), ('ref', lltype.Ptr(OBJECT))) nodeobj = lltype.malloc(NODEOBJ) nodeobjvalue = lltype.cast_opaque_ptr(llmemory.GCREF, nodeobj) refdescr = cpu.fielddescrof(NODEOBJ, 'ref') INTOBJ_NOIMMUT = lltype.GcStruct('INTOBJ_NOIMMUT', ('parent', OBJECT), ('intval', lltype.Signed)) INTOBJ_IMMUT = lltype.GcStruct('INTOBJ_IMMUT', ('parent', OBJECT), ('intval', lltype.Signed), hints={'immutable': True}) intobj_noimmut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) intobj_immut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) noimmut_intval = cpu.fielddescrof(INTOBJ_NOIMMUT, 'intval') immut_intval = cpu.fielddescrof(INTOBJ_IMMUT, 'intval') immut = lltype.malloc(INTOBJ_IMMUT, zero=True) immutaddr = lltype.cast_opaque_ptr(llmemory.GCREF, immut) noimmut_descr = cpu.sizeof(INTOBJ_NOIMMUT, intobj_noimmut_vtable) immut_descr = cpu.sizeof(INTOBJ_IMMUT, intobj_immut_vtable) PTROBJ_IMMUT = lltype.GcStruct('PTROBJ_IMMUT', ('parent', OBJECT), ('ptrval', lltype.Ptr(OBJECT)), hints={'immutable': True}) ptrobj_immut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) ptrobj_immut_descr = cpu.sizeof(PTROBJ_IMMUT, ptrobj_immut_vtable) immut_ptrval = cpu.fielddescrof(PTROBJ_IMMUT, 'ptrval') arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed)) int32arraydescr = cpu.arraydescrof(lltype.GcArray(rffi.INT)) int16arraydescr = cpu.arraydescrof(lltype.GcArray(rffi.SHORT)) float32arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.SingleFloat)) arraydescr_tid = arraydescr.get_type_id() array = lltype.malloc(lltype.GcArray(lltype.Signed), 15, zero=True) arrayref = lltype.cast_opaque_ptr(llmemory.GCREF, array) array2 = lltype.malloc(lltype.GcArray(lltype.Ptr(S)), 15, zero=True) array2ref = lltype.cast_opaque_ptr(llmemory.GCREF, array2) gcarraydescr = cpu.arraydescrof(lltype.GcArray(llmemory.GCREF)) gcarraydescr_tid = gcarraydescr.get_type_id() floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float)) arrayimmutdescr = cpu.arraydescrof( lltype.GcArray(lltype.Signed, hints={"immutable": True})) immutarray = lltype.cast_opaque_ptr( llmemory.GCREF, lltype.malloc(arrayimmutdescr.A, 13, zero=True)) gcarrayimmutdescr = cpu.arraydescrof( lltype.GcArray(llmemory.GCREF, hints={"immutable": True})) floatarrayimmutdescr = cpu.arraydescrof( lltype.GcArray(lltype.Float, hints={"immutable": True})) # a GcStruct not inheriting from OBJECT tpl = lltype.malloc(S, zero=True) tupleaddr = lltype.cast_opaque_ptr(llmemory.GCREF, tpl) nodefull2 = lltype.malloc(NODE, zero=True) nodefull2addr = lltype.cast_opaque_ptr(llmemory.GCREF, nodefull2) ssize = cpu.sizeof(S, None) adescr = cpu.fielddescrof(S, 'a') abisdescr = cpu.fielddescrof(S, 'abis') bdescr = cpu.fielddescrof(S, 'b') #sbox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S))) arraydescr2 = cpu.arraydescrof(lltype.GcArray(lltype.Ptr(S))) T = lltype.GcStruct('TUPLE', ('c', lltype.Signed), ('d', lltype.Ptr(lltype.GcArray(lltype.Ptr(NODE))))) W_ROOT = lltype.GcStruct( 'W_ROOT', ('parent', OBJECT), ('inst_w_seq', llmemory.GCREF), ('inst_index', lltype.Signed), ('inst_w_list', llmemory.GCREF), ('inst_length', lltype.Signed), ('inst_start', lltype.Signed), ('inst_step', lltype.Signed)) inst_w_seq = cpu.fielddescrof(W_ROOT, 'inst_w_seq') inst_index = cpu.fielddescrof(W_ROOT, 'inst_index') inst_length = cpu.fielddescrof(W_ROOT, 'inst_length') inst_start = cpu.fielddescrof(W_ROOT, 'inst_start') inst_step = cpu.fielddescrof(W_ROOT, 'inst_step') inst_w_list = cpu.fielddescrof(W_ROOT, 'inst_w_list') w_root_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) tsize = cpu.sizeof(T, None) cdescr = cpu.fielddescrof(T, 'c') ddescr = cpu.fielddescrof(T, 'd') arraydescr3 = cpu.arraydescrof(lltype.GcArray(lltype.Ptr(NODE3))) U = lltype.GcStruct('U', ('parent', OBJECT), ('one', lltype.Ptr(lltype.GcArray(lltype.Ptr(NODE))))) u_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) SIMPLE = lltype.GcStruct('simple', ('parent', OBJECT), ('value', lltype.Signed)) simplevalue = cpu.fielddescrof(SIMPLE, 'value') simple_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) simpledescr = cpu.sizeof(SIMPLE, simple_vtable) simple = lltype.malloc(SIMPLE, zero=True) simpleaddr = lltype.cast_opaque_ptr(llmemory.GCREF, simple) #usize = cpu.sizeof(U, ...) onedescr = cpu.fielddescrof(U, 'one') FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) elidablecalldescr = cpu.calldescrof( FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([valuedescr], [], [], [valuedescr], [], [], EffectInfo.EF_ELIDABLE_CANNOT_RAISE)) elidable2calldescr = cpu.calldescrof( FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([valuedescr], [], [], [valuedescr], [], [], EffectInfo.EF_ELIDABLE_OR_MEMORYERROR)) elidable3calldescr = cpu.calldescrof( FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([valuedescr], [], [], [valuedescr], [], [], EffectInfo.EF_ELIDABLE_CAN_RAISE)) nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [])) writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [adescr], [], [])) writearraydescr = cpu.calldescrof( FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [adescr], [arraydescr], [])) writevalue3descr = cpu.calldescrof( FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [valuedescr3], [], [])) readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([adescr], [], [], [], [], [])) mayforcevirtdescr = cpu.calldescrof( FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([nextdescr], [], [], [], [], [], EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, can_invalidate=True)) arraycopydescr = cpu.calldescrof( FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [arraydescr], [], [], [arraydescr], [], EffectInfo.EF_CANNOT_RAISE, oopspecindex=EffectInfo.OS_ARRAYCOPY)) raw_malloc_descr = cpu.calldescrof( FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [], EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_RAW_MALLOC_VARSIZE_CHAR)) raw_free_descr = cpu.calldescrof( FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE, oopspecindex=EffectInfo.OS_RAW_FREE)) chararray = lltype.GcArray(lltype.Char) chararraydescr = cpu.arraydescrof(chararray) u2array = lltype.GcArray(rffi.USHORT) u2arraydescr = cpu.arraydescrof(u2array) nodefull = lltype.malloc(NODE2, zero=True) nodefull.parent.next = lltype.cast_pointer(lltype.Ptr(NODE), nodefull) nodefull.parent.nexttuple = tpl nodefulladdr = lltype.cast_opaque_ptr(llmemory.GCREF, nodefull) # array of structs (complex data) complexarray = lltype.GcArray( lltype.Struct( "complex", ("real", lltype.Float), ("imag", lltype.Float), )) complexarraydescr = cpu.arraydescrof(complexarray) complexrealdescr = cpu.interiorfielddescrof(complexarray, "real") compleximagdescr = cpu.interiorfielddescrof(complexarray, "imag") complexarraycopydescr = cpu.calldescrof( FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [complexarraydescr], [], [], [complexarraydescr], [], EffectInfo.EF_CANNOT_RAISE, oopspecindex=EffectInfo.OS_ARRAYCOPY)) rawarraydescr = cpu.arraydescrof( lltype.Array(lltype.Signed, hints={'nolength': True})) rawarraydescr_char = cpu.arraydescrof( lltype.Array(lltype.Char, hints={'nolength': True})) rawarraydescr_float = cpu.arraydescrof( lltype.Array(lltype.Float, hints={'nolength': True})) fc_array = lltype.GcArray( lltype.Struct("floatchar", ("float", lltype.Float), ("char", lltype.Char))) fc_array_descr = cpu.arraydescrof(fc_array) fc_array_floatdescr = cpu.interiorfielddescrof(fc_array, "float") fc_array_chardescr = cpu.interiorfielddescrof(fc_array, "char") for _name, _os in [ ('strconcatdescr', 'OS_STR_CONCAT'), ('strslicedescr', 'OS_STR_SLICE'), ('strequaldescr', 'OS_STR_EQUAL'), ('streq_slice_checknull_descr', 'OS_STREQ_SLICE_CHECKNULL'), ('streq_slice_nonnull_descr', 'OS_STREQ_SLICE_NONNULL'), ('streq_slice_char_descr', 'OS_STREQ_SLICE_CHAR'), ('streq_nonnull_descr', 'OS_STREQ_NONNULL'), ('streq_nonnull_char_descr', 'OS_STREQ_NONNULL_CHAR'), ('streq_checknull_char_descr', 'OS_STREQ_CHECKNULL_CHAR'), ('streq_lengthok_descr', 'OS_STREQ_LENGTHOK'), ]: if _name in ('strconcatdescr', 'strslicedescr'): _extra = EffectInfo.EF_ELIDABLE_OR_MEMORYERROR else: _extra = EffectInfo.EF_ELIDABLE_CANNOT_RAISE _oopspecindex = getattr(EffectInfo, _os) locals()[_name] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [], _extra, oopspecindex=_oopspecindex)) # _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI')) locals()[_name.replace('str', 'unicode')] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [], _extra, oopspecindex=_oopspecindex)) s2u_descr = cpu.calldescrof( FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [], EffectInfo.EF_ELIDABLE_CAN_RAISE, oopspecindex=EffectInfo.OS_STR2UNICODE)) # class LoopToken(AbstractDescr): pass asmdescr = LoopToken() # it can be whatever, it's not a descr though class FakeWarmRunnerDesc: pass FakeWarmRunnerDesc.cpu = cpu vrefinfo = VirtualRefInfo(FakeWarmRunnerDesc) virtualtokendescr = vrefinfo.descr_virtual_token virtualforceddescr = vrefinfo.descr_forced FUNC = lltype.FuncType([], lltype.Void) ei = EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE, can_invalidate=False, oopspecindex=EffectInfo.OS_JIT_FORCE_VIRTUALIZABLE) clear_vable = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, ei) jit_virtual_ref_vtable = vrefinfo.jit_virtual_ref_vtable vref_descr = cpu.sizeof(vrefinfo.JIT_VIRTUAL_REF, jit_virtual_ref_vtable) FUNC = lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed) ei = EffectInfo([], [], [], [], [], [], EffectInfo.EF_ELIDABLE_CANNOT_RAISE, can_invalidate=False, oopspecindex=EffectInfo.OS_INT_PY_DIV) int_py_div_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, ei) ei = EffectInfo([], [], [], [], [], [], EffectInfo.EF_ELIDABLE_CANNOT_RAISE, can_invalidate=False, oopspecindex=EffectInfo.OS_INT_UDIV) int_udiv_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, ei) ei = EffectInfo([], [], [], [], [], [], EffectInfo.EF_ELIDABLE_CANNOT_RAISE, can_invalidate=False, oopspecindex=EffectInfo.OS_INT_PY_MOD) int_py_mod_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, ei) FUNC = lltype.FuncType([], llmemory.GCREF) ei = EffectInfo([], [], [], [], [], [], EffectInfo.EF_ELIDABLE_CAN_RAISE) plain_r_calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, ei) namespace = locals()
def _get_NODE(self): NODE = lltype.GcForwardReference() NODE.become( lltype.GcStruct('NODE', ('value', lltype.Signed), ('next', lltype.Ptr(NODE)))) return NODE
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_r(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_r(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 # the gcmap should contain three things, p0, p1 and p3 # p3 stays in a register # while p0 and p1 are on the frame b = getmap(frame) nos = [len(b) - 1 - i.start() for i in re.finditer('1', b)] nos.reverse() if self.cpu.backend_name.startswith('x86'): if self.cpu.IS_64_BIT: assert nos == [0, 1, 31] else: assert nos == [0, 1, 25] elif self.cpu.backend_name.startswith('arm'): assert nos == [0, 1, 47] elif self.cpu.backend_name.startswith('ppc64'): assert nos == [0, 1, 33] elif self.cpu.backend_name.startswith('zarch'): assert nos == [0, 1, 29] else: raise Exception("write the data here") 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_r(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_i(i4, descr=intdescr) guard_nonnull(i11) [i4, i5, i6, i7, i0, i1, i11, i8] i13 = getfield_gc_i(i11, descr=intdescr) guard_isnull(i13) [i4, i5, i6, i7, i0, i1, i11, i8] i15 = getfield_gc_i(i4, descr=intdescr) i17 = int_lt(i15, 0) guard_false(i17) [i4, i5, i6, i7, i0, i1, i11, i15, i8] i18 = getfield_gc_i(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_i(i11, descr=intdescr) i22 = getfield_gc_i(i11, descr=intdescr) i23 = int_mul(i15, i22) i24 = int_add(i21, i23) i25 = getfield_gc_i(i4, descr=intdescr) i27 = int_add(i25, 1) setfield_gc(i4, i27, descr=intdescr) i29 = getfield_raw_i(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_i(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)
from rpython.rtyper.rbytearray import AbstractByteArrayRepr from rpython.rtyper.lltypesystem import lltype, rstr from rpython.rlib.debug import ll_assert BYTEARRAY = lltype.GcForwardReference() def mallocbytearray(size): return lltype.malloc(BYTEARRAY, size) _, _, copy_bytearray_contents = rstr._new_copy_contents_fun( BYTEARRAY, BYTEARRAY, lltype.Char, 'bytearray') _, _, copy_bytearray_contents_from_str = rstr._new_copy_contents_fun( rstr.STR, BYTEARRAY, lltype.Char, 'bytearray_from_str') def _empty_bytearray(): return empty BYTEARRAY.become( lltype.GcStruct( 'rpy_bytearray', ('chars', lltype.Array(lltype.Char)), adtmeths={ 'malloc': lltype.staticAdtMethod(mallocbytearray), 'copy_contents': lltype.staticAdtMethod(copy_bytearray_contents), 'copy_contents_from_str': lltype.staticAdtMethod(copy_bytearray_contents_from_str),
# ------------------------------------------------------------ def dont_inline(func): func._dont_inline_ = True return func def always_inline(func): func._always_inline_ = True return func STRINGPIECE = lltype.GcStruct( 'stringpiece', ('buf', lltype.Ptr(STR)), ('prev_piece', lltype.Ptr(lltype.GcForwardReference()))) STRINGPIECE.prev_piece.TO.become(STRINGPIECE) STRINGBUILDER = lltype.GcStruct('stringbuilder', ('current_buf', lltype.Ptr(STR)), ('current_pos', lltype.Signed), ('current_end', lltype.Signed), ('total_size', lltype.Signed), ('extra_pieces', lltype.Ptr(STRINGPIECE)), adtmeths={ 'copy_string_contents': staticAdtMethod(rstr.copy_string_contents), 'copy_raw_to_string': staticAdtMethod(rstr.copy_raw_to_string), 'mallocfn': staticAdtMethod(rstr.mallocstr),
class BlockBuilderMixin(object): _mixin_ = True # A base class to generate assembler. It is equivalent to just a list # of chars, but it is potentially more efficient for that usage. # It works by allocating the assembler SUBBLOCK_SIZE bytes at a time. # Ideally, this number should be a power of two that fits the GC's most # compact allocation scheme (which is so far 35 * WORD for minimark.py). WORD = LONG_BIT // 8 SUBBLOCK_SIZE = 32 * WORD SUBBLOCK_PTR = lltype.Ptr(lltype.GcForwardReference()) SUBBLOCK = lltype.GcStruct( 'SUBBLOCK', ('prev', SUBBLOCK_PTR), ('data', lltype.FixedSizeArray(lltype.Char, SUBBLOCK_SIZE))) SUBBLOCK_PTR.TO.become(SUBBLOCK) ALIGN_MATERIALIZE = 16 gcroot_markers = None def __init__(self, translated=None): if translated is None: translated = we_are_translated() if translated: self.init_block_builder() else: self._become_a_plain_block_builder() self.rawstart = 0 def init_block_builder(self): self._cursubblock = lltype.nullptr(self.SUBBLOCK) self._baserelpos = -self.SUBBLOCK_SIZE self._make_new_subblock() def _make_new_subblock(self): nextsubblock = lltype.malloc(self.SUBBLOCK) nextsubblock.prev = self._cursubblock self._cursubblock = nextsubblock self._cursubindex = 0 self._baserelpos += self.SUBBLOCK_SIZE _make_new_subblock._dont_inline_ = True def writechar(self, char): index = self._cursubindex if index == self.SUBBLOCK_SIZE: self._make_new_subblock() index = 0 self._cursubblock.data[index] = char self._cursubindex = index + 1 def absolute_addr(self): return self.rawstart def overwrite(self, index, char): assert 0 <= index < self.get_relative_pos() block = self._cursubblock index -= self._baserelpos while index < 0: block = block.prev index += self.SUBBLOCK_SIZE block.data[index] = char def overwrite32(self, index, val): self.overwrite(index, chr(val & 0xff)) self.overwrite(index + 1, chr((val >> 8) & 0xff)) self.overwrite(index + 2, chr((val >> 16) & 0xff)) self.overwrite(index + 3, chr((val >> 24) & 0xff)) def get_relative_pos(self): return self._baserelpos + self._cursubindex def copy_to_raw_memory(self, addr): # indirection for _become_a_plain_block_builder() and for subclasses self._copy_to_raw_memory(addr) def _copy_to_raw_memory(self, addr): block = self._cursubblock blocksize = self._cursubindex targetindex = self._baserelpos while targetindex >= 0: dst = rffi.cast(rffi.CCHARP, addr + targetindex) for j in range(blocksize): dst[j] = block.data[j] block = block.prev blocksize = self.SUBBLOCK_SIZE targetindex -= self.SUBBLOCK_SIZE assert not block def copy_core_dump(self, addr, offset=0, count=-1): HEX = '0123456789ABCDEF' dump = [] src = rffi.cast(rffi.CCHARP, addr) end = self.get_relative_pos() if count != -1: end = offset + count for p in range(offset, end): o = ord(src[p]) dump.append(HEX[o >> 4]) dump.append(HEX[o & 15]) return ''.join(dump) def _dump(self, addr, logname, backend=None): debug_start(logname) if have_debug_prints(): # if backend is not None: debug_print('BACKEND', backend) # from rpython.jit.backend.hlinfo import highleveljitinfo if highleveljitinfo.sys_executable: debug_print('SYS_EXECUTABLE', highleveljitinfo.sys_executable) else: debug_print('SYS_EXECUTABLE', '??') # dump = self.copy_core_dump(addr) debug_print( 'CODE_DUMP', '@%x' % addr, '+0 ', # backwards compatibility dump) # debug_stop(logname) def materialize(self, cpu, allblocks, gcrootmap=None): size = self.get_relative_pos() align = self.ALIGN_MATERIALIZE size += align - 1 malloced = cpu.asmmemmgr.malloc(size, size) allblocks.append(malloced) rawstart = malloced[0] rawstart = (rawstart + align - 1) & (-align) self.rawstart = rawstart self.copy_to_raw_memory(rawstart) if self.gcroot_markers is not None: assert gcrootmap is not None for pos, mark in self.gcroot_markers: gcrootmap.register_asm_addr(rawstart + pos, mark) return rawstart def _become_a_plain_block_builder(self): # hack purely for speed of tests self._data = [] self.writechar = self._data.append self.overwrite = self._data.__setitem__ self.get_relative_pos = self._data.__len__ def plain_copy_to_raw_memory(addr): dst = rffi.cast(rffi.CCHARP, addr) for i, c in enumerate(self._data): dst[i] = c self._copy_to_raw_memory = plain_copy_to_raw_memory def insert_gcroot_marker(self, mark): if self.gcroot_markers is None: self.gcroot_markers = [] self.gcroot_markers.append((self.get_relative_pos(), mark))
class LLtypeMixin(object): type_system = 'lltype' def get_class_of_box(self, box): return box.getref(rclass.OBJECTPTR).typeptr node_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) node_vtable.name = rclass.alloc_array_name('node') node_vtable_adr = llmemory.cast_ptr_to_adr(node_vtable) node_vtable2 = lltype.malloc(OBJECT_VTABLE, immortal=True) node_vtable2.name = rclass.alloc_array_name('node2') node_vtable_adr2 = llmemory.cast_ptr_to_adr(node_vtable2) cpu = runner.LLGraphCPU(None) NODE = lltype.GcForwardReference() NODE.become(lltype.GcStruct('NODE', ('parent', OBJECT), ('value', lltype.Signed), ('floatval', lltype.Float), ('charval', lltype.Char), ('next', lltype.Ptr(NODE)))) NODE2 = lltype.GcStruct('NODE2', ('parent', NODE), ('other', lltype.Ptr(NODE))) node = lltype.malloc(NODE) node.parent.typeptr = node_vtable node2 = lltype.malloc(NODE2) node2.parent.parent.typeptr = node_vtable2 nodebox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, node)) myptr = nodebox.value myptr2 = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(NODE)) nullptr = lltype.nullptr(llmemory.GCREF.TO) nodebox2 = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, node2)) nodesize = cpu.sizeof(NODE) nodesize2 = cpu.sizeof(NODE2) valuedescr = cpu.fielddescrof(NODE, 'value') floatdescr = cpu.fielddescrof(NODE, 'floatval') chardescr = cpu.fielddescrof(NODE, 'charval') nextdescr = cpu.fielddescrof(NODE, 'next') otherdescr = cpu.fielddescrof(NODE2, 'other') accessor = FieldListAccessor() accessor.initialize(None, {'inst_field': IR_QUASIIMMUTABLE}) QUASI = lltype.GcStruct('QUASIIMMUT', ('inst_field', lltype.Signed), ('mutate_field', rclass.OBJECTPTR), hints={'immutable_fields': accessor}) quasisize = cpu.sizeof(QUASI) quasi = lltype.malloc(QUASI, immortal=True) quasi.inst_field = -4247 quasifielddescr = cpu.fielddescrof(QUASI, 'inst_field') quasibox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, quasi)) quasiptr = quasibox.value quasiimmutdescr = QuasiImmutDescr(cpu, quasibox, quasifielddescr, cpu.fielddescrof(QUASI, 'mutate_field')) NODEOBJ = lltype.GcStruct('NODEOBJ', ('parent', OBJECT), ('ref', lltype.Ptr(OBJECT))) nodeobj = lltype.malloc(NODEOBJ) nodeobjvalue = lltype.cast_opaque_ptr(llmemory.GCREF, nodeobj) refdescr = cpu.fielddescrof(NODEOBJ, 'ref') INTOBJ_NOIMMUT = lltype.GcStruct('INTOBJ_NOIMMUT', ('parent', OBJECT), ('intval', lltype.Signed)) INTOBJ_IMMUT = lltype.GcStruct('INTOBJ_IMMUT', ('parent', OBJECT), ('intval', lltype.Signed), hints={'immutable': True}) intobj_noimmut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) intobj_immut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) noimmut_intval = cpu.fielddescrof(INTOBJ_NOIMMUT, 'intval') immut_intval = cpu.fielddescrof(INTOBJ_IMMUT, 'intval') PTROBJ_IMMUT = lltype.GcStruct('PTROBJ_IMMUT', ('parent', OBJECT), ('ptrval', lltype.Ptr(OBJECT)), hints={'immutable': True}) ptrobj_immut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) immut_ptrval = cpu.fielddescrof(PTROBJ_IMMUT, 'ptrval') arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed)) floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float)) # a GcStruct not inheriting from OBJECT S = lltype.GcStruct('TUPLE', ('a', lltype.Signed), ('b', lltype.Ptr(NODE))) ssize = cpu.sizeof(S) adescr = cpu.fielddescrof(S, 'a') bdescr = cpu.fielddescrof(S, 'b') sbox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S))) arraydescr2 = cpu.arraydescrof(lltype.GcArray(lltype.Ptr(S))) T = lltype.GcStruct('TUPLE', ('c', lltype.Signed), ('d', lltype.Ptr(lltype.GcArray(lltype.Ptr(NODE))))) tsize = cpu.sizeof(T) cdescr = cpu.fielddescrof(T, 'c') ddescr = cpu.fielddescrof(T, 'd') arraydescr3 = cpu.arraydescrof(lltype.GcArray(lltype.Ptr(NODE))) U = lltype.GcStruct('U', ('parent', OBJECT), ('one', lltype.Ptr(lltype.GcArray(lltype.Ptr(NODE))))) u_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True) u_vtable_adr = llmemory.cast_ptr_to_adr(u_vtable) usize = cpu.sizeof(U) onedescr = cpu.fielddescrof(U, 'one') FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [])) writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [adescr], [], [])) writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [adescr], [arraydescr], [])) readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([adescr], [], [], [], [], [])) mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([nextdescr], [], [], [], [], [], EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE, can_invalidate=True)) arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [arraydescr], [], [], [arraydescr], [], EffectInfo.EF_CANNOT_RAISE, oopspecindex=EffectInfo.OS_ARRAYCOPY)) raw_malloc_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [], EffectInfo.EF_CAN_RAISE, oopspecindex=EffectInfo.OS_RAW_MALLOC_VARSIZE_CHAR)) raw_free_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE, oopspecindex=EffectInfo.OS_RAW_FREE)) chararray = lltype.GcArray(lltype.Char) chararraydescr = cpu.arraydescrof(chararray) u2array = lltype.GcArray(rffi.USHORT) u2arraydescr = cpu.arraydescrof(u2array) # array of structs (complex data) complexarray = lltype.GcArray( lltype.Struct("complex", ("real", lltype.Float), ("imag", lltype.Float), ) ) complexarraydescr = cpu.arraydescrof(complexarray) complexrealdescr = cpu.interiorfielddescrof(complexarray, "real") compleximagdescr = cpu.interiorfielddescrof(complexarray, "imag") complexarraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [complexarraydescr], [], [], [complexarraydescr], [], EffectInfo.EF_CANNOT_RAISE, oopspecindex=EffectInfo.OS_ARRAYCOPY)) rawarraydescr = cpu.arraydescrof(lltype.Array(lltype.Signed, hints={'nolength': True})) rawarraydescr_char = cpu.arraydescrof(lltype.Array(lltype.Char, hints={'nolength': True})) rawarraydescr_float = cpu.arraydescrof(lltype.Array(lltype.Float, hints={'nolength': True})) fc_array = lltype.GcArray( lltype.Struct( "floatchar", ("float", lltype.Float), ("char", lltype.Char))) fc_array_descr = cpu.arraydescrof(fc_array) fc_array_floatdescr = cpu.interiorfielddescrof(fc_array, "float") fc_array_chardescr = cpu.interiorfielddescrof(fc_array, "char") for _name, _os in [ ('strconcatdescr', 'OS_STR_CONCAT'), ('strslicedescr', 'OS_STR_SLICE'), ('strequaldescr', 'OS_STR_EQUAL'), ('streq_slice_checknull_descr', 'OS_STREQ_SLICE_CHECKNULL'), ('streq_slice_nonnull_descr', 'OS_STREQ_SLICE_NONNULL'), ('streq_slice_char_descr', 'OS_STREQ_SLICE_CHAR'), ('streq_nonnull_descr', 'OS_STREQ_NONNULL'), ('streq_nonnull_char_descr', 'OS_STREQ_NONNULL_CHAR'), ('streq_checknull_char_descr', 'OS_STREQ_CHECKNULL_CHAR'), ('streq_lengthok_descr', 'OS_STREQ_LENGTHOK'), ]: _oopspecindex = getattr(EffectInfo, _os) locals()[_name] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE, oopspecindex=_oopspecindex)) # _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI')) locals()[_name.replace('str', 'unicode')] = \ cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE, oopspecindex=_oopspecindex)) s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], [], [], [], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE)) # class LoopToken(AbstractDescr): pass asmdescr = LoopToken() # it can be whatever, it's not a descr though from rpython.jit.metainterp.virtualref import VirtualRefInfo class FakeWarmRunnerDesc: pass FakeWarmRunnerDesc.cpu = cpu vrefinfo = VirtualRefInfo(FakeWarmRunnerDesc) virtualtokendescr = vrefinfo.descr_virtual_token virtualforceddescr = vrefinfo.descr_forced FUNC = lltype.FuncType([], lltype.Void) ei = EffectInfo([], [], [], [], [], [], EffectInfo.EF_CANNOT_RAISE, can_invalidate=False, oopspecindex=EffectInfo.OS_JIT_FORCE_VIRTUALIZABLE) clear_vable = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, ei) jit_virtual_ref_vtable = vrefinfo.jit_virtual_ref_vtable jvr_vtable_adr = llmemory.cast_ptr_to_adr(jit_virtual_ref_vtable) register_known_gctype(cpu, node_vtable, NODE) register_known_gctype(cpu, node_vtable2, NODE2) register_known_gctype(cpu, u_vtable, U) register_known_gctype(cpu, jit_virtual_ref_vtable,vrefinfo.JIT_VIRTUAL_REF) register_known_gctype(cpu, intobj_noimmut_vtable, INTOBJ_NOIMMUT) register_known_gctype(cpu, intobj_immut_vtable, INTOBJ_IMMUT) register_known_gctype(cpu, ptrobj_immut_vtable, PTROBJ_IMMUT) namespace = locals()
def get_shadowstackref(root_walker, gctransformer): if hasattr(gctransformer, '_SHADOWSTACKREF'): return gctransformer._SHADOWSTACKREF # Helpers to same virtual address space by limiting to MAX the # number of full shadow stacks. If there are more, we compact # them into a separately-allocated zone of memory of just the right # size. See the comments in the definition of fullstack_cache below. def ll_prepare_free_slot(_unused): """Free up a slot in the array of MAX entries, ready for storing a new shadowstackref. Return the memory of the now-unused full shadowstack. """ index = fullstack_cache[0] if index > 0: return llmemory.NULL # there is already at least one free slot # # make a compact copy in one old entry and return the # original full-sized memory index = -index ll_assert(index > 0, "prepare_free_slot: cache[0] == 0") compacting = lltype.cast_int_to_ptr(SHADOWSTACKREFPTR, fullstack_cache[index]) index += 1 if index >= ShadowStackPool.MAX: index = 1 fullstack_cache[0] = -index # update to the next value in order # compacting.detach() original = compacting.base size = compacting.top - original new = llmemory.raw_malloc(size) if new == llmemory.NULL: return llmemory.NULL llmemory.raw_memcopy(original, new, size) compacting.base = new compacting.top = new + size return original def ll_attach(shadowstackref): """After prepare_free_slot(), store a shadowstackref in that slot.""" index = fullstack_cache[0] ll_assert(index > 0, "fullstack attach: no free slot") fullstack_cache[0] = fullstack_cache[index] fullstack_cache[index] = lltype.cast_ptr_to_int(shadowstackref) ll_assert(shadowstackref.fsindex == 0, "fullstack attach: already one?") shadowstackref.fsindex = index # > 0 def ll_detach(shadowstackref): """Detach a shadowstackref from the array of MAX entries.""" index = shadowstackref.fsindex ll_assert(index > 0, "detach: unattached shadowstackref") ll_assert(fullstack_cache[index] == lltype.cast_ptr_to_int(shadowstackref), "detach: bad fullstack_cache") shadowstackref.fsindex = 0 fullstack_cache[index] = fullstack_cache[0] fullstack_cache[0] = index def ll_rebuild(shadowstackref, fullstack_base): if shadowstackref.fsindex > 0: shadowstackref.detach() return fullstack_base else: # make an expanded copy of the compact shadowstack stored in # 'shadowstackref' and free that compact = shadowstackref.base size = shadowstackref.top - compact shadowstackref.base = fullstack_base shadowstackref.top = fullstack_base + size llmemory.raw_memcopy(compact, fullstack_base, size) llmemory.raw_free(compact) return llmemory.NULL SHADOWSTACKREFPTR = lltype.Ptr(lltype.GcForwardReference()) SHADOWSTACKREF = lltype.GcStruct('ShadowStackRef', ('base', llmemory.Address), ('top', llmemory.Address), ('context', llmemory.Address), ('fsindex', lltype.Signed), rtti=True, adtmeths={'prepare_free_slot': ll_prepare_free_slot, 'attach': ll_attach, 'detach': ll_detach, 'rebuild': ll_rebuild}) SHADOWSTACKREFPTR.TO.become(SHADOWSTACKREF) # Items 1..MAX-1 of the following array can be SHADOWSTACKREF # addresses cast to integer. Or, they are small numbers and they # make up a free list, rooted in item 0, which goes on until # terminated with a negative item. This negative item gives (the # opposite of) the index of the entry we try to remove next. # Initially all items are in this free list and the end is '-1'. fullstack_cache = lltype.malloc(lltype.Array(lltype.Signed), ShadowStackPool.MAX, flavor='raw', immortal=True) for i in range(len(fullstack_cache) - 1): fullstack_cache[i] = i + 1 fullstack_cache[len(fullstack_cache) - 1] = -1 def customtrace(gc, obj, callback, arg): obj = llmemory.cast_adr_to_ptr(obj, SHADOWSTACKREFPTR) index = obj.fsindex if index > 0: # Haaaaaaack: fullstack_cache[] is just an integer, so it # doesn't follow the SHADOWSTACKREF when it moves. But we # know this customtrace() will be called just after the # move. So we fix the fullstack_cache[] now... :-/ fullstack_cache[index] = lltype.cast_ptr_to_int(obj) addr = obj.top start = obj.base while addr != start: addr -= sizeofaddr gc._trace_callback(callback, arg, addr) gc = gctransformer.gcdata.gc assert not hasattr(gc, 'custom_trace_dispatcher') # ^^^ create_custom_trace_funcs() must not run before this gctransformer.translator.rtyper.custom_trace_funcs.append( (SHADOWSTACKREF, customtrace)) def shadowstack_destructor(shadowstackref): if root_walker.stacklet_support: from rpython.rlib import _rffi_stacklet as _c h = shadowstackref.context h = llmemory.cast_adr_to_ptr(h, _c.handle) shadowstackref.context = llmemory.NULL # if shadowstackref.fsindex > 0: shadowstackref.detach() base = shadowstackref.base shadowstackref.base = llmemory.NULL shadowstackref.top = llmemory.NULL llmemory.raw_free(base) # if root_walker.stacklet_support: if h: _c.destroy(h) destrptr = gctransformer.annotate_helper(shadowstack_destructor, [SHADOWSTACKREFPTR], lltype.Void) lltype.attachRuntimeTypeInfo(SHADOWSTACKREF, destrptr=destrptr) gctransformer._SHADOWSTACKREF = SHADOWSTACKREF return SHADOWSTACKREF
class TestARM(LLtypeBackendTest): # for the individual tests see # ====> ../../test/runner_test.py add_loop_instructions = 'ldr; adds; cmp; beq; b;' arch_version = detect_arch_version() if arch_version == 7: bridge_loop_instructions = ('ldr; movw; nop; cmp; bge; ' 'push; movw; movt; push; movw; movt; ' 'blx; movw; movt; bx;') else: bridge_loop_instructions = ( 'ldr; mov; nop; nop; nop; cmp; bge; ' 'push; ldr; mov; ' '[^;]+; ' # inline constant 'push; ldr; mov; ' '[^;]+; ' # inline constant 'blx; ldr; mov; ' '[^;]+; ' # inline constant 'bx;') def get_cpu(self): cpu = CPU(rtyper=None, stats=FakeStats()) cpu.setup_once() return cpu def test_result_is_spilled(self): cpu = self.cpu inp = [InputArgInt(i) for i in range(1, 15)] looptoken = JitCellToken() targettoken = TargetToken() operations = [ ResOperation(rop.LABEL, inp, descr=targettoken), ResOperation(rop.INT_ADD, [inp[0], inp[1]]), ResOperation(rop.INT_ADD, [inp[2], inp[3]]), ResOperation(rop.INT_ADD, [inp[4], inp[5]]), ResOperation(rop.INT_ADD, [inp[6], inp[7]]), ResOperation(rop.INT_ADD, [inp[8], inp[9]]), ResOperation(rop.INT_ADD, [inp[10], inp[11]]), ResOperation(rop.INT_ADD, [inp[12], inp[13]]), ResOperation(rop.INT_ADD, [inp[0], inp[1]]), ResOperation(rop.INT_ADD, [inp[2], inp[3]]), ResOperation(rop.INT_ADD, [inp[4], inp[5]]), ResOperation(rop.INT_ADD, [inp[6], inp[7]]), ResOperation(rop.INT_ADD, [inp[8], inp[9]]), ResOperation(rop.INT_ADD, [inp[10], inp[11]]), ResOperation(rop.INT_ADD, [inp[12], inp[13]]), ResOperation(rop.GUARD_FALSE, [inp[1]], descr=BasicFailDescr(1)), ResOperation(rop.FINISH, [inp[1]], descr=BasicFinalDescr(1)), ] operations[-2].setfailargs(operations[1:15]) cpu.compile_loop(inp, operations, looptoken) args = [i for i in range(1, 15)] deadframe = self.cpu.execute_token(looptoken, *args) output = [ self.cpu.get_int_value(deadframe, i - 1) for i in range(1, 15) ] expected = [3, 7, 11, 15, 19, 23, 27, 3, 7, 11, 15, 19, 23, 27] assert output == expected def test_redirect_call_assembler2(self): def assembler_helper(deadframe, virtualizable): x = self.cpu.get_int_value(deadframe, 0) assert x == 11 return 7 FUNCPTR = lltype.Ptr( lltype.FuncType([llmemory.GCREF, llmemory.GCREF], lltype.Signed)) class FakeJitDriverSD: index_of_virtualizable = -1 _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper) assembler_helper_adr = llmemory.cast_ptr_to_adr( _assembler_helper_ptr) FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof( lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)), [lltype.Signed], lltype.Signed, EffectInfo.MOST_GENERAL) lt1, lt2, lt3 = [JitCellToken() for x in range(3)] lt2.outermost_jitdriver_sd = FakeJitDriverSD() loop1 = parse(''' [i0] i1 = call_assembler_i(i0, descr=lt2) guard_not_forced()[] finish(i1) ''', namespace=locals()) loop2 = parse(''' [i0] i1 = int_add(i0, 1) finish(i1) ''') loop3 = parse(''' [i0] i1 = int_sub(i0, 1) finish(i1) ''') self.cpu.compile_loop(loop2.inputargs, loop2.operations, lt2) self.cpu.compile_loop(loop3.inputargs, loop3.operations, lt3) self.cpu.compile_loop(loop1.inputargs, loop1.operations, lt1) df = self.cpu.execute_token(lt1, 10) assert self.cpu.get_int_value(df, 0) == 7 self.cpu.redirect_call_assembler(lt2, lt3) df = self.cpu.execute_token(lt1, 12) assert self.cpu.get_int_value(df, 0) == 7 SFloat = lltype.GcForwardReference() SFloat.become( lltype.GcStruct('SFloat', ('parent', rclass.OBJECT), ('v1', lltype.Signed), ('v2', lltype.Signed), ('v3', lltype.Signed), ('v4', lltype.Signed), ('v5', lltype.Signed), ('v6', lltype.Signed), ('v7', lltype.Signed), ('v8', lltype.Signed), ('v9', lltype.Signed), ('v10', lltype.Signed), ('v11', lltype.Signed), ('v12', lltype.Signed), ('v13', lltype.Signed), ('v14', lltype.Signed), ('v15', lltype.Signed), ('v16', lltype.Signed), ('v17', lltype.Signed), ('v18', lltype.Signed), ('v19', lltype.Signed), ('v20', lltype.Signed), ('w1', lltype.Signed), ('w2', lltype.Signed), ('w3', lltype.Signed), ('w4', lltype.Signed), ('w5', lltype.Signed), ('w6', lltype.Signed), ('w7', lltype.Signed), ('w8', lltype.Signed), ('w9', lltype.Signed), ('w10', lltype.Signed), ('w11', lltype.Signed), ('w12', lltype.Signed), ('w13', lltype.Signed), ('w14', lltype.Signed), ('w15', lltype.Signed), ('w16', lltype.Signed), ('w17', lltype.Signed), ('w18', lltype.Signed), ('w19', lltype.Signed), ('w20', lltype.Signed), ('x1', lltype.Signed), ('x2', lltype.Signed), ('x3', lltype.Signed), ('x4', lltype.Signed), ('x5', lltype.Signed), ('x6', lltype.Signed), ('x7', lltype.Signed), ('x8', lltype.Signed), ('x9', lltype.Signed), ('x10', lltype.Signed), ('x11', lltype.Signed), ('x12', lltype.Signed), ('x13', lltype.Signed), ('x14', lltype.Signed), ('x15', lltype.Signed), ('x16', lltype.Signed), ('x17', lltype.Signed), ('x18', lltype.Signed), ('x19', lltype.Signed), ('x20', lltype.Signed), ('y1', lltype.Signed), ('y2', lltype.Signed), ('y3', lltype.Signed), ('y4', lltype.Signed), ('y5', lltype.Signed), ('y6', lltype.Signed), ('y7', lltype.Signed), ('y8', lltype.Signed), ('y9', lltype.Signed), ('y10', lltype.Signed), ('y11', lltype.Signed), ('y12', lltype.Signed), ('y13', lltype.Signed), ('y14', lltype.Signed), ('y15', lltype.Signed), ('y16', lltype.Signed), ('y17', lltype.Signed), ('y18', lltype.Signed), ('y19', lltype.Signed), ('y20', lltype.Signed), ('float', lltype.Float))) TFloat = lltype.GcStruct('TFloat', ('parent', SFloat), ('next', lltype.Ptr(SFloat))) def test_float_field(self): if not self.cpu.supports_floats: py.test.skip('requires floats') t_box, T_box, _ = self.alloc_instance(self.TFloat) floatdescr = self.cpu.fielddescrof(self.SFloat, 'float') self.execute_operation(rop.SETFIELD_GC, [t_box, boxfloat(3.4)], 'void', descr=floatdescr) res = self.execute_operation(rop.GETFIELD_GC_F, [t_box], 'float', descr=floatdescr) assert longlong.getrealfloat(res) == 3.4 # self.execute_operation(rop.SETFIELD_GC, [t_box, constfloat(-3.6)], 'void', descr=floatdescr) res = self.execute_operation(rop.GETFIELD_GC_F, [t_box], 'float', descr=floatdescr) assert longlong.getrealfloat(res) == -3.6 def test_compile_loop_many_int_args(self): for numargs in range(2, 30): ops = [] arglist = "[%s]\n" % ", ".join(["i%d" % i for i in range(numargs)]) ops.append(arglist) arg1 = 0 arg2 = 1 res = numargs for i in range(numargs - 1): op = "i%d = int_add(i%d, i%d)\n" % (res, arg1, arg2) arg1 = res res += 1 arg2 += 1 ops.append(op) ops.append("finish(i%d)" % (res - 1)) ops = "".join(ops) loop = parse(ops) looptoken = JitCellToken() self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) ARGS = [lltype.Signed] * numargs RES = lltype.Signed args = [i + 1 for i in range(numargs)] deadframe = self.cpu.execute_token(looptoken, *args) assert self.cpu.get_int_value(deadframe, 0) == sum(args) def test_debugger_on(self): py.test.skip("I don't care for now") from rpython.rlib import debug targettoken, preambletoken = TargetToken(), TargetToken() loop = """ [i0] label(i0, descr=preambletoken) debug_merge_point('xyz', 0) i1 = int_add(i0, 1) i2 = int_ge(i1, 10) guard_false(i2) [] label(i1, descr=targettoken) debug_merge_point('xyz', 0) i11 = int_add(i1, 1) i12 = int_ge(i11, 10) guard_false(i12) [] jump(i11, descr=targettoken) """ ops = parse(loop, namespace={ 'targettoken': targettoken, 'preambletoken': preambletoken }) debug._log = dlog = debug.DebugLog() try: self.cpu.assembler.set_debug(True) looptoken = JitCellToken() self.cpu.compile_loop(ops.inputargs, ops.operations, looptoken) self.cpu.execute_token(looptoken, 0) # check debugging info struct = self.cpu.assembler.loop_run_counters[0] assert struct.i == 1 struct = self.cpu.assembler.loop_run_counters[1] assert struct.i == 1 struct = self.cpu.assembler.loop_run_counters[2] assert struct.i == 9 self.cpu.finish_once() finally: debug._log = None l0 = ('debug_print', 'entry -1:1') l1 = ('debug_print', preambletoken.repr_of_descr() + ':1') l2 = ('debug_print', targettoken.repr_of_descr() + ':9') assert ('jit-backend-counts', [l0, l1, l2]) in dlog def test_label_float_in_reg_and_on_stack(self): targettoken = TargetToken() ops = """ [i0, f3] i2 = same_as_i(i0) # but forced to be in a register force_spill(i2) force_spill(f3) f4 = float_add(f3, 5.0) label(f3, f4, descr=targettoken) force_spill(f3) f5 = same_as_f(f3) # but forced to be in a register finish(f5) """ faildescr = BasicFailDescr(2) loop = parse(ops, self.cpu, namespace=locals()) looptoken = JitCellToken() info = self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) ops2 = """ [i0, f1] i1 = same_as_i(i0) f2 = same_as_f(f1) f3 = float_add(f1, 10.0) force_spill(f3) force_spill(i1) f4 = float_add(f3, f1) jump(f3, f4, descr=targettoken) """ loop2 = parse(ops2, self.cpu, namespace=locals()) looptoken2 = JitCellToken() info = self.cpu.compile_loop(loop2.inputargs, loop2.operations, looptoken2) deadframe = self.cpu.execute_token(looptoken, -9, longlong.getfloatstorage(-13.5)) res = longlong.getrealfloat(self.cpu.get_float_value(deadframe, 0)) assert res == -13.5 # deadframe = self.cpu.execute_token(looptoken2, -9, longlong.getfloatstorage(-13.5)) res = longlong.getrealfloat(self.cpu.get_float_value(deadframe, 0)) assert res == -3.5
[<length> <virtual> <vref> <virtual> <vref>] for virtualrefs [<pc> <jitcode> <numb> <numb> <numb>] the frames [<pc> <jitcode> <numb> <numb>] ... until the size of the resume section # ----- optimization section <more code> further sections according to bridgeopt.py """ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib import objectmodel NUMBERINGP = lltype.Ptr(lltype.GcForwardReference()) NUMBERING = lltype.GcStruct('Numbering', ('code', lltype.Array(rffi.UCHAR))) NUMBERINGP.TO.become(NUMBERING) NULL_NUMBER = lltype.nullptr(NUMBERING) def append_numbering(lst, item): item = rffi.cast(lltype.Signed, item) item *= 2 if item < 0: item = -1 - item assert item >= 0 if item < 2**7: lst.append(rffi.cast(rffi.UCHAR, item)) elif item < 2**14:
def jitframe_allocate(frame_info): rgc.register_custom_trace_hook(JITFRAME, lambda_jitframe_trace) frame = lltype.malloc(JITFRAME, frame_info.jfi_frame_depth) frame.jf_frame_info = frame_info return frame def jitframe_resolve(frame): while frame.jf_forward: frame = frame.jf_forward return frame JITFRAME = lltype.GcForwardReference() JITFRAME.become( lltype.GcStruct( 'JITFRAME', ('jf_frame_info', lltype.Ptr(JITFRAMEINFO)), # Once the execute_token() returns, the field 'jf_descr' stores the # descr of the last executed operation (either a GUARD, or FINISH). # This field is also set immediately before doing CALL_MAY_FORCE # or CALL_ASSEMBLER. ('jf_descr', llmemory.GCREF), # guard_not_forced descr ('jf_force_descr', llmemory.GCREF), # a map of GC pointers ('jf_gcmap', lltype.Ptr(GCMAP)), # For the front-end: a GCREF for the savedata
import py from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.memory.gc.incminimark import IncrementalMiniMarkGC from rpython.memory.gc.test.test_direct import BaseDirectGCTest from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT PYOBJ_HDR = IncrementalMiniMarkGC.PYOBJ_HDR PYOBJ_HDR_PTR = IncrementalMiniMarkGC.PYOBJ_HDR_PTR S = lltype.GcForwardReference() S.become( lltype.GcStruct('S', ('x', lltype.Signed), ('prev', lltype.Ptr(S)), ('next', lltype.Ptr(S)))) class TestRawRefCount(BaseDirectGCTest): GCClass = IncrementalMiniMarkGC def _collect(self, major, expected_trigger=0): if major: self.gc.collect() else: self.gc._minor_collection() count1 = len(self.trigger) self.gc.rrc_invoke_callback() count2 = len(self.trigger) assert count2 - count1 == expected_trigger def _rawrefcount_pair(self, intval,
def get_ll_dict(DICTKEY, DICTVALUE, get_custom_eq_hash=None, DICT=None, ll_fasthash_function=None, ll_hash_function=None, ll_eq_function=None, method_cache={}, dummykeyobj=None, dummyvalueobj=None, rtyper=None): # get the actual DICT type. if DICT is None, it's created, otherwise # forward reference is becoming DICT if DICT is None: DICT = lltype.GcForwardReference() # compute the shape of the DICTENTRY structure entryfields = [] entrymeths = { 'allocate': lltype.typeMethod(_ll_malloc_entries), 'delete': _ll_free_entries, 'must_clear_key': (isinstance(DICTKEY, lltype.Ptr) and DICTKEY._needsgc()), 'must_clear_value': (isinstance(DICTVALUE, lltype.Ptr) and DICTVALUE._needsgc()), } if getattr(ll_eq_function, 'no_direct_compare', False): entrymeths['no_direct_compare'] = True # * the key entryfields.append(("key", DICTKEY)) # * the state of the entry - trying to encode it as dummy objects if dummykeyobj: # all the state can be encoded in the key entrymeths['dummy_obj'] = dummykeyobj entrymeths['valid'] = ll_valid_from_key entrymeths['mark_deleted'] = ll_mark_deleted_in_key # the key is overwritten by 'dummy' when the entry is deleted entrymeths['must_clear_key'] = False elif dummyvalueobj: # all the state can be encoded in the value entrymeths['dummy_obj'] = dummyvalueobj entrymeths['valid'] = ll_valid_from_value entrymeths['mark_deleted'] = ll_mark_deleted_in_value # value is overwritten by 'dummy' when entry is deleted entrymeths['must_clear_value'] = False else: # we need a flag to know if the entry was ever used entryfields.append(("f_valid", lltype.Bool)) entrymeths['valid'] = ll_valid_from_flag entrymeths['mark_deleted'] = ll_mark_deleted_in_flag # * the value entryfields.append(("value", DICTVALUE)) if ll_fasthash_function is None: entryfields.append(("f_hash", lltype.Signed)) entrymeths['hash'] = ll_hash_from_cache else: entrymeths['hash'] = ll_hash_recomputed entrymeths['fasthashfn'] = ll_fasthash_function # Build the lltype data structures DICTENTRY = lltype.Struct("odictentry", *entryfields) DICTENTRYARRAY = lltype.GcArray(DICTENTRY, adtmeths=entrymeths) fields = [("num_live_items", lltype.Signed), ("num_ever_used_items", lltype.Signed), ("resize_counter", lltype.Signed), ("indexes", llmemory.GCREF), ("lookup_function_no", lltype.Signed), ("entries", lltype.Ptr(DICTENTRYARRAY))] if get_custom_eq_hash is not None: r_rdict_eqfn, r_rdict_hashfn = get_custom_eq_hash() fields.extend([("fnkeyeq", r_rdict_eqfn.lowleveltype), ("fnkeyhash", r_rdict_hashfn.lowleveltype)]) adtmeths = { 'keyhash': ll_keyhash_custom, 'keyeq': ll_keyeq_custom, 'r_rdict_eqfn': r_rdict_eqfn, 'r_rdict_hashfn': r_rdict_hashfn, 'paranoia': True, } else: # figure out which functions must be used to hash and compare ll_keyhash = ll_hash_function ll_keyeq = ll_eq_function ll_keyhash = lltype.staticAdtMethod(ll_keyhash) if ll_keyeq is not None: ll_keyeq = lltype.staticAdtMethod(ll_keyeq) adtmeths = { 'keyhash': ll_keyhash, 'keyeq': ll_keyeq, 'paranoia': False, } adtmeths['KEY'] = DICTKEY adtmeths['VALUE'] = DICTVALUE adtmeths['lookup_function'] = lltype.staticAdtMethod( ll_call_lookup_function) adtmeths['allocate'] = lltype.typeMethod(_ll_malloc_dict) DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths, *fields)) return DICT