def insert_stackcheck(ann): from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles edges = [] graphs_to_patch = {} for callposition, (caller, callee) in ann.translator.callgraph.items(): if getattr(getattr(callee, 'func', None), 'insert_stack_check_here', False): graphs_to_patch[callee] = True continue edge = Edge(caller, callee) edge.callposition = callposition edges.append(edge) for graph in graphs_to_patch: v = Variable() ann.setbinding(v, annmodel.SomeImpossibleValue()) unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v) graph.startblock.operations.insert(0, unwind_op) edgedict = make_edge_dict(edges) for edge in break_cycles(edgedict, edgedict): caller = edge.source _, _, call_tag = edge.callposition if call_tag: caller_block, _ = call_tag else: ann.warning("cycle detected but no information on where to insert " "stack_check()") continue # caller block found, insert stack_check() v = Variable() # push annotation on v ann.setbinding(v, annmodel.SomeImpossibleValue()) unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v) caller_block.operations.insert(0, unwind_op)
def test_regalloc_lists(self): v1 = Variable() v1.concretetype = lltype.Signed v2 = Variable() v2.concretetype = lltype.Signed v3 = Variable() v3.concretetype = lltype.Signed v4 = Variable() v4.concretetype = lltype.Signed v5 = Variable() v5.concretetype = lltype.Signed block = Block([v1]) block.operations = [ SpaceOperation('int_add', [v1, Constant(1, lltype.Signed)], v2), SpaceOperation('rescall', [ListOfKind('int', [v1, v2])], v5), SpaceOperation('rescall', [ListOfKind('int', [v1, v2])], v3), ] graph = FunctionGraph('f', block, v4) block.closeblock(Link([v3], graph.returnblock)) # self.check_assembler( graph, """ int_add %i0, $1 -> %i1 rescall I[%i0, %i1] -> %i2 rescall I[%i0, %i1] -> %i0 int_return %i0 """)
def test_func_simple(): # -------------------- flowgraph building -------------------- # def f(x): # return x+1 x = Variable("x") x.concretetype = Signed result = Variable("result") result.concretetype = Signed one = Constant(1) one.concretetype = Signed op = SpaceOperation("int_add", [x, one], result) block = Block([x]) graph = FunctionGraph("f", block) block.operations.append(op) block.closeblock(Link([result], graph.returnblock)) graph.getreturnvar().concretetype = Signed # -------------------- end -------------------- F = FuncType([Signed], Signed) f = functionptr(F, "f", graph=graph) db = LowLevelDatabase() db.get(f) db.complete() dump_on_stdout(db) S = GcStruct('testing', ('fptr', Ptr(F))) s = malloc(S) s.fptr = f db = LowLevelDatabase() db.get(s) db.complete() dump_on_stdout(db)
def test_funny_links(): from pypy.objspace.flow.model import Block, FunctionGraph, \ SpaceOperation, Variable, Constant, Link for i in range(2): v_i = Variable("i") v_case = Variable("case") block = Block([v_i]) g = FunctionGraph("is_one", block) block.operations.append( SpaceOperation("eq", [v_i, Constant(1)], v_case)) block.exitswitch = v_case tlink = Link([Constant(1)], g.returnblock, True) flink = Link([Constant(0)], g.returnblock, False) links = [tlink, flink] if i: links.reverse() block.closeblock(*links) t = TranslationContext() a = t.buildannotator() a.build_graph_types(g, [annmodel.SomeInteger()]) rtyper = t.buildrtyper() rtyper.specialize() interp = LLInterpreter(rtyper) assert interp.eval_graph(g, [1]) == 1 assert interp.eval_graph(g, [0]) == 0
def test_decode_builtin_call_method(): A = lltype.GcArray(lltype.Signed) def myfoobar(a, i, marker, c): assert marker == 'mymarker' return a[i] * ord(c) myfoobar.oopspec = 'spam.foobar(a, 2, c, i)' TYPE = lltype.FuncType([lltype.Ptr(A), lltype.Signed, lltype.Void, lltype.Char], lltype.Signed) fnobj = lltype.functionptr(TYPE, 'foobar', _callable=myfoobar) vi = Variable('i') vi.concretetype = lltype.Signed vc = Variable('c') vc.concretetype = lltype.Char v_result = Variable('result') v_result.concretetype = lltype.Signed myarray = lltype.malloc(A, 10) myarray[5] = 42 op = SpaceOperation('direct_call', [newconst(fnobj), newconst(myarray), vi, voidconst('mymarker'), vc], v_result) oopspec, opargs = decode_builtin_call(op) assert oopspec == 'spam.foobar' assert opargs == [newconst(myarray), newconst(2), vc, vi]
def builder(translator, func): # build a hacked graph that doesn't take a *arg any more, but # individual extra arguments graph = translator.buildflowgraph(func) argnames, vararg, kwarg = graph.signature assert vararg, "graph should have a *arg at this point" assert not kwarg, "where does this **arg come from??" argscopy = [Variable(v) for v in graph.getargs()] starargs = [ Variable('stararg%d' % i) for i in range(nb_extra_args) ] newstartblock = Block(argscopy[:-1] + starargs) newtup = SpaceOperation('newtuple', starargs, argscopy[-1]) newstartblock.operations.append(newtup) newstartblock.closeblock(Link(argscopy, graph.startblock)) graph.startblock.isstartblock = False graph.startblock = newstartblock newstartblock.isstartblock = True argnames = argnames + ['.star%d' % i for i in range(nb_extra_args)] graph.signature = Signature(argnames) # note that we can mostly ignore defaults: if nb_extra_args > 0, # then defaults aren't applied. if nb_extra_args == 0, then this # just removes the *arg and the defaults keep their meaning. if nb_extra_args > 0: graph.defaults = None # shouldn't be used in this case checkgraph(graph) return graph
def test_optimize_goto_if_not__ptr_iszero(): for opname in ['ptr_iszero', 'ptr_nonzero']: v1 = Variable() v3 = Variable() v3.concretetype = lltype.Bool block = Block([v1]) block.operations = [SpaceOperation(opname, [v1], v3)] block.exitswitch = v3 block.exits = exits = [FakeLink(False), FakeLink(True)] res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [] assert block.exitswitch == (opname, v1, '-live-before') assert block.exits == exits
def test_rename_on_links(): v1 = Variable() v2 = Variable() v2.concretetype = llmemory.Address v3 = Variable() block = Block([v1]) block.operations = [SpaceOperation('cast_pointer', [v1], v2)] block2 = Block([v3]) block.closeblock(Link([v2], block2)) Transformer().optimize_block(block) assert block.inputargs == [v1] assert block.operations == [] assert block.exits[0].target is block2 assert block.exits[0].args == [v1]
def test_guess_call_kind_and_calls_from_graphs(self): from pypy.objspace.flow.model import SpaceOperation, Constant, Variable portal_runner_ptr = object() g = object() g1 = object() cw = CodeWriter(None) cw.candidate_graphs = [g, g1] cw.portal_runner_ptr = portal_runner_ptr op = SpaceOperation('direct_call', [Constant(portal_runner_ptr)], Variable()) assert cw.guess_call_kind(op) == 'recursive' op = SpaceOperation('direct_call', [Constant(object())], Variable()) assert cw.guess_call_kind(op) == 'residual' class funcptr: class graph: class func: oopspec = "spec" op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) assert cw.guess_call_kind(op) == 'builtin' class funcptr: graph = g op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cw.graphs_from(op) assert res == [g] assert cw.guess_call_kind(op) == 'regular' class funcptr: graph = object() op = SpaceOperation('direct_call', [Constant(funcptr)], Variable()) res = cw.graphs_from(op) assert res is None assert cw.guess_call_kind(op) == 'residual' h = object() op = SpaceOperation('indirect_call', [Variable(), Constant([g, g1, h])], Variable()) res = cw.graphs_from(op) assert res == [g, g1] assert cw.guess_call_kind(op) == 'regular' op = SpaceOperation('indirect_call', [Variable(), Constant([h])], Variable()) res = cw.graphs_from(op) assert res is None assert cw.guess_call_kind(op) == 'residual'
def test_optimize_goto_if_not__incoming(): v1 = Variable() v1.concretetype = lltype.Bool block = Block([v1]) block.exitswitch = v1 block.exits = [FakeLink(False), FakeLink(True)] assert not Transformer().optimize_goto_if_not(block)
def render_method(self, method_name, method, ilasm): args, retval = method.args, method.retval.name if len(args) == 0 or args[-1].name != 'callback': args.append(ArgDesc('callback', lambda: None)) real_args = list(arg.name for arg in args) # FIXME: dirty JS here data = "{%s}" % ",".join( ["'%s':%s" % (i, i) for i in real_args if i != 'callback']) real_callback = Variable("callback").name if len(self.base_url) > 0 and not self.base_url.endswith("/"): url = self.base_url + "/" + method_name else: url = self.base_url + method_name METHOD_BODY = globals()[self.method + "_METHOD_BODY"] if USE_MOCHIKIT and self.use_xml: assert 0, "Cannot use mochikit and xml requests at the same time" if USE_MOCHIKIT and self.method == "POST": assert 0, "Cannot use mochikit with POST method" if USE_MOCHIKIT: ilasm.codegenerator.write(MOCHIKIT_BODY % {'class':self.name, 'method':method_name,\ 'args':','.join(real_args), 'data':data, 'call':url}) else: if not self.use_xml: callback_body = CALLBACK_BODY else: callback_body = CALLBACK_XML_BODY ilasm.codegenerator.write(callback_body % {'real_callback': real_callback}) ilasm.codegenerator.write(METHOD_BODY % {'class':self.name, 'method':method_name,\ 'args':",".join(real_args), 'data':data, 'call':url,\ 'real_callback':real_callback})
def insert_ll_stackcheck(translator): from pypy.translator.backendopt.support import find_calls_from from pypy.rlib.rstack import stack_check from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles rtyper = translator.rtyper graph = rtyper.annotate_helper(stack_check, []) rtyper.specialize_more_blocks() stack_check_ptr = rtyper.getcallable(graph) stack_check_ptr_const = Constant(stack_check_ptr, lltype.typeOf(stack_check_ptr)) edges = [] graphs_to_patch = {} insert_in = {} for caller in translator.graphs: for block, callee in find_calls_from(translator, caller): if getattr(getattr(callee, 'func', None), 'insert_stack_check_here', False): insert_in[callee.startblock] = True continue edge = Edge(caller, callee) edge.block = block edges.append(edge) edgedict = make_edge_dict(edges) for edge in break_cycles(edgedict, edgedict): block = edge.block insert_in[block] = True for block in insert_in: v = Variable() v.concretetype = lltype.Void unwind_op = SpaceOperation('direct_call', [stack_check_ptr_const], v) block.operations.insert(0, unwind_op) return len(insert_in)
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 instrument_inline_candidates(graphs, threshold): cache = {None: False} def candidate(graph): try: return cache[graph] except KeyError: res = static_instruction_count(graph) <= threshold cache[graph] = res return res n = 0 for parentgraph in graphs: for block in parentgraph.iterblocks(): ops = block.operations i = len(ops)-1 while i >= 0: op = ops[i] i -= 1 if op.opname == "direct_call": funcobj = get_funcobj(op.args[0].value) graph = getattr(funcobj, 'graph', None) if graph is not None: if getattr(getattr(funcobj, '_callable', None), '_dont_inline_', False): continue if candidate(graph): tag = Constant('inline', Void) label = Constant(n, Signed) dummy = Variable() dummy.concretetype = Void count = SpaceOperation('instrument_count', [tag, label], dummy) ops.insert(i+1, count) n += 1 log.inlining("%d call sites instrumented" % n)
def test_optimize_goto_if_not(): v1 = Variable() v2 = Variable() v3 = Variable() v3.concretetype = lltype.Bool sp1 = SpaceOperation('foobar', [], None) sp2 = SpaceOperation('foobaz', [], None) block = Block([v1, v2]) block.operations = [sp1, SpaceOperation('int_gt', [v1, v2], v3), sp2] block.exitswitch = v3 block.exits = exits = [FakeLink(False), FakeLink(True)] res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [sp1, sp2] assert block.exitswitch == ('int_gt', v1, v2) assert block.exits == exits
def insert_ll_stackcheck(translator): from pypy.translator.backendopt.support import find_calls_from from pypy.rlib.rstack import stack_check from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles_v rtyper = translator.rtyper graph = rtyper.annotate_helper(stack_check, []) rtyper.specialize_more_blocks() stack_check_ptr = rtyper.getcallable(graph) stack_check_ptr_const = Constant(stack_check_ptr, lltype.typeOf(stack_check_ptr)) edges = set() insert_in = set() for caller in translator.graphs: for block, callee in find_calls_from(translator, caller): if getattr(getattr(callee, 'func', None), 'insert_stack_check_here', False): insert_in.add(callee.startblock) continue if block is not caller.startblock: edges.add((caller.startblock, block)) edges.add((block, callee.startblock)) edgelist = [Edge(block1, block2) for (block1, block2) in edges] edgedict = make_edge_dict(edgelist) for block in break_cycles_v(edgedict, edgedict): insert_in.add(block) for block in insert_in: v = Variable() v.concretetype = lltype.Void unwind_op = SpaceOperation('direct_call', [stack_check_ptr_const], v) block.operations.insert(0, unwind_op) return len(insert_in)
def prepare_constant_fold_link(link, constants, splitblocks): block = link.target if not block.operations: # when the target block has no operation, there is nothing we can do # except trying to fold an exitswitch if block.exitswitch is not None and block.exitswitch in constants: llexitvalue = constants[block.exitswitch].value rewire_link_for_known_exitswitch(link, llexitvalue) return folded_count = fold_op_list(block.operations, constants, exit_early=True) n = len(block.operations) if block.exitswitch == c_last_exception: n -= 1 # is the next, non-folded operation an indirect_call? m = folded_count while m < n and block.operations[m].opname == 'keepalive': m += 1 if m < n: nextop = block.operations[m] if nextop.opname == 'indirect_call' and nextop.args[0] in constants: # indirect_call -> direct_call callargs = [constants[nextop.args[0]]] constants1 = constants.copy() complete_constants(link, constants1) newkeepalives = [] for i in range(folded_count, m): [v] = block.operations[i].args v = constants1.get(v, v) v_void = Variable() v_void.concretetype = lltype.Void newkeepalives.append(SpaceOperation('keepalive', [v], v_void)) for v in nextop.args[1:-1]: callargs.append(constants1.get(v, v)) v_result = Variable(nextop.result) v_result.concretetype = nextop.result.concretetype constants[nextop.result] = v_result callop = SpaceOperation('direct_call', callargs, v_result) newblock = insert_empty_block(None, link, newkeepalives + [callop]) [link] = newblock.exits assert link.target is block folded_count = m + 1 if folded_count > 0: splits = splitblocks.setdefault(block, []) splits.append((folded_count, link, constants))
def do_inline(self, block, index_operation): splitlink = split_block(None, block, index_operation) afterblock = splitlink.target # these variables have to be passed along all the links in the inlined # graph because the original function needs them in the blocks after # the inlined function # for every inserted block we need a new copy of these variables, # this copy is created with the method passon_vars self.original_passon_vars = [arg for arg in block.exits[0].args if isinstance(arg, Variable)] n = 0 while afterblock.operations[n].opname == 'keepalive': n += 1 assert afterblock.operations[n].opname == self.op.opname self.op = afterblock.operations.pop(n) #vars that need to be passed through the blocks of the inlined function linktoinlined = splitlink copiedstartblock = self.copy_block(self.graph_to_inline.startblock) copiedstartblock.isstartblock = False #find args passed to startblock of inlined function passon_args = [] for arg in self.op.args[1:]: if isinstance(arg, Constant): passon_args.append(arg) else: index = afterblock.inputargs.index(arg) passon_args.append(linktoinlined.args[index]) passon_args += self.original_passon_vars if self.op.opname == 'oosend' and not isinstance(self.op.args[1], Constant): # if we try to inline a graph defined in a superclass, the # type of 'self' on the graph differs from the current linkv = passon_args[0] inputv = copiedstartblock.inputargs[0] LINK_SELF = linkv.concretetype INPUT_SELF = inputv.concretetype if LINK_SELF != INPUT_SELF: # need to insert an upcast assert ootype.isSubclass(LINK_SELF, INPUT_SELF) v = Variable() v.concretetype = INPUT_SELF upcast = SpaceOperation('ooupcast', [linkv], v) block.operations.append(upcast) passon_args[0] = v #rewire blocks linktoinlined.target = copiedstartblock linktoinlined.args = passon_args afterblock.inputargs = [self.op.result] + afterblock.inputargs if self.graph_to_inline.returnblock in self.entrymap: self.rewire_returnblock(afterblock) if self.graph_to_inline.exceptblock in self.entrymap: self.rewire_exceptblock(afterblock) if self.exception_guarded: assert afterblock.exits[0].exitcase is None afterblock.recloseblock(afterblock.exits[0]) afterblock.exitswitch = None self.search_for_calls(afterblock) self.search_for_calls(block)
def replace_graph_with_bootstrap(GeneratorIterator, graph): Entry = GeneratorIterator.Entry newblock = Block(graph.startblock.inputargs) v_generator = Variable('generator') v_entry = Variable('entry') newblock.operations.append( SpaceOperation('simple_call', [Constant(Entry)], v_entry)) assert len(graph.startblock.inputargs) == len(Entry.varnames) for v, name in zip(graph.startblock.inputargs, Entry.varnames): newblock.operations.append( SpaceOperation('setattr', [v_entry, Constant(name), v], Variable())) newblock.operations.append( SpaceOperation('simple_call', [Constant(GeneratorIterator), v_entry], v_generator)) newblock.closeblock(Link([v_generator], graph.returnblock)) graph.startblock = newblock
def test_optimize_goto_if_not__unknownop(): v3 = Variable() v3.concretetype = lltype.Bool block = Block([]) block.operations = [SpaceOperation('foobar', [], v3)] block.exitswitch = v3 block.exits = [FakeLink(False), FakeLink(True)] assert not Transformer().optimize_goto_if_not(block)
def transform_except_block(self, graph, block): # attach an except block -- let's hope that nobody uses it graph.exceptblock = Block([ Variable('etype'), # exception class Variable('evalue') ]) # exception value graph.exceptblock.operations = () graph.exceptblock.closeblock() result = Variable() result.concretetype = lltype.Void block.operations = [ SpaceOperation("direct_call", [self.rpyexc_raise_ptr] + block.inputargs, result) ] l = Link([error_constant(graph.returnblock.inputargs[0].concretetype)], graph.returnblock) block.recloseblock(l)
def test_optimize_goto_if_not__exit(): # this case occurs in practice, e.g. with RPython code like: # return bool(p) and p.somefield > 0 v1 = Variable() v2 = Variable() v3 = Variable() v3.concretetype = lltype.Bool block = Block([v1, v2]) block.operations = [SpaceOperation('int_gt', [v1, v2], v3)] block.exitswitch = v3 block.exits = exits = [FakeLink(False), FakeLink(True)] block.exits[1].args = [v3] res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [] assert block.exitswitch == ('int_gt', v1, v2) assert block.exits == exits assert exits[1].args == [const(True)]
def _insert_reads(block, varnames): assert len(varnames) == len(block.inputargs) v_entry1 = Variable('entry') for i, name in enumerate(varnames): block.operations.insert( i, SpaceOperation('getattr', [v_entry1, Constant(name)], block.inputargs[i])) block.inputargs = [v_entry1]
def flowin(self, block, count, vars, newvarsmap): # in this 'block', follow where the 'var' goes to and replace # it by a flattened-out family of variables. This family is given # by newvarsmap, whose keys are the 'flatnames'. self.last_removed_access = None def list_newvars(): return [newvarsmap[key] for key in self.flatnames] assert block.operations != () self.newops = [] for op in block.operations: for arg in op.args[1:]: # should be the first arg only assert arg not in vars if op.args and op.args[0] in vars: self.flowin_op(op, vars, newvarsmap) elif op.result in vars: assert op.opname == self.MALLOC_OP progress = True # drop the "malloc" operation newvarsmap = self.flatconstants.copy() # zero initial values # if there are substructures, they are now individually # malloc'ed in an exploded way. (They will typically be # removed again by the next malloc removal pass.) for key in self.needsubmallocs: v = Variable() v.concretetype = self.newvarstype[key] c = Constant(v.concretetype.TO, lltype.Void) if c.value == op.args[0].value: progress = False # replacing a malloc with # the same malloc! newop = self.recreate_malloc(c, v) self.newops.append(newop) newvarsmap[key] = v count[0] += progress else: self.newops.append(op) assert block.exitswitch not in vars for link in block.exits: appended = False newargs = [] for arg in link.args: if arg in vars: if not appended: newargs += list_newvars() appended = True else: newargs.append(arg) link.args[:] = newargs self.insert_keepalives(list_newvars()) block.operations[:] = self.newops
def insert_keepalives(self, newvars): if self.last_removed_access is not None: keepalives = [] for v in newvars: T = v.concretetype if isinstance(T, lltype.Ptr) and T._needsgc(): v0 = Variable() v0.concretetype = lltype.Void newop = SpaceOperation('keepalive', [v], v0) keepalives.append(newop) self.newops[self.last_removed_access:self. last_removed_access] = keepalives
def transform_graph(self, graph): if graph in self.minimal_transform: if self.minimalgctransformer: self.minimalgctransformer.transform_graph(graph) del self.minimal_transform[graph] return if graph in self.seen_graphs: return self.seen_graphs[graph] = True self.links_to_split = {} # link -> vars to pop_alive across the link # for sanity, we need an empty block at the start of the graph inserted_empty_startblock = False if not starts_with_empty_block(graph): insert_empty_startblock(self.translator.annotator, graph) inserted_empty_startblock = True is_borrowed = self.compute_borrowed_vars(graph) for block in graph.iterblocks(): self.transform_block(block, is_borrowed) for link, livecounts in self.links_to_split.iteritems(): llops = LowLevelOpList() for var, livecount in livecounts.iteritems(): for i in range(livecount): self.pop_alive(var, llops) for i in range(-livecount): self.push_alive(var, llops) if llops: if link.prevblock.exitswitch is None: link.prevblock.operations.extend(llops) else: insert_empty_block(self.translator.annotator, link, llops) # remove the empty block at the start of the graph, which should # still be empty (but let's check) if starts_with_empty_block(graph) and inserted_empty_startblock: old_startblock = graph.startblock graph.startblock.isstartblock = False graph.startblock = graph.startblock.exits[0].target graph.startblock.isstartblock = True checkgraph(graph) self.links_to_split = None v = Variable('vanishing_exc_value') v.concretetype = self.get_lltype_of_exception_value() llops = LowLevelOpList() self.pop_alive(v, llops) graph.exc_cleanup = (v, list(llops)) return is_borrowed # xxx for tests only
def create_proxy_graph(self, op): """ creates a graph which calls the original function, checks for raised exceptions, fetches and then raises them again. If this graph is inlined, the correct exception matching blocks are produced.""" # XXX slightly annoying: construct a graph by hand # but better than the alternative result = copyvar(None, op.result) opargs = [] inputargs = [] callargs = [] ARGTYPES = [] for var in op.args: if isinstance(var, Variable): v = Variable() v.concretetype = var.concretetype inputargs.append(v) opargs.append(v) callargs.append(var) ARGTYPES.append(var.concretetype) else: opargs.append(var) newop = SpaceOperation(op.opname, opargs, result) startblock = Block(inputargs) startblock.operations.append(newop) newgraph = FunctionGraph("dummy_exc1", startblock) startblock.closeblock(Link([result], newgraph.returnblock)) newgraph.returnblock.inputargs[0].concretetype = op.result.concretetype self.gen_exc_check(startblock, newgraph.returnblock) excblock = Block([]) llops = rtyper.LowLevelOpList(None) var_value = self.gen_getfield('exc_value', llops) var_type = self.gen_getfield('exc_type', llops) # c_check1 = self.c_assertion_error_ll_exc_type c_check2 = self.c_n_i_error_ll_exc_type llops.genop('debug_catch_exception', [var_type, c_check1, c_check2]) # self.gen_setfield('exc_value', self.c_null_evalue, llops) self.gen_setfield('exc_type', self.c_null_etype, llops) excblock.operations[:] = llops newgraph.exceptblock.inputargs[ 0].concretetype = self.lltype_of_exception_type newgraph.exceptblock.inputargs[ 1].concretetype = self.lltype_of_exception_value excblock.closeblock(Link([var_type, var_value], newgraph.exceptblock)) startblock.exits[True].target = excblock startblock.exits[True].args = [] fptr = self.constant_func("dummy_exc1", ARGTYPES, op.result.concretetype, newgraph) return newgraph, SpaceOperation("direct_call", [fptr] + callargs, op.result)
def test_decode_builtin_call_nomethod(): def myfoobar(i, marker, c): assert marker == 'mymarker' return i * ord(c) myfoobar.oopspec = 'foobar(2, c, i)' TYPE = lltype.FuncType([lltype.Signed, lltype.Void, lltype.Char], lltype.Signed) fnobj = lltype.functionptr(TYPE, 'foobar', _callable=myfoobar) vi = Variable('i') vi.concretetype = lltype.Signed vc = Variable('c') vc.concretetype = lltype.Char v_result = Variable('result') v_result.concretetype = lltype.Signed op = SpaceOperation('direct_call', [newconst(fnobj), vi, voidconst('mymarker'), vc], v_result) oopspec, opargs = decode_builtin_call(op) assert oopspec == 'foobar' assert opargs == [newconst(2), vc, vi]
def generate_keepalive(vars, annotator=None): keepalive_ops = [] for v in vars: if isinstance(v, Constant): continue if v.concretetype._is_atomic(): continue v_keepalive = Variable() v_keepalive.concretetype = lltype.Void if annotator is not None: annotator.setbinding(v_keepalive, s_ImpossibleValue) keepalive_ops.append(SpaceOperation('keepalive', [v], v_keepalive)) return keepalive_ops
def test_SSA_to_SSI_2(): x = Variable('x') y = Variable('y') z = Variable('z') b1 = Block([x]) b2 = Block([y]) b3 = Block([]) b3.operations.append(SpaceOperation('hello', [y], z)) b1.closeblock(Link([x], b2), Link([], b3)) SSA_to_SSI({ b1: True, # reachable from outside b2: False, b3: False }) assert b1.inputargs == [x] assert b2.inputargs == [y] assert b3.inputargs == [b3.operations[0].args[0]] assert b1.exits[0].args == [x] assert b1.exits[1].args == [x]