def chooser(x): s = lltype.malloc(STRUCT, flavor="raw") if x: s.bar = llhelper(FTPTR, a_f.make_func()) else: s.bar = llhelper(FTPTR, a_g.make_func()) return f(s)
def finish_type_2(space, pto, w_obj): """ Sets up other attributes, when the interpreter type has been created. """ pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w)) base = pto.c_tp_base if base: inherit_special(space, pto, base) for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)): inherit_slots(space, pto, w_base) if not pto.c_tp_setattro: from pypy.module.cpyext.object import PyObject_GenericSetAttr pto.c_tp_setattro = llhelper( PyObject_GenericSetAttr.api_func.functype, PyObject_GenericSetAttr.api_func.get_wrapper(space)) if not pto.c_tp_getattro: from pypy.module.cpyext.object import PyObject_GenericGetAttr pto.c_tp_getattro = llhelper( PyObject_GenericGetAttr.api_func.functype, PyObject_GenericGetAttr.api_func.get_wrapper(space)) if w_obj.is_cpytype(): Py_DecRef(space, pto.c_tp_dict) w_dict = w_obj.getdict(space) pto.c_tp_dict = make_ref(space, w_dict)
def setup_buffer_buffer_procs(space, pto): c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True) lltype.render_immortal(c_buf) c_buf.c_bf_getsegcount = llhelper(str_segcount.api_func.functype, str_segcount.api_func.get_wrapper(space)) c_buf.c_bf_getreadbuffer = llhelper(buf_getreadbuffer.api_func.functype, buf_getreadbuffer.api_func.get_wrapper(space)) pto.c_tp_as_buffer = c_buf
def h(x, y, z): s = malloc(S) s.x = x s.y = y fptr = llhelper(F, f) gptr = llhelper(G, g) assert typeOf(fptr) == F return fptr(s, z)+fptr(s, z*2)+gptr(s)
def type_attach(space, py_obj, w_type): """ Fills a newly allocated PyTypeObject from an existing type. """ from pypy.module.cpyext.object import PyObject_Del assert isinstance(w_type, W_TypeObject) pto = rffi.cast(PyTypeObjectPtr, py_obj) typedescr = get_typedescr(w_type.layout.typedef) # dealloc pto.c_tp_dealloc = typedescr.get_dealloc(space) # buffer protocol if space.is_w(w_type, space.w_str): setup_string_buffer_procs(space, pto) if space.is_w(w_type, space.w_buffer): setup_buffer_buffer_procs(space, pto) pto.c_tp_free = llhelper(PyObject_Del.api_func.functype, PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) if pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE: w_typename = space.getattr(w_type, space.wrap('__name__')) heaptype = rffi.cast(PyHeapTypeObject, pto) heaptype.c_ht_name = make_ref(space, w_typename) from pypy.module.cpyext.bytesobject import PyString_AsString pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name) else: pto.c_tp_name = rffi.str2charp(w_type.name) # uninitialized fields: # c_tp_print, c_tp_getattr, c_tp_setattr # XXX implement # c_tp_compare and the following fields (see http://docs.python.org/c-api/typeobj.html ) w_base = best_base(space, w_type.bases_w) pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base)) builder = space.fromcache(StaticObjectBuilder) if builder.cpyext_type_init is not None: builder.cpyext_type_init.append((pto, w_type)) else: finish_type_1(space, pto) finish_type_2(space, pto, w_type) pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct) if pto.c_tp_base: if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize: pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize # will be filled later on with the correct value # may not be 0 if space.is_w(w_type, space.w_object): pto.c_tp_new = rffi.cast(newfunc, 1) update_all_slots(space, w_type, pto) pto.c_tp_flags |= Py_TPFLAGS_READY return pto
def _build_release_gil(self, gcrootmap): if gcrootmap is None or gcrootmap.is_shadow_stack: reacqgil_func = llhelper(self._REACQGIL0_FUNC, self._reacquire_gil_shadowstack) self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func) else: reacqgil_func = llhelper(self._REACQGIL2_FUNC, self._reacquire_gil_asmgcc) self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func)
def _setup_frame_realloc(self, translate_support_code): FUNC_TP = lltype.Ptr(lltype.FuncType([llmemory.GCREF, lltype.Signed], llmemory.GCREF)) base_ofs = self.get_baseofs_of_frame_field() def realloc_frame(frame, size): try: if not we_are_translated(): assert not self._exception_emulator[0] frame = lltype.cast_opaque_ptr(jitframe.JITFRAMEPTR, frame) if size > frame.jf_frame_info.jfi_frame_depth: # update the frame_info size, which is for whatever reason # not up to date frame.jf_frame_info.update_frame_depth(base_ofs, size) new_frame = jitframe.JITFRAME.allocate(frame.jf_frame_info) frame.jf_forward = new_frame i = 0 while i < len(frame.jf_frame): new_frame.jf_frame[i] = frame.jf_frame[i] frame.jf_frame[i] = 0 i += 1 new_frame.jf_savedata = frame.jf_savedata new_frame.jf_guard_exc = frame.jf_guard_exc # all other fields are empty llop.gc_writebarrier(lltype.Void, new_frame) return lltype.cast_opaque_ptr(llmemory.GCREF, new_frame) except Exception as e: print "Unhandled exception", e, "in realloc_frame" return lltype.nullptr(llmemory.GCREF.TO) def realloc_frame_crash(frame, size): print "frame", frame, "size", size return lltype.nullptr(llmemory.GCREF.TO) if not translate_support_code: fptr = llhelper(FUNC_TP, realloc_frame) else: FUNC = FUNC_TP.TO args_s = [lltype_to_annotation(ARG) for ARG in FUNC.ARGS] s_result = lltype_to_annotation(FUNC.RESULT) mixlevelann = MixLevelHelperAnnotator(self.rtyper) graph = mixlevelann.getgraph(realloc_frame, args_s, s_result) fptr = mixlevelann.graph2delayed(graph, FUNC) mixlevelann.finish() self.realloc_frame = heaptracker.adr2int(llmemory.cast_ptr_to_adr(fptr)) if not translate_support_code: fptr = llhelper(FUNC_TP, realloc_frame_crash) else: FUNC = FUNC_TP.TO args_s = [lltype_to_annotation(ARG) for ARG in FUNC.ARGS] s_result = lltype_to_annotation(FUNC.RESULT) mixlevelann = MixLevelHelperAnnotator(self.rtyper) graph = mixlevelann.getgraph(realloc_frame_crash, args_s, s_result) fptr = mixlevelann.graph2delayed(graph, FUNC) mixlevelann.finish() self.realloc_frame_crash = heaptracker.adr2int(llmemory.cast_ptr_to_adr(fptr))
def setup_string_buffer_procs(space, pto): c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True) lltype.render_immortal(c_buf) c_buf.c_bf_getsegcount = llhelper(str_segcount.api_func.functype, str_segcount.api_func.get_wrapper(space)) c_buf.c_bf_getreadbuffer = llhelper(str_getreadbuffer.api_func.functype, str_getreadbuffer.api_func.get_wrapper(space)) c_buf.c_bf_getcharbuffer = llhelper(str_getcharbuffer.api_func.functype, str_getcharbuffer.api_func.get_wrapper(space)) pto.c_tp_as_buffer = c_buf pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
def invoke_around_extcall(before, after): """Call before() before any external function call, and after() after. At the moment only one pair before()/after() can be registered at a time. """ # NOTE: the hooks are cleared during translation! To be effective # in a compiled program they must be set at run-time. from rpython.rtyper.lltypesystem import rffi rffi.aroundstate.before = before rffi.aroundstate.after = after # the 'aroundstate' contains regular function and not ll pointers to them, # but let's call llhelper() anyway to force their annotation from rpython.rtyper.annlowlevel import llhelper llhelper(rffi.AroundFnPtr, before) llhelper(rffi.AroundFnPtr, after)
def vmprof_execute_code(name, get_code_fn, result_class=None, _hack_update_stack_untranslated=False): """Decorator to be used on the function that interprets a code object. 'name' must be a unique name. 'get_code_fn(*args)' is called to extract the code object from the arguments given to the decorated function. 'result_class' is ignored (backward compatibility). """ if _hack_update_stack_untranslated: from rpython.rtyper.annlowlevel import llhelper enter_code = llhelper(lltype.Ptr( lltype.FuncType([lltype.Signed], cintf.PVMPROFSTACK)), cintf.enter_code) leave_code = llhelper(lltype.Ptr( lltype.FuncType([cintf.PVMPROFSTACK], lltype.Void)), cintf.leave_code) else: enter_code = cintf.enter_code leave_code = cintf.leave_code def decorate(func): try: _get_vmprof() except cintf.VMProfPlatformUnsupported: return func @jit.oopspec("rvmprof.jitted(unique_id)") def decorated_jitted_function(unique_id, *args): return func(*args) def decorated_function(*args): unique_id = get_code_fn(*args)._vmprof_unique_id unique_id = rffi.cast(lltype.Signed, unique_id) # ^^^ removes the "known non-negative" hint for annotation if not jit.we_are_jitted(): x = enter_code(unique_id) try: return func(*args) finally: leave_code(x) else: return decorated_jitted_function(unique_id, *args) decorated_function.__name__ = func.__name__ + '_rvmprof' return decorated_function return decorate
def setup_method(self, meth): visited = [] def helper(): trace = [] stack = cintf.vmprof_tl_stack.getraw() while stack: trace.append((stack.c_kind, stack.c_value)) stack = stack.c_next visited.append(trace) llfn = llhelper(lltype.Ptr(lltype.FuncType([], lltype.Void)), helper) class CodeObj(object): def __init__(self, name): self.name = name def get_code_fn(codes, code, arg, c): return code def get_name(code): return "foo" _get_vmprof().use_weaklist = False register_code_object_class(CodeObj, get_name) self.misc = visited, llfn, CodeObj, get_code_fn, get_name
def build_slot_tp_function(space, typedef, name): w_type = space.gettypeobject(typedef) if name == 'tp_setattro': setattr_fn = w_type.getdictvalue(space, '__setattr__') delattr_fn = w_type.getdictvalue(space, '__delattr__') if setattr_fn is None: return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1) # XXX should be header=None @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: space.call_function(setattr_fn, w_self, w_name, w_value) else: space.call_function(delattr_fn, w_self, w_name) return 0 api_func = slot_tp_setattro.api_func elif name == 'tp_getattro': getattr_fn = w_type.getdictvalue(space, '__getattribute__') if getattr_fn is None: return @cpython_api([PyObject, PyObject], PyObject) @func_renamer("cpyext_tp_getattro_%s" % (typedef.name,)) def slot_tp_getattro(space, w_self, w_name): return space.call_function(getattr_fn, w_self, w_name) api_func = slot_tp_getattro.api_func else: return return lambda: llhelper(api_func.functype, api_func.get_wrapper(space))
def define_custom_trace(cls): from rpython.rtyper.annlowlevel import llhelper from rpython.rtyper.lltypesystem import llmemory # S = lltype.GcStruct('S', ('x', llmemory.Address), rtti=True) T = lltype.GcStruct('T', ('z', lltype.Signed)) offset_of_x = llmemory.offsetof(S, 'x') def customtrace(obj, prev): if not prev: return obj + offset_of_x else: return llmemory.NULL CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], llmemory.Address) customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace) lltype.attachRuntimeTypeInfo(S, customtraceptr=customtraceptr) # def setup(): s1 = lltype.malloc(S) tx = lltype.malloc(T) tx.z = 4243 s1.x = llmemory.cast_ptr_to_adr(tx) return s1 def f(): s1 = setup() llop.gc__collect(lltype.Void) return llmemory.cast_adr_to_ptr(s1.x, lltype.Ptr(T)).z return f
def test_call_many_float_args(self): from rpython.rtyper.annlowlevel import llhelper from rpython.jit.codewriter.effectinfo import EffectInfo seen = [] def func(*args): seen.append(args) return -42 F = lltype.Float I = lltype.Signed FUNC = self.FuncType([F] * 7 + [I] + [F] * 7 + [I] + [F], I) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) cpu = self.cpu calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) argvals = [.1 * i for i in range(15)] argvals.insert(7, 77) argvals.insert(15, 1515) argvals = tuple(argvals) argboxes = [] for x in argvals: if isinstance(x, float): argboxes.append(InputArgFloat(x)) else: argboxes.append(InputArgInt(x)) res = self.execute_operation(rop.CALL_I, [funcbox] + argboxes, 'int', descr=calldescr) assert res == -42 assert seen == [argvals]
def get_tp_function(space, typedef): @cpython_api([], lltype.Signed, error=-1, external=False) def slot_tp_function(space): return typedef.value api_func = slot_tp_function.api_func return lambda: llhelper(api_func.functype, api_func.get_wrapper(space))
def h(x, y, z): s = malloc(S) s.x = x s.y = y fptr = llhelper(F, myfuncs[z]) assert typeOf(fptr) == F return fptr(s)
def entry_point(argv): ll_dealloc_trigger_callback = llhelper(FTYPE, dealloc_trigger) rawrefcount.init(ll_dealloc_trigger_callback) ob, p = make_p() if state.seen != []: print "OB COLLECTED REALLY TOO SOON" return 1 rgc.collect() if state.seen != []: print "OB COLLECTED TOO SOON" return 1 objectmodel.keepalive_until_here(p) p = None rgc.collect() if state.seen != [1]: print "OB NOT COLLECTED" return 1 if rawrefcount.next_dead(PyObject) != ob: print "NEXT_DEAD != OB" return 1 if rawrefcount.next_dead(PyObject) != lltype.nullptr(PyObjectS): print "NEXT_DEAD second time != NULL" return 1 if rawrefcount.to_obj(W_Root, ob) is not None: print "to_obj(dead) is not None?" return 1 rawrefcount.mark_deallocating(w_marker, ob) if rawrefcount.to_obj(W_Root, ob) is not w_marker: print "to_obj(marked-dead) is not w_marker" return 1 print "OK!" lltype.free(ob, flavor='raw') return 0
def produce_into(self, builder, r): fail_subset = builder.subset_of_intvars(r) v_cond = builder.get_bool_var(r) subset = builder.subset_of_intvars(r)[:4] for i in range(len(subset)): if r.random() < 0.35: subset[i] = ConstInt(r.random_integer()) # seen = [] def call_me(*args): if len(seen) == 0: seen.append(args) else: assert seen[0] == args # TP = lltype.FuncType([lltype.Signed] * len(subset), lltype.Void) ptr = llhelper(lltype.Ptr(TP), call_me) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [v_cond, c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None, descr=builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op)
def test_float_hf_call_mixed(self): if not self.cpu.supports_floats: py.test.skip("requires floats") cpu = self.cpu callargs = [] def func(f0, f1, f2, f3, f4, f5, f6, i0, f7, i1, f8, f9): callargs.append(zip(range(12), [f0, f1, f2, f3, f4, f5, f6, i0, f7, i1, f8, f9])) return f0 + f1 + f2 + f3 + f4 + f5 + f6 + float(i0 + i1) + f7 + f8 + f9 F = lltype.Float I = lltype.Signed FUNC = self.FuncType([F] * 7 + [I] + [F] + [I] + [F] * 2, F) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) args = [boxfloat(0.1) for i in range(7)] + [BoxInt(1), boxfloat(0.2), BoxInt(2), boxfloat(0.3), boxfloat(0.4)] res = self.execute_operation(rop.CALL, [funcbox] + args, "float", descr=calldescr) for i, j in enumerate(callargs[0]): box = args[i] if box.type == "f": assert (i, args[i].getfloat()) == j else: assert (i, args[i].getint()) == j assert abs(res.getfloat() - 4.6) < 0.0001
def define_custom_trace(cls): from rpython.rtyper.annlowlevel import llhelper # S = lltype.GcStruct('S', ('x', llmemory.Address), rtti=True) offset_of_x = llmemory.offsetof(S, 'x') def customtrace(obj, prev): if not prev: return obj + offset_of_x else: return llmemory.NULL CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], llmemory.Address) customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace) lltype.attachRuntimeTypeInfo(S, customtraceptr=customtraceptr) # def setup(): s = lltype.nullptr(S) for i in range(10000): t = lltype.malloc(S) t.x = llmemory.cast_ptr_to_adr(s) s = t return s def measure_length(s): res = 0 while s: res += 1 s = llmemory.cast_adr_to_ptr(s.x, lltype.Ptr(S)) return res def f(n): s1 = setup() llop.gc__collect(lltype.Void) return measure_length(s1) return f
def test_shadowstack_cond_call(self): cpu = self.cpu cpu.gc_ll_descr.init_nursery(100) cpu.setup_once() def check(i, frame): frame = lltype.cast_opaque_ptr(JITFRAMEPTR, frame) assert frame.jf_gcmap[0] # is not empty is good enough CHECK = lltype.FuncType([lltype.Signed, llmemory.GCREF], lltype.Void) checkptr = llhelper(lltype.Ptr(CHECK), check) checkdescr = cpu.calldescrof(CHECK, CHECK.ARGS, CHECK.RESULT, EffectInfo.MOST_GENERAL) loop = self.parse(""" [i0, p0] p = force_token() cond_call(i0, ConstClass(funcptr), i0, p, descr=calldescr) guard_true(i0, descr=faildescr) [p0] """, namespace={ 'faildescr': BasicFailDescr(), 'funcptr': checkptr, 'calldescr': checkdescr, }) token = JitCellToken() cpu.compile_loop(loop.inputargs, loop.operations, token) S = self.S s = lltype.malloc(S) cpu.execute_token(token, 1, s)
def test_shadowstack_collecting_call_float(self): cpu = self.cpu def float_return(i, f): # mark frame for write barrier frame = rffi.cast(lltype.Ptr(JITFRAME), i) frame.hdr |= 1 return 1.2 + f FUNC = lltype.FuncType([lltype.Signed, lltype.Float], lltype.Float) fptr = llhelper(lltype.Ptr(FUNC), float_return) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) loop = self.parse(""" [f0] i = force_token() f1 = call(ConstClass(fptr), i, f0, descr=calldescr) finish(f1, descr=finaldescr) """, namespace={'fptr': fptr, 'calldescr': calldescr, 'finaldescr': BasicFinalDescr(1)}) token = JitCellToken() cpu.gc_ll_descr.init_nursery(20) cpu.setup_once() cpu.compile_loop(loop.inputargs, loop.operations, token) arg = longlong.getfloatstorage(2.3) frame = cpu.execute_token(token, arg) ofs = cpu.get_baseofs_of_frame_field() f = cpu.read_float_at_mem(frame, ofs) f = longlong.getrealfloat(f) assert f == 2.3 + 1.2
def test_call_function(self): functype = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) call_addr = rffi.cast(lltype.Signed, llhelper(functype, func)) a = PPCBuilder() # NOW EXPLICITLY: # # - Load the address of the function to call into a register x # - Move the content of this register x into CTR # - Set the LR manually (or with bctrl) # - Do jump a.li(3, 50) if IS_PPC_32: a.load_imm(r10, call_addr) elif IS_BIG_ENDIAN: # load the 3-words descriptor a.load_from_addr(r10, call_addr) a.load_from_addr(r2, call_addr + WORD) a.load_from_addr(r11, call_addr + 2 * WORD) else: # no descriptor on little-endian, but the ABI says r12 must # contain the function pointer a.load_imm(r10, call_addr) a.mr(12, 10) a.mtctr(10) a.bctr() a.blr() f = a.get_assembler_function() assert f() == 65
def test_call_argument_spilling(self): # bug when we have a value in r0, that is overwritten by an argument # and needed after the call, so that the register gets spilled after it # was overwritten with the argument to the call def func(a): return a + 16 I = lltype.Signed FUNC = self.FuncType([I], I) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(self.cpu, func_ptr) args = ", ".join(["i%d" % i for i in range(11)]) ops = """ [%s] i99 = call(ConstClass(func_ptr), 22, descr=calldescr) guard_true(i0) [%s, i99] finish()""" % ( args, args, ) loop = parse(ops, namespace=locals()) looptoken = JitCellToken() self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) args = [x for x in range(11)] deadframe = self.cpu.execute_token(looptoken, *args) for x in range(11): assert self.cpu.get_int_value(deadframe, x) == x assert self.cpu.get_int_value(deadframe, 11) == 38
def getInterpreterProxy(): if not IProxy.vm_initialized: vm_proxy = lltype.malloc(VirtualMachine, flavor='raw') for func_name, signature, func in proxy_functions: setattr(vm_proxy, func_name, llhelper(signature, func)) IProxy.vm_proxy = vm_proxy IProxy.vm_initialized = True return IProxy.vm_proxy
def test_call_python_func(self): functype = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) call_addr = rffi.cast(lltype.Signed, llhelper(functype, callme)) self.a.gen_func_prolog() self.a.mc.MOV_ri(r.r0.value, 123) self.a.mc.BL(call_addr) self.a.gen_func_epilog() assert run_asm(self.a) == 133
def helper_func(self, FUNCPTR, func): if not self.cpu.translate_support_code: return llhelper(FUNCPTR, func) FUNC = FUNCPTR.TO args_s = [annmodel.lltype_to_annotation(ARG) for ARG in FUNC.ARGS] s_result = annmodel.lltype_to_annotation(FUNC.RESULT) graph = self.annhelper.getgraph(func, args_s, s_result) return self.annhelper.graph2delayed(graph, FUNC)
def test_call_aligned_with_spilled_values(self): cpu = self.cpu if not cpu.supports_floats: py.test.skip('requires floats') def func(*args): return float(sum(args)) F = lltype.Float I = lltype.Signed floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] ints = [7, 11, 23, 13, -42, 1111, 95, 1] for case in range(256): local_floats = list(floats) local_ints = list(ints) args = [] spills = [] funcargs = [] float_count = 0 int_count = 0 for i in range(8): if case & (1<<i): args.append('f%d' % float_count) spills.append('force_spill(f%d)' % float_count) float_count += 1 funcargs.append(F) else: args.append('i%d' % int_count) spills.append('force_spill(i%d)' % int_count) int_count += 1 funcargs.append(I) arguments = ', '.join(args) spill_ops = '\n'.join(spills) FUNC = self.FuncType(funcargs, F) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) ops = '[%s]\n' % arguments ops += '%s\n' % spill_ops ops += 'f99 = call_f(ConstClass(func_ptr), %s, descr=calldescr)\n' % arguments ops += 'i99 = same_as_i(0)\n' ops += 'guard_true(i99) [f99, %s]\n' % arguments ops += 'finish()\n' loop = parse(ops, namespace=locals()) looptoken = JitCellToken() self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) argvals, expected_result = self._prepare_args(args, floats, ints) deadframe = self.cpu.execute_token(looptoken, *argvals) x = longlong.getrealfloat(cpu.get_float_value(deadframe, 0)) assert abs(x - expected_result) < 0.0001
def test_call_release_gil(self): py.test.skip( "xxx fix this test: the code is now assuming that " "'before' is just rgil.release_gil(), and 'after' is " "only needed if 'rpy_fastgil' was not changed." ) # note that we can't test floats here because when untranslated # people actually wreck xmm registers cpu = self.cpu l = [] copied_stack = [None] def before(): # put nonsense on the top of shadowstack frame = rffi.cast(JITFRAMEPTR, cpu.gc_ll_descr.gcrootmap.stack[0]) assert getmap(frame).count("1") == 7 # copied_stack[0] = cpu.gc_ll_descr.gcrootmap.stack[0] cpu.gc_ll_descr.gcrootmap.stack[0] = -42 l.append("before") def after(): cpu.gc_ll_descr.gcrootmap.stack[0] = copied_stack[0] l.append("after") invoke_around_extcall(before, after) def f(frame, x): # all the gc pointers are alive p1 -> p7 (but not p0) assert x == 1 return 2 FUNC = lltype.FuncType([JITFRAMEPTR, lltype.Signed], lltype.Signed) fptr = llhelper(lltype.Ptr(FUNC), f) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) loop = self.parse( """ [i0, p1, p2, p3, p4, p5, p6, p7] p0 = force_token() i1 = call_release_gil(ConstClass(fptr), p0, i0, descr=calldescr) guard_not_forced(descr=faildescr) [p1, p2, p3, p4, p5, p6, p7] finish(i1, descr=finaldescr) """, namespace={ "fptr": fptr, "calldescr": calldescr, "faildescr": BasicFailDescr(), "finaldescr": BasicFinalDescr(), }, ) token = JitCellToken() cpu.gc_ll_descr.init_nursery(100) cpu.setup_once() cpu.compile_loop(loop.inputargs, loop.operations, token) args = [lltype.nullptr(llmemory.GCREF.TO) for i in range(7)] frame = cpu.execute_token(token, 1, *args) frame = rffi.cast(JITFRAMEPTR, frame) assert frame.jf_frame[0] == 2 assert l == ["before", "after"]
def test_call_with_singlefloats(self): cpu = self.cpu if not cpu.supports_floats or not cpu.supports_singlefloats: py.test.skip('requires floats and singlefloats') import random from rpython.rlib.rarithmetic import r_singlefloat def func(*args): res = 0.0 for i, x in enumerate(args): res += (i + 1.1) * float(x) return res F = lltype.Float S = lltype.SingleFloat I = lltype.Signed floats = [random.random() - 0.5 for i in range(20)] singlefloats = [r_singlefloat(random.random() - 0.5) for i in range(20)] ints = [random.randrange(-99, 99) for i in range(20)] for repeat in range(100): args = [] argvalues = [] argslist = [] local_floats = list(floats) local_singlefloats = list(singlefloats) local_ints = list(ints) for i in range(random.randrange(4, 20)): case = random.randrange(0, 6) if case & 1: boxme = InputArgInt else: boxme = ConstInt if case < 2: args.append(F) arg = arg1 = local_floats.pop() if case & 1: boxme = boxfloat else: boxme = constfloat elif case < 4: args.append(S) arg = local_singlefloats.pop() arg1 = longlong.singlefloat2int(arg) else: args.append(I) arg = arg1 = local_ints.pop() argslist.append(boxme(arg1)) argvalues.append(arg) FUNC = self.FuncType(args, F) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) res = self.execute_operation(rop.CALL_F, [funcbox] + argslist, 'float', descr=calldescr) expected = func(*argvalues) res = longlong.getrealfloat(res) assert abs(res - expected) < 0.0001
def make_finalizer_funcptr_for_type(self, TYPE): from rpython.memory.gctransform.support import get_rtti rtti = get_rtti(TYPE) if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] destrgraph = destrptr._obj.graph else: return None, False t = self.llinterp.typer.annotator.translator light = not FinalizerAnalyzer(t).analyze_light_finalizer(destrgraph) def ll_finalizer(addr): try: v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) self.llinterp.eval_graph(destrgraph, [v], recursive=True) except llinterp.LLException: raise RuntimeError( "a finalizer raised an exception, shouldn't happen") return llhelper(gctypelayout.GCData.FINALIZER, ll_finalizer), light
def new(self, thrd, callback, arg): self.newthrd = thrd._thrd self.runfn = callback self.arg = arg # make a fresh new clean SUSPSTACK rgc.register_custom_trace_hook(SUSPSTACK, lambda_customtrace) newsuspstack = lltype.malloc(SUSPSTACK) newsuspstack.handle = _c.null_handle self.suspstack = newsuspstack # Invoke '_new_callback' by closing the stack # callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address) newsuspstack.callback_pieces = callback_pieces # h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _new_callback), alternateanchor) h = rffi.cast(_c.handle, h) # llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces) return self.get_result_suspstack(h)
def produce_into(self, builder, r): subset, f, exc = self.raising_func_code(builder, r) TP = lltype.FuncType([lltype.Signed] * len(subset), lltype.Void) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) while True: _, vtableptr = builder.get_random_structure_type_and_vtable(r) if vtableptr != exc: break other_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) op = ResOperation(rop.GUARD_EXCEPTION, [other_box], descr=builder.getfaildescr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) op.setfailargs(builder.subset_of_intvars(r)) builder.should_fail_by = op builder.guard_op = op builder.loop.operations.append(op)
def test_call_aligned_with_args_on_the_stack(self): cpu = self.cpu if not cpu.supports_floats: py.test.skip('requires floats') def func(*args): return float(sum(args)) F = lltype.Float I = lltype.Signed floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] ints = [7, 11, 23, 13, -42, 1111, 95, 1] for case in range(256): result = 0.0 args = [] argslist = [] local_floats = list(floats) local_ints = list(ints) for i in range(8): if case & (1 << i): args.append(F) arg = local_floats.pop() result += arg argslist.append(boxfloat(arg)) else: args.append(I) arg = local_ints.pop() result += arg argslist.append(InputArgInt(arg)) FUNC = self.FuncType(args, F) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) res = self.execute_operation(rop.CALL_F, [funcbox] + argslist, 'float', descr=calldescr) res = longlong.getrealfloat(res) assert abs(res - result) < 0.0001
def finish_type_2(space, pto, w_obj): """ Sets up other attributes, when the interpreter type has been created. """ pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w)) base = pto.c_tp_base if base: inherit_special(space, pto, base) for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)): inherit_slots(space, pto, w_base) if not pto.c_tp_setattro: from pypy.module.cpyext.object import PyObject_GenericSetAttr pto.c_tp_setattro = llhelper( PyObject_GenericSetAttr.api_func.functype, PyObject_GenericSetAttr.api_func.get_wrapper(space)) if w_obj.is_cpytype(): Py_DecRef(space, pto.c_tp_dict) w_dict = w_obj.getdict(space) pto.c_tp_dict = make_ref(space, w_dict)
def produce_into(self, builder, r): subset, f = self.non_raising_func_code(builder, r) if len(subset) == 0: RES = lltype.Void else: RES = lltype.Signed TP = lltype.FuncType([lltype.Signed] * len(subset), RES) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) _, vtableptr = builder.get_random_structure_type_and_vtable(r) exc_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(), descr=builder.getfaildescr()) op.setfailargs(builder.subset_of_intvars(r)) op._exc_box = None builder.should_fail_by = op builder.guard_op = op builder.loop.operations.append(op)
def switch(self, suspstack): # Immediately before the switch, 'suspstack' describes the suspended # state of the *target* of the switch. Then it is theoretically # freed. In fact what occurs is that we reuse the same 'suspstack' # object in the target, just after the switch, to store the # description of where we came from. Then that "other" 'suspstack' # object is returned. self.suspstack = suspstack # callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address) old_callback_pieces = suspstack.callback_pieces suspstack.callback_pieces = callback_pieces # h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _switch_callback), alternateanchor) h = rffi.cast(_c.handle, h) # llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces) if not h: self.suspstack.callback_pieces = old_callback_pieces # return self.get_result_suspstack(h)
def test_one(self): py.test.skip("needs thread-locals in the JIT, which is only available " "after translation") visited = [] def helper(): stack = cintf.vmprof_tl_stack.getraw() if stack: # not during tracing visited.append(stack.c_value) else: visited.append(0) llfn = llhelper(lltype.Ptr(lltype.FuncType([], lltype.Void)), helper) driver = jit.JitDriver(greens=[], reds='auto') def f(n): i = 0 while i < n: driver.jit_merge_point() i += 1 llfn() class Hooks(jit.JitHookInterface): def after_compile(self, debug_info): self.raw_start = debug_info.asminfo.rawstart hooks = Hooks() null = lltype.nullptr(cintf.VMPROFSTACK) cintf.vmprof_tl_stack.setraw(null) # make it empty self.meta_interp(f, [10], policy=JitPolicy(hooks)) v = set(visited) assert 0 in v v.remove(0) assert len(v) == 1 assert 0 <= list(v)[0] - hooks.raw_start <= 10 * 1024 assert cintf.vmprof_tl_stack.getraw() == null
def test_float_hf_call_int(self): cpu = self.cpu callargs = [] def func(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9): callargs.append(zip(range(10), [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9])) return f0 + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 I = lltype.Signed FUNC = self.FuncType([I] * 10, I) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) args = ([BoxInt(1) for i in range(10)]) res = self.execute_operation(rop.CALL, [funcbox] + args, 'int', descr=calldescr) for i,j in enumerate(callargs[0]): assert (i, 1) == j assert res.getint() == 10
def test_float_hf_call_mixed(self): if not self.cpu.supports_floats: py.test.skip("requires floats") cpu = self.cpu callargs = [] def func(f0, f1, f2, f3, f4, f5, f6, i0, f7, i1, f8, f9): callargs.append( zip(range(12), [f0, f1, f2, f3, f4, f5, f6, i0, f7, i1, f8, f9])) return f0 + f1 + f2 + f3 + f4 + f5 + f6 + float(i0 + i1) + f7 + f8 + f9 F = lltype.Float I = lltype.Signed FUNC = self.FuncType([F] * 7 + [I] + [F] + [I] + [F] * 2, F) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) args = ( [boxfloat(.1) for i in range(7)] + [boxint(1), boxfloat(.2), boxint(2), boxfloat(.3), boxfloat(.4)]) res = self.execute_operation(rop.CALL_F, [funcbox] + args, 'float', descr=calldescr) for i, j in enumerate(callargs[0]): box = args[i] if box.type == 'f': assert (i, args[i].getfloat()) == j else: assert (i, args[i].getint()) == j assert abs(res.getfloat() - 4.6) < 0.0001
def build_slot_tp_function(space, typedef, name): w_type = space.gettypeobject(typedef) if name == 'tp_setattro': setattr_fn = w_type.getdictvalue(space, '__setattr__') delattr_fn = w_type.getdictvalue(space, '__delattr__') if setattr_fn is None: return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1, external=True) # XXX should not be exported @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: space.call_function(setattr_fn, w_self, w_name, w_value) else: space.call_function(delattr_fn, w_self, w_name) return 0 api_func = slot_tp_setattro.api_func else: return return lambda: llhelper(api_func.functype, api_func.get_wrapper(space))
def test_float_hf_call_float(self): if not self.cpu.supports_floats: py.test.skip("requires floats") cpu = self.cpu callargs = [] def func(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9): callargs.append(zip(range(10), [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9])) return f0 + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 F = lltype.Float FUNC = self.FuncType([F] * 10, F) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) args = ([boxfloat(.1) for i in range(10)]) res = self.execute_operation(rop.CALL, [funcbox] + args, 'float', descr=calldescr) for i,j in enumerate(callargs[0]): assert (i, 0.1) == j assert abs(res.getfloat() - 1) < 0.0001
def test_call_stubs_single_float(): from rpython.rlib.longlong2float import uint2singlefloat, singlefloat2uint from rpython.rlib.rarithmetic import r_singlefloat, intmask # c0 = GcCache(False) ARGS = [lltype.SingleFloat, lltype.SingleFloat, lltype.SingleFloat] RES = lltype.SingleFloat def f(a, b, c): a = float(a) b = float(b) c = float(c) x = a - (b / c) return r_singlefloat(x) fnptr = llhelper(lltype.Ptr(lltype.FuncType(ARGS, RES)), f) descr2 = get_call_descr(c0, ARGS, RES) a = intmask(singlefloat2uint(r_singlefloat(-10.0))) b = intmask(singlefloat2uint(r_singlefloat(3.0))) c = intmask(singlefloat2uint(r_singlefloat(2.0))) res = descr2.call_stub_i(rffi.cast(lltype.Signed, fnptr), [a, b, c], [], []) assert float(uint2singlefloat(rffi.r_uint(res))) == -11.5
def entry_point(argv): ll_dealloc_trigger_callback = llhelper(FTYPE, dealloc_trigger) rawrefcount.init(ll_dealloc_trigger_callback) ob, p = make_p() if state.seen != []: print "OB COLLECTED REALLY TOO SOON" return 1 rgc.collect() if state.seen != []: print "OB COLLECTED TOO SOON" return 1 objectmodel.keepalive_until_here(p) p = None rgc.collect() if state.seen != [1]: print "OB NOT COLLECTED" return 1 if rawrefcount.next_dead(PyObject) != ob: print "NEXT_DEAD != OB" return 1 if ob.c_ob_refcnt != 1: print "next_dead().ob_refcnt != 1" return 1 if rawrefcount.next_dead(PyObject) != lltype.nullptr(PyObjectS): print "NEXT_DEAD second time != NULL" return 1 if rawrefcount.to_obj(W_Root, ob) is not None: print "to_obj(dead) is not None?" return 1 rawrefcount.mark_deallocating(w_marker, ob) if rawrefcount.to_obj(W_Root, ob) is not w_marker: print "to_obj(marked-dead) is not w_marker" return 1 print "OK!" lltype.free(ob, flavor='raw') return 0
class FakeJitDriverSD: index_of_virtualizable = -1 _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper) assembler_helper_adr = llmemory.cast_ptr_to_adr( _assembler_helper_ptr)
def fn16(n): a = A() a.n = n h = llhelper(F, h1) h2 = lloperation.llop.same_as(F, h) return h2(a.n)
def wrapper(*args): real_args = () to_free = () for i, TARGET in unrolling_arg_tps: arg = args[i] freeme = None if TARGET == CCHARP: if arg is None: arg = lltype.nullptr(CCHARP.TO) # None => (char*)NULL freeme = arg elif isinstance(arg, str): arg = str2charp(arg) # XXX leaks if a str2charp() fails with MemoryError # and was not the first in this function freeme = arg elif TARGET == CWCHARP: if arg is None: arg = lltype.nullptr(CWCHARP.TO) # None => (wchar_t*)NULL freeme = arg elif isinstance(arg, unicode): arg = unicode2wcharp(arg) # XXX leaks if a unicode2wcharp() fails with MemoryError # and was not the first in this function freeme = arg elif TARGET is VOIDP: if arg is None: arg = lltype.nullptr(VOIDP.TO) elif isinstance(arg, str): arg = str2charp(arg) freeme = arg elif isinstance(arg, unicode): arg = unicode2wcharp(arg) freeme = arg elif _isfunctype(TARGET) and not _isllptr(arg): # XXX pass additional arguments use_gil = invoke_around_handlers arg = llhelper(TARGET, _make_wrapper_for(TARGET, arg, callbackholder, use_gil)) else: SOURCE = lltype.typeOf(arg) if SOURCE != TARGET: if TARGET is lltype.Float: arg = float(arg) elif ((isinstance(SOURCE, lltype.Number) or SOURCE is lltype.Bool) and (isinstance(TARGET, lltype.Number) or TARGET is lltype.Bool)): arg = cast(TARGET, arg) real_args = real_args + (arg,) to_free = to_free + (freeme,) res = call_external_function(*real_args) for i, TARGET in unrolling_arg_tps: if to_free[i]: lltype.free(to_free[i], flavor='raw') if rarithmetic.r_int is not r_int: if result is INT: return cast(lltype.Signed, res) elif result is UINT: return cast(lltype.Unsigned, res) return res
def get_malloc_fn(self, funcname): func = getattr(self, funcname) FUNC = getattr(self, funcname + '_FUNCPTR') return llhelper(FUNC, func)
def insert_stack_check(): endaddr = rstack._stack_get_end_adr() lengthaddr = rstack._stack_get_length_adr() f = llhelper(STACK_CHECK_SLOWPATH, rstack.stack_check_slowpath) slowpathaddr = rffi.cast(lltype.Signed, f) return endaddr, lengthaddr, slowpathaddr
os.close(fd) return ''.join(blocks) def read_code(): from pypy.module.marshal.interp_marshal import dumps filename = 'pypyjit_demo.py' source = readfile(filename) ec = space.getexecutioncontext() code = ec.compiler.compile(source, filename, 'exec', 0) return llstr(space.str_w(dumps(space, code, space.wrap(2)))) FPTR = lltype.Ptr(lltype.FuncType([], lltype.Ptr(STR))) read_code_ptr = llhelper(FPTR, read_code) def entry_point(): space.startup() from pypy.module.marshal.interp_marshal import loads code = loads(space, space.wrap(hlstr(read_code_ptr()))) assert isinstance(code, PyCode) code.exec_code(space, w_dict, w_dict) def test_run_translation(): from pypy.tool.ann_override import PyPyAnnotatorPolicy from rpython.rtyper.test.test_llinterp import get_interpreter # first annotate and rtype
def helper_func(self, FUNCPTR, func): from rpython.rtyper.annlowlevel import llhelper return llhelper(FUNCPTR, func)
def get_write_barrier_from_array_failing_case(self, FPTRTYPE): if self._have_wb_from_array: return llhelper(FPTRTYPE, self._write_barrier_from_array_failing_case) else: return lltype.nullptr(FPTRTYPE.TO)
p[0] = rffi.cast(rffi.ULONGLONG, 123321) return rffi.cast(rffi.INT, 1) FETCH_CB_P = rffi.CCallback([rffi.ULONGLONGP], rffi.INT) ctx_globals = lltype.malloc(rffi.CArray(parse_c_type.GLOBAL_S), len(global_names), flavor='raw', zero=True, track_allocation=False) c_glob_names = [rffi.str2charp(_n.encode('ascii')) for _n in global_names] _helpers_keepalive = [] for _i, _fn in enumerate( [fetch_constant_five, fetch_constant_neg, fetch_constant_zero]): llf = llhelper(FETCH_CB_P, _fn) _helpers_keepalive.append(llf) ctx_globals[_i].c_name = c_glob_names[_i] ctx_globals[_i].c_address = rffi.cast(rffi.VOIDP, llf) type_op = (cffi_opcode.OP_CONSTANT_INT if _i != 1 else cffi_opcode.OP_ENUM) ctx_globals[_i].c_type_op = rffi.cast(rffi.VOIDP, type_op) ctx.c_globals = ctx_globals rffi.setintfield(ctx, 'c_num_globals', len(global_names)) def parse(input): OUTPUT_SIZE = 100 out = lltype.malloc(rffi.VOIDPP.TO, OUTPUT_SIZE, flavor='raw', track_allocation=False)
def test_shadowstack_call(self): cpu = self.cpu cpu.gc_ll_descr.init_nursery(100) cpu.setup_once() S = self.S frames = [] def check(i): assert cpu.gc_ll_descr.gcrootmap.curtop() == i frame = rffi.cast(JITFRAMEPTR, i) assert len(frame.jf_frame) == self.cpu.JITFRAME_FIXED_SIZE + 4 # we "collect" frames.append(frame) new_frame = JITFRAME.allocate(frame.jf_frame_info) gcmap = unpack_gcmap(frame) if self.cpu.backend_name.startswith('ppc64'): assert gcmap == [30, 31, 32] elif self.cpu.backend_name.startswith('zarch'): # 10 gpr, 14 fpr -> 25 is the first slot assert gcmap == [26, 27, 28] elif self.cpu.IS_64_BIT: assert gcmap == [28, 29, 30] elif self.cpu.backend_name.startswith('arm'): assert gcmap == [44, 45, 46] else: assert gcmap == [22, 23, 24] for item, s in zip(gcmap, new_items): new_frame.jf_frame[item] = rffi.cast(lltype.Signed, s) assert cpu.gc_ll_descr.gcrootmap.curtop() == rffi.cast(lltype.Signed, frame) cpu.gc_ll_descr.gcrootmap.settop(rffi.cast(lltype.Signed, new_frame)) print '"Collecting" moved the frame from %d to %d' % ( i, cpu.gc_ll_descr.gcrootmap.curtop()) frames.append(new_frame) def check2(i): assert cpu.gc_ll_descr.gcrootmap.curtop() == i frame = rffi.cast(JITFRAMEPTR, i) assert frame == frames[1] assert frame != frames[0] CHECK = lltype.FuncType([lltype.Signed], lltype.Void) checkptr = llhelper(lltype.Ptr(CHECK), check) check2ptr = llhelper(lltype.Ptr(CHECK), check2) checkdescr = cpu.calldescrof(CHECK, CHECK.ARGS, CHECK.RESULT, EffectInfo.MOST_GENERAL) loop = self.parse(""" [p0, p1, p2] pf = force_token() # this is the frame call_n(ConstClass(check_adr), pf, descr=checkdescr) # this can collect p3 = getfield_gc_r(p0, descr=fielddescr) pf2 = force_token() call_n(ConstClass(check2_adr), pf2, descr=checkdescr) guard_nonnull(p3, descr=faildescr) [p0, p1, p2, p3] p4 = getfield_gc_r(p0, descr=fielddescr) finish(p4, descr=finaldescr) """, namespace={'finaldescr': BasicFinalDescr(), 'faildescr': BasicFailDescr(), 'check_adr': checkptr, 'check2_adr': check2ptr, 'checkdescr': checkdescr, 'fielddescr': cpu.fielddescrof(S, 'x')}) token = JitCellToken() cpu.compile_loop(loop.inputargs, loop.operations, token) p0 = lltype.malloc(S, zero=True) p1 = lltype.malloc(S) p2 = lltype.malloc(S) new_items = [lltype.malloc(S), lltype.malloc(S), lltype.malloc(S)] new_items[0].x = new_items[2] frame = cpu.execute_token(token, p0, p1, p2) frame = lltype.cast_opaque_ptr(JITFRAMEPTR, frame) gcmap = unpack_gcmap(lltype.cast_opaque_ptr(JITFRAMEPTR, frame)) assert len(gcmap) == 1 assert gcmap[0] < self.cpu.JITFRAME_FIXED_SIZE item = rffi.cast(lltype.Ptr(S), frame.jf_frame[gcmap[0]]) assert item == new_items[2]
def get_llhelper(self): return llhelper(FTPTR, self.make_func())
class CustomBaseTestRegalloc(BaseTestRegalloc): cpu = CPU(None, None) cpu.setup_once() def raising_func(i): if i: raise LLException(zero_division_error, zero_division_value) FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) raising_fptr = llhelper(FPTR, raising_func) def f(a): return 23 FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) f_fptr = llhelper(FPTR, f) f_calldescr = cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT, EffectInfo.MOST_GENERAL) zero_division_tp, zero_division_value = get_zero_division_error(cpu) zd_addr = cpu.cast_int_to_adr(zero_division_tp) zero_division_error = llmemory.cast_adr_to_ptr( zd_addr, lltype.Ptr(rclass.OBJECT_VTABLE)) raising_calldescr = cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT, EffectInfo.MOST_GENERAL) targettoken = TargetToken() targettoken2 = TargetToken() fdescr1 = BasicFailDescr(1) fdescr2 = BasicFailDescr(2) fdescr3 = BasicFailDescr(3) def setup_method(self, meth): self.targettoken._ll_loop_code = 0 self.targettoken2._ll_loop_code = 0 def f1(x): return x + 1 def f2(x, y): return x * y def f10(*args): assert len(args) == 10 return sum(args) F1PTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) F2PTR = lltype.Ptr(lltype.FuncType([lltype.Signed] * 2, lltype.Signed)) F10PTR = lltype.Ptr(lltype.FuncType([lltype.Signed] * 10, lltype.Signed)) f1ptr = llhelper(F1PTR, f1) f2ptr = llhelper(F2PTR, f2) f10ptr = llhelper(F10PTR, f10) f1_calldescr = cpu.calldescrof(F1PTR.TO, F1PTR.TO.ARGS, F1PTR.TO.RESULT, EffectInfo.MOST_GENERAL) f2_calldescr = cpu.calldescrof(F2PTR.TO, F2PTR.TO.ARGS, F2PTR.TO.RESULT, EffectInfo.MOST_GENERAL) f10_calldescr = cpu.calldescrof(F10PTR.TO, F10PTR.TO.ARGS, F10PTR.TO.RESULT, EffectInfo.MOST_GENERAL) typesystem = 'lltype' namespace = locals().copy()
def entry_point(argv): x = llhelper(FUNC_TP, f) s = lltype.malloc(S) s.f = x glob.s = s # escape return 0
class BaseTestRegalloc(object): cpu = CPU(None, None) cpu.setup_once() def raising_func(i): if i: raise LLException(zero_division_error, zero_division_value) FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) raising_fptr = llhelper(FPTR, raising_func) zero_division_tp, zero_division_value = get_zero_division_error(cpu) zd_addr = cpu.cast_int_to_adr(zero_division_tp) zero_division_error = llmemory.cast_adr_to_ptr( zd_addr, lltype.Ptr(rclass.OBJECT_VTABLE)) raising_calldescr = cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT, EffectInfo.MOST_GENERAL) targettoken = TargetToken() targettoken2 = TargetToken() fdescr1 = BasicFailDescr(1) fdescr2 = BasicFailDescr(2) fdescr3 = BasicFailDescr(3) def setup_method(self, meth): self.targettoken._ll_loop_code = 0 self.targettoken2._ll_loop_code = 0 def f1(x): return x + 1 def f2(x, y): return x * y def f10(*args): assert len(args) == 10 return sum(args) F1PTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) F2PTR = lltype.Ptr(lltype.FuncType([lltype.Signed] * 2, lltype.Signed)) F10PTR = lltype.Ptr(lltype.FuncType([lltype.Signed] * 10, lltype.Signed)) f1ptr = llhelper(F1PTR, f1) f2ptr = llhelper(F2PTR, f2) f10ptr = llhelper(F10PTR, f10) f1_calldescr = cpu.calldescrof(F1PTR.TO, F1PTR.TO.ARGS, F1PTR.TO.RESULT, EffectInfo.MOST_GENERAL) f2_calldescr = cpu.calldescrof(F2PTR.TO, F2PTR.TO.ARGS, F2PTR.TO.RESULT, EffectInfo.MOST_GENERAL) f10_calldescr = cpu.calldescrof(F10PTR.TO, F10PTR.TO.ARGS, F10PTR.TO.RESULT, EffectInfo.MOST_GENERAL) namespace = locals().copy() def parse(self, s, boxkinds=None, namespace=None): return parse(s, self.cpu, namespace or self.namespace, boxkinds=boxkinds) def interpret(self, ops, args, run=True, namespace=None): loop = self.parse(ops, namespace=namespace) self.loop = loop looptoken = JitCellToken() self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) arguments = [] for arg in args: if isinstance(arg, int): arguments.append(arg) elif isinstance(arg, float): arg = longlong.getfloatstorage(arg) arguments.append(arg) else: assert isinstance(lltype.typeOf(arg), lltype.Ptr) llgcref = lltype.cast_opaque_ptr(llmemory.GCREF, arg) arguments.append(llgcref) loop._jitcelltoken = looptoken if run: self.deadframe = self.cpu.execute_token(looptoken, *arguments) return loop def prepare_loop(self, ops): loop = self.parse(ops) regalloc = self.cpu.build_regalloc() regalloc.prepare_loop(loop.inputargs, loop.operations, loop.original_jitcell_token, []) return regalloc def getint(self, index): return self.cpu.get_int_value(self.deadframe, index) def getfloat(self, index): return self.cpu.get_float_value(self.deadframe, index) def getints(self, end): return [ self.cpu.get_int_value(self.deadframe, index) for index in range(0, end) ] def getfloats(self, end): return [ longlong.getrealfloat( self.cpu.get_float_value(self.deadframe, index)) for index in range(0, end) ] def getptr(self, index, T): gcref = self.cpu.get_ref_value(self.deadframe, index) return lltype.cast_opaque_ptr(T, gcref) def attach_bridge(self, ops, loop, guard_op_index, **kwds): guard_op = loop.operations[guard_op_index] assert guard_op.is_guard() bridge = self.parse(ops, **kwds) assert ([box.type for box in bridge.inputargs ] == [box.type for box in guard_op.getfailargs()]) faildescr = guard_op.getdescr() self.cpu.compile_bridge(faildescr, bridge.inputargs, bridge.operations, loop._jitcelltoken) return bridge def run(self, loop, *arguments): self.deadframe = self.cpu.execute_token(loop._jitcelltoken, *arguments) return self.cpu.get_latest_descr(self.deadframe)
def get_write_barrier_failing_case(self, FPTRTYPE): return llhelper(FPTRTYPE, self._write_barrier_failing_case)
def _setup_frame_realloc(self, translate_support_code): FUNC_TP = lltype.Ptr(lltype.FuncType([llmemory.GCREF, lltype.Signed], llmemory.GCREF)) base_ofs = self.get_baseofs_of_frame_field() def realloc_frame(frame, size): try: if not we_are_translated(): assert not self._exception_emulator[0] frame = lltype.cast_opaque_ptr(jitframe.JITFRAMEPTR, frame) if size > frame.jf_frame_info.jfi_frame_depth: # update the frame_info size, which is for whatever reason # not up to date # frame info lives on assembler stack, so we need to enable # writing enter_assembler_writing() frame.jf_frame_info.update_frame_depth(base_ofs, size) leave_assembler_writing() new_frame = jitframe.JITFRAME.allocate(frame.jf_frame_info) frame.jf_forward = new_frame i = 0 while i < len(frame.jf_frame): new_frame.jf_frame[i] = frame.jf_frame[i] frame.jf_frame[i] = 0 i += 1 new_frame.jf_savedata = frame.jf_savedata new_frame.jf_guard_exc = frame.jf_guard_exc # all other fields are empty llop.gc_writebarrier(lltype.Void, new_frame) return lltype.cast_opaque_ptr(llmemory.GCREF, new_frame) except Exception as e: print "Unhandled exception", e, "in realloc_frame" return lltype.nullptr(llmemory.GCREF.TO) def realloc_frame_crash(frame, size): print "frame", frame, "size", size return lltype.nullptr(llmemory.GCREF.TO) if not translate_support_code: fptr = llhelper(FUNC_TP, realloc_frame) else: FUNC = FUNC_TP.TO args_s = [lltype_to_annotation(ARG) for ARG in FUNC.ARGS] s_result = lltype_to_annotation(FUNC.RESULT) mixlevelann = MixLevelHelperAnnotator(self.rtyper) graph = mixlevelann.getgraph(realloc_frame, args_s, s_result) fptr = mixlevelann.graph2delayed(graph, FUNC) mixlevelann.finish() self.realloc_frame = ptr2int(fptr) if not translate_support_code: fptr = llhelper(FUNC_TP, realloc_frame_crash) else: FUNC = FUNC_TP.TO args_s = [lltype_to_annotation(ARG) for ARG in FUNC.ARGS] s_result = lltype_to_annotation(FUNC.RESULT) mixlevelann = MixLevelHelperAnnotator(self.rtyper) graph = mixlevelann.getgraph(realloc_frame_crash, args_s, s_result) fptr = mixlevelann.graph2delayed(graph, FUNC) mixlevelann.finish() self.realloc_frame_crash = ptr2int(fptr)