def finish_rtype(self): rtyper = self.rtyper translator = rtyper.annotator.translator original_graph_count = len(translator.graphs) rtyper.type_system.perform_normalizations(rtyper) for r in self.delayedreprs: r.set_setup_delayed(False) rtyper.call_all_setups() for p, repr, obj in self.delayedconsts: p._become(repr.convert_const(obj)) rtyper.call_all_setups() for p, graph in self.delayedfuncs: self.newgraphs[graph] = True real_p = rtyper.getcallable(graph) REAL = get_functype(lltype.typeOf(real_p)) FUNCTYPE = get_functype(lltype.typeOf(p)) if isinstance(FUNCTYPE, (lltype.ForwardReference, ootype.ForwardReference)): FUNCTYPE.become(REAL) assert FUNCTYPE == REAL p._become(real_p) rtyper.specialize_more_blocks() self.delayedreprs.clear() del self.delayedconsts[:] del self.delayedfuncs[:] for graph in translator.graphs[original_graph_count:]: self.newgraphs[graph] = True
def indirect_call(hs_v1, *args_hs): hs_graph_list = args_hs[-1] args_hs = args_hs[:-1] assert hs_graph_list.is_constant() graph_list = hs_graph_list.const FUNC = get_functype(hs_v1.concretetype) return hs_v1._call_multiple_graphs(graph_list, FUNC.RESULT, *args_hs)
def call_primitive(self, op, module, name): from pypy.translator.simplify import get_functype callee = op.args[0].value # it could be an rffi lltype, see test_primitive.test_rffi_ooprimitive TYPE = get_functype(callee._TYPE) jargtypes, jrettype = self.db.types_for_signature(TYPE.ARGS, TYPE.RESULT) # Determine what class the primitive is implemented in: if module == 'll_os': jcls = jvm.jll_os else: jcls = jPyPy # Determine the method signature: # n.b.: if the method returns a generated type, then # it's static type will be Object. This is because # the method cannot directly refer to the Java type in # .java source, as its name is not yet known. if jrettype.is_generated(): mthd = jvm.Method.v(jcls, name, jargtypes, jvm.jObject) else: mthd = jvm.Method.v(jcls, name, jargtypes, jrettype) # Invoke the method self.emit(mthd) # Cast the result, if needed if jrettype.is_generated(): self.downcast_jtype(jrettype)
def helper_func(self, FUNCPTR, func): if not self.cpu.translate_support_code: return llhelper(FUNCPTR, func) FUNC = get_functype(FUNCPTR) args_s = [annmodel.lltype_to_annotation(ARG) for ARG in FUNC.ARGS] s_result = annmodel.lltype_to_annotation(FUNC.RESULT) graph = self.annhelper.getgraph(func, args_s, s_result) return self.annhelper.graph2delayed(graph, FUNC)
def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE, extraeffect=None): """Return the calldescr that describes all calls done by 'op'. This returns a calldescr that we can put in the corresponding call operation in the calling jitcode. It gets an effectinfo describing the effect of the call: which field types it may change, whether it can force virtualizables, whether it can raise, etc. """ NON_VOID_ARGS = [x.concretetype for x in op.args[1:] if x.concretetype is not lltype.Void] RESULT = op.result.concretetype # check the number and type of arguments FUNC = get_functype(op.args[0].concretetype) ARGS = FUNC.ARGS assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok # get the 'pure' and 'loopinvariant' flags from the function object pure = False loopinvariant = False if op.opname == "direct_call": func = getattr(get_funcobj(op.args[0].value), '_callable', None) pure = getattr(func, "_pure_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") # build the extraeffect can_invalidate = self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT elif pure: # XXX check what to do about exceptions (also MemoryError?) extraeffect = EffectInfo.EF_PURE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: extraeffect = EffectInfo.EF_CANNOT_RAISE # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, oopspecindex, can_invalidate) # if oopspecindex != EffectInfo.OS_NONE: assert effectinfo is not None if pure or loopinvariant: assert effectinfo is not None assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but # it can't because our analyzer is not good enough for now # (and getexecutioncontext() can't really invalidate) # return self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT, effectinfo)
def specialize_call(self, hop): args_r = [hop.rtyper.getrepr(s) for s in self.instance.args_s] r_res = hop.rtyper.getrepr(self.instance.s_result) vlist = hop.inputargs(*args_r) p = self.instance.llfnptr TYPE = lltype.typeOf(p) c_func = Constant(p, TYPE) FUNCTYPE = get_functype(TYPE) for r_arg, ARGTYPE in zip(args_r, FUNCTYPE.ARGS): assert r_arg.lowleveltype == ARGTYPE assert r_res.lowleveltype == FUNCTYPE.RESULT hop.exception_is_here() return hop.genop('direct_call', [c_func] + vlist, resulttype = r_res)
def specialize_call(self, hop): args_r = [hop.rtyper.getrepr(s) for s in self.instance.args_s] r_res = hop.rtyper.getrepr(self.instance.s_result) vlist = hop.inputargs(*args_r) p = self.instance.llfnptr TYPE = lltype.typeOf(p) c_func = Constant(p, TYPE) FUNCTYPE = get_functype(TYPE) for r_arg, ARGTYPE in zip(args_r, FUNCTYPE.ARGS): assert r_arg.lowleveltype == ARGTYPE assert r_res.lowleveltype == FUNCTYPE.RESULT hop.exception_is_here() return hop.genop('direct_call', [c_func] + vlist, resulttype=r_res)
def get_jitcode_calldescr(self, graph): """Return the calldescr that describes calls to the 'graph'. This returns a calldescr that is appropriate to attach to the jitcode corresponding to 'graph'. It has no extra effectinfo, because it is not needed there; it is only used by the blackhole interp to really do the call corresponding to 'inline_call' ops. """ fnptr = self.rtyper.type_system.getcallable(graph) FUNC = get_functype(lltype.typeOf(fnptr)) assert lltype.Ptr(lltype.PyObject) not in FUNC.ARGS if self.rtyper.type_system.name == 'ootypesystem': XXX else: fnaddr = llmemory.cast_ptr_to_adr(fnptr) NON_VOID_ARGS = [ARG for ARG in FUNC.ARGS if ARG is not lltype.Void] calldescr = self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), FUNC.RESULT) return (fnaddr, calldescr)
def get_jitcode_calldescr(self, graph): """Return the calldescr that describes calls to the 'graph'. This returns a calldescr that is appropriate to attach to the jitcode corresponding to 'graph'. It has no extra effectinfo, because it is not needed there; it is only used by the blackhole interp to really do the call corresponding to 'inline_call' ops. """ fnptr = self.rtyper.type_system.getcallable(graph) FUNC = get_functype(lltype.typeOf(fnptr)) assert lltype.Ptr(lltype.PyObject) not in FUNC.ARGS if self.rtyper.type_system.name == 'ootypesystem': XXX else: fnaddr = llmemory.cast_ptr_to_adr(fnptr) NON_VOID_ARGS = [ARG for ARG in FUNC.ARGS if ARG is not lltype.Void] calldescr = self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), FUNC.RESULT, EffectInfo.MOST_GENERAL) return (fnaddr, calldescr)
def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE, extraeffect=None): """Return the calldescr that describes all calls done by 'op'. This returns a calldescr that we can put in the corresponding call operation in the calling jitcode. It gets an effectinfo describing the effect of the call: which field types it may change, whether it can force virtualizables, whether it can raise, etc. """ NON_VOID_ARGS = [x.concretetype for x in op.args[1:] if x.concretetype is not lltype.Void] RESULT = op.result.concretetype # check the number and type of arguments FUNC = get_functype(op.args[0].concretetype) ARGS = FUNC.ARGS assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void] assert RESULT == FUNC.RESULT # ok # get the 'elidable' and 'loopinvariant' flags from the function object elidable = False loopinvariant = False if op.opname == "direct_call": funcobj = get_funcobj(op.args[0].value) assert getattr(funcobj, 'calling_conv', 'c') == 'c', ( "%r: getcalldescr() with a non-default call ABI" % (op,)) func = getattr(funcobj, '_callable', None) elidable = getattr(func, "_elidable_function_", False) loopinvariant = getattr(func, "_jit_loop_invariant_", False) if loopinvariant: assert not NON_VOID_ARGS, ("arguments not supported for " "loop-invariant function!") # build the extraeffect random_effects = self.randomeffects_analyzer.analyze(op) if random_effects: extraeffect = EffectInfo.EF_RANDOM_EFFECTS # random_effects implies can_invalidate can_invalidate = random_effects or self.quasiimmut_analyzer.analyze(op) if extraeffect is None: if self.virtualizable_analyzer.analyze(op): extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE elif loopinvariant: extraeffect = EffectInfo.EF_LOOPINVARIANT elif elidable: if self._canraise(op): extraeffect = EffectInfo.EF_ELIDABLE_CAN_RAISE else: extraeffect = EffectInfo.EF_ELIDABLE_CANNOT_RAISE elif self._canraise(op): extraeffect = EffectInfo.EF_CAN_RAISE else: extraeffect = EffectInfo.EF_CANNOT_RAISE # effectinfo = effectinfo_from_writeanalyze( self.readwrite_analyzer.analyze(op), self.cpu, extraeffect, oopspecindex, can_invalidate) # assert effectinfo is not None if elidable or loopinvariant: assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE # XXX this should also say assert not can_invalidate, but # it can't because our analyzer is not good enough for now # (and getexecutioncontext() can't really invalidate) # return self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT, effectinfo)