def main(s): g1 = Green() g2 = Green() g1_ptr = cast_instance_to_gcref(g1) g2_ptr = cast_instance_to_gcref(g2) loop(10, g1) assert jit_hooks.get_jitcell_at_key("jit", g1_ptr) assert not jit_hooks.get_jitcell_at_key("jit", g2_ptr) jit_hooks.trace_next_iteration("jit", g2_ptr) loop(2, g2) assert jit_hooks.get_jitcell_at_key("jit", g2_ptr)
def emit_op(self, op): op = self.get_box_replacement(op) orig_op = op replaced = False opnum = op.getopnum() keep = (opnum == rop.JIT_DEBUG) for i in range(op.numargs()): orig_arg = op.getarg(i) arg = self.get_box_replacement(orig_arg) if isinstance(arg, ConstPtr) and bool(arg.value) and not keep: arg = self.remove_constptr(arg) if orig_arg is not arg: if not replaced: op = op.copy_and_change(opnum) orig_op.set_forwarded(op) replaced = True op.setarg(i, arg) if rop.is_guard(opnum): if not replaced: op = op.copy_and_change(opnum) orig_op.set_forwarded(op) op.setfailargs([self.get_box_replacement(a, True) for a in op.getfailargs()]) if rop.is_guard(opnum) or opnum == rop.FINISH: llref = cast_instance_to_gcref(op.getdescr()) self.gcrefs_output_list.append(llref) self._newops.append(op)
def store_info_on_descr(self, startspos, guardtok): withfloats = False for box in guardtok.failargs: if box is not None and box.type == FLOAT: withfloats = True break exc = guardtok.exc target = self.failure_recovery_code[exc + 2 * withfloats] fail_descr = cast_instance_to_gcref(guardtok.faildescr) fail_descr = rffi.cast(lltype.Signed, fail_descr) base_ofs = self.cpu.get_baseofs_of_frame_field() positions = [0] * len(guardtok.fail_locs) for i, loc in enumerate(guardtok.fail_locs): if loc is None: positions[i] = -1 elif loc.is_stack(): positions[i] = loc.value - base_ofs else: assert loc is not self.cpu.frame_reg # for now if self.cpu.IS_64_BIT: coeff = 1 else: coeff = 2 if loc.is_float(): v = len(self.cpu.gen_regs) + loc.value * coeff else: v = self.cpu.all_reg_indexes[loc.value] positions[i] = v * WORD # write down the positions of locs guardtok.faildescr.rd_locs = positions # we want the descr to keep alive guardtok.faildescr.rd_loop_token = self.current_clt return fail_descr, target
def store_info_on_descr(self, startspos, guardtok): withfloats = False for box in guardtok.failargs: if box is not None and box.type == FLOAT: withfloats = True break exc = guardtok.exc target = self.failure_recovery_code[exc + 2 * withfloats] fail_descr = cast_instance_to_gcref(guardtok.faildescr) fail_descr = rffi.cast(lltype.Signed, fail_descr) base_ofs = self.cpu.get_baseofs_of_frame_field() positions = [rffi.cast(rffi.USHORT, 0)] * len(guardtok.fail_locs) for i, loc in enumerate(guardtok.fail_locs): if loc is None: position = 0xFFFF elif loc.is_stack(): assert (loc.value & (WORD - 1)) == 0, \ "store_info_on_descr: misaligned" position = (loc.value - base_ofs) // WORD assert 0 < position < 0xFFFF, "store_info_on_descr: overflow!" else: assert loc is not self.cpu.frame_reg # for now if self.cpu.IS_64_BIT: coeff = 1 else: coeff = 2 if loc.is_float(): position = len(self.cpu.gen_regs) + loc.value * coeff else: position = self.cpu.all_reg_indexes[loc.value] positions[i] = rffi.cast(rffi.USHORT, position) # write down the positions of locs guardtok.faildescr.rd_locs = positions return fail_descr, target
def _store_force_index(self, guard_op): assert guard_op.getopnum() == rop.GUARD_NOT_FORCED or guard_op.getopnum() == rop.GUARD_NOT_FORCED_2 faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field("jf_force_descr") value = rffi.cast(lltype.Signed, cast_instance_to_gcref(faildescr)) self.mc.gen_load_int(r.ip.value, value) self.store_reg(self.mc, r.ip, r.fp, ofs)
def _record_constptrs(self, op, gcrefs_output_list, ops_with_movable_const_ptr, changeable_const_pointers): l = None for i in range(op.numargs()): v = op.getarg(i) if isinstance(v, ConstPtr) and bool(v.value): p = v.value if rgc._make_sure_does_not_move(p): gcrefs_output_list.append(p) else: if l is None: l = [i] else: l.append(i) if v not in changeable_const_pointers: changeable_const_pointers.append(v) # if op.is_guard() or op.getopnum() == rop.FINISH: llref = cast_instance_to_gcref(op.getdescr()) assert rgc._make_sure_does_not_move(llref) gcrefs_output_list.append(llref) # if l: ops_with_movable_const_ptr[op] = l
def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): cpu = metainterp_sd.cpu exception = cpu.grab_exc_value(deadframe) if not exception: exception = cast_instance_to_gcref(memory_error) assert exception, "PropagateExceptionDescr: no exception??" raise jitexc.ExitFrameWithExceptionRef(cpu, exception)
def emit_op(self, op): op = self.get_box_replacement(op) orig_op = op replaced = False opnum = op.getopnum() keep = (opnum == rop.JIT_DEBUG) for i in range(op.numargs()): orig_arg = op.getarg(i) arg = self.get_box_replacement(orig_arg) if isinstance(arg, ConstPtr) and bool(arg.value) and not keep: arg = self.remove_constptr(arg) if orig_arg is not arg: if not replaced: op = op.copy_and_change(opnum) orig_op.set_forwarded(op) replaced = True op.setarg(i, arg) if rop.is_guard(opnum): if not replaced: op = op.copy_and_change(opnum) orig_op.set_forwarded(op) op.setfailargs( [self.get_box_replacement(a, True) for a in op.getfailargs()]) if rop.is_guard(opnum) or opnum == rop.FINISH: llref = cast_instance_to_gcref(op.getdescr()) self.gcrefs_output_list.append(llref) self._newops.append(op)
def test_cast_instance_to_gcref(self): class X(object): pass x = X() ptr = annlowlevel.cast_instance_to_gcref(x) assert lltype.typeOf(ptr) == llmemory.GCREF y = annlowlevel.cast_gcref_to_instance(X, ptr) assert y is x
def get_gcref_from_faildescr(self, descr): """This assumes that it is called in order for all faildescrs.""" search = cast_instance_to_gcref(descr) while not _safe_eq( self._allgcrefs[self._allgcrefs_faildescr_next], search): self._allgcrefs_faildescr_next += 1 assert self._allgcrefs_faildescr_next < len(self._allgcrefs) return self._allgcrefs_faildescr_next
def get_gcref_from_faildescr(self, descr): """This assumes that it is called in order for all faildescrs.""" search = cast_instance_to_gcref(descr) while not _safe_eq(self._allgcrefs[self._allgcrefs_faildescr_next], search): self._allgcrefs_faildescr_next += 1 assert self._allgcrefs_faildescr_next < len(self._allgcrefs) return self._allgcrefs_faildescr_next
def execute_frame(frame, w_inputvalue=None, operr=None): # go through the asm trampoline ONLY if we are translated but not being JITted. # # If we are not translated, we obviously don't want to go through the # trampoline because there is no C function it can call. # # If we are being JITted, we want to skip the trampoline, else the JIT # cannot see throug it if we_are_translated() and not jit.we_are_jitted(): # if we are translated, call the trampoline gc_frame = cast_instance_to_gcref(frame) gc_inputvalue = cast_instance_to_gcref(w_inputvalue) gc_operr = cast_instance_to_gcref(operr) unique_id = frame.pycode._unique_id gc_result = pypy_execute_frame_trampoline(gc_frame, gc_inputvalue, gc_operr, unique_id) return cast_base_ptr_to_instance(W_Root, gc_result) else: return original_execute_frame(frame, w_inputvalue, operr)
def set(value): assert isinstance(value, Cls) or value is None if we_are_translated(): from rpython.rtyper.annlowlevel import cast_instance_to_gcref gcref = cast_instance_to_gcref(value) value = lltype.cast_ptr_to_int(gcref) setraw(value) rgc.register_custom_trace_hook(TRACETLREF, _lambda_trace_tlref) rgc.ll_writebarrier(_tracetlref_obj) else: self.local.value = value
def _record_constptrs(self, op, gcrefs_output_list): for i in range(op.numargs()): v = op.getarg(i) if isinstance(v, ConstPtr) and bool(v.value): p = v.value rgc._make_sure_does_not_move(p) gcrefs_output_list.append(p) if op.is_guard() or op.getopnum() == rop.FINISH: llref = cast_instance_to_gcref(op.getdescr()) rgc._make_sure_does_not_move(llref) gcrefs_output_list.append(llref)
def lower(*args): if len(args) == 0: return (), "" ll_args, token = lower(*args[1:]) ll_arg = args[0] if isinstance(ll_arg, int): tok = "i" else: tok = "r" ll_arg = cast_instance_to_gcref(ll_arg) return (ll_arg, ) + ll_args, tok + token
def lower(*args): if len(args) == 0: return (), "" ll_args, token = lower(*args[1:]) ll_arg = args[0] if isinstance(ll_arg, int): tok = "i" else: tok = "r" ll_arg = cast_instance_to_gcref(ll_arg) return (ll_arg,) + ll_args, tok + token
def prepare_finish(self, op): descr = op.getdescr() fail_descr = cast_instance_to_gcref(descr) # we know it does not move, but well rgc._make_sure_does_not_move(fail_descr) fail_descr = rffi.cast(lltype.Signed, fail_descr) if op.numargs() > 0: loc = self.ensure_reg(op.getarg(0)) locs = [loc, imm(fail_descr)] else: locs = [imm(fail_descr)] return locs
def store_info_on_descr(self, startspos, guardtok): withfloats = False for box in guardtok.failargs: if box is not None and \ (box.type == FLOAT or box.type == VECTOR): withfloats = True break exc = guardtok.must_save_exception() target = self.failure_recovery_code[exc + 2 * withfloats] fail_descr = cast_instance_to_gcref(guardtok.faildescr) fail_descr = rffi.cast(lltype.Signed, fail_descr) base_ofs = self.cpu.get_baseofs_of_frame_field() # # in practice, about 2/3rd of 'positions' lists that we build are # exactly the same as the previous one, so share the lists to # conserve memory if len(self._previous_rd_locs) == len(guardtok.fail_locs): positions = self._previous_rd_locs # tentatively shared = True else: positions = [rffi.cast(rffi.USHORT, 0)] * len(guardtok.fail_locs) shared = False # for i, loc in enumerate(guardtok.fail_locs): if loc is None: position = 0xFFFF elif loc.is_stack(): assert (loc.value & (WORD - 1)) == 0, \ "store_info_on_descr: misaligned" position = (loc.value - base_ofs) // WORD assert 0 < position < 0xFFFF, "store_info_on_descr: overflow!" else: assert loc is not self.cpu.frame_reg # for now if self.cpu.IS_64_BIT: coeff = 1 else: coeff = 2 if loc.is_float(): position = len(self.cpu.gen_regs) + loc.value * coeff else: position = self.cpu.all_reg_indexes[loc.value] if shared: if (rffi.cast(lltype.Signed, self._previous_rd_locs[i]) == rffi.cast(lltype.Signed, position)): continue # still equal positions = positions[:] shared = False positions[i] = rffi.cast(rffi.USHORT, position) self._previous_rd_locs = positions # write down the positions of locs guardtok.faildescr.rd_locs = positions return fail_descr, target
def call_assembler(self, op, guard_op, argloc, vloc, result_loc, tmploc): self._store_force_index(guard_op) descr = op.getdescr() assert isinstance(descr, JitCellToken) # # Write a call to the target assembler # we need to allocate the frame, keep in sync with runner's # execute_token jd = descr.outermost_jitdriver_sd self._call_assembler_emit_call(self.imm(descr._ll_function_addr), argloc, tmploc) if op.result is None: assert result_loc is None value = self.cpu.done_with_this_frame_descr_void else: kind = op.result.type if kind == INT: assert result_loc is tmploc value = self.cpu.done_with_this_frame_descr_int elif kind == REF: assert result_loc is tmploc value = self.cpu.done_with_this_frame_descr_ref elif kind == FLOAT: value = self.cpu.done_with_this_frame_descr_float else: raise AssertionError(kind) gcref = cast_instance_to_gcref(value) rgc._make_sure_does_not_move(gcref) value = rffi.cast(lltype.Signed, gcref) je_location = self._call_assembler_check_descr(value, tmploc) # # Path A: use assembler_helper_adr assert jd is not None asm_helper_adr = self.cpu.cast_adr_to_int(jd.assembler_helper_adr) self._call_assembler_emit_helper_call(self.imm(asm_helper_adr), [tmploc, vloc], result_loc) jmp_location = self._call_assembler_patch_je(result_loc, je_location) # Path B: fast path. Must load the return value, and reset the token # Reset the vable token --- XXX really too much special logic here:-( if jd.index_of_virtualizable >= 0: self._call_assembler_reset_vtoken(jd, vloc) # self._call_assembler_load_result(op, result_loc) # # Here we join Path A and Path B again self._call_assembler_patch_jmp(jmp_location)
def call_assembler(self, op, guard_op, argloc, vloc, result_loc, tmploc): self._store_force_index(guard_op) descr = op.getdescr() assert isinstance(descr, JitCellToken) # # Write a call to the target assembler # we need to allocate the frame, keep in sync with runner's # execute_token jd = descr.outermost_jitdriver_sd self._call_assembler_emit_call(self.imm(descr._ll_function_addr), argloc, tmploc) if op.result is None: assert result_loc is None value = self.cpu.done_with_this_frame_descr_void else: kind = op.result.type if kind == INT: assert result_loc is tmploc value = self.cpu.done_with_this_frame_descr_int elif kind == REF: assert result_loc is tmploc value = self.cpu.done_with_this_frame_descr_ref elif kind == FLOAT: value = self.cpu.done_with_this_frame_descr_float else: raise AssertionError(kind) gcref = cast_instance_to_gcref(value) if gcref: rgc._make_sure_does_not_move(gcref) value = rffi.cast(lltype.Signed, gcref) je_location = self._call_assembler_check_descr(value, tmploc) # # Path A: use assembler_helper_adr assert jd is not None asm_helper_adr = self.cpu.cast_adr_to_int(jd.assembler_helper_adr) self._call_assembler_emit_helper_call(self.imm(asm_helper_adr), [tmploc, vloc], result_loc) jmp_location = self._call_assembler_patch_je(result_loc, je_location) # Path B: fast path. Must load the return value # self._call_assembler_load_result(op, result_loc) # # Here we join Path A and Path B again self._call_assembler_patch_jmp(jmp_location)
def prepare_op_finish(self, op, fcond): # the frame is in fp, but we have to point where in the frame is # the potential argument to FINISH descr = op.getdescr() fail_descr = cast_instance_to_gcref(descr) # we know it does not move, but well rgc._make_sure_does_not_move(fail_descr) fail_descr = rffi.cast(lltype.Signed, fail_descr) if op.numargs() == 1: loc = self.make_sure_var_in_reg(op.getarg(0)) locs = [loc, imm(fail_descr)] else: locs = [imm(fail_descr)] return locs
def set(value): assert isinstance(value, Cls) or value is None if we_are_translated(): from rpython.rtyper.annlowlevel import cast_instance_to_gcref from rpython.rlib.rgc import _make_sure_does_not_move from rpython.rlib.objectmodel import running_on_llinterp gcref = cast_instance_to_gcref(value) if not running_on_llinterp: if gcref: _make_sure_does_not_move(gcref) value = lltype.cast_ptr_to_int(gcref) setraw(value) else: self.local.value = value
def register_finalizer(self, obj): from rpython.rtyper.lltypesystem.llmemory import GCREF if self.Class is None: assert lltype.typeOf(obj) == GCREF else: assert isinstance(obj, self.Class) if we_are_translated(): from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rtyper.annlowlevel import cast_instance_to_gcref tag = FinalizerQueue._get_tag(self) if self.Class is not None: obj = cast_instance_to_gcref(obj) llop.gc_fq_register(lltype.Void, tag, obj) return else: self._untranslated_register_finalizer(obj)
def _record_constptrs(self, op, gcrefs_output_list, ops_with_movable_const_ptr, changeable_const_pointers): ops_with_movable_const_ptr[op] = [] for i in range(op.numargs()): v = op.getarg(i) if isinstance(v, ConstPtr) and bool(v.value): p = v.value if rgc._make_sure_does_not_move(p): gcrefs_output_list.append(p) else: ops_with_movable_const_ptr[op].append(i) if v not in changeable_const_pointers: changeable_const_pointers.append(v) # if op.is_guard() or op.getopnum() == rop.FINISH: llref = cast_instance_to_gcref(op.getdescr()) assert rgc._make_sure_does_not_move(llref) gcrefs_output_list.append(llref) # if len(ops_with_movable_const_ptr[op]) == 0: del ops_with_movable_const_ptr[op]
def dont_trace_here(space, next_instr, is_being_profiled, w_pycode): ll_pycode = cast_instance_to_gcref(w_pycode) jit_hooks.dont_trace_here( 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) return space.w_None
def _store_force_index(self, guard_op): assert guard_op.getopnum() == rop.GUARD_NOT_FORCED or guard_op.getopnum() == rop.GUARD_NOT_FORCED_2 faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field("jf_force_descr") self.mc.load_imm(r.SCRATCH, rffi.cast(lltype.Signed, cast_instance_to_gcref(faildescr))) self.mc.STG(r.SCRATCH, l.addr(ofs, r.SPP))
def hide(self, cpu): return cast_instance_to_gcref(self)
def call_assembler(self, op, argloc, vloc, result_loc, tmploc): """ * argloc: location of the frame argument that we're passing to the called assembler (this is the first return value of locs_for_call_assembler()) * vloc: location of the virtualizable (not in a register; this is the optional second return value of locs_for_call_assembler(), or imm(0) if none returned) * result_loc: location of op.result (which is not be confused with the next one) * tmploc: location where the actual call to the other piece of assembler will return its jitframe result (which is always a REF), before the helper may be called """ descr = op.getdescr() assert isinstance(descr, JitCellToken) # # Write a call to the target assembler # we need to allocate the frame, keep in sync with runner's # execute_token jd = descr.outermost_jitdriver_sd self._call_assembler_emit_call(self.imm(descr._ll_function_addr), argloc, tmploc) if op.type == 'v': assert result_loc is None value = self.cpu.done_with_this_frame_descr_void else: kind = op.type if kind == INT: assert result_loc is tmploc value = self.cpu.done_with_this_frame_descr_int elif kind == REF: assert result_loc is tmploc value = self.cpu.done_with_this_frame_descr_ref elif kind == FLOAT: value = self.cpu.done_with_this_frame_descr_float else: raise AssertionError(kind) gcref = cast_instance_to_gcref(value) if gcref: rgc._make_sure_does_not_move(gcref) # but should be prebuilt value = rffi.cast(lltype.Signed, gcref) je_location = self._call_assembler_check_descr(value, tmploc) # # Path A: use assembler_helper_adr assert jd is not None asm_helper_adr = self.cpu.cast_adr_to_int(jd.assembler_helper_adr) self._call_assembler_emit_helper_call(self.imm(asm_helper_adr), [tmploc, vloc], result_loc) jmp_location = self._call_assembler_patch_je(result_loc, je_location) # Path B: fast path. Must load the return value # self._call_assembler_load_result(op, result_loc) # # Here we join Path A and Path B again self._call_assembler_patch_jmp(jmp_location)
def call_assembler(self, op, argloc, vloc, result_loc, tmploc): """ * argloc: location of the frame argument that we're passing to the called assembler (this is the first return value of locs_for_call_assembler()) * vloc: location of the virtualizable (not in a register; this is the optional second return value of locs_for_call_assembler(), or imm(0) if none returned) * result_loc: location of op.result (which is not be confused with the next one) * tmploc: location where the actual call to the other piece of assembler will return its jitframe result (which is always a REF), before the helper may be called """ descr = op.getdescr() assert isinstance(descr, JitCellToken) # # Write a call to the target assembler # we need to allocate the frame, keep in sync with runner's # execute_token jd = descr.outermost_jitdriver_sd self._call_assembler_emit_call(self.imm(descr._ll_function_addr), argloc, tmploc) if op.type == 'v': assert result_loc is None value = self.cpu.done_with_this_frame_descr_void else: kind = op.type if kind == INT: assert result_loc is tmploc value = self.cpu.done_with_this_frame_descr_int elif kind == REF: assert result_loc is tmploc value = self.cpu.done_with_this_frame_descr_ref elif kind == FLOAT: value = self.cpu.done_with_this_frame_descr_float else: raise AssertionError(kind) gcref = cast_instance_to_gcref(value) if gcref: rgc._make_sure_does_not_move(gcref) value = rffi.cast(lltype.Signed, gcref) je_location = self._call_assembler_check_descr(value, tmploc) # # Path A: use assembler_helper_adr assert jd is not None asm_helper_adr = self.cpu.cast_adr_to_int(jd.assembler_helper_adr) self._call_assembler_emit_helper_call(self.imm(asm_helper_adr), [tmploc, vloc], result_loc) jmp_location = self._call_assembler_patch_je(result_loc, je_location) # Path B: fast path. Must load the return value # self._call_assembler_load_result(op, result_loc) # # Here we join Path A and Path B again self._call_assembler_patch_jmp(jmp_location)
def get_jitcell_at_key(space, next_instr, is_being_profiled, w_pycode): ll_pycode = cast_instance_to_gcref(w_pycode) return space.wrap(bool(jit_hooks.get_jitcell_at_key( 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode)))
def trace_next_iteration(space, next_instr, is_being_profiled, w_pycode): ll_pycode = cast_instance_to_gcref(w_pycode) jit_hooks.trace_next_iteration( 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) return space.w_None