def dispatcher(self, shape, index, argtypes, resulttype): key = shape, index, tuple(argtypes), resulttype if key in self._dispatch_cache: return self._dispatch_cache[key] from rpython.translator.unsimplify import varoftype from rpython.flowspace.model import FunctionGraph, Link, Block, SpaceOperation inputargs = [varoftype(t) for t in [Char] + argtypes] startblock = Block(inputargs) startblock.exitswitch = inputargs[0] graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype)) row_of_graphs = self.callfamily.calltables[shape][index] links = [] descs = list(self.s_pbc.descriptions) if self.s_pbc.can_be_None: descs.insert(0, None) for desc in descs: if desc is None: continue args_v = [varoftype(t) for t in argtypes] b = Block(args_v) llfn = self.rtyper.getcallable(row_of_graphs[desc]) v_fn = inputconst(typeOf(llfn), llfn) v_result = varoftype(resulttype) b.operations.append( SpaceOperation("direct_call", [v_fn] + args_v, v_result)) b.closeblock(Link([v_result], graph.returnblock)) i = self.descriptions.index(desc) links.append(Link(inputargs[1:], b, chr(i))) links[-1].llexitcase = chr(i) startblock.closeblock(*links) self.rtyper.annotator.translator.graphs.append(graph) ll_ret = getfunctionptr(graph) #FTYPE = FuncType c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret) return c_ret
def make_dispatcher(self, shape, index, argtypes, resulttype): inputargs = [varoftype(t) for t in [Char] + argtypes] startblock = Block(inputargs) startblock.exitswitch = inputargs[0] graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype)) row_of_graphs = self.callfamily.calltables[shape][index] links = [] descs = list(self.s_pbc.descriptions) if self.s_pbc.can_be_None: descs.insert(0, None) for desc in descs: if desc is None: continue args_v = [varoftype(t) for t in argtypes] b = Block(args_v) llfn = self.rtyper.getcallable(row_of_graphs[desc]) v_fn = inputconst(typeOf(llfn), llfn) v_result = varoftype(resulttype) b.operations.append( SpaceOperation("direct_call", [v_fn] + args_v, v_result)) b.closeblock(Link([v_result], graph.returnblock)) i = self.descriptions.index(desc) links.append(Link(inputargs[1:], b, chr(i))) links[-1].llexitcase = chr(i) startblock.closeblock(*links) return graph
def test_SSA_to_SSI(): c = Variable('c') x = Variable('x') y = Variable('y') b1 = Block([c]) b2 = Block([x]) b3 = Block([]) graph = FunctionGraph('x', b1) b2.operations.append(SpaceOperation('add', [x, c], y)) b2.exitswitch = y b1.closeblock(Link([Constant(0)], b2)) b2.closeblock(Link([y], b2), Link([], b3)) b3.closeblock(Link([y, c], graph.exceptblock)) SSA_to_SSI(graph) assert len(b1.inputargs) == 1 assert len(b2.inputargs) == 2 assert len(b3.inputargs) == 2 assert b2.inputargs == b2.operations[0].args assert len(b1.exits[0].args) == 2 assert b1.exits[0].args[1] is c assert len(b2.exits[0].args) == 2 assert b2.exits[0].args == [y, b2.inputargs[1]] assert len(b2.exits[1].args) == 2 assert len(b3.exits[0].args) == 2 index = b3.inputargs.index(b3.exits[0].args[0]) assert b2.exits[1].args[index] is b2.operations[0].result index = b3.inputargs.index(b3.exits[0].args[1]) assert b2.exits[1].args[index] is b2.inputargs[1]
def guessexception(self, ctx, *cases): block = self.crnt_block links = [] for case in [None] + list(cases): if case is not None: if case is Exception: last_exc = Variable('last_exception') else: last_exc = Constant(case) last_exc_value = Variable('last_exc_value') vars = [last_exc, last_exc_value] vars2 = [Variable(), Variable()] else: vars = [] vars2 = [] egg = EggBlock(vars2, block, case) ctx.pendingblocks.append(egg) link = Link(vars, egg, case) if case is not None: link.extravars(last_exception=last_exc, last_exc_value=last_exc_value) egg.extravars(last_exception=last_exc) links.append(link) block.exitswitch = c_last_exception block.closeblock(*links) raise StopFlowing
def test_funny_links(): from rpython.flowspace.model import Block, FunctionGraph, \ Variable, Constant, Link from rpython.flowspace.operation import op for i in range(2): v_i = Variable("i") block = Block([v_i]) g = FunctionGraph("is_one", block) op1 = op.eq(v_i, Constant(1)) block.operations.append(op1) block.exitswitch = op1.result 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 guessexception(self, ctx, *cases): block = self.crnt_block bvars = vars = vars2 = block.getvariables() links = [] for case in [None] + list(cases): if case is not None: assert block.operations[-1].result is bvars[-1] vars = bvars[:-1] vars2 = bvars[:-1] if case is Exception: last_exc = Variable('last_exception') else: last_exc = Constant(case) last_exc_value = Variable('last_exc_value') vars.extend([last_exc, last_exc_value]) vars2.extend([Variable(), Variable()]) egg = EggBlock(vars2, block, case) ctx.pendingblocks.append(egg) link = Link(vars, egg, case) if case is not None: link.extravars(last_exception=last_exc, last_exc_value=last_exc_value) egg.extravars(last_exception=last_exc) links.append(link) block.exitswitch = c_last_exception block.closeblock(*links) raise StopFlowing
def copy_link(self, link, prevblock): newargs = [self.get_new_name(a) for a in link.args] + self.passon_vars(prevblock) newlink = Link(newargs, self.copy_block(link.target), link.exitcase) newlink.last_exception = self.get_new_name(link.last_exception) newlink.last_exc_value = self.get_new_name(link.last_exc_value) if hasattr(link, 'llexitcase'): newlink.llexitcase = link.llexitcase return newlink
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 = op.result.copy() 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_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 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 = op.newtuple(*starargs) newtup.result = argscopy[-1] newstartblock.operations.append(newtup) newstartblock.closeblock(Link(argscopy, graph.startblock)) graph.startblock = newstartblock 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 call_final_function(translator, final_func, annhelper=None): """When the program finishes normally, call 'final_func()'.""" from rpython.annotator import model as annmodel from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator own_annhelper = (annhelper is None) if own_annhelper: annhelper = MixLevelHelperAnnotator(translator.rtyper) c_final_func = annhelper.constfunc(final_func, [], annmodel.s_None) if own_annhelper: annhelper.finish() entry_point = translator.entry_point_graph v = entry_point.getreturnvar().copy() extrablock = Block([v]) v_none = varoftype(lltype.Void) newop = SpaceOperation('direct_call', [c_final_func], v_none) extrablock.operations = [newop] extrablock.closeblock(Link([v], entry_point.returnblock)) for block in entry_point.iterblocks(): if block is not extrablock: for link in block.exits: if link.target is entry_point.returnblock: link.target = extrablock checkgraph(entry_point)
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 mergeblock(self, currentblock, currentstate): next_offset = currentstate.next_offset # can 'currentstate' be merged with one of the blocks that # already exist for this bytecode position? candidates = self.joinpoints.setdefault(next_offset, []) for block in candidates: newstate = block.framestate.union(currentstate) if newstate is not None: break else: newstate = currentstate.copy() newblock = SpamBlock(newstate) # unconditionally link the current block to the newblock outputargs = currentstate.getoutputargs(newstate) link = Link(outputargs, newblock) currentblock.closeblock(link) candidates.insert(0, newblock) self.pendingblocks.append(newblock) return if newstate.matches(block.framestate): outputargs = currentstate.getoutputargs(newstate) currentblock.closeblock(Link(outputargs, block)) return newblock = SpamBlock(newstate) varnames = self.pycode.co_varnames for name, w_value in zip(varnames, newstate.mergeable): if isinstance(w_value, Variable): w_value.rename(name) # unconditionally link the current block to the newblock outputargs = currentstate.getoutputargs(newstate) link = Link(outputargs, newblock) currentblock.closeblock(link) # to simplify the graph, we patch the old block to point # directly at the new block which is its generalization block.dead = True block.operations = () block.exitswitch = None outputargs = block.framestate.getoutputargs(newstate) block.recloseblock(Link(outputargs, newblock)) candidates.remove(block) candidates.insert(0, newblock) self.pendingblocks.append(newblock)
def nomoreblocks(self, ctx): w_exc = self.w_exc if w_exc.w_type == const(ImportError): msg = 'import statement always raises %s' % self raise ImportError(msg) link = Link([w_exc.w_type, w_exc.w_value], ctx.graph.exceptblock) ctx.recorder.crnt_block.closeblock(link) raise StopFlowing
def rewire_returnblock(self, afterblock): copiedreturnblock = self.copy_block(self.graph_to_inline.returnblock) linkargs = ([copiedreturnblock.inputargs[0]] + self.passon_vars(self.graph_to_inline.returnblock)) linkfrominlined = Link(linkargs, afterblock) copiedreturnblock.exitswitch = None copiedreturnblock.recloseblock(linkfrominlined) assert copiedreturnblock.exits[0].target == afterblock
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)) graph = FunctionGraph('x', b1) SSA_to_SSI(graph) 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]
def insert_along_link(link, opname, args, cache): b2 = link.target if b2 not in cache: newblock = Block([v.copy() for v in b2.inputargs]) newblock.operations.append( SpaceOperation(opname, args, varoftype(lltype.Void))) newblock.closeblock(Link(list(newblock.inputargs), b2)) cache[b2] = newblock link.target = cache[b2]
def nomoreblocks(self, ctx): w_exc = self.w_exc if w_exc.w_type == const(ImportError): msg = 'ImportError is raised in RPython: %s' % (getattr( w_exc.w_value, 'value', '<not a constant message>'), ) raise ImportError(msg) link = Link([w_exc.w_type, w_exc.w_value], ctx.graph.exceptblock) ctx.recorder.crnt_block.closeblock(link) raise StopFlowing
def make_next_block(self, block, state): newstate = state.copy() newblock = SpamBlock(newstate) # unconditionally link the current block to the newblock outputargs = state.getoutputargs(newstate) link = Link(outputargs, newblock) block.closeblock(link) self.pendingblocks.append(newblock) return newblock
def record_block(self, block): self.setstate(block.framestate) next_offset = block.framestate.next_offset self.recorder = block.make_recorder() try: while True: next_offset = self.handle_bytecode(next_offset) self.recorder.final_state = self.getstate(next_offset) except RaiseImplicit as e: w_exc = e.w_exc if isinstance(w_exc.w_type, Constant): exc_cls = w_exc.w_type.value else: exc_cls = Exception msg = "implicit %s shouldn't occur" % exc_cls.__name__ w_type = Constant(AssertionError) w_value = Constant(AssertionError(msg)) link = Link([w_type, w_value], self.graph.exceptblock) self.recorder.crnt_block.closeblock(link) except Raise as e: w_exc = e.w_exc if w_exc.w_type == const(ImportError): msg = 'import statement always raises %s' % e raise ImportError(msg) link = Link([w_exc.w_type, w_exc.w_value], self.graph.exceptblock) self.recorder.crnt_block.closeblock(link) except StopFlowing: pass except Return as exc: w_result = exc.w_value link = Link([w_result], self.graph.returnblock) self.recorder.crnt_block.closeblock(link) except FlowingError as exc: if exc.ctx is None: exc.ctx = self raise self.recorder = None
def generic_exception_matching(self, afterblock, copiedexceptblock): #XXXXX don't look: insert blocks that do exception matching #for the cases where direct matching did not work exc_match = Constant( self.translator.rtyper.exceptiondata.fn_exception_match) exc_match.concretetype = typeOf(exc_match.value) blocks = [] for i, link in enumerate(afterblock.exits[1:]): etype = copiedexceptblock.inputargs[0].copy() evalue = copiedexceptblock.inputargs[1].copy() passon_vars = self.passon_vars(i) block = Block([etype, evalue] + passon_vars) res = Variable() res.concretetype = Bool cexitcase = Constant(link.llexitcase) cexitcase.concretetype = typeOf(cexitcase.value) args = [exc_match, etype, cexitcase] block.operations.append(SpaceOperation("direct_call", args, res)) block.exitswitch = res linkargs = self.find_args_in_exceptional_case(link, link.target, etype, evalue, afterblock, passon_vars) l = Link(linkargs, link.target) l.prevblock = block l.exitcase = True l.llexitcase = True block.closeblock(l) if i > 0: l = Link(blocks[-1].inputargs, block) l.exitcase = False l.llexitcase = False blocks[-1].recloseblock(l, *blocks[-1].exits) blocks.append(block) blocks[-1].recloseblock(*blocks[-1].exits[:1]) blocks[-1].operations = [] blocks[-1].exitswitch = None blocks[-1].exits[0].exitcase = None del blocks[-1].exits[0].llexitcase linkargs = copiedexceptblock.inputargs copiedexceptblock.recloseblock(Link(linkargs, blocks[0]))
def nomoreblocks(self, ctx): w_exc = self.w_exc if isinstance(w_exc.w_type, Constant): exc_cls = w_exc.w_type.value else: exc_cls = Exception msg = "implicit %s shouldn't occur" % exc_cls.__name__ w_type = Constant(AssertionError) w_value = Constant(AssertionError(msg)) link = Link([w_type, w_value], ctx.graph.exceptblock) ctx.recorder.crnt_block.closeblock(link) raise StopFlowing
def test_regalloc_exitswitch_2(self): v1 = Variable(); v1.concretetype = rclass.CLASSTYPE v2 = Variable(); v2.concretetype = rclass.CLASSTYPE v3 = Variable(); v3.concretetype = rclass.CLASSTYPE v4 = Variable(); v4.concretetype = rclass.CLASSTYPE block = Block([]) block.operations = [ SpaceOperation('res_call', [], v1), SpaceOperation('-live-', [], None), ] graph = FunctionGraph('f', block, v4) exclink = Link([v2], graph.returnblock) exclink.llexitcase = 123 # normally an exception class exclink.last_exception = v2 exclink.last_exc_value = "unused" block.exitswitch = c_last_exception block.closeblock(Link([v1], graph.returnblock), exclink) # self.check_assembler(graph, """ res_call -> %i0 -live- catch_exception L1 int_return %i0 --- L1: goto_if_exception_mismatch $123, L2 last_exception -> %i0 int_return %i0 --- L2: reraise """)
def replace_graph_with_bootstrap(GeneratorIterator, graph): Entry = GeneratorIterator.Entry newblock = Block(graph.startblock.inputargs) op_entry = op.simple_call(const(Entry)) v_entry = op_entry.result newblock.operations.append(op_entry) assert len(graph.startblock.inputargs) == len(Entry.varnames) for v, name in zip(graph.startblock.inputargs, Entry.varnames): newblock.operations.append(op.setattr(v_entry, Constant(name), v)) op_generator = op.simple_call(const(GeneratorIterator), v_entry) newblock.operations.append(op_generator) newblock.closeblock(Link([op_generator.result], graph.returnblock)) graph.startblock = newblock
def normalize_calltable_row_annotation(annotator, graphs): if len(graphs) <= 1: return False # nothing to do graph_bindings = {} for graph in graphs: graph_bindings[graph] = [annotator.binding(v) for v in graph.getargs()] iterbindings = graph_bindings.itervalues() nbargs = len(iterbindings.next()) for binding in iterbindings: assert len(binding) == nbargs generalizedargs = [] for i in range(nbargs): args_s = [] for graph, bindings in graph_bindings.items(): args_s.append(bindings[i]) s_value = annmodel.unionof(*args_s) generalizedargs.append(s_value) result_s = [ annotator.binding(graph.getreturnvar()) for graph in graph_bindings ] generalizedresult = annmodel.unionof(*result_s) conversion = False for graph in graphs: bindings = graph_bindings[graph] need_conversion = (generalizedargs != bindings) if need_conversion: conversion = True oldblock = graph.startblock inlist = [] for j, s_value in enumerate(generalizedargs): v = Variable(graph.getargs()[j]) annotator.setbinding(v, s_value) inlist.append(v) newblock = Block(inlist) # prepare the output args of newblock and link outlist = inlist[:] newblock.closeblock(Link(outlist, oldblock)) graph.startblock = newblock # finished checkgraph(graph) annotator.annotated[newblock] = annotator.annotated[oldblock] # convert the return value too if annotator.binding(graph.getreturnvar()) != generalizedresult: conversion = True annotator.setbinding(graph.getreturnvar(), generalizedresult) return conversion
def get_exc_reconstruction_block(self, typedesc): exceptblock = self.graph.exceptblock self.mallocv.fixup_except_block(exceptblock) TEXC = exceptblock.inputargs[0].concretetype TVAL = exceptblock.inputargs[1].concretetype # v_ignored_type = varoftype(TEXC) v_incoming_value = varoftype(TVAL) block = Block([v_ignored_type, v_incoming_value]) # c_EXCTYPE = Constant(typedesc.MALLOCTYPE, lltype.Void) v = varoftype(lltype.Ptr(typedesc.MALLOCTYPE)) c_flavor = Constant({'flavor': 'gc'}, lltype.Void) op = SpaceOperation('malloc', [c_EXCTYPE, c_flavor], v) block.operations.append(op) # for name, FIELDTYPE in typedesc.names_and_types: EXACTPTR = lltype.Ptr(typedesc.name2subtype[name]) c_name = Constant(name) c_name.concretetype = lltype.Void # v_in = varoftype(EXACTPTR) op = SpaceOperation('cast_pointer', [v_incoming_value], v_in) block.operations.append(op) # v_field = varoftype(FIELDTYPE) op = SpaceOperation('getfield', [v_in, c_name], v_field) block.operations.append(op) # v_out = varoftype(EXACTPTR) op = SpaceOperation('cast_pointer', [v], v_out) block.operations.append(op) # v0 = varoftype(lltype.Void) op = SpaceOperation('setfield', [v_out, c_name, v_field], v0) block.operations.append(op) # v_exc_value = varoftype(TVAL) op = SpaceOperation('cast_pointer', [v], v_exc_value) block.operations.append(op) # exc_type = self.mallocv.EXCTYPE_to_vtable[typedesc.MALLOCTYPE] c_exc_type = Constant(exc_type, TEXC) block.closeblock(Link([c_exc_type, v_exc_value], exceptblock)) return block
def create_outgoing_link(self, currentframe, targetblock, nodelist, renamings, v_expand_malloc=None): assert len(nodelist) == len(targetblock.inputargs) # if is_except(targetblock): v_expand_malloc = None while currentframe.callerframe is not None: currentframe = currentframe.callerframe newlink = self.handle_catch(currentframe, nodelist, renamings) if newlink: return newlink else: targetblock = self.exception_escapes(nodelist, renamings) assert len(nodelist) == len(targetblock.inputargs) if (currentframe.callerframe is None and is_trivial_nodelist(nodelist)): # there is no more VirtualSpecNodes being passed around, # so we can stop specializing rtnodes = nodelist specblock = targetblock else: if is_return(targetblock): v_expand_malloc = None newframe = self.return_to_caller(currentframe, nodelist[0]) else: targetnodes = dict(zip(targetblock.inputargs, nodelist)) newframe = VirtualFrame(targetblock, 0, targetnodes, callerframe=currentframe.callerframe, calledgraphs=currentframe.calledgraphs) rtnodes = newframe.find_rt_nodes() specblock = self.get_specialized_block(newframe, v_expand_malloc) linkargs = [renamings[rtnode] for rtnode in rtnodes] return Link(linkargs, specblock)
def create_instantiate_function(annotator, classdef): # build the graph of a function that looks like # # def my_instantiate(): # return instantiate(cls) # if hasattr(classdef, 'my_instantiate_graph'): return v = Variable() block = Block([]) block.operations.append(SpaceOperation('instantiate1', [], v)) name = valid_identifier('instantiate_' + classdef.name) graph = FunctionGraph(name, block) block.closeblock(Link([v], graph.returnblock)) annotator.setbinding(v, annmodel.SomeInstance(classdef)) annotator.annotated[block] = graph # force the result to be converted to a generic OBJECTPTR generalizedresult = annmodel.SomeInstance(classdef=None) annotator.setbinding(graph.getreturnvar(), generalizedresult) classdef.my_instantiate_graph = graph annotator.translator.graphs.append(graph)
def call_initial_function(translator, initial_func, annhelper=None): """Before the program starts, call 'initial_func()'.""" from rpython.annotator import model as annmodel from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator own_annhelper = (annhelper is None) if own_annhelper: annhelper = MixLevelHelperAnnotator(translator.rtyper) c_initial_func = annhelper.constfunc(initial_func, [], annmodel.s_None) if own_annhelper: annhelper.finish() entry_point = translator.entry_point_graph args = [v.copy() for v in entry_point.getargs()] extrablock = Block(args) v_none = varoftype(lltype.Void) newop = SpaceOperation('direct_call', [c_initial_func], v_none) extrablock.operations = [newop] extrablock.closeblock(Link(args, entry_point.startblock)) entry_point.startblock = extrablock checkgraph(entry_point)
def insert_empty_block(link, newops=[]): """Insert and return a new block along the given link.""" vars = {} for v in link.args: if isinstance(v, Variable): vars[v] = True for op in newops: for v in op.args: if isinstance(v, Variable): vars.setdefault(v, True) vars[op.result] = False vars = [v for v, keep in vars.items() if keep] mapping = {} for v in vars: mapping[v] = v.copy() newblock = Block(vars) newblock.operations.extend(newops) newblock.closeblock(Link(link.args, link.target)) newblock.renamevariables(mapping) link.args[:] = vars link.target = newblock return newblock
def transform_jump_to_except_block(self, graph, entrymap, link): reraise = self.comes_from_last_exception(entrymap, link) result = Variable() result.concretetype = lltype.Void block = Block([v.copy() for v in graph.exceptblock.inputargs]) if reraise: block.operations = [ SpaceOperation("direct_call", [self.rpyexc_reraise_ptr] + block.inputargs, result), ] else: block.operations = [ SpaceOperation("direct_call", [self.rpyexc_raise_ptr] + block.inputargs, result), SpaceOperation('debug_record_traceback', [], varoftype(lltype.Void)), ] link.target = block l = Link([error_constant(graph)], graph.returnblock) block.recloseblock(l)
def generic_exception_matching(self, afterblock, copiedexceptblock): #XXXXX don't look: insert blocks that do exception matching #for the cases where direct matching did not work exc_match = Constant( self.translator.rtyper.exceptiondata.fn_exception_match) exc_match.concretetype = typeOf(exc_match.value) blocks = [] for i, link in enumerate(afterblock.exits[1:]): etype = copyvar(None, copiedexceptblock.inputargs[0]) evalue = copyvar(None, copiedexceptblock.inputargs[1]) passon_vars = self.passon_vars(i) block = Block([etype, evalue] + passon_vars) res = Variable() res.concretetype = Bool cexitcase = Constant(link.llexitcase) cexitcase.concretetype = typeOf(cexitcase.value) args = [exc_match, etype, cexitcase] block.operations.append(SpaceOperation("direct_call", args, res)) block.exitswitch = res linkargs = self.find_args_in_exceptional_case(link, link.target, etype, evalue, afterblock, passon_vars) l = Link(linkargs, link.target) l.prevblock = block l.exitcase = True l.llexitcase = True block.closeblock(l) if i > 0: l = Link(blocks[-1].inputargs, block) l.exitcase = False l.llexitcase = False blocks[-1].recloseblock(l, *blocks[-1].exits) blocks.append(block) blocks[-1].recloseblock(*blocks[-1].exits[:1]) blocks[-1].operations = [] blocks[-1].exitswitch = None blocks[-1].exits[0].exitcase = None del blocks[-1].exits[0].llexitcase linkargs = copiedexceptblock.inputargs copiedexceptblock.recloseblock(Link(linkargs, blocks[0]))
def cutoff_alwaysraising_block(self, block): "Fix a block whose end can never be reached at run-time." # search the operation that cannot succeed can_succeed = [ op for op in block.operations if op.result.annotation is not None ] cannot_succeed = [ op for op in block.operations if op.result.annotation is None ] n = len(can_succeed) # check consistency assert can_succeed == block.operations[:n] assert cannot_succeed == block.operations[n:] assert 0 <= n < len(block.operations) # chop off the unreachable end of the block del block.operations[n + 1:] self.setbinding(block.operations[n].result, annmodel.s_ImpossibleValue) # insert the equivalent of 'raise AssertionError' graph = self.annotated[block] msg = "Call to %r should have raised an exception" % (getattr( graph, 'func', None), ) c1 = Constant(AssertionError) c2 = Constant(AssertionError(msg)) errlink = Link([c1, c2], graph.exceptblock) block.recloseblock(errlink, *block.exits) # record new link to make the transformation idempotent self.links_followed[errlink] = True # fix the annotation of the exceptblock.inputargs etype, evalue = graph.exceptblock.inputargs s_type = annmodel.SomeType() s_type.is_type_of = [evalue] s_value = annmodel.SomeInstance( self.bookkeeper.getuniqueclassdef(Exception)) self.setbinding(etype, s_type) self.setbinding(evalue, s_value) # make sure the bookkeeper knows about AssertionError self.bookkeeper.getuniqueclassdef(AssertionError)
def tweak_generator_body_graph(Entry, graph): # First, always run simplify_graph in order to reduce the number of # variables passed around simplify_graph(graph) insert_empty_startblock(None, graph) _insert_reads(graph.startblock, Entry.varnames) Entry.block = graph.startblock # mappings = [Entry] # stopblock = Block([]) op0 = op.simple_call(const(StopIteration)) op1 = op.type(op0.result) stopblock.operations = [op0, op1] stopblock.closeblock(Link([op1.result, op0.result], graph.exceptblock)) # for block in list(graph.iterblocks()): for exit in block.exits: if exit.target is graph.returnblock: exit.args = [] exit.target = stopblock assert block is not stopblock for index in range(len(block.operations)-1, -1, -1): hlop = block.operations[index] if hlop.opname == 'yield_': [v_yielded_value] = hlop.args del block.operations[index] newlink = split_block(None, block, index) newblock = newlink.target # class Resume(AbstractPosition): _immutable_ = True block = newblock Resume.__name__ = 'Resume%d' % len(mappings) mappings.append(Resume) varnames = get_variable_names(newlink.args) # _insert_reads(newblock, varnames) # op_resume = op.simple_call(const(Resume)) block.operations.append(op_resume) v_resume = op_resume.result for i, name in enumerate(varnames): block.operations.append( op.setattr(v_resume, const(name), newlink.args[i])) op_pair = op.newtuple(v_resume, v_yielded_value) block.operations.append(op_pair) newlink.args = [op_pair.result] newlink.target = graph.returnblock # regular_entry_block = Block([Variable('entry')]) block = regular_entry_block for Resume in mappings: op_check = op.simple_call( const(isinstance), block.inputargs[0], const(Resume)) block.operations.append(op_check) block.exitswitch = op_check.result link1 = Link([block.inputargs[0]], Resume.block) link1.exitcase = True nextblock = Block([Variable('entry')]) link2 = Link([block.inputargs[0]], nextblock) link2.exitcase = False block.closeblock(link1, link2) block = nextblock block.closeblock(Link([Constant(AssertionError), Constant(AssertionError("bad generator class"))], graph.exceptblock)) graph.startblock = regular_entry_block graph.signature = Signature(['entry']) graph.defaults = () checkgraph(graph) eliminate_empty_blocks(graph)
def tweak_generator_body_graph(Entry, graph): # First, always run simplify_graph in order to reduce the number of # variables passed around simplify_graph(graph) # assert graph.startblock.operations[0].opname == 'generator_mark' graph.startblock.operations.pop(0) # insert_empty_startblock(None, graph) _insert_reads(graph.startblock, Entry.varnames) Entry.block = graph.startblock # mappings = [Entry] # stopblock = Block([]) v0 = Variable() v1 = Variable() stopblock.operations = [ SpaceOperation('simple_call', [Constant(StopIteration)], v0), SpaceOperation('type', [v0], v1), ] stopblock.closeblock(Link([v1, v0], graph.exceptblock)) # for block in list(graph.iterblocks()): for exit in block.exits: if exit.target is graph.returnblock: exit.args = [] exit.target = stopblock assert block is not stopblock for index in range(len(block.operations)-1, -1, -1): op = block.operations[index] if op.opname == 'yield': [v_yielded_value] = op.args del block.operations[index] newlink = split_block(None, block, index) newblock = newlink.target # class Resume(AbstractPosition): _immutable_ = True block = newblock Resume.__name__ = 'Resume%d' % len(mappings) mappings.append(Resume) varnames = get_variable_names(newlink.args) # _insert_reads(newblock, varnames) # v_resume = Variable('resume') block.operations.append( SpaceOperation('simple_call', [Constant(Resume)], v_resume)) for i, name in enumerate(varnames): block.operations.append( SpaceOperation('setattr', [v_resume, Constant(name), newlink.args[i]], Variable())) v_pair = Variable('pair') block.operations.append( SpaceOperation('newtuple', [v_resume, v_yielded_value], v_pair)) newlink.args = [v_pair] newlink.target = graph.returnblock # regular_entry_block = Block([Variable('entry')]) block = regular_entry_block for Resume in mappings: v_check = Variable() block.operations.append( SpaceOperation('simple_call', [Constant(isinstance), block.inputargs[0], Constant(Resume)], v_check)) block.exitswitch = v_check link1 = Link([block.inputargs[0]], Resume.block) link1.exitcase = True nextblock = Block([Variable('entry')]) link2 = Link([block.inputargs[0]], nextblock) link2.exitcase = False block.closeblock(link1, link2) block = nextblock block.closeblock(Link([Constant(AssertionError), Constant(AssertionError("bad generator class"))], graph.exceptblock)) graph.startblock = regular_entry_block graph.signature = Signature(['entry']) graph.defaults = () checkgraph(graph) eliminate_empty_blocks(graph)