def rewrite_can_enter_jit(self, jd, can_enter_jits): FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn) if len(can_enter_jits) == 0: # see test_warmspot.test_no_loop_at_all operations = jd.portal_graph.startblock.operations op1 = operations[0] assert (op1.opname == 'jit_marker' and op1.args[0].value == 'jit_merge_point') op0 = SpaceOperation( 'jit_marker', [Constant('can_enter_jit', lltype.Void)] + op1.args[1:], None) operations.insert(0, op0) can_enter_jits = [(jd.portal_graph, jd.portal_graph.startblock, 0)] for graph, block, index in can_enter_jits: if graph is jd._jit_merge_point_in: continue op = block.operations[index] greens_v, reds_v = support.decode_hp_hint_args(op) args_v = greens_v + reds_v vlist = [Constant(jit_enter_fnptr, FUNCPTR)] + args_v v_result = Variable() v_result.concretetype = lltype.Void newop = SpaceOperation('direct_call', vlist, v_result) block.operations[index] = newop
def rewrite_can_enter_jit(self, jd, can_enter_jits): FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn) if len(can_enter_jits) == 0: # see test_warmspot.test_no_loop_at_all operations = jd.portal_graph.startblock.operations op1 = operations[0] assert (op1.opname == 'jit_marker' and op1.args[0].value == 'jit_merge_point') op0 = SpaceOperation('jit_marker', [Constant('can_enter_jit', lltype.Void)] + op1.args[1:], None) operations.insert(0, op0) can_enter_jits = [(jd.portal_graph, jd.portal_graph.startblock, 0)] for graph, block, index in can_enter_jits: if graph is jd._jit_merge_point_in: continue op = block.operations[index] greens_v, reds_v = support.decode_hp_hint_args(op) args_v = greens_v + reds_v vlist = [Constant(jit_enter_fnptr, FUNCPTR)] + args_v v_result = Variable() v_result.concretetype = lltype.Void newop = SpaceOperation('direct_call', vlist, v_result) block.operations[index] = newop
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 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)
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)
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 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 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)