Example #1
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
Example #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
Example #3
0
 def find_portal(self):
     graphs = self.translator.graphs
     self.jit_merge_point_pos = find_jit_merge_point(graphs)
     graph, block, pos = self.jit_merge_point_pos
     op = block.operations[pos]
     args = op.args[2:]
     s_binding = self.translator.annotator.binding
     self.portal_args_s = [s_binding(v) for v in args]
     graph = copygraph(graph)
     graph.startblock.isstartblock = False
     graph.startblock = support.split_before_jit_merge_point(
         *find_jit_merge_point([graph]))
     graph.startblock.isstartblock = True
     # a crash in the following checkgraph() means that you forgot
     # to list some variable in greens=[] or reds=[] in JitDriver.
     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)
     self.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
     self.jitdriver = block.operations[pos].args[1].value
Example #4
0
 def split_graph_and_record_jitdriver(self, graph, block, pos):
     op = block.operations[pos]
     jd = JitDriverStaticData()
     jd._jit_merge_point_pos = (graph, op)
     args = op.args[2:]
     s_binding = self.translator.annotator.binding
     jd._portal_args_s = [s_binding(v) for v in args]
     graph = copygraph(graph)
     graph.startblock.isstartblock = False
     [jmpp] = find_jit_merge_points([graph])
     graph.startblock = support.split_before_jit_merge_point(*jmpp)
     graph.startblock.isstartblock = True
     # a crash in the following checkgraph() means that you forgot
     # to list some variable in greens=[] or reds=[] in JitDriver.
     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)
Example #5
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)
Example #6
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)
Example #7
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)
     # 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)
Example #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)
Example #9
0
 def cachedgraph(self, key, alt_name=None):
     verbose = self.bookkeeper.annotator.translator.config.translation.verbose
     try:
         return self._cache[key]
     except KeyError:
         bk = self.bookkeeper
         look = bk.annotator.policy.look_inside_graph(self.origgraph)
         if look and not callable(look):
             # normal case
             graph = copygraph(self.origgraph, varmap=TIMESHIFTMAP)
             if not self._cache:
                 bk.nonstuboriggraphcount += 1
             if verbose:
                 log(str(graph))
             else:
                 log.dot()
         else:
             graph = self.build_callback_graph(self.origgraph, look)
             if not self._cache:
                 bk.stuboriggraphcount += 1                
             if verbose:
                 log.stub(str(graph))
             else:
                 log.stub.dot()
         graph.tag = 'timeshifted'
         try:
             etrafo = bk.annotator.exceptiontransformer
         except AttributeError:
             pass
         else:
             # except transform the copied graph before its hint-annotation
             etrafo.create_exception_handling(graph, always_exc_clear=True)
         if alt_name is not None:
             graph.name = alt_name
         self._cache[key] = graph
         self.bookkeeper.annotator.translator.graphs.append(graph)
         return graph
Example #10
0
 def patch_graph(self):
     graph = self.graph
     self.gcrootscount = 0
     if self.db.gctransformer:
         # inline the GC helpers (malloc, write_barrier) into
         # a copy of the graph
         graph = copygraph(graph, shallow=True)
         self.db.gctransformer.inline_helpers(graph)
         # the 'gc_reload_possibly_moved' operations make the graph not
         # really SSA.  Fix them now.
         for block in graph.iterblocks():
             rename = {}
             for op in block.operations:
                 if rename:
                     op.args = [rename.get(v, v) for v in op.args]
                 if op.opname == 'gc_reload_possibly_moved':
                     v_newaddr, v_targetvar = op.args
                     assert isinstance(v_targetvar.concretetype, lltype.Ptr)
                     v_newptr = Variable()
                     v_newptr.concretetype = v_targetvar.concretetype
                     op.opname = 'cast_adr_to_ptr'
                     op.args = [v_newaddr]
                     op.result = v_newptr
                     rename[v_targetvar] = v_newptr
                 elif op.opname == 'llvm_store_gcroot':
                     index = op.args[0].value
                     self.gcrootscount = max(self.gcrootscount, index+1)
             if rename:
                 block.exitswitch = rename.get(block.exitswitch,
                                               block.exitswitch)
                 for link in block.exits:
                     link.args = [rename.get(v, v) for v in link.args]
     # fix special cases that llvm can't handle
     remove_double_links(self.db.translator.annotator, graph)
     no_links_to_startblock(graph)
     return graph
Example #11
0
 def patch_graph(self):
     graph = self.graph
     self.gcrootscount = 0
     if self.db.gctransformer:
         # inline the GC helpers (malloc, write_barrier) into
         # a copy of the graph
         graph = copygraph(graph, shallow=True)
         self.db.gctransformer.inline_helpers(graph)
         # the 'gc_reload_possibly_moved' operations make the graph not
         # really SSA.  Fix them now.
         for block in graph.iterblocks():
             rename = {}
             for op in block.operations:
                 if rename:
                     op.args = [rename.get(v, v) for v in op.args]
                 if op.opname == 'gc_reload_possibly_moved':
                     v_newaddr, v_targetvar = op.args
                     assert isinstance(v_targetvar.concretetype, lltype.Ptr)
                     v_newptr = Variable()
                     v_newptr.concretetype = v_targetvar.concretetype
                     op.opname = 'cast_adr_to_ptr'
                     op.args = [v_newaddr]
                     op.result = v_newptr
                     rename[v_targetvar] = v_newptr
                 elif op.opname == 'llvm_store_gcroot':
                     index = op.args[0].value
                     self.gcrootscount = max(self.gcrootscount, index + 1)
             if rename:
                 block.exitswitch = rename.get(block.exitswitch,
                                               block.exitswitch)
                 for link in block.exits:
                     link.args = [rename.get(v, v) for v in link.args]
     # fix special cases that llvm can't handle
     remove_double_links(self.db.translator.annotator, graph)
     no_links_to_startblock(graph)
     return graph
Example #12
0
 def handle_call_with_close_stack(self, hop):
     fnptr = hop.spaceop.args[0].value
     # 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.  We need to 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)
             sradict[key] = Constant(p, lltype.Ptr(CONTAINER))
         sra.append(sradict[key])
     #
     # store the value of the arguments
     livevars = self.push_roots(hop)
     c_item0 = Constant('item0', lltype.Void)
     for v_arg, c_p in zip(hop.spaceop.args[1:], sra):
         if isinstance(v_arg.concretetype, lltype.Ptr):
             v_arg = hop.genop("cast_ptr_to_adr", [v_arg],
                               resulttype=llmemory.Address)
         hop.genop("bare_setfield", [c_p, c_item0, v_arg])
     #
     # make a copy of the graph that will reload the values
     graph2 = copygraph(fnptr._obj.graph)
     block2 = graph2.startblock
     block2.isstartblock = False
     block1 = Block([])
     reloadedvars = []
     for v, c_p in zip(block2.inputargs, sra):
         v = copyvar(None, v)
         if isinstance(v.concretetype, lltype.Ptr):
             w = Variable('tmp')
             w.concretetype = 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))
     block1.isstartblock = True
     graph2.startblock = block1
     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)], FUNC1.RESULT)
     #
     v_asm_stackwalk = hop.genop("cast_pointer", [c_asm_stackwalk],
                                 resulttype=lltype.Ptr(HELPERFUNC))
     hop.genop("indirect_call",
               [v_asm_stackwalk, c_fnptr2, Constant(None, lltype.Void)],
               resultvar=hop.spaceop.result)
     self.pop_roots(hop, livevars)
Example #13
0
 def handle_call_with_close_stack(self, hop):
     fnptr = hop.spaceop.args[0].value
     # 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.  We need to 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])
     #
     # store the value of the arguments
     livevars = self.push_roots(hop)
     c_item0 = Constant('item0', lltype.Void)
     for v_arg, c_p in zip(hop.spaceop.args[1:], sra):
         if isinstance(v_arg.concretetype, lltype.Ptr):
             v_arg = hop.genop("cast_ptr_to_adr", [v_arg],
                               resulttype=llmemory.Address)
         hop.genop("bare_setfield", [c_p, c_item0, v_arg])
     #
     # make a copy of the graph that will reload the values
     graph2 = copygraph(fnptr._obj.graph)
     block2 = graph2.startblock
     block1 = Block([])
     reloadedvars = []
     for v, c_p in zip(block2.inputargs, sra):
         v = copyvar(None, v)
         if isinstance(v.concretetype, lltype.Ptr):
             w = Variable('tmp')
             w.concretetype = 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
     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 = hop.genop("cast_pointer", [c_asm_stackwalk],
                                 resulttype=lltype.Ptr(HELPERFUNC))
     hop.genop("indirect_call",
               [v_asm_stackwalk, c_fnptr2, c_gcrootanchor,
                Constant(None, lltype.Void)],
               resultvar=hop.spaceop.result)
     self.pop_roots(hop, livevars)