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 patch_graph(self, copy_graph): graph = self.graph if self.db.gctransformer and self.db.gctransformer.inline: if copy_graph: graph = copygraph(graph, shallow=True) self.db.gctransformer.inline_helpers(graph) return graph
def transform_graph_to_jitcode(self, graph, jitcode, verbose): """Transform a graph into a JitCode containing the same bytecode in a different format. """ portal_jd = self.callcontrol.jitdriver_sd_from_portal_graph(graph) graph = copygraph(graph, shallowvars=True) # # step 1: mangle the graph so that it contains the final instructions # that we want in the JitCode, but still as a control flow graph transform_graph(graph, self.cpu, self.callcontrol, portal_jd) # # step 2: perform register allocation on it regallocs = {} for kind in KINDS: regallocs[kind] = perform_register_allocation(graph, kind) # # step 3: flatten the graph to produce human-readable "assembler", # which means mostly producing a linear list of operations and # inserting jumps or conditional jumps. This is a list of tuples # of the shape ("opname", arg1, ..., argN) or (Label(...),). ssarepr = flatten_graph(graph, regallocs) # # step 3b: compute the liveness around certain operations compute_liveness(ssarepr) # # step 4: "assemble" it into a JitCode, which contains a sequence # of bytes and lists of constants. It's during this step that # constants are cast to their normalized type (Signed, GCREF or # Float). self.assembler.assemble(ssarepr, jitcode) # # print the resulting assembler if self.debug: self.print_ssa_repr(ssarepr, portal_jd, verbose)
def transform_graph_to_jitcode(self, graph, jitcode, verbose, index): """Transform a graph into a JitCode containing the same bytecode in a different format. """ portal_jd = self.callcontrol.jitdriver_sd_from_portal_graph(graph) graph = copygraph(graph, shallowvars=True) # # step 1: mangle the graph so that it contains the final instructions # that we want in the JitCode, but still as a control flow graph transform_graph(graph, self.cpu, self.callcontrol, portal_jd) # # step 2: perform register allocation on it regallocs = {} for kind in KINDS: regallocs[kind] = perform_register_allocation(graph, kind) # # step 3: flatten the graph to produce human-readable "assembler", # which means mostly producing a linear list of operations and # inserting jumps or conditional jumps. This is a list of tuples # of the shape ("opname", arg1, ..., argN) or (Label(...),). ssarepr = flatten_graph(graph, regallocs, cpu=self.callcontrol.cpu) # # step 3b: compute the liveness around certain operations compute_liveness(ssarepr) # # step 4: "assemble" it into a JitCode, which contains a sequence # of bytes and lists of constants. It's during this step that # constants are cast to their normalized type (Signed, GCREF or # Float). self.assembler.assemble(ssarepr, jitcode) jitcode.index = index # # print the resulting assembler if self.debug: self.print_ssa_repr(ssarepr, portal_jd, verbose)
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 build_specialized_graph(self, graph, key, nodelist): graph2 = copygraph(graph) virtualframe = VirtualFrame(graph2.startblock, 0, nodelist) graphbuilder = GraphBuilder(self, graph2) specblock = graphbuilder.start_from_virtualframe(virtualframe) specgraph = graph2 specgraph.name += '_mallocv' specgraph.startblock = specblock self.specialized_graphs[key] = ('call', specgraph) try: graphbuilder.propagate_specializations() except ForcedInline, e: if self.verbose: log.mallocv('%s inlined: %s' % (graph.name, e)) self.specialized_graphs[key] = ('inline', None)
def _transform_hint_close_stack(self, fnptr): # We cannot easily pass variable amount of arguments of the call # across the call to the pypy_asm_stackwalk helper. So we store # them away and restore them. More precisely, we need to # replace 'graph' with code that saves the arguments, and make # a new graph that starts with restoring the arguments. if self._asmgcc_save_restore_arguments is None: self._asmgcc_save_restore_arguments = {} sradict = self._asmgcc_save_restore_arguments sra = [] # list of pointers to raw-malloced containers for args seen = {} FUNC1 = lltype.typeOf(fnptr).TO for TYPE in FUNC1.ARGS: if isinstance(TYPE, lltype.Ptr): TYPE = llmemory.Address num = seen.get(TYPE, 0) seen[TYPE] = num + 1 key = (TYPE, num) if key not in sradict: CONTAINER = lltype.FixedSizeArray(TYPE, 1) p = lltype.malloc(CONTAINER, flavor='raw', zero=True, immortal=True) sradict[key] = Constant(p, lltype.Ptr(CONTAINER)) sra.append(sradict[key]) # # make a copy of the graph that will reload the values graph = fnptr._obj.graph graph2 = copygraph(graph) # # edit the original graph to only store the value of the arguments block = Block(graph.startblock.inputargs) c_item0 = Constant('item0', lltype.Void) assert len(block.inputargs) == len(sra) for v_arg, c_p in zip(block.inputargs, sra): if isinstance(v_arg.concretetype, lltype.Ptr): v_adr = varoftype(llmemory.Address) block.operations.append( SpaceOperation("cast_ptr_to_adr", [v_arg], v_adr)) v_arg = v_adr v_void = varoftype(lltype.Void) block.operations.append( SpaceOperation("bare_setfield", [c_p, c_item0, v_arg], v_void)) # # call asm_stackwalk(graph2) FUNC2 = lltype.FuncType([], FUNC1.RESULT) fnptr2 = lltype.functionptr(FUNC2, fnptr._obj._name + '_reload', graph=graph2) c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2)) HELPERFUNC = lltype.FuncType([lltype.Ptr(FUNC2), ASM_FRAMEDATA_HEAD_PTR], FUNC1.RESULT) v_asm_stackwalk = varoftype(lltype.Ptr(HELPERFUNC), "asm_stackwalk") block.operations.append( SpaceOperation("cast_pointer", [c_asm_stackwalk], v_asm_stackwalk)) v_result = varoftype(FUNC1.RESULT) block.operations.append( SpaceOperation("indirect_call", [v_asm_stackwalk, c_fnptr2, c_gcrootanchor, Constant(None, lltype.Void)], v_result)) block.closeblock(Link([v_result], graph.returnblock)) graph.startblock = block # # edit the copy of the graph to reload the values block2 = graph2.startblock block1 = Block([]) reloadedvars = [] for v, c_p in zip(block2.inputargs, sra): v = v.copy() if isinstance(v.concretetype, lltype.Ptr): w = varoftype(llmemory.Address) else: w = v block1.operations.append(SpaceOperation('getfield', [c_p, c_item0], w)) if w is not v: block1.operations.append(SpaceOperation('cast_adr_to_ptr', [w], v)) reloadedvars.append(v) block1.closeblock(Link(reloadedvars, block2)) graph2.startblock = block1 # checkgraph(graph) checkgraph(graph2)
def _transform_hint_close_stack(self, fnptr): # We cannot easily pass variable amount of arguments of the call # across the call to the pypy_asm_stackwalk helper. So we store # them away and restore them. More precisely, we need to # replace 'graph' with code that saves the arguments, and make # a new graph that starts with restoring the arguments. if self._asmgcc_save_restore_arguments is None: self._asmgcc_save_restore_arguments = {} sradict = self._asmgcc_save_restore_arguments sra = [] # list of pointers to raw-malloced containers for args seen = {} FUNC1 = lltype.typeOf(fnptr).TO for TYPE in FUNC1.ARGS: if isinstance(TYPE, lltype.Ptr): TYPE = llmemory.Address num = seen.get(TYPE, 0) seen[TYPE] = num + 1 key = (TYPE, num) if key not in sradict: CONTAINER = lltype.FixedSizeArray(TYPE, 1) p = lltype.malloc(CONTAINER, flavor='raw', zero=True, immortal=True) sradict[key] = Constant(p, lltype.Ptr(CONTAINER)) sra.append(sradict[key]) # # make a copy of the graph that will reload the values graph = fnptr._obj.graph graph2 = copygraph(graph) # # edit the original graph to only store the value of the arguments block = Block(graph.startblock.inputargs) c_item0 = Constant('item0', lltype.Void) assert len(block.inputargs) == len(sra) for v_arg, c_p in zip(block.inputargs, sra): if isinstance(v_arg.concretetype, lltype.Ptr): v_adr = varoftype(llmemory.Address) block.operations.append( SpaceOperation("cast_ptr_to_adr", [v_arg], v_adr)) v_arg = v_adr v_void = varoftype(lltype.Void) block.operations.append( SpaceOperation("bare_setfield", [c_p, c_item0, v_arg], v_void)) # # call asm_stackwalk(graph2) FUNC2 = lltype.FuncType([], FUNC1.RESULT) fnptr2 = lltype.functionptr(FUNC2, fnptr._obj._name + '_reload', graph=graph2) c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2)) HELPERFUNC = lltype.FuncType( [lltype.Ptr(FUNC2), ASM_FRAMEDATA_HEAD_PTR], FUNC1.RESULT) v_asm_stackwalk = varoftype(lltype.Ptr(HELPERFUNC), "asm_stackwalk") block.operations.append( SpaceOperation("cast_pointer", [c_asm_stackwalk], v_asm_stackwalk)) v_result = varoftype(FUNC1.RESULT) block.operations.append( SpaceOperation("indirect_call", [ v_asm_stackwalk, c_fnptr2, c_gcrootanchor, Constant(None, lltype.Void) ], v_result)) block.closeblock(Link([v_result], graph.returnblock)) graph.startblock = block # # edit the copy of the graph to reload the values block2 = graph2.startblock block1 = Block([]) reloadedvars = [] for v, c_p in zip(block2.inputargs, sra): v = v.copy() if isinstance(v.concretetype, lltype.Ptr): w = varoftype(llmemory.Address) else: w = v block1.operations.append( SpaceOperation('getfield', [c_p, c_item0], w)) if w is not v: block1.operations.append( SpaceOperation('cast_adr_to_ptr', [w], v)) reloadedvars.append(v) block1.closeblock(Link(reloadedvars, block2)) graph2.startblock = block1 # checkgraph(graph) checkgraph(graph2)