def indirect_residual_call_test(argtypes, restype, expectedkind): # an indirect call that is residual in all cases is very similar to # a residual direct call op = get_direct_call_op(argtypes, restype) op.opname = "indirect_call" op.args[0] = varoftype(op.args[0].concretetype) op.args.append(Constant(["somegraph1", "somegraph2"], lltype.Void)) tr = Transformer(FakeCPU(), FakeResidualIndirectCallControl()) tr.graph = "someinitialgraph" oplist = tr.rewrite_operation(op) op0, op1 = oplist reskind = getkind(restype)[0] assert op0.opname == "residual_call_%s_%s" % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == op.args[0] assert op0.args[-1] == "calldescr" assert len(op0.args) == 1 + len(expectedkind) + 1 for sublist, kind1 in zip(op0.args[1:-1], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [v for v in op.args[1:] if getkind(v.concretetype) == sublist.kind] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == "void" or kind[0] in expectedkind assert op1.opname == "-live-" assert op1.args == []
def calldescrof(self, FUNC, ARGS, RESULT, effect_info): key = ('call', getkind(RESULT), tuple([getkind(A) for A in ARGS]), effect_info) try: return self.descrs[key] except KeyError: descr = CallDescr(RESULT, ARGS, effect_info) self.descrs[key] = descr return descr
def make_args_specification(self, jd): graph = jd._jit_merge_point_in _, _, op = locate_jit_merge_point(graph) greens_v, reds_v = support.decode_hp_hint_args(op) ALLARGS = [v.concretetype for v in (greens_v + reds_v)] jd._green_args_spec = [v.concretetype for v in greens_v] jd.red_args_types = [history.getkind(v.concretetype) for v in reds_v] jd.num_green_args = len(jd._green_args_spec) jd.num_red_args = len(jd.red_args_types) RESTYPE = graph.getreturnvar().concretetype (jd._JIT_ENTER_FUNCTYPE, jd._PTR_JIT_ENTER_FUNCTYPE) = self.cpu.ts.get_FuncType( ALLARGS, lltype.Void) (jd._PORTAL_FUNCTYPE, jd._PTR_PORTAL_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, RESTYPE) # if jd.result_type == 'v': ASMRESTYPE = lltype.Void elif jd.result_type == history.INT: ASMRESTYPE = lltype.Signed elif jd.result_type == history.REF: ASMRESTYPE = llmemory.GCREF elif jd.result_type == history.FLOAT: ASMRESTYPE = lltype.Float else: assert False (_, jd._PTR_ASSEMBLER_HELPER_FUNCTYPE) = self.cpu.ts.get_FuncType( [llmemory.GCREF, llmemory.GCREF], ASMRESTYPE)
def split_graph_and_record_jitdriver(self, graph, block, pos): op = block.operations[pos] jd = JitDriverStaticData() jd._jit_merge_point_in = graph args = op.args[2:] s_binding = self.translator.annotator.binding jd._portal_args_s = [s_binding(v) for v in args] graph = copygraph(graph) [jmpp] = find_jit_merge_points([graph]) graph.startblock = support.split_before_jit_merge_point(*jmpp) # XXX this is incredibly obscure, but this is sometiems necessary # so we don't explode in checkgraph. for reasons unknown this # is not contanied within simplify_graph removenoops.remove_same_as(graph) # a crash in the following checkgraph() means that you forgot # to list some variable in greens=[] or reds=[] in JitDriver, # or that a jit_merge_point() takes a constant as an argument. checkgraph(graph) for v in graph.getargs(): assert isinstance(v, Variable) assert len(dict.fromkeys(graph.getargs())) == len(graph.getargs()) self.translator.graphs.append(graph) jd.portal_graph = graph # it's a bit unbelievable to have a portal without func assert hasattr(graph, "func") graph.func._dont_inline_ = True graph.func._jit_unroll_safe_ = True jd.jitdriver = block.operations[pos].args[1].value jd.portal_runner_ptr = "<not set so far>" jd.result_type = history.getkind(jd.portal_graph.getreturnvar() .concretetype)[0] self.jitdrivers_sd.append(jd)
def split_graph_and_record_jitdriver(self, graph, block, pos): op = block.operations[pos] jd = JitDriverStaticData() jd._jit_merge_point_in = graph args = op.args[2:] s_binding = self.translator.annotator.binding jd._portal_args_s = [s_binding(v) for v in args] graph = copygraph(graph) [jmpp] = find_jit_merge_points([graph]) graph.startblock = support.split_before_jit_merge_point(*jmpp) # XXX this is incredibly obscure, but this is sometiems necessary # so we don't explode in checkgraph. for reasons unknown this # is not contanied within simplify_graph removenoops.remove_same_as(graph) # a crash in the following checkgraph() means that you forgot # to list some variable in greens=[] or reds=[] in JitDriver, # or that a jit_merge_point() takes a constant as an argument. checkgraph(graph) for v in graph.getargs(): assert isinstance(v, Variable) assert len(dict.fromkeys(graph.getargs())) == len(graph.getargs()) self.translator.graphs.append(graph) jd.portal_graph = graph # it's a bit unbelievable to have a portal without func assert hasattr(graph, "func") graph.func._dont_inline_ = True graph.func._jit_unroll_safe_ = True jd.jitdriver = block.operations[pos].args[1].value jd.portal_runner_ptr = "<not set so far>" jd.result_type = history.getkind( jd.portal_graph.getreturnvar().concretetype)[0] self.jitdrivers_sd.append(jd)
def make_args_specification(self, jd): graph = jd._jit_merge_point_in _, _, op = locate_jit_merge_point(graph) greens_v, reds_v = support.decode_hp_hint_args(op) ALLARGS = [v.concretetype for v in (greens_v + reds_v)] jd._green_args_spec = [v.concretetype for v in greens_v] jd.red_args_types = [history.getkind(v.concretetype) for v in reds_v] jd.num_green_args = len(jd._green_args_spec) jd.num_red_args = len(jd.red_args_types) RESTYPE = graph.getreturnvar().concretetype (jd._JIT_ENTER_FUNCTYPE, jd._PTR_JIT_ENTER_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, lltype.Void) (jd._PORTAL_FUNCTYPE, jd._PTR_PORTAL_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, RESTYPE) # if jd.result_type == 'v': ASMRESTYPE = lltype.Void elif jd.result_type == history.INT: ASMRESTYPE = lltype.Signed elif jd.result_type == history.REF: ASMRESTYPE = llmemory.GCREF elif jd.result_type == history.FLOAT: ASMRESTYPE = lltype.Float else: assert False (_, jd._PTR_ASSEMBLER_HELPER_FUNCTYPE) = self.cpu.ts.get_FuncType( [llmemory.GCREF, llmemory.GCREF], ASMRESTYPE)
def __init__(self, TYPE): DescrWithKey.__init__(self, TYPE) from rpython.jit.backend.llgraph.runner import boxresult from rpython.jit.metainterp.warmstate import unwrap ARRAY = ootype.Array(TYPE) def create(): if isinstance(TYPE, ootype.OOType): return boxresult(TYPE, ootype.new(TYPE)) return None def create_array(lengthbox): n = lengthbox.getint() return boxresult(ARRAY, ootype.oonewarray(ARRAY, n)) def getarrayitem(arraybox, ibox): array = arraybox.getref(ARRAY) i = ibox.getint() if TYPE is not ootype.Void: return boxresult(TYPE, array.ll_getitem_fast(i)) def setarrayitem(arraybox, ibox, valuebox): array = arraybox.getref(ARRAY) i = ibox.getint() value = unwrap(TYPE, valuebox) array.ll_setitem_fast(i, value) def getarraylength(arraybox): array = arraybox.getref(ARRAY) return boxresult(ootype.Signed, array.ll_length()) def instanceof(box): if isinstance(TYPE, ootype.Instance): obj = box.getref(ootype.ROOT) return BoxInt(ootype.instanceof(obj, TYPE)) return None self.create = create self.create_array = create_array self.getarrayitem = getarrayitem self.setarrayitem = setarrayitem self.getarraylength = getarraylength self.instanceof = instanceof self.ooclass = get_class_for_type(TYPE) self.typename = TYPE._short_name() self._is_array_of_pointers = (history.getkind(TYPE) == 'ref') self._is_array_of_floats = (history.getkind(TYPE) == 'float')
def serialize_op(self, op): args = self.flatten_list(op.args) if op.result is not None: kind = getkind(op.result.concretetype) if kind != 'void': args.append("->") args.append(self.getcolor(op.result)) self.emitline(op.opname, *args)
def cast_arg(TP, x): kind = getkind(TP) if kind == 'int': return cast_from_int(TP, x) elif kind == 'ref': return cast_from_ptr(TP, x) else: assert kind == 'float' return cast_from_floatstorage(TP, x)
def cast_arg(TP, x): kind = getkind(TP) if kind == "int": return cast_from_int(TP, x) elif kind == "ref": return cast_from_ptr(TP, x) else: assert kind == "float" return cast_from_floatstorage(TP, x)
def make_execute_token(self, *ARGS): """Build and return a function for executing the given JIT token. Each chunk of compiled code is represented by an integer "function id". We need to look up the id, build the necessary frame, and then call the helper function "jitInvoke" to execute the compiled function. """ # This is mostly copied from llsupport/llmodel.py, but with changes # to invoke the external javascript helper thingy. lst = [(i, history.getkind(ARG)[0]) for i, ARG in enumerate(ARGS)] kinds = unrolling_iterable(lst) def execute_token(executable_token, *args): clt = executable_token.compiled_loop_token assert isinstance(clt, CompiledLoopTokenASMJS) funcid = clt.func.compiled_funcid loopid = clt.compiled_loopid frame_info = clt.func.frame_info frame = self.gc_ll_descr.malloc_jitframe(frame_info) ll_frame = lltype.cast_opaque_ptr(llmemory.GCREF, frame) locs = clt._ll_initial_locs if SANITYCHECK: assert len(locs) == len(args) if not self.translate_support_code: prev_interpreter = LLInterpreter.current_interpreter LLInterpreter.current_interpreter = self.debug_ll_interpreter try: # Store each argument into the frame. for i, kind in kinds: arg = args[i] num = locs[i] if kind == history.INT: self.set_int_value(ll_frame, num, arg) elif kind == history.FLOAT: self.set_float_value(ll_frame, num, arg) else: assert kind == history.REF self.set_ref_value(ll_frame, num, arg) llop.gc_writebarrier(lltype.Void, ll_frame) # Send the threadlocaladdr. if self.translate_support_code: ll_tlref = llop.threadlocalref_addr(llmemory.Address) else: ll_tlref = rffi.cast(llmemory.Address, self._debug_errno_container) # Invoke it via the helper. ll_frameadr = self.cast_ptr_to_int(ll_frame) ll_tladdr = self.cast_adr_to_int(ll_tlref) ll_frameadr = support.jitInvoke(funcid, ll_frameadr, ll_tladdr, loopid) ll_frame = self.cast_int_to_ptr(ll_frameadr, llmemory.GCREF) finally: if not self.translate_support_code: LLInterpreter.current_interpreter = prev_interpreter return ll_frame return execute_token
def make_execute_token(self, *ARGS): """Build and return a function for executing the given JIT token. Each chunk of compiled code is represented by an integer "function id". We need to look up the id, build the necessary frame, and then call the helper function "jitInvoke" to execute the compiled function. """ # This is mostly copied from llsupport/llmodel.py, but with changes # to invoke the external javascript helper thingy. lst = [(i, history.getkind(ARG)[0]) for i, ARG in enumerate(ARGS)] kinds = unrolling_iterable(lst) def execute_token(executable_token, *args): clt = executable_token.compiled_loop_token assert isinstance(clt, CompiledLoopTokenASMJS) funcid = clt.func.compiled_funcid loopid = clt.compiled_loopid frame_info = clt.func.frame_info frame = self.gc_ll_descr.malloc_jitframe(frame_info) ll_frame = lltype.cast_opaque_ptr(llmemory.GCREF, frame) locs = clt._ll_initial_locs if SANITYCHECK: assert len(locs) == len(args) if not self.translate_support_code: prev_interpreter = LLInterpreter.current_interpreter LLInterpreter.current_interpreter = self.debug_ll_interpreter try: # Store each argument into the frame. for i, kind in kinds: arg = args[i] num = locs[i] if kind == history.INT: self.set_int_value(ll_frame, num, arg) elif kind == history.FLOAT: self.set_float_value(ll_frame, num, arg) else: assert kind == history.REF self.set_ref_value(ll_frame, num, arg) llop.gc_writebarrier(lltype.Void, ll_frame) # Send the threadlocaladdr. if self.translate_support_code: ll_tlref = llop.threadlocalref_addr( llmemory.Address) else: ll_tlref = rffi.cast(llmemory.Address, self._debug_errno_container) # Invoke it via the helper. ll_frameadr = self.cast_ptr_to_int(ll_frame) ll_tladdr = self.cast_adr_to_int(ll_tlref) ll_frameadr = support.jitInvoke(funcid, ll_frameadr, ll_tladdr, loopid) ll_frame = self.cast_int_to_ptr(ll_frameadr, llmemory.GCREF) finally: if not self.translate_support_code: LLInterpreter.current_interpreter = prev_interpreter return ll_frame return execute_token
def make_execute_token(self, *ARGS): # The JIT backend must generate functions with the following # signature: it takes the jitframe and the threadlocal_addr # as arguments, and it returns the (possibly reallocated) jitframe. # The backend can optimize OS_THREADLOCALREF_GET calls to return a # field of this threadlocal_addr, but only if 'translate_support_code': # in untranslated tests, threadlocal_addr is a dummy container # for errno tests only. FUNCPTR = lltype.Ptr( lltype.FuncType([llmemory.GCREF, llmemory.Address], llmemory.GCREF)) lst = [(i, history.getkind(ARG)[0]) for i, ARG in enumerate(ARGS)] kinds = unrolling_iterable(lst) def execute_token(executable_token, *args): clt = executable_token.compiled_loop_token assert len(args) == clt._debug_nbargs # addr = executable_token._ll_function_addr func = rffi.cast(FUNCPTR, addr) #llop.debug_print(lltype.Void, ">>>> Entering", addr) frame_info = clt.frame_info frame = self.gc_ll_descr.malloc_jitframe(frame_info) ll_frame = lltype.cast_opaque_ptr(llmemory.GCREF, frame) locs = executable_token.compiled_loop_token._ll_initial_locs prev_interpreter = None # help flow space if not self.translate_support_code: prev_interpreter = LLInterpreter.current_interpreter LLInterpreter.current_interpreter = self.debug_ll_interpreter try: for i, kind in kinds: arg = args[i] num = locs[i] if kind == history.INT: self.set_int_value(ll_frame, num, arg) elif kind == history.FLOAT: self.set_float_value(ll_frame, num, arg) else: assert kind == history.REF self.set_ref_value(ll_frame, num, arg) if self.translate_support_code: ll_threadlocal_addr = llop.threadlocalref_addr( llmemory.Address) else: ll_threadlocal_addr = rffi.cast( llmemory.Address, self._debug_errno_container) llop.gc_writebarrier(lltype.Void, ll_frame) ll_frame = func(ll_frame, ll_threadlocal_addr) finally: if not self.translate_support_code: LLInterpreter.current_interpreter = prev_interpreter #llop.debug_print(lltype.Void, "<<<< Back") return ll_frame return execute_token
def getcolor(self, v): if isinstance(v, Constant): return v kind = getkind(v.concretetype) col = self.regallocs[kind].getcolor(v) # if kind=='void', fix caller try: r = self.registers[kind, col] except KeyError: r = self.registers[kind, col] = Register(kind, col) return r
def residual_call_test(argtypes, restype, expectedkind): op = get_direct_call_op(argtypes, restype) tr = Transformer(FakeCPU(), FakeResidualCallControl()) oplist = tr.rewrite_operation(op) op0, op1 = oplist reskind = getkind(restype)[0] assert op0.opname == "residual_call_%s_%s" % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == op.args[0] assert op0.args[-1] == "calldescr" assert len(op0.args) == 1 + len(expectedkind) + 1 for sublist, kind1 in zip(op0.args[1:-1], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [v for v in op.args[1:] if getkind(v.concretetype) == sublist.kind] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == "void" or kind[0] in expectedkind assert op1.opname == "-live-" assert op1.args == []
def direct_call_test(argtypes, restype, expectedkind): op = get_direct_call_op(argtypes, restype) tr = Transformer(FakeCPU(), FakeRegularCallControl()) tr.graph = "someinitialgraph" oplist = tr.rewrite_operation(op) op0, op1 = oplist reskind = getkind(restype)[0] assert op0.opname == "inline_call_%s_%s" % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == "somejitcode" assert len(op0.args) == 1 + len(expectedkind) for sublist, kind1 in zip(op0.args[1:], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [v for v in op.args[1:] if getkind(v.concretetype) == sublist.kind] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == "void" or kind[0] in expectedkind assert op1.opname == "-live-" assert op1.args == []
def make_execute_token(self, *ARGS): # The JIT backend must generate functions with the following # signature: it takes the jitframe and the threadlocal_addr # as arguments, and it returns the (possibly reallocated) jitframe. # The backend can optimize OS_THREADLOCALREF_GET calls to return a # field of this threadlocal_addr, but only if 'translate_support_code': # in untranslated tests, threadlocal_addr is a dummy container # for errno tests only. FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF, llmemory.Address], llmemory.GCREF)) lst = [(i, history.getkind(ARG)[0]) for i, ARG in enumerate(ARGS)] kinds = unrolling_iterable(lst) def execute_token(executable_token, *args): clt = executable_token.compiled_loop_token assert len(args) == clt._debug_nbargs # addr = executable_token._ll_function_addr func = rffi.cast(FUNCPTR, addr) #llop.debug_print(lltype.Void, ">>>> Entering", addr) frame_info = clt.frame_info frame = self.gc_ll_descr.malloc_jitframe(frame_info) ll_frame = lltype.cast_opaque_ptr(llmemory.GCREF, frame) locs = executable_token.compiled_loop_token._ll_initial_locs prev_interpreter = None # help flow space if not self.translate_support_code: prev_interpreter = LLInterpreter.current_interpreter LLInterpreter.current_interpreter = self.debug_ll_interpreter try: for i, kind in kinds: arg = args[i] num = locs[i] if kind == history.INT: self.set_int_value(ll_frame, num, arg) elif kind == history.FLOAT: self.set_float_value(ll_frame, num, arg) else: assert kind == history.REF self.set_ref_value(ll_frame, num, arg) if self.translate_support_code: ll_threadlocal_addr = llop.threadlocalref_addr( llmemory.Address) else: ll_threadlocal_addr = rffi.cast(llmemory.Address, self._debug_errno_container) llop.gc_writebarrier(lltype.Void, ll_frame) ll_frame = func(ll_frame, ll_threadlocal_addr) finally: if not self.translate_support_code: LLInterpreter.current_interpreter = prev_interpreter #llop.debug_print(lltype.Void, "<<<< Back") return ll_frame return execute_token
def cast_result(TP, x): kind = getkind(TP) if kind == 'int': return cast_to_int(x) elif kind == 'ref': return cast_to_ptr(x) elif kind == 'float': return cast_to_floatstorage(x) else: assert kind == 'void' assert x is None return None
def map_type_to_argclass(ARG, accept_void=False): kind = getkind(ARG) if kind == 'int': if ARG is lltype.SingleFloat: return 'S' else: return 'i' elif kind == 'ref': return 'r' elif kind == 'float': if is_longlong(ARG): return 'L' else: return 'f' elif kind == 'void': if accept_void: return 'v' raise NotImplementedError('ARG = %r' % (ARG, ))
def map_type_to_argclass(ARG, accept_void=False): kind = getkind(ARG) if kind == 'int': if ARG is lltype.SingleFloat: return 'S' else: return 'i' elif kind == 'ref': return 'r' elif kind == 'float': if is_longlong(ARG): return 'L' else: return 'f' elif kind == 'void': if accept_void: return 'v' raise NotImplementedError('ARG = %r' % (ARG,))
def cast_result(TP, x): kind = getkind(TP) if kind == "int": return cast_to_int(x) elif kind == "ref": return cast_to_ptr(x) elif kind == "float": return cast_to_floatstorage(x) else: assert kind == "void" assert x is None return None
def __init__(self, TYPE, fieldname): DescrWithKey.__init__(self, (TYPE, fieldname)) from rpython.jit.backend.llgraph.runner import boxresult from rpython.jit.metainterp.warmstate import unwrap _, T = TYPE._lookup_field(fieldname) def getfield(objbox): obj = objbox.getref(TYPE) value = getattr(obj, fieldname) return boxresult(T, value) def setfield(objbox, valuebox): obj = objbox.getref(TYPE) value = unwrap(T, valuebox) setattr(obj, fieldname, value) self.getfield = getfield self.setfield = setfield self.selfclass = ootype.runtimeClass(TYPE) self.fieldname = fieldname self.key = key_manager.getkey((TYPE, fieldname)) self._is_pointer_field = (history.getkind(T) == 'ref') self._is_float_field = (history.getkind(T) == 'float')
def enforce_input_args(self): inputargs = self.graph.startblock.inputargs numkinds = {} for v in inputargs: kind = getkind(v.concretetype) if kind == 'void': continue curcol = self.regallocs[kind].getcolor(v) realcol = numkinds.get(kind, 0) numkinds[kind] = realcol + 1 if curcol != realcol: assert curcol > realcol self.regallocs[kind].swapcolors(realcol, curcol)
def indirect_regular_call_test(argtypes, restype, expectedkind): # a regular indirect call is preceded by a guard_value on the # function address, so that pyjitpl can know which jitcode to follow from rpython.jit.codewriter.flatten import IndirectCallTargets op = get_direct_call_op(argtypes, restype) op.opname = "indirect_call" op.args[0] = varoftype(op.args[0].concretetype) op.args.append(Constant(["somegraph1", "somegraph2"], lltype.Void)) tr = Transformer(FakeCPU(), FakeRegularIndirectCallControl()) tr.graph = "someinitialgraph" oplist = tr.rewrite_operation(op) op0gv, op1gv, op0, op1 = oplist assert op0gv.opname == "-live-" assert op0gv.args == [] assert op1gv.opname == "int_guard_value" assert op1gv.args == [op.args[0]] assert op1gv.result is None # reskind = getkind(restype)[0] assert op0.opname == "residual_call_%s_%s" % (expectedkind, reskind) assert op0.result == op.result assert op0.args[0] == op.args[0] assert isinstance(op0.args[1], IndirectCallTargets) assert op0.args[1].lst == ["somejitcode1", "somejitcode2"] assert op0.args[-1] == "calldescr" assert len(op0.args) == 2 + len(expectedkind) + 1 for sublist, kind1 in zip(op0.args[2:-1], expectedkind): assert sublist.kind.startswith(kind1) assert list(sublist) == [v for v in op.args[1:] if getkind(v.concretetype) == sublist.kind] for v in op.args[1:]: kind = getkind(v.concretetype) assert kind == "void" or kind[0] in expectedkind # Note: we still expect a -live- here, even though canraise() returns # False, because this 'residual_call' will likely call further jitcodes # which can do e.g. guard_class or other stuff requiring anyway a -live-. assert op1.opname == "-live-" assert op1.args == []
def execute_call(self, calldescr, func, *args): effectinfo = calldescr.get_extra_info() if effectinfo is not None and hasattr(effectinfo, 'oopspecindex'): oopspecindex = effectinfo.oopspecindex if oopspecindex == EffectInfo.OS_MATH_SQRT: return self._do_math_sqrt(args[0]) TP = llmemory.cast_int_to_adr(func).ptr._obj._TYPE call_args = support.cast_call_args_in_order(TP.ARGS, args) try: res = self.cpu.maybe_on_top_of_llinterp(func, call_args, TP.RESULT) self.last_exception = None except LLException, lle: self.last_exception = lle res = _example_res[getkind(TP.RESULT)[0]]
def str_storage_getitem(self, TYPE, buf, offset): def f(): return str_storage_getitem(TYPE, buf, offset) res = self.interp_operations(f, [], supports_singlefloats=True) # kind = getkind(TYPE)[0] # 'i' or 'f' self.check_operations_history({'gc_load_indexed_%s' % kind: 1, 'finish': 1}) # if TYPE == lltype.SingleFloat: # interp_operations returns the int version of r_singlefloat, but # our tests expects to receive an r_singlefloat: let's convert it # back! return longlong.int2singlefloat(res) return res
def make_return(self, args): if len(args) == 1: # return from function [v] = args kind = getkind(v.concretetype) if kind == 'void': self.emitline("void_return") else: self.emitline("%s_return" % kind, self.getcolor(args[0])) elif len(args) == 2: # exception block, raising an exception from a function if isinstance(args[1], Variable): self.emitline("-live-") # xxx hack self.emitline("raise", self.getcolor(args[1])) else: raise Exception("?") self.emitline("---")
def gc_load_from_string(self, TYPE, buf, offset): def f(offset): return str_gc_load(TYPE, buf, offset) res = self.interp_operations(f, [offset], supports_singlefloats=True) # kind = getkind(TYPE)[0] # 'i' or 'f' self.check_operations_history({ 'gc_load_indexed_%s' % kind: 1, 'finish': 1 }) # if TYPE == lltype.SingleFloat: # interp_operations returns the int version of r_singlefloat, but # our tests expects to receive an r_singlefloat: let's convert it # back! return longlong.int2singlefloat(res) return res
def field_descr(self, builder, r): v, S = builder.get_structptr_var(r, ) names = S._names if names[0] == 'parent': names = names[1:] choice = [] kind = optypes[self.opnum] for name in names: FIELD = getattr(S, name) if not isinstance(FIELD, lltype.Ptr): if kind == 'n' or getkind(FIELD)[0] == kind: choice.append(name) if not choice: raise test_random.CannotProduceOperation name = r.choice(choice) descr = builder.cpu.fielddescrof(S, name) descr._random_info = 'cpu.fielddescrof(..., %r)' % (name,) descr._random_type = S TYPE = getattr(S, name) return v, descr, TYPE
def field_descr(self, builder, r): v, S = builder.get_structptr_var(r, ) names = S._names if names[0] == 'parent': names = names[1:] choice = [] kind = optypes[self.opnum] for name in names: FIELD = getattr(S, name) if not isinstance(FIELD, lltype.Ptr): if kind == 'n' or getkind(FIELD)[0] == kind: choice.append(name) if not choice: raise test_random.CannotProduceOperation name = r.choice(choice) descr = builder.cpu.fielddescrof(S, name) descr._random_info = 'cpu.fielddescrof(..., %r)' % (name, ) descr._random_type = S TYPE = getattr(S, name) return v, descr, TYPE
def cast_call_args_in_order(ARGS, args): call_args = [] i = 0 for ARG in ARGS: kind = getkind(ARG) if kind == "int": n = cast_from_int(ARG, args[i]) i += 1 elif kind == "ref": n = cast_from_ptr(ARG, args[i]) i += 1 elif kind == "float": n = cast_from_floatstorage(ARG, args[i]) i += 1 elif kind == "void": n = None else: raise AssertionError(kind) call_args.append(n) assert i == len(args) return call_args
def cast_call_args_in_order(ARGS, args): call_args = [] i = 0 for ARG in ARGS: kind = getkind(ARG) if kind == 'int': n = cast_from_int(ARG, args[i]) i += 1 elif kind == 'ref': n = cast_from_ptr(ARG, args[i]) i += 1 elif kind == 'float': n = cast_from_floatstorage(ARG, args[i]) i += 1 elif kind == 'void': n = None else: raise AssertionError(kind) call_args.append(n) assert i == len(args) return call_args
def sort_vars(args_v): from rpython.jit.metainterp.history import getkind _kind2count = {'int': 1, 'ref': 2, 'float': 3} return sorted(args_v, key=lambda v: _kind2count[getkind(v.concretetype)])
def get_arg_types(self): return ''.join([getkind(ARG)[0] for ARG in self.ARGS])
def _get_jitcodes(testself, CPUClass, func, values, supports_floats=True, supports_longlong=False, supports_singlefloats=False, translationoptions={}, **kwds): from rpython.jit.codewriter import support class FakeJitCell(object): __product_token = None def get_procedure_token(self): return self.__product_token def set_procedure_token(self, token): self.__product_token = token class FakeWarmRunnerState(object): def attach_procedure_to_interp(self, greenkey, procedure_token): assert greenkey == [] self._cell.set_procedure_token(procedure_token) def helper_func(self, FUNCPTR, func): from rpython.rtyper.annlowlevel import llhelper return llhelper(FUNCPTR, func) def get_unique_id(self, *args): return 0 def get_location_str(self, args): return 'location' class JitCell: @staticmethod def get_jit_cell_at_key(greenkey): assert greenkey == [] return FakeWarmRunnerState._cell _cell = FakeJitCell() trace_limit = sys.maxint enable_opts = ALL_OPTS_DICT vec = True if kwds.pop('disable_optimizations', False): FakeWarmRunnerState.enable_opts = {} func._jit_unroll_safe_ = True rtyper = support.annotate(func, values, translationoptions=translationoptions) graphs = rtyper.annotator.translator.graphs testself.all_graphs = graphs result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0] class FakeJitDriverSD: num_green_args = 0 portal_graph = graphs[0] virtualizable_info = None greenfield_info = None result_type = result_kind portal_runner_ptr = "???" vec = False stats = history.Stats(None) cpu = CPUClass(rtyper, stats, None, False) cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()]) cw.debug = True testself.cw = cw if supports_floats and not cpu.supports_floats: py.test.skip("this test requires supports_floats=True") if supports_longlong and not cpu.supports_longlong: py.test.skip("this test requires supports_longlong=True") if supports_singlefloats and not cpu.supports_singlefloats: py.test.skip("this test requires supports_singlefloats=True") policy = JitPolicy() policy.set_supports_floats(supports_floats) policy.set_supports_longlong(supports_longlong) policy.set_supports_singlefloats(supports_singlefloats) graphs = cw.find_all_graphs(policy) if kwds.get("backendopt"): backend_optimizations(rtyper.annotator.translator, graphs=graphs) # testself.warmrunnerstate = FakeWarmRunnerState() testself.warmrunnerstate.cpu = cpu FakeJitDriverSD.warmstate = testself.warmrunnerstate if hasattr(testself, 'finish_setup_for_interp_operations'): testself.finish_setup_for_interp_operations() # cw.make_jitcodes(verbose=True) return stats
def rewrite_jit_merge_point(self, jd, policy): # # Mutate the original portal graph from this: # # def original_portal(..): # stuff # while 1: # jit_merge_point(*args) # more stuff # # to that: # # def original_portal(..): # stuff # return portal_runner(*args) # # def portal_runner(*args): # while 1: # try: # return portal(*args) # except ContinueRunningNormally, e: # *args = *e.new_args # except DoneWithThisFrame, e: # return e.return # except ExitFrameWithException, e: # raise Exception, e.value # # def portal(*args): # while 1: # more stuff # origportalgraph = jd._jit_merge_point_in portalgraph = jd.portal_graph PORTALFUNC = jd._PORTAL_FUNCTYPE # ____________________________________________________________ # Prepare the portal_runner() helper # from rpython.jit.metainterp.warmstate import specialize_value from rpython.jit.metainterp.warmstate import unspecialize_value portal_ptr = self.cpu.ts.functionptr(PORTALFUNC, 'portal', graph=portalgraph) jd._portal_ptr = portal_ptr # portalfunc_ARGS = [] nums = {} for i, ARG in enumerate(PORTALFUNC.ARGS): kind = history.getkind(ARG) assert kind != 'void' if i < len(jd.jitdriver.greens): color = 'green' else: color = 'red' attrname = '%s_%s' % (color, kind) count = nums.get(attrname, 0) nums[attrname] = count + 1 portalfunc_ARGS.append((ARG, attrname, count)) portalfunc_ARGS = unrolling_iterable(portalfunc_ARGS) # rtyper = self.translator.rtyper RESULT = PORTALFUNC.RESULT result_kind = history.getkind(RESULT) ts = self.cpu.ts state = jd.warmstate maybe_compile_and_run = jd._maybe_compile_and_run_fn def ll_portal_runner(*args): start = True while 1: try: # maybe enter from the function's start. Note that the # 'start' variable is constant-folded away because it's # the first statement in the loop. if start: maybe_compile_and_run( state.increment_function_threshold, *args) # # then run the normal portal function, i.e. the # interpreter's main loop. It might enter the jit # via maybe_enter_jit(), which typically ends with # handle_fail() being called, which raises on the # following exceptions --- catched here, because we # want to interrupt the whole interpreter loop. return support.maybe_on_top_of_llinterp( rtyper, portal_ptr)(*args) except jitexc.ContinueRunningNormally, e: args = () for ARGTYPE, attrname, count in portalfunc_ARGS: x = getattr(e, attrname)[count] x = specialize_value(ARGTYPE, x) args = args + (x, ) start = False continue except jitexc.DoneWithThisFrameVoid: assert result_kind == 'void' return except jitexc.DoneWithThisFrameInt, e: assert result_kind == 'int' return specialize_value(RESULT, e.result)
def get_result_type(self): return getkind(self.RESULT)[0]
def rewrite_jit_merge_point(self, jd, policy): # # Mutate the original portal graph from this: # # def original_portal(..): # stuff # while 1: # jit_merge_point(*args) # more stuff # # to that: # # def original_portal(..): # stuff # return portal_runner(*args) # # def portal_runner(*args): # while 1: # try: # return portal(*args) # except JitException, e: # return handle_jitexception(e) # # def portal(*args): # while 1: # more stuff # origportalgraph = jd._jit_merge_point_in portalgraph = jd.portal_graph PORTALFUNC = jd._PORTAL_FUNCTYPE # ____________________________________________________________ # Prepare the portal_runner() helper # from rpython.jit.metainterp.warmstate import specialize_value from rpython.jit.metainterp.warmstate import unspecialize_value portal_ptr = self.cpu.ts.functionptr(PORTALFUNC, 'portal', graph=portalgraph) jd._portal_ptr = portal_ptr # portalfunc_ARGS = [] nums = {} for i, ARG in enumerate(PORTALFUNC.ARGS): kind = history.getkind(ARG) assert kind != 'void' if i < len(jd.jitdriver.greens): color = 'green' else: color = 'red' attrname = '%s_%s' % (color, kind) count = nums.get(attrname, 0) nums[attrname] = count + 1 portalfunc_ARGS.append((ARG, attrname, count)) portalfunc_ARGS = unrolling_iterable(portalfunc_ARGS) # rtyper = self.translator.rtyper RESULT = PORTALFUNC.RESULT result_kind = history.getkind(RESULT) assert result_kind.startswith(jd.result_type) ts = self.cpu.ts state = jd.warmstate maybe_compile_and_run = jd._maybe_compile_and_run_fn EnterJitAssembler = jd._EnterJitAssembler def ll_portal_runner(*args): try: # maybe enter from the function's start. maybe_compile_and_run(state.increment_function_threshold, *args) # # then run the normal portal function, i.e. the # interpreter's main loop. It might enter the jit # via maybe_enter_jit(), which typically ends with # handle_fail() being called, which raises on the # following exceptions --- catched here, because we # want to interrupt the whole interpreter loop. return support.maybe_on_top_of_llinterp(rtyper, portal_ptr)(*args) except jitexc.JitException as e: result = handle_jitexception(e) if result_kind != 'void': result = specialize_value(RESULT, result) return result def handle_jitexception(e): # XXX there are too many exceptions all around... while True: if isinstance(e, EnterJitAssembler): try: return e.execute() except jitexc.JitException as e: continue # if isinstance(e, jitexc.ContinueRunningNormally): args = () for ARGTYPE, attrname, count in portalfunc_ARGS: x = getattr(e, attrname)[count] x = specialize_value(ARGTYPE, x) args = args + (x, ) try: result = support.maybe_on_top_of_llinterp( rtyper, portal_ptr)(*args) except jitexc.JitException as e: continue if result_kind != 'void': result = unspecialize_value(result) return result # if result_kind == 'void': if isinstance(e, jitexc.DoneWithThisFrameVoid): return None if result_kind == 'int': if isinstance(e, jitexc.DoneWithThisFrameInt): return e.result if result_kind == 'ref': if isinstance(e, jitexc.DoneWithThisFrameRef): return e.result if result_kind == 'float': if isinstance(e, jitexc.DoneWithThisFrameFloat): return e.result # if isinstance(e, jitexc.ExitFrameWithExceptionRef): value = ts.cast_to_baseclass(e.value) if not we_are_translated(): raise LLException(ts.get_typeptr(value), value) else: value = cast_base_ptr_to_instance(Exception, value) assert value is not None raise value # raise AssertionError("all cases should have been handled") jd._ll_portal_runner = ll_portal_runner # for debugging jd.portal_runner_ptr = self.helper_func(jd._PTR_PORTAL_FUNCTYPE, ll_portal_runner) jd.portal_runner_adr = llmemory.cast_ptr_to_adr(jd.portal_runner_ptr) jd.portal_calldescr = self.cpu.calldescrof( jd._PTR_PORTAL_FUNCTYPE.TO, jd._PTR_PORTAL_FUNCTYPE.TO.ARGS, jd._PTR_PORTAL_FUNCTYPE.TO.RESULT, EffectInfo.MOST_GENERAL) vinfo = jd.virtualizable_info def assembler_call_helper(deadframe, virtualizableref): fail_descr = self.cpu.get_latest_descr(deadframe) try: fail_descr.handle_fail(deadframe, self.metainterp_sd, jd) except jitexc.JitException as e: return handle_jitexception(e) else: assert 0, "should have raised" jd._assembler_call_helper = assembler_call_helper # for debugging jd._assembler_helper_ptr = self.helper_func( jd._PTR_ASSEMBLER_HELPER_FUNCTYPE, assembler_call_helper) jd.assembler_helper_adr = llmemory.cast_ptr_to_adr( jd._assembler_helper_ptr) if vinfo is not None: jd.vable_token_descr = vinfo.vable_token_descr def handle_jitexception_from_blackhole(bhcaller, e): result = handle_jitexception(e) if result_kind == 'void': pass elif result_kind == 'int': bhcaller._setup_return_value_i(result) elif result_kind == 'ref': bhcaller._setup_return_value_r(result) elif result_kind == 'float': bhcaller._setup_return_value_f(result) else: assert False jd.handle_jitexc_from_bh = handle_jitexception_from_blackhole # ____________________________________________________________ # Now mutate origportalgraph to end with a call to portal_runner_ptr # origblock, origindex, op = locate_jit_merge_point(origportalgraph) assert op.opname == 'jit_marker' assert op.args[0].value == 'jit_merge_point' greens_v, reds_v = support.decode_hp_hint_args(op) vlist = [Constant(jd.portal_runner_ptr, jd._PTR_PORTAL_FUNCTYPE)] vlist += greens_v vlist += reds_v v_result = Variable() v_result.concretetype = PORTALFUNC.RESULT newop = SpaceOperation('direct_call', vlist, v_result) del origblock.operations[origindex:] origblock.operations.append(newop) origblock.exitswitch = None origblock.recloseblock(Link([v_result], origportalgraph.returnblock)) # the origportal now can raise (even if it did not raise before), # which means that we cannot inline it anywhere any more, but that's # fine since any forced inlining has been done before # checkgraph(origportalgraph)
def __init__(self, warmrunnerdesc, VTYPEPTR): self.warmrunnerdesc = warmrunnerdesc cpu = warmrunnerdesc.cpu self.cpu = cpu # VTYPEPTR1 = VTYPEPTR while 'virtualizable_accessor' not in deref(VTYPEPTR)._hints: VTYPEPTR = cpu.ts.get_superclass(VTYPEPTR) assert VTYPEPTR is not None, ( "%r is listed in the jit driver's 'virtualizables', " "but that class doesn't have a '_virtualizable_' attribute " "(if it has _virtualizable2_, rename it to _virtualizable_)" % (VTYPEPTR1, )) self.VTYPEPTR = VTYPEPTR self.VTYPE = VTYPE = deref(VTYPEPTR) self.vable_token_descr = cpu.fielddescrof(VTYPE, 'vable_token') # accessor = VTYPE._hints['virtualizable_accessor'] all_fields = accessor.fields static_fields = [] array_fields = [] for name, tp in all_fields.iteritems(): if tp == IR_IMMUTABLE_ARRAY: array_fields.append(name) elif tp == IR_IMMUTABLE: static_fields.append(name) else: raise Exception("unknown type: %s" % tp) self.static_fields = static_fields self.array_fields = array_fields # FIELDTYPES = [fieldType(VTYPE, name) for name in static_fields] ARRAYITEMTYPES = [] for name in array_fields: ARRAYPTR = fieldType(VTYPE, name) ARRAY = deref(ARRAYPTR) assert isinstance(ARRAYPTR, lltype.Ptr) if not isinstance(ARRAY, lltype.GcArray): raise Exception( "The virtualizable field '%s' is not an array (found %r)." " It usually means that you must try harder to ensure that" " the list is not resized at run-time. You can do that by" " using rpython.rlib.debug.make_sure_not_resized()." % (name, ARRAY)) ARRAYITEMTYPES.append(arrayItem(ARRAY)) self.array_descrs = [ cpu.arraydescrof(deref(fieldType(VTYPE, name))) for name in array_fields ] # self.num_static_extra_boxes = len(static_fields) self.num_arrays = len(array_fields) self.static_field_to_extra_box = dict([ (name, i) for (i, name) in enumerate(static_fields) ]) self.array_field_counter = dict([ (name, i) for (i, name) in enumerate(array_fields) ]) self.static_extra_types = [ history.getkind(TYPE) for TYPE in FIELDTYPES ] self.arrayitem_extra_types = [ history.getkind(ITEM) for ITEM in ARRAYITEMTYPES ] self.static_field_descrs = [ cpu.fielddescrof(VTYPE, name) for name in static_fields ] self.array_field_descrs = [ cpu.fielddescrof(VTYPE, name) for name in array_fields ] for descr in self.static_field_descrs: descr.vinfo = self for descr in self.array_field_descrs: descr.vinfo = self self.static_field_by_descrs = dict([ (descr, i) for (i, descr) in enumerate(self.static_field_descrs) ]) self.array_field_by_descrs = dict([ (descr, i) for (i, descr) in enumerate(self.array_field_descrs) ]) # getlength = cpu.ts.getlength getarrayitem = cpu.ts.getarrayitem setarrayitem = cpu.ts.setarrayitem def read_boxes(cpu, virtualizable): assert lltype.typeOf(virtualizable) == llmemory.GCREF virtualizable = cast_gcref_to_vtype(virtualizable) boxes = [] for _, fieldname in unroll_static_fields: x = getattr(virtualizable, fieldname) boxes.append(wrap(cpu, x)) for _, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) for i in range(getlength(lst)): boxes.append(wrap(cpu, getarrayitem(lst, i))) return boxes def write_boxes(virtualizable, boxes): virtualizable = cast_gcref_to_vtype(virtualizable) i = 0 for FIELDTYPE, fieldname in unroll_static_fields: x = unwrap(FIELDTYPE, boxes[i]) setattr(virtualizable, fieldname, x) i = i + 1 for ARRAYITEMTYPE, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) for j in range(getlength(lst)): x = unwrap(ARRAYITEMTYPE, boxes[i]) setarrayitem(lst, j, x) i = i + 1 assert len(boxes) == i + 1 def get_total_size(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) size = 0 for _, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) size += getlength(lst) for _, fieldname in unroll_static_fields: size += 1 return size def write_from_resume_data_partial(virtualizable, reader): virtualizable = cast_gcref_to_vtype(virtualizable) # Load values from the reader (see resume.py) described by # the list of numbers 'nums', and write them in their proper # place in the 'virtualizable'. for FIELDTYPE, fieldname in unroll_static_fields: x = reader.load_next_value_of_type(FIELDTYPE) setattr(virtualizable, fieldname, x) for ARRAYITEMTYPE, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) for j in range(getlength(lst)): x = reader.load_next_value_of_type(ARRAYITEMTYPE) setarrayitem(lst, j, x) def load_list_of_boxes(virtualizable, reader, vable_box): virtualizable = cast_gcref_to_vtype(virtualizable) # Uses 'virtualizable' only to know the length of the arrays; # does not write anything into it. The returned list is in # the format expected of virtualizable_boxes, so it ends in # the virtualizable itself. boxes = [] for FIELDTYPE, fieldname in unroll_static_fields: box = reader.next_box_of_type(FIELDTYPE) boxes.append(box) for ARRAYITEMTYPE, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) for j in range(getlength(lst)): box = reader.next_box_of_type(ARRAYITEMTYPE) boxes.append(box) boxes.append(vable_box) return boxes def check_boxes(virtualizable, boxes): virtualizable = cast_gcref_to_vtype(virtualizable) # for debugging i = 0 for FIELDTYPE, fieldname in unroll_static_fields: x = unwrap(FIELDTYPE, boxes[i]) assert getattr(virtualizable, fieldname) == x i = i + 1 for ARRAYITEMTYPE, fieldname in unroll_array_fields: lst = getattr(virtualizable, fieldname) for j in range(getlength(lst)): x = unwrap(ARRAYITEMTYPE, boxes[i]) assert getarrayitem(lst, j) == x i = i + 1 assert len(boxes) == i + 1 def get_index_in_array(virtualizable, arrayindex, index): virtualizable = cast_gcref_to_vtype(virtualizable) index += self.num_static_extra_boxes j = 0 for _, fieldname in unroll_array_fields: if arrayindex == j: return index lst = getattr(virtualizable, fieldname) index += getlength(lst) j = j + 1 assert False, "invalid arrayindex" def get_array_length(virtualizable, arrayindex): virtualizable = cast_gcref_to_vtype(virtualizable) j = 0 for _, fieldname in unroll_array_fields: if arrayindex == j: lst = getattr(virtualizable, fieldname) return getlength(lst) j += 1 assert False, "invalid arrayindex" unroll_static_fields = unrolling_iterable( zip(FIELDTYPES, static_fields)) unroll_array_fields = unrolling_iterable( zip(ARRAYITEMTYPES, array_fields)) unroll_static_fields_rev = unrolling_iterable( reversed(list(unroll_static_fields))) unroll_array_fields_rev = unrolling_iterable( reversed(list(unroll_array_fields))) self.read_boxes = read_boxes self.write_boxes = write_boxes self.write_from_resume_data_partial = write_from_resume_data_partial self.load_list_of_boxes = load_list_of_boxes self.check_boxes = check_boxes self.get_index_in_array = get_index_in_array self.get_array_length = get_array_length self.get_total_size = get_total_size def cast_to_vtype(virtualizable): return self.cpu.ts.cast_to_instance_maybe(VTYPEPTR, virtualizable) self.cast_to_vtype = cast_to_vtype def cast_gcref_to_vtype(virtualizable): assert lltype.typeOf(virtualizable) == llmemory.GCREF return lltype.cast_opaque_ptr(VTYPEPTR, virtualizable) self.cast_gcref_to_vtype = cast_gcref_to_vtype def clear_vable_token(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: force_now(virtualizable) assert not virtualizable.vable_token self.clear_vable_token = clear_vable_token def tracing_before_residual_call(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) assert not virtualizable.vable_token virtualizable.vable_token = TOKEN_TRACING_RESCALL self.tracing_before_residual_call = tracing_before_residual_call def tracing_after_residual_call(virtualizable): """ Returns whether or not the virtualizable was forced during a CALL_MAY_FORCE. """ virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: # not modified by the residual call; assert that it is still # set to TOKEN_TRACING_RESCALL and clear it. assert virtualizable.vable_token == TOKEN_TRACING_RESCALL virtualizable.vable_token = TOKEN_NONE return False else: # marker "modified during residual call" set. return True self.tracing_after_residual_call = tracing_after_residual_call def force_now(virtualizable): token = virtualizable.vable_token if token == TOKEN_TRACING_RESCALL: # The values in the virtualizable are always correct during # tracing. We only need to reset vable_token to TOKEN_NONE # as a marker for the tracing, to tell it that this # virtualizable escapes. virtualizable.vable_token = TOKEN_NONE else: from rpython.jit.metainterp.compile import ResumeGuardForcedDescr ResumeGuardForcedDescr.force_now(cpu, token) assert virtualizable.vable_token == TOKEN_NONE force_now._dont_inline_ = True self.force_now = force_now def is_token_nonnull_gcref(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) return bool(virtualizable.vable_token) self.is_token_nonnull_gcref = is_token_nonnull_gcref def reset_token_gcref(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) virtualizable.vable_token = TOKEN_NONE self.reset_token_gcref = reset_token_gcref def reset_vable_token(virtualizable): virtualizable.vable_token = TOKEN_NONE self.reset_vable_token = reset_vable_token
def bh_new_array(self, length, arraydescr): array = lltype.malloc(arraydescr.A, length, zero=True) assert getkind(arraydescr.A.OF) != 'ref' # getkind crashes on structs return lltype.cast_opaque_ptr(llmemory.GCREF, array)
def perform_register_allocation(graph, kind): checkkind = lambda v: getkind(v.concretetype) == kind return regalloc.perform_register_allocation(graph, checkkind, ListOfKind)
def write_insn(self, insn): if insn[0] == '---': return if isinstance(insn[0], Label): self.label_positions[insn[0].name] = len(self.code) return if insn[0] == '-live-': key = len(self.code) live_i, live_r, live_f = self.liveness.get(key, ("", "", "")) live_i = self.get_liveness_info(live_i, insn[1:], 'int') live_r = self.get_liveness_info(live_r, insn[1:], 'ref') live_f = self.get_liveness_info(live_f, insn[1:], 'float') self.liveness[key] = live_i, live_r, live_f return startposition = len(self.code) self.code.append("temporary placeholder") # argcodes = [] allow_short = (insn[0] in USE_C_FORM) for x in insn[1:]: if isinstance(x, Register): self.emit_reg(x) argcodes.append(x.kind[0]) elif isinstance(x, Constant): kind = getkind(x.concretetype) is_short = self.emit_const(x, kind, allow_short=allow_short) if is_short: argcodes.append('c') else: argcodes.append(kind[0]) elif isinstance(x, TLabel): self.alllabels.add(len(self.code)) self.tlabel_positions.append((x.name, len(self.code))) self.code.append("temp 1") self.code.append("temp 2") argcodes.append('L') elif isinstance(x, ListOfKind): itemkind = x.kind lst = list(x) assert len(lst) <= 255, "list too long!" self.code.append(chr(len(lst))) for item in lst: if isinstance(item, Register): assert itemkind == item.kind self.emit_reg(item) elif isinstance(item, Constant): assert itemkind == getkind(item.concretetype) self.emit_const(item, itemkind) else: raise NotImplementedError("found in ListOfKind(): %r" % (item,)) argcodes.append(itemkind[0].upper()) elif isinstance(x, AbstractDescr): if x not in self._descr_dict: self._descr_dict[x] = len(self.descrs) self.descrs.append(x) if isinstance(x, SwitchDictDescr): self.switchdictdescrs.append(x) num = self._descr_dict[x] assert 0 <= num <= 0xFFFF, "too many AbstractDescrs!" self.code.append(chr(num & 0xFF)) self.code.append(chr(num >> 8)) argcodes.append('d') elif isinstance(x, IndirectCallTargets): self.indirectcalltargets.update(x.lst) elif x == '->': assert '>' not in argcodes argcodes.append('>') else: raise NotImplementedError(x) # opname = insn[0] if '>' in argcodes: assert argcodes.index('>') == len(argcodes) - 2 self.resulttypes[len(self.code)] = argcodes[-1] key = opname + '/' + ''.join(argcodes) num = self.insns.setdefault(key, len(self.insns)) self.code[startposition] = chr(num) self.startpoints.add(startposition)
def write_insn(self, insn): if insn[0] == '---': return if isinstance(insn[0], Label): self.label_positions[insn[0].name] = len(self.code) return if insn[0] == '-live-': key = len(self.code) live_i, live_r, live_f = self.liveness.get(key, ("", "", "")) live_i = self.get_liveness_info(live_i, insn[1:], 'int') live_r = self.get_liveness_info(live_r, insn[1:], 'ref') live_f = self.get_liveness_info(live_f, insn[1:], 'float') self.liveness[key] = live_i, live_r, live_f return startposition = len(self.code) self.code.append("temporary placeholder") # argcodes = [] allow_short = (insn[0] in USE_C_FORM) for x in insn[1:]: if isinstance(x, Register): self.emit_reg(x) argcodes.append(x.kind[0]) elif isinstance(x, Constant): kind = getkind(x.concretetype) is_short = self.emit_const(x, kind, allow_short=allow_short) if is_short: argcodes.append('c') else: argcodes.append(kind[0]) elif isinstance(x, TLabel): self.alllabels.add(len(self.code)) self.tlabel_positions.append((x.name, len(self.code))) self.code.append("temp 1") self.code.append("temp 2") argcodes.append('L') elif isinstance(x, ListOfKind): itemkind = x.kind lst = list(x) assert len(lst) <= 255, "list too long!" self.code.append(chr(len(lst))) for item in lst: if isinstance(item, Register): assert itemkind == item.kind self.emit_reg(item) elif isinstance(item, Constant): assert itemkind == getkind(item.concretetype) self.emit_const(item, itemkind) else: raise NotImplementedError("found in ListOfKind(): %r" % (item, )) argcodes.append(itemkind[0].upper()) elif isinstance(x, AbstractDescr): if x not in self._descr_dict: self._descr_dict[x] = len(self.descrs) self.descrs.append(x) if isinstance(x, SwitchDictDescr): self.switchdictdescrs.append(x) num = self._descr_dict[x] assert 0 <= num <= 0xFFFF, "too many AbstractDescrs!" self.code.append(chr(num & 0xFF)) self.code.append(chr(num >> 8)) argcodes.append('d') elif isinstance(x, IndirectCallTargets): self.indirectcalltargets.update(x.lst) elif x == '->': assert '>' not in argcodes argcodes.append('>') else: raise NotImplementedError(x) # opname = insn[0] if '>' in argcodes: assert argcodes.index('>') == len(argcodes) - 2 self.resulttypes[len(self.code)] = argcodes[-1] key = opname + '/' + ''.join(argcodes) num = self.insns.setdefault(key, len(self.insns)) self.code[startposition] = chr(num) self.startpoints.add(startposition)
def insert_exits(self, block): if len(block.exits) == 1: # A single link, fall-through link = block.exits[0] assert link.exitcase in (None, False, True) # the cases False or True should not really occur, but can show # up in the manually hacked graphs for generators... self.make_link(link) # elif block.exitswitch is c_last_exception: # An exception block. See test_exc_exitswitch in test_flatten.py # for an example of what kind of code this makes. index = -1 while True: lastopname = block.operations[index].opname if lastopname != '-live-': break index -= 1 assert block.exits[0].exitcase is None # is this always True? # if not self._include_all_exc_links: if index == -1: # cannot raise: the last instruction is not # actually a '-live-' self.make_link(block.exits[0]) return # self.emitline('catch_exception', TLabel(block.exits[0])) self.make_link(block.exits[0]) self.emitline(Label(block.exits[0])) for link in block.exits[1:]: if (link.exitcase is Exception or (link.exitcase is OverflowError and lastopname.startswith('int_') and lastopname.endswith('_ovf'))): # this link captures all exceptions self.make_exception_link(link) break self.emitline( 'goto_if_exception_mismatch', Constant(link.llexitcase, lltype.typeOf(link.llexitcase)), TLabel(link)) self.make_exception_link(link) self.emitline(Label(link)) else: # no link captures all exceptions, so we have to put a reraise # for the other exceptions self.emitline("reraise") self.emitline("---") # elif len(block.exits) == 2 and (isinstance(block.exitswitch, tuple) or block.exitswitch.concretetype == lltype.Bool): # Two exit links with a boolean condition linkfalse, linktrue = block.exits if linkfalse.llexitcase == True: linkfalse, linktrue = linktrue, linkfalse opname = 'goto_if_not' livebefore = False if isinstance(block.exitswitch, tuple): # special case produced by jtransform.optimize_goto_if_not() opname = 'goto_if_not_' + block.exitswitch[0] opargs = block.exitswitch[1:] if opargs[-1] == '-live-before': livebefore = True opargs = opargs[:-1] else: assert block.exitswitch.concretetype == lltype.Bool opargs = [block.exitswitch] # lst = self.flatten_list(opargs) + [TLabel(linkfalse)] if livebefore: self.emitline('-live-') self.emitline(opname, *lst) if not livebefore: self.emitline('-live-', TLabel(linkfalse)) # true path: self.make_link(linktrue) # false path: self.emitline(Label(linkfalse)) self.make_link(linkfalse) # else: # A switch. # switches = [ link for link in block.exits if link.exitcase != 'default' ] switches.sort(key=lambda link: link.llexitcase) kind = getkind(block.exitswitch.concretetype) assert kind == 'int' # XXX # # A switch on an integer, implementable efficiently with the # help of a SwitchDictDescr. We use this even if there are # very few cases: in pyjitpl.py, opimpl_switch() will promote # the int only if it matches one of the cases. from rpython.jit.codewriter.jitcode import SwitchDictDescr switchdict = SwitchDictDescr() switchdict._labels = [] self.emitline('-live-') # for 'guard_value' self.emitline('switch', self.getcolor(block.exitswitch), switchdict) # emit the default path if block.exits[-1].exitcase == 'default': self.make_link(block.exits[-1]) else: self.emitline("unreachable") self.emitline("---") # for switch in switches: key = lltype.cast_primitive(lltype.Signed, switch.llexitcase) switchdict._labels.append((key, TLabel(switch))) # emit code for that path # note: we need a -live- for all the 'guard_false' we produce # if the switched value doesn't match any case. self.emitline(Label(switch)) self.emitline('-live-') self.make_link(switch)
def get_integer_max(self): if getkind(self.FIELD) != 'int': assert False return intbounds.get_integer_max( not _is_signed_kind(self.FIELD), rffi.sizeof(self.FIELD))
def rewrite_jit_merge_point(self, jd, policy): # # Mutate the original portal graph from this: # # def original_portal(..): # stuff # while 1: # jit_merge_point(*args) # more stuff # # to that: # # def original_portal(..): # stuff # return portal_runner(*args) # # def portal_runner(*args): # while 1: # try: # return portal(*args) # except ContinueRunningNormally, e: # *args = *e.new_args # except DoneWithThisFrame, e: # return e.return # except ExitFrameWithException, e: # raise Exception, e.value # # def portal(*args): # while 1: # more stuff # origportalgraph = jd._jit_merge_point_in portalgraph = jd.portal_graph PORTALFUNC = jd._PORTAL_FUNCTYPE # ____________________________________________________________ # Prepare the portal_runner() helper # from rpython.jit.metainterp.warmstate import specialize_value from rpython.jit.metainterp.warmstate import unspecialize_value portal_ptr = self.cpu.ts.functionptr(PORTALFUNC, 'portal', graph=portalgraph) jd._portal_ptr = portal_ptr # portalfunc_ARGS = [] nums = {} for i, ARG in enumerate(PORTALFUNC.ARGS): kind = history.getkind(ARG) assert kind != 'void' if i < len(jd.jitdriver.greens): color = 'green' else: color = 'red' attrname = '%s_%s' % (color, kind) count = nums.get(attrname, 0) nums[attrname] = count + 1 portalfunc_ARGS.append((ARG, attrname, count)) portalfunc_ARGS = unrolling_iterable(portalfunc_ARGS) # rtyper = self.translator.rtyper RESULT = PORTALFUNC.RESULT result_kind = history.getkind(RESULT) ts = self.cpu.ts state = jd.warmstate maybe_compile_and_run = jd._maybe_compile_and_run_fn def ll_portal_runner(*args): start = True while 1: try: # maybe enter from the function's start. Note that the # 'start' variable is constant-folded away because it's # the first statement in the loop. if start: maybe_compile_and_run( state.increment_function_threshold, *args) # # then run the normal portal function, i.e. the # interpreter's main loop. It might enter the jit # via maybe_enter_jit(), which typically ends with # handle_fail() being called, which raises on the # following exceptions --- catched here, because we # want to interrupt the whole interpreter loop. return support.maybe_on_top_of_llinterp(rtyper, portal_ptr)(*args) except jitexc.ContinueRunningNormally, e: args = () for ARGTYPE, attrname, count in portalfunc_ARGS: x = getattr(e, attrname)[count] x = specialize_value(ARGTYPE, x) args = args + (x,) start = False continue except jitexc.DoneWithThisFrameVoid: assert result_kind == 'void' return except jitexc.DoneWithThisFrameInt, e: assert result_kind == 'int' return specialize_value(RESULT, e.result)
def get_integer_max(self): if getkind(self.FIELD) != 'int': assert False return intbounds.get_integer_max(not _is_signed_kind(self.FIELD), rffi.sizeof(self.FIELD))