Ejemplo n.º 1
0
 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)
Ejemplo n.º 2
0
 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
Ejemplo n.º 3
0
 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)
Ejemplo n.º 4
0
 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)
Ejemplo n.º 5
0
 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)
Ejemplo n.º 6
0
 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
Ejemplo n.º 7
0
 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)
Ejemplo n.º 8
0
 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)
Ejemplo n.º 9
0
 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)
Ejemplo n.º 10
0
 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)