Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
    def get_resume_point_link(self, block):
        try:
            return self.resumepoints[block]
        except KeyError:
            resumeblock = Block([])
            redcount   = 0
            greencount = 0
            newvars = []
            for v in block.inputargs:
                if v.concretetype is lltype.Void:
                    v1 = self.c_dummy
                elif self.hannotator.binding(v).is_green():
                    c = inputconst(lltype.Signed, greencount)
                    v1 = self.genop(resumeblock, 'restore_green', [c],
                                    result_like = v)
                    greencount += 1
                else:
                    c = inputconst(lltype.Signed, redcount)
                    v1 = self.genop(resumeblock, 'restore_local', [c],
                                    result_like = v)
                    redcount += 1
                newvars.append(v1)

            resumeblock.closeblock(Link(newvars, block))
            reenter_link = Link([], resumeblock)
            N = len(self.resumepoints)
            reenter_link.exitcase = N
            self.resumepoints[block] = reenter_link
            return reenter_link
Ejemplo n.º 4
0
 def new_block_before(self, block):
     newinputargs = [copyvar(self.hannotator, var)
                     for var in block.inputargs]
     newblock = Block(newinputargs)
     bridge = Link(newinputargs, block)
     newblock.closeblock(bridge)
     return newblock
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
 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
     """)
Ejemplo n.º 7
0
 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 += tuple(['.star%d' % i for i in range(nb_extra_args)])
     graph.signature = argnames, None, None
     # 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
Ejemplo n.º 8
0
    def handle_oopspec_call(self, block, pos, withexc):
        op = block.operations[pos]
        assert op.opname == 'direct_call'
        if withexc:
            op.opname = 'oopspec_call'            
        else:
            op.opname = 'oopspec_call_noexc'            
        if withexc:
            link = split_block(self.hannotator, block, pos+1)
            nextblock = link.target
            linkargs = link.args
            v_residual  =self.genop(block, 'oopspec_was_residual', [],
                                    resulttype = lltype.Bool)
            residualblock = Block([])
            self.genswitch(block, v_residual, true = residualblock,
                                              false = None)
            link_f = block.exits[0]
            link_f.args = linkargs
            link_f.target = nextblock
            residualblock.closeblock(Link(linkargs, nextblock))
            blockset = { block: True,
                         nextblock: False,
                         residualblock: False }
            self.handle_after_residual_call_details(
                                  residualblock, 0, [], blockset, oop=True,
                                  withexc=True)

            SSA_to_SSI(blockset, self.hannotator)
Ejemplo n.º 9
0
 def naive_split_block(self, block, position):
     newblock = Block([])
     newblock.operations = block.operations[position:]
     del block.operations[position:]
     newblock.exitswitch = block.exitswitch
     block.exitswitch = None
     newblock.recloseblock(*block.exits)
     block.recloseblock(Link([], newblock))
     return newblock
Ejemplo n.º 10
0
    def handle_after_residual_call_details(self, block, pos, newops, blockset,
                                           withexc, oop = False):
        dopts = {'withexc': withexc, 'oop': oop }
        copts = Constant(dopts, lltype.Void)
        v_flags = self.genop(newops, 'after_residual_call', [copts],
                             resulttype=lltype.Signed, red=True)
        residual_fetch_index = len(newops)
        self.genop(newops, 'residual_fetch', [v_flags, copts])
        residual_fetch_pos = pos+residual_fetch_index
        block.operations[pos:pos+1] = newops

        link_t = split_block(self.hannotator, block, residual_fetch_pos)
        nextblock = link_t.target
        blockset[nextblock] = False
        i_flags = link_t.args.index(v_flags)

        reds, greens = self.sort_by_color(link_t.args)
        self.genop(block, 'save_locals', reds)

        SPLIT_FOR_ZERO = False

        if SPLIT_FOR_ZERO:
            promoteblock = Block([copyvar(self.hannotator, v)
                                  for v in link_t.args])
            link_f = Link(link_t.args, promoteblock)
            promoteblock.recloseblock(Link(promoteblock.inputargs, nextblock))
            blockset[promoteblock] = False
            v_flags2 = promoteblock.inputargs[i_flags]
        else:
            promoteblock = block
            v_flags2 = v_flags
        # if there is no global merge point, this 'promote' will actually
        # always see a constant red box
        v_finished_flag = self.genop(promoteblock, 'promote', [v_flags2],
                                     resulttype = lltype.Bool)
        self.go_to_dispatcher_if(promoteblock, v_finished_flag)

        if SPLIT_FOR_ZERO:
            c_zero = inputconst(lltype.Signed, 0)
            link_t.args = link_t.args[:]
            link_t.args[i_flags] = c_zero

            resumepoint = self.get_resume_point(promoteblock)
            c_resumepoint = inputconst(lltype.Signed, resumepoint)
            v_is_zero = self.genop(block, 'int_eq', [v_flags, c_zero],
                                   resulttype=lltype.Bool, red=True)
            v_is_zero = self.genop(block, 'split',
                                   [v_is_zero, c_resumepoint] + greens,
                                   resulttype = lltype.Bool)
            block.exitswitch = v_is_zero
            link_t.exitcase = True
            link_f.exitcase = False
            block.recloseblock(link_f, link_t)
Ejemplo n.º 11
0
 def copy_block(self, block):
     if block in self._copied_blocks:
         return self._copied_blocks[block]
     args = ([self.get_new_name(var) for var in block.inputargs] +
             self.passon_vars(block))
     newblock = Block(args)
     self._copied_blocks[block] = newblock
     newblock.operations = [self.copy_operation(op) for op in block.operations]
     newblock.closeblock(*[self.copy_link(link, block) for link in block.exits])
     newblock.exitswitch = self.get_new_name(block.exitswitch)
     self.search_for_calls(newblock)
     return newblock
Ejemplo n.º 12
0
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
Ejemplo n.º 13
0
def test_rename_on_links():
    v1 = Variable()
    v2 = Variable()
    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]
Ejemplo n.º 14
0
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))
            oldblock.isstartblock = False
            newblock.isstartblock = True
            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
Ejemplo n.º 15
0
def test_optimize_goto_if_not__ptr_eq():
    for opname in ["ptr_eq", "ptr_ne"]:
        v1 = Variable()
        v2 = Variable()
        v3 = Variable()
        v3.concretetype = lltype.Bool
        block = Block([v1, v2])
        block.operations = [SpaceOperation(opname, [v1, v2], 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, v2)
        assert block.exits == exits
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
 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([copyvar(None, v) 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
     RETTYPE = graph.returnblock.inputargs[0].concretetype
     l = Link([error_constant(RETTYPE)], graph.returnblock)
     block.recloseblock(l)
Ejemplo n.º 18
0
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)]
Ejemplo n.º 19
0
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
Ejemplo n.º 20
0
Archivo: rpbc.py Proyecto: ieure/pypy
 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 pypy.translator.unsimplify import varoftype
     from pypy.objspace.flow.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 = self.rtyper.type_system.getcallable(graph)
     #FTYPE = FuncType
     c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret)
     return c_ret
Ejemplo n.º 21
0
 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
Ejemplo n.º 22
0
def test_switch_no_default():
    from pypy.objspace.flow.model import FunctionGraph, Block, Constant, Link
    from pypy.rpython.lltypesystem.lltype import FuncType, Signed, functionptr
    from pypy.translator.unsimplify import varoftype
    block = Block([varoftype(Signed)])
    block.exitswitch = block.inputargs[0]
    graph = FunctionGraph("t", block, varoftype(Signed))
    links = []
    for i in range(10):
        links.append(Link([Constant(i*i, Signed)], graph.returnblock, i))
        links[-1].llexitcase = i
    block.closeblock(*links)
    fptr = functionptr(FuncType([Signed], Signed), "t", graph=graph)
    def func(x):
        return fptr(x)
    f = compile_function(func, [int])
    res = f(4)
    assert res == 16
Ejemplo n.º 23
0
 def test_regalloc_call(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
     block = Block([v1])
     block.operations = [
         SpaceOperation('int_add', [v1, Constant(1, lltype.Signed)], v2),
         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] -> %i0
         int_return %i0
     """)
Ejemplo n.º 24
0
    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.getexceptiondata().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]))
        copiedexceptblock.operations += self.generate_keepalive(linkargs)
Ejemplo n.º 25
0
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]
Ejemplo n.º 26
0
 def build_callback_graph(self, graph, metadesccls=False):
     args_v = [copyvar(None, v) for v in graph.getargs()]
     v_res = copyvar(None, graph.getreturnvar())
     rtyper = self.bookkeeper.annotator.base_translator.rtyper  # fish
     fnptr = rtyper.getcallable(graph)
     v_ptr = Constant(fnptr, lltype.typeOf(fnptr))
     newstartblock = Block(args_v)
     if metadesccls:
         v_metadesccls = Constant(metadesccls, lltype.Void)
         args_v = [v_metadesccls] + args_v
         opname = 'ts_metacall'
         suffix = 'ts_metacall'
     else:
         opname = 'direct_call'
         suffix = 'ts_stub'
     newstartblock.operations.append(
         SpaceOperation(opname, [v_ptr] + args_v, v_res))
     newgraph = FunctionGraph('%s_%s' % (graph.name, suffix), newstartblock)
     newgraph.getreturnvar().concretetype = v_res.concretetype
     newstartblock.closeblock(Link([v_res], newgraph.returnblock))
     return newgraph
Ejemplo n.º 27
0
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)
Ejemplo n.º 28
0
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
Ejemplo n.º 29
0
def test_SSA_to_SSI():
    c = Variable('c')
    x = Variable('x')
    y = Variable('y')
    b1 = Block([c])
    b2 = Block([x])
    b3 = Block([])

    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], None))

    SSA_to_SSI({b1: True,     # reachable from outside
                b2: False,
                b3: False})

    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]
Ejemplo n.º 30
0
def test_promote_2():
    v1 = varoftype(lltype.Signed)
    v2 = varoftype(lltype.Signed)
    op = SpaceOperation('hint',
                        [v1, Constant({'promote': True}, lltype.Void)], v2)
    returnblock = Block([varoftype(lltype.Signed)])
    returnblock.operations = ()
    block = Block([v1])
    block.operations = [op]
    block.closeblock(Link([v2], returnblock))
    Transformer().optimize_block(block)
    assert len(block.operations) == 2
    assert block.operations[0].opname == '-live-'
    assert block.operations[0].args == []
    assert block.operations[1].opname == 'int_guard_value'
    assert block.operations[1].args == [v1]
    assert block.operations[1].result is None
    assert block.exits[0].args == [v1]
Ejemplo n.º 31
0
 def copy_block(self, block):
     if block in self._copied_blocks:
         return self._copied_blocks[block]
     args = ([self.get_new_name(var) for var in block.inputargs] +
             self.passon_vars(block))
     newblock = Block(args)
     self._copied_blocks[block] = newblock
     newblock.operations = [self.copy_operation(op) for op in block.operations]
     newblock.closeblock(*[self.copy_link(link, block) for link in block.exits])
     newblock.exitswitch = self.get_new_name(block.exitswitch)
     self.search_for_calls(newblock)
     return newblock
Ejemplo n.º 32
0
    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) 
Ejemplo n.º 33
0
    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)
Ejemplo n.º 34
0
 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 pypy.translator.unsimplify import varoftype
     from pypy.objspace.flow.model import FunctionGraph, Link, Block, SpaceOperation
     inputargs = [varoftype(t) for t in [Char] + argtypes]
     startblock = Block(inputargs)
     startblock.exitswitch = inputargs[0]
     #startblock.operations.append(SpaceOperation('debug_pdb', [], varoftype(Void)))
     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 = self.rtyper.type_system.getcallable(graph)
     #FTYPE = FuncType
     c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret)
     return c_ret
Ejemplo n.º 35
0
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]
Ejemplo n.º 36
0
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]
Ejemplo n.º 37
0
 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([copyvar(None, v) 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
     RETTYPE = graph.returnblock.inputargs[0].concretetype
     l = Link([error_constant(RETTYPE)], graph.returnblock)
     block.recloseblock(l)
Ejemplo n.º 38
0
 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
     """)
Ejemplo n.º 39
0
    def gen_exc_check(self, block, returnblock, normalafterblock=None):
        #var_exc_occured = Variable()
        #var_exc_occured.concretetype = lltype.Bool
        #block.operations.append(SpaceOperation("safe_call", [self.rpyexc_occured_ptr], var_exc_occured))

        llops = rtyper.LowLevelOpList(None)

        spaceop = block.operations[-1]
        alloc_shortcut = self.check_for_alloc_shortcut(spaceop)

        # XXX: does alloc_shortcut make sense also for ootype?
        if alloc_shortcut:
            T = spaceop.result.concretetype
            var_no_exc = self.gen_nonnull(spaceop.result, llops)
        else:
            v_exc_type = self.gen_getfield('exc_type', llops)
            var_no_exc = self.gen_isnull(v_exc_type, llops)

        block.operations.extend(llops)

        block.exitswitch = var_no_exc
        #exception occurred case
        b = Block([])
        b.operations = [
            SpaceOperation('debug_record_traceback', [],
                           varoftype(lltype.Void))
        ]
        l = Link([error_constant(returnblock.inputargs[0].concretetype)],
                 returnblock)
        b.closeblock(l)
        l = Link([], b)
        l.exitcase = l.llexitcase = False

        #non-exception case
        l0 = block.exits[0]
        l0.exitcase = l0.llexitcase = True

        block.recloseblock(l0, l)

        insert_zeroing_op = False
        # XXX this is not right. it also inserts zero_gc_pointers_inside
        # XXX on a path that malloc_nonmovable returns null, but does not raise
        # XXX which might end up with a segfault. But we don't have such gc now
        if spaceop.opname == 'malloc' or spaceop.opname == 'malloc_nonmovable':
            flavor = spaceop.args[1].value['flavor']
            if flavor == 'gc':
                insert_zeroing_op = True

        if insert_zeroing_op:
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            v_result = spaceop.result
            if v_result in l0.args:
                result_i = l0.args.index(v_result)
                v_result_after = normalafterblock.inputargs[result_i]
            else:
                v_result_after = copyvar(None, v_result)
                l0.args.append(v_result)
                normalafterblock.inputargs.append(v_result_after)
            normalafterblock.operations.insert(
                0,
                SpaceOperation('zero_gc_pointers_inside', [v_result_after],
                               varoftype(lltype.Void)))

        if self.always_exc_clear:
            # insert code that clears the exception even in the non-exceptional
            # case...  this is a hint for the JIT, but pointless otherwise
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            llops = rtyper.LowLevelOpList(None)
            self.gen_setfield('exc_value', self.c_null_evalue, llops)
            self.gen_setfield('exc_type', self.c_null_etype, llops)
            normalafterblock.operations[:0] = llops
Ejemplo n.º 40
0
def new_wrapper(func, translator, newname=None):
    # The basic idea is to produce a flow graph from scratch, using the
    # help of the rtyper for the conversion of the arguments after they
    # have been decoded.
    
    bk = translator.annotator.bookkeeper
    graph = bk.getdesc(func).getuniquegraph()

    f = getfunctionptr(graph)
    FUNCTYPE = typeOf(f).TO

    newops = LowLevelOpList(translator.rtyper)

    varguments = []
    for var in graph.startblock.inputargs:
        v = Variable(var)
        v.concretetype = PyObjPtr
        varguments.append(v)

    wrapper_inputargs = varguments[:]
    # use the rtyper to produce the conversions
    inputargs = f._obj.graph.getargs()
    for i in range(len(varguments)):
        if FUNCTYPE.ARGS[i] != PyObjPtr:
            rtyper = translator.rtyper
            r_arg = rtyper.bindingrepr(inputargs[i])
            # give the rtyper a chance to know which function we are wrapping
            rtyper.set_wrapper_context(func)
            varguments[i] = newops.convertvar(varguments[i],
                                              r_from = pyobj_repr,
                                              r_to = r_arg)
            rtyper.set_wrapper_context(None)

    vlist = [inputconst(typeOf(f), f)] + varguments
    vresult = newops.genop('direct_call', vlist, resulttype=FUNCTYPE.RESULT)

    if FUNCTYPE.RESULT != PyObjPtr:
        # convert "result" back to a PyObject
        rtyper = translator.rtyper
        assert rtyper is not None, (
            "needs the rtyper to perform function result conversions")
        r_result = rtyper.bindingrepr(f._obj.graph.getreturnvar())
        vresult = newops.convertvar(vresult,
                                    r_from = r_result,
                                    r_to = pyobj_repr)

    # "return result"
    block = Block(wrapper_inputargs)
    wgraph = FunctionGraph('pyfn_' + (newname or func.func_name), block)
    translator.update_call_graph(wgraph, graph, object())
    translator.graphs.append(wgraph)
    block.operations[:] = newops
    block.closeblock(Link([vresult], wgraph.returnblock))
    wgraph.getreturnvar().concretetype = PyObjPtr
    checkgraph(wgraph)

    # the above convertvar()s may have created and annotated new helpers
    # that need to be specialized now
    translator.rtyper.specialize_more_blocks()

    return functionptr(FuncType([PyObjPtr] * len(wrapper_inputargs),
                                PyObjPtr),
                       wgraph.name,
                       graph = wgraph,
                       exception_policy = "CPython")
Ejemplo n.º 41
0
def normalize_calltable_row_signature(annotator, shape, row):
    graphs = row.values()
    assert graphs, "no graph??"
    sig0 = graphs[0].signature
    defaults0 = graphs[0].defaults
    for graph in graphs[1:]:
        if graph.signature != sig0:
            break
        if graph.defaults != defaults0:
            break
    else:
        return False   # nothing to do, all signatures already match
    
    shape_cnt, shape_keys, shape_star, shape_stst = shape
    assert not shape_star, "XXX not implemented"
    assert not shape_stst, "XXX not implemented"

    # for the first 'shape_cnt' arguments we need to generalize to
    # a common type
    call_nbargs = shape_cnt + len(shape_keys)

    did_something = False
    NODEFAULT = object()

    for graph in graphs:
        argnames, varargname, kwargname = graph.signature
        assert not varargname, "XXX not implemented"
        assert not kwargname, "XXX not implemented" # ?
        inputargs_s = [annotator.binding(v) for v in graph.getargs()]
        argorder = range(shape_cnt)
        for key in shape_keys:
            i = list(argnames).index(key)
            assert i not in argorder
            argorder.append(i)
        need_reordering = (argorder != range(call_nbargs))
        if need_reordering or len(graph.getargs()) != call_nbargs:
            oldblock = graph.startblock
            inlist = []
            defaults = graph.defaults or ()
            num_nondefaults = len(inputargs_s) - len(defaults)
            defaults = [NODEFAULT] * num_nondefaults + list(defaults)
            newdefaults = []
            for j in argorder:
                v = Variable(graph.getargs()[j])
                annotator.setbinding(v, inputargs_s[j])
                inlist.append(v)
                newdefaults.append(defaults[j])
            newblock = Block(inlist)
            # prepare the output args of newblock:
            # 1. collect the positional arguments
            outlist = inlist[:shape_cnt]
            # 2. add defaults and keywords
            for j in range(shape_cnt, len(inputargs_s)):
                try:
                    i = argorder.index(j)
                    v = inlist[i]
                except ValueError:
                    default = defaults[j]
                    if default is NODEFAULT:
                        raise TyperError(
                            "call pattern has %d positional arguments, "
                            "but %r takes at least %d arguments" % (
                                shape_cnt, graph.name, num_nondefaults))
                    v = Constant(default)
                outlist.append(v)
            newblock.closeblock(Link(outlist, oldblock))
            graph.startblock = newblock
            for i in range(len(newdefaults)-1,-1,-1):
                if newdefaults[i] is NODEFAULT:
                    newdefaults = newdefaults[i:]
                    break
            graph.defaults = tuple(newdefaults)
            graph.signature = Signature([argnames[j] for j in argorder], 
                                        None, None)
            # finished
            checkgraph(graph)
            annotator.annotated[newblock] = annotator.annotated[oldblock]
            did_something = True
    return did_something
Ejemplo n.º 42
0
def test_SSA_to_SSI():
    c = Variable('c')
    x = Variable('x')
    y = Variable('y')
    b1 = Block([c])
    b2 = Block([x])
    b3 = Block([])

    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], None))

    SSA_to_SSI({
        b1: True,  # reachable from outside
        b2: False,
        b3: False
    })

    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]
Ejemplo n.º 43
0
 def insert_integer_search(self, block, cases, defaultlink, blockset,
                           range_start, range_stop):
     # fix the exit of the 'block' to check for the given remaining
     # 'cases', knowing that if we get there then the value must
     # be contained in range(range_start, range_stop).
     if not cases:
         assert defaultlink is not None
         block.exitswitch = None
         block.recloseblock(Link(defaultlink.args, defaultlink.target))
     elif len(cases) == 1 and (defaultlink is None or
                               range_start == range_stop-1):
         block.exitswitch = None
         block.recloseblock(cases.values()[0])
     else:
         intvalues = cases.keys()
         intvalues.sort()
         if len(intvalues) <= 3:
             # not much point in being clever with no more than 3 cases
             intval = intvalues[-1]
             remainingcases = cases.copy()
             link = remainingcases.pop(intval)
             c_intval = inputconst(lltype.Signed, intval)
             v = self.genop(block, 'int_eq', [block.exitswitch, c_intval],
                            resulttype=lltype.Bool, red=True)
             link.exitcase = True
             link.llexitcase = True
             falseblock = Block([])
             falseblock.exitswitch = block.exitswitch
             blockset[falseblock] = False
             falselink = Link([], falseblock)
             falselink.exitcase = False
             falselink.llexitcase = False
             block.exitswitch = v
             block.recloseblock(falselink, link)
             if defaultlink is None or intval == range_stop-1:
                 range_stop = intval
             self.insert_integer_search(falseblock, remainingcases,
                                        defaultlink, blockset,
                                        range_start, range_stop)
         else:
             intval = intvalues[len(intvalues) // 2]
             c_intval = inputconst(lltype.Signed, intval)
             v = self.genop(block, 'int_ge', [block.exitswitch, c_intval],
                            resulttype=lltype.Bool, red=True)
             falseblock = Block([])
             falseblock.exitswitch = block.exitswitch
             trueblock  = Block([])
             trueblock.exitswitch = block.exitswitch
             blockset[falseblock] = False
             blockset[trueblock]  = False
             falselink = Link([], falseblock)
             falselink.exitcase = False
             falselink.llexitcase = False
             truelink = Link([], trueblock)
             truelink.exitcase = True
             truelink.llexitcase = True
             block.exitswitch = v
             block.recloseblock(falselink, truelink)
             falsecases = {}
             truecases = {}
             for intval1, link1 in cases.items():
                 if intval1 < intval:
                     falsecases[intval1] = link1
                 else:
                     truecases[intval1] = link1
             self.insert_integer_search(falseblock, falsecases,
                                        defaultlink, blockset,
                                        range_start, intval)
             self.insert_integer_search(trueblock, truecases,
                                        defaultlink, blockset,
                                        intval, range_stop)
Ejemplo n.º 44
0
    def handle_red_call(self, block, pos, withexc, color='red'):
        link = split_block(self.hannotator, block, pos+1)
        op = block.operations.pop(pos)
        #if op.opname == 'direct_call':
        #    f = open('LOG', 'a')
        #    print >> f, color, op.args[0].value
        #    f.close()
        assert len(block.operations) == pos
        nextblock = link.target
        linkargs = link.args
        varsalive = list(linkargs)

        if color != 'gray':
            # the result will be either passed as an extra local 0
            # by the caller, or restored by a restore_local
            try:
                index = varsalive.index(op.result)
            except ValueError:
                linkargs.insert(0, op.result)
                v_result = copyvar(self.hannotator, op.result)
                nextblock.inputargs.insert(0, v_result)
            else:
                del varsalive[index]
                old_v_result = linkargs.pop(index)
                linkargs.insert(0, old_v_result)
                v_result = nextblock.inputargs.pop(index)
                nextblock.inputargs.insert(0, v_result)
        else:
            if op.result in varsalive:
                index = varsalive.index(op.result)
                del varsalive[index]
                linkargs.pop(index)
                c_void = Constant(None, lltype.Void)
                linkargs.insert(0, c_void)
                v_result = nextblock.inputargs.pop(index)
                nextblock.inputargs.insert(0, v_result)                                
        reds, greens = self.sort_by_color(varsalive)

        blockset = {}
        blockset[block] = True     # reachable from outside
        blockset[nextblock] = False

        v_func = op.args[0]
        hs_func = self.hannotator.binding(v_func)
        if hs_func.is_green():
            constantblock = block
            nonconstantblock = None
        else:
            constantblock = Block([])
            nonconstantblock = Block([])
            blockset[constantblock] = False
            blockset[nonconstantblock] = False
            v_is_constant = self.genop(block, 'is_constant', [v_func],
                                       resulttype = lltype.Bool)
            self.genswitch(block, v_is_constant, true  = constantblock,
                                                 false = nonconstantblock)

        postconstantblock = self.naive_split_block(constantblock,
                                                 len(constantblock.operations))
        blockset[postconstantblock] = False
        self.make_call(constantblock, op, reds, color)

        conversionblock = nextblock
        if color == 'red':
            assert not self.hannotator.binding(op.result).is_green()
        elif color == 'yellow':
            conversionblock = Block([copyvar(self.hannotator, v)
                                     for v in nextblock.inputargs])
            v0 = conversionblock.inputargs[0]
            already_green = self.hannotator.binding(op.result).is_green()
            assert already_green == self.hannotator.binding(v0).is_green()
            if not already_green:
                RESULT = self.hannotator.binding(v0).concretetype
                hs = hintmodel.SomeLLAbstractConstant(RESULT, {})
                self.hannotator.bindings[v0] = hs
            conversionblock.closeblock(Link(conversionblock.inputargs,
                                            nextblock))
            blockset[conversionblock] = False
            # to merge some of the possibly many return jitstates
            self.mergepoint_set[nextblock] = 'local'

        resumepoint = self.get_resume_point(conversionblock)
        c_resumepoint = inputconst(lltype.Signed, resumepoint)
        self.genop(postconstantblock, 'collect_split', [c_resumepoint] + greens)
        resumeblock = self.get_resume_point_link(conversionblock).target
        postconstantblock.recloseblock(Link([], resumeblock))
        blockset[resumeblock] = True    # reachable from outside

        if nonconstantblock is not None:
            nonconstantblock.recloseblock(Link(linkargs, nextblock))
            v_res = self.handle_residual_call_details(
                                            nonconstantblock, 0, op,
                                            color, blockset, preserve_res =
                                            (color != 'gray'),
                                            withexc=withexc)

        SSA_to_SSI(blockset, self.hannotator)
Ejemplo n.º 45
0
class BlockSpecializer(object):

    def __init__(self, graphbuilder, v_expand_malloc=None):
        self.graphbuilder = graphbuilder
        self.v_expand_malloc = v_expand_malloc
        self.specblock = Block([])

    def initialize_renamings(self, virtualframe, keep_inputargs=False):
        # we make a copy of the original 'virtualframe' because the
        # specialize_operations() will mutate some of its content.
        virtualframe = virtualframe.copy({})
        self.virtualframe = virtualframe
        self.nodes = virtualframe.get_nodes_in_use()
        self.renamings = {}    # {RuntimeSpecNode(): Variable()}
        if keep_inputargs:
            assert virtualframe.varlist == virtualframe.sourceblock.inputargs
        specinputargs = []
        for i, rtnode in enumerate(virtualframe.find_rt_nodes()):
            if keep_inputargs:
                v = virtualframe.varlist[i]
                assert v.concretetype == rtnode.TYPE
            else:
                v = rtnode.newvar()
            self.renamings[rtnode] = v
            specinputargs.append(v)
        self.specblock.inputargs = specinputargs

    def setnode(self, v, node):
        assert v not in self.nodes
        self.nodes[v] = node

    def getnode(self, v):
        if isinstance(v, Variable):
            return self.nodes[v]
        else:
            return getconstnode(v, self.renamings)

    def rename_nonvirtual(self, v, where=None):
        if not isinstance(v, Variable):
            return v
        node = self.nodes[v]
        if not isinstance(node, RuntimeSpecNode):
            raise CannotVirtualize(where)
        return self.renamings[node]

    def expand_nodes(self, nodelist):
        rtnodes, vtnodes = find_all_nodes(nodelist)
        return [self.renamings[rtnode] for rtnode in rtnodes]

    def specialize_operations(self):
        newoperations = []
        self.ops_produced_by_last_op = 0
        # note that 'self.virtualframe' can be changed during the loop!
        while True:
            operations = self.virtualframe.sourceblock.operations
            try:
                op = operations[self.virtualframe.nextopindex]
                self.virtualframe.nextopindex += 1
            except IndexError:
                break

            meth = getattr(self, 'handle_op_' + op.opname,
                           self.handle_default)
            newops_for_this_op = meth(op)
            newoperations += newops_for_this_op
            self.ops_produced_by_last_op = len(newops_for_this_op)
        for op in newoperations:
            if op.opname == 'direct_call':
                graph = graph_called_by(op)
                if graph in self.virtualframe.calledgraphs:
                    raise CannotVirtualize("recursion in residual call")
        self.specblock.operations = newoperations

    def follow_exits(self):
        block = self.virtualframe.sourceblock
        self.specblock.exitswitch = self.rename_nonvirtual(block.exitswitch,
                                                           'exitswitch')
        links = block.exits
        catch_exc = self.specblock.exitswitch == c_last_exception

        if not catch_exc and isinstance(self.specblock.exitswitch, Constant):
            # constant-fold the switch
            for link in links:
                if link.exitcase == 'default':
                    break
                if link.llexitcase == self.specblock.exitswitch.value:
                    break
            else:
                raise Exception("exit case not found?")
            links = (link,)
            self.specblock.exitswitch = None

        if catch_exc and self.ops_produced_by_last_op == 0:
            # the last op of the sourceblock did not produce any
            # operation in specblock, so we need to discard the
            # exception-catching.
            catch_exc = False
            links = links[:1]
            assert links[0].exitcase is None  # the non-exception-catching case
            self.specblock.exitswitch = None

        newlinks = []
        for link in links:
            is_catch_link = catch_exc and link.exitcase is not None
            if is_catch_link:
                extravars = []
                for attr in ['last_exception', 'last_exc_value']:
                    v = getattr(link, attr)
                    if isinstance(v, Variable):
                        rtnode = RuntimeSpecNode(v, v.concretetype)
                        self.setnode(v, rtnode)
                        self.renamings[rtnode] = v = rtnode.newvar()
                    extravars.append(v)

            linkargsnodes = [self.getnode(v1) for v1 in link.args]
            #
            newlink = self.graphbuilder.create_outgoing_link(
                self.virtualframe, link.target, linkargsnodes,
                self.renamings, self.v_expand_malloc)
            #
            if self.specblock.exitswitch is not None:
                newlink.exitcase = link.exitcase
                if hasattr(link, 'llexitcase'):
                    newlink.llexitcase = link.llexitcase
                if is_catch_link:
                    newlink.extravars(*extravars)
            newlinks.append(newlink)

        self.specblock.closeblock(*newlinks)

    def make_rt_result(self, v_result):
        newrtnode = RuntimeSpecNode(v_result, v_result.concretetype)
        self.setnode(v_result, newrtnode)
        v_new = newrtnode.newvar()
        self.renamings[newrtnode] = v_new
        return v_new

    def make_const_rt_result(self, v_result, value):
        newrtnode = RuntimeSpecNode(v_result, v_result.concretetype)
        self.setnode(v_result, newrtnode)
        if v_result.concretetype is not lltype.Void:
            assert v_result.concretetype == lltype.typeOf(value)
        c_value = Constant(value)
        c_value.concretetype = v_result.concretetype
        self.renamings[newrtnode] = c_value

    def handle_default(self, op):
        newargs = [self.rename_nonvirtual(v, op) for v in op.args]
        constresult = try_fold_operation(op.opname, newargs,
                                         op.result.concretetype)
        if constresult:
            self.make_const_rt_result(op.result, constresult[0])
            return []
        else:
            newresult = self.make_rt_result(op.result)
            return [SpaceOperation(op.opname, newargs, newresult)]

    def handle_unreachable(self, op):
        from pypy.rpython.lltypesystem.rstr import string_repr
        msg = 'unreachable: %s' % (op,)
        ll_msg = string_repr.convert_const(msg)
        c_msg = Constant(ll_msg, lltype.typeOf(ll_msg))
        newresult = self.make_rt_result(op.result)
        return [SpaceOperation('debug_fatalerror', [c_msg], newresult)]

    def handle_op_getfield(self, op):
        node = self.getnode(op.args[0])
        if isinstance(node, VirtualSpecNode):
            fieldname = op.args[1].value
            index = node.typedesc.name2index[fieldname]
            self.setnode(op.result, node.fields[index])
            return []
        else:
            return self.handle_default(op)

    def handle_op_setfield(self, op):
        node = self.getnode(op.args[0])
        if isinstance(node, VirtualSpecNode):
            if node.readonly:
                raise ForcedInline(op)
            fieldname = op.args[1].value
            index = node.typedesc.name2index[fieldname]
            node.fields[index] = self.getnode(op.args[2])
            return []
        else:
            return self.handle_default(op)

    def handle_op_same_as(self, op):
        node = self.getnode(op.args[0])
        if isinstance(node, VirtualSpecNode):
            node = self.getnode(op.args[0])
            self.setnode(op.result, node)
            return []
        else:
            return self.handle_default(op)

    def handle_op_cast_pointer(self, op):
        node = self.getnode(op.args[0])
        if isinstance(node, VirtualSpecNode):
            node = self.getnode(op.args[0])
            SOURCEPTR = lltype.Ptr(node.typedesc.MALLOCTYPE)
            TARGETPTR = op.result.concretetype
            try:
                if lltype.castable(TARGETPTR, SOURCEPTR) < 0:
                    raise lltype.InvalidCast
            except lltype.InvalidCast:
                return self.handle_unreachable(op)
            self.setnode(op.result, node)
            return []
        else:
            return self.handle_default(op)

    def handle_op_ptr_nonzero(self, op):
        node = self.getnode(op.args[0])
        if isinstance(node, VirtualSpecNode):
            self.make_const_rt_result(op.result, True)
            return []
        else:
            return self.handle_default(op)

    def handle_op_ptr_iszero(self, op):
        node = self.getnode(op.args[0])
        if isinstance(node, VirtualSpecNode):
            self.make_const_rt_result(op.result, False)
            return []
        else:
            return self.handle_default(op)

    def handle_op_ptr_eq(self, op):
        node0 = self.getnode(op.args[0])
        node1 = self.getnode(op.args[1])
        if (isinstance(node0, VirtualSpecNode) or
            isinstance(node1, VirtualSpecNode)):
            self.make_const_rt_result(op.result, node0 is node1)
            return []
        else:
            return self.handle_default(op)

    def handle_op_ptr_ne(self, op):
        node0 = self.getnode(op.args[0])
        node1 = self.getnode(op.args[1])
        if (isinstance(node0, VirtualSpecNode) or
            isinstance(node1, VirtualSpecNode)):
            self.make_const_rt_result(op.result, node0 is not node1)
            return []
        else:
            return self.handle_default(op)

    def handle_op_malloc(self, op):
        if op.result is self.v_expand_malloc:
            MALLOCTYPE = op.result.concretetype.TO
            typedesc = self.graphbuilder.mallocv.getmalloctypedesc(MALLOCTYPE)
            virtualnode = VirtualSpecNode(typedesc, [])
            self.setnode(op.result, virtualnode)
            for name, FIELDTYPE in typedesc.names_and_types:
                fieldnode = RuntimeSpecNode(name, FIELDTYPE)
                virtualnode.fields.append(fieldnode)
                c = Constant(FIELDTYPE._defl())
                c.concretetype = FIELDTYPE
                self.renamings[fieldnode] = c
            self.v_expand_malloc = None      # done
            return []
        else:
            return self.handle_default(op)

    def handle_op_direct_call(self, op):
        graph = graph_called_by(op)
        if graph is None:
            return self.handle_default(op)
        nb_args = len(op.args) - 1
        assert nb_args == len(graph.getargs())
        newnodes = [self.getnode(v) for v in op.args[1:]]
        myframe = self.get_updated_frame(op)
        mallocv = self.graphbuilder.mallocv

        if op.result is self.v_expand_malloc:
            # move to inlining the callee, and continue looking for the
            # malloc to expand in the callee's graph
            op_to_remove = mallocv.inline_and_remove[graph]
            self.v_expand_malloc = op_to_remove.result
            return self.handle_inlined_call(myframe, graph, newnodes)

        argnodes = copynodes(newnodes, flagreadonly=myframe.find_vt_nodes())
        kind, newgraph = mallocv.get_specialized_graph(graph, argnodes)
        if kind == 'trivial':
            return self.handle_default(op)
        elif kind == 'inline':
            return self.handle_inlined_call(myframe, graph, newnodes)
        elif kind == 'call':
            return self.handle_residual_call(op, newgraph, newnodes)
        elif kind == 'fail':
            raise CannotVirtualize(op)
        else:
            raise ValueError(kind)

    def get_updated_frame(self, op):
        sourceblock = self.virtualframe.sourceblock
        nextopindex = self.virtualframe.nextopindex
        self.nodes[op.result] = FutureReturnValue(op)
        myframe = VirtualFrame(sourceblock, nextopindex, self.nodes,
                               self.virtualframe.callerframe,
                               self.virtualframe.calledgraphs)
        del self.nodes[op.result]
        return myframe

    def handle_residual_call(self, op, newgraph, newnodes):
        fspecptr = getfunctionptr(newgraph)
        newargs = [Constant(fspecptr,
                            concretetype=lltype.typeOf(fspecptr))]
        newargs += self.expand_nodes(newnodes)
        newresult = self.make_rt_result(op.result)
        newop = SpaceOperation('direct_call', newargs, newresult)
        return [newop]

    def handle_inlined_call(self, myframe, graph, newnodes):
        assert len(graph.getargs()) == len(newnodes)
        targetnodes = dict(zip(graph.getargs(), newnodes))
        calledgraphs = myframe.calledgraphs.copy()
        if graph in calledgraphs:
            raise CannotVirtualize("recursion during inlining")
        calledgraphs[graph] = True
        calleeframe = VirtualFrame(graph.startblock, 0,
                                   targetnodes, myframe, calledgraphs)
        self.virtualframe = calleeframe
        self.nodes = calleeframe.get_nodes_in_use()
        return []

    def handle_op_indirect_call(self, op):
        v_func = self.rename_nonvirtual(op.args[0], op)
        if isinstance(v_func, Constant):
            op = SpaceOperation('direct_call', [v_func] + op.args[1:-1],
                                op.result)
            return self.handle_op_direct_call(op)
        else:
            return self.handle_default(op)
Ejemplo n.º 46
0
 def __init__(self, graphbuilder, v_expand_malloc=None):
     self.graphbuilder = graphbuilder
     self.v_expand_malloc = v_expand_malloc
     self.specblock = Block([])
Ejemplo n.º 47
0
    def gen_exc_check(self, block, returnblock, normalafterblock=None):
        #var_exc_occured = Variable()
        #var_exc_occured.concretetype = lltype.Bool
        #block.operations.append(SpaceOperation("safe_call", [self.rpyexc_occured_ptr], var_exc_occured))

        llops = rtyper.LowLevelOpList(None)

        spaceop = block.operations[-1]
        alloc_shortcut = self.check_for_alloc_shortcut(spaceop)

        # XXX: does alloc_shortcut make sense also for ootype?
        if alloc_shortcut:
            T = spaceop.result.concretetype
            var_no_exc = self.gen_nonnull(spaceop.result, llops)
        else:
            v_exc_type = self.gen_getfield('exc_type', llops)
            var_no_exc = self.gen_isnull(v_exc_type, llops)

        block.operations.extend(llops)

        block.exitswitch = var_no_exc
        #exception occurred case
        b = Block([])
        b.operations = [
            SpaceOperation('debug_record_traceback', [],
                           varoftype(lltype.Void))
        ]
        l = Link([error_constant(returnblock.inputargs[0].concretetype)],
                 returnblock)
        b.closeblock(l)
        l = Link([], b)
        l.exitcase = l.llexitcase = False

        #non-exception case
        l0 = block.exits[0]
        l0.exitcase = l0.llexitcase = True

        block.recloseblock(l0, l)

        insert_zeroing_op = False
        if spaceop.opname == 'malloc':
            flavor = spaceop.args[1].value['flavor']
            if flavor == 'gc':
                insert_zeroing_op = True
        elif spaceop.opname == 'malloc_nonmovable':
            # xxx we cannot insert zero_gc_pointers_inside after
            # malloc_nonmovable, because it can return null.  For now
            # we simply always force the zero=True flag on
            # malloc_nonmovable.
            c_flags = spaceop.args[1]
            c_flags.value = c_flags.value.copy()
            spaceop.args[1].value['zero'] = True
        # NB. when inserting more special-cases here, keep in mind that
        # you also need to list the opnames in transform_block()
        # (see "special cases")

        if insert_zeroing_op:
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            v_result = spaceop.result
            if v_result in l0.args:
                result_i = l0.args.index(v_result)
                v_result_after = normalafterblock.inputargs[result_i]
            else:
                v_result_after = copyvar(None, v_result)
                l0.args.append(v_result)
                normalafterblock.inputargs.append(v_result_after)
            normalafterblock.operations.insert(
                0,
                SpaceOperation('zero_gc_pointers_inside', [v_result_after],
                               varoftype(lltype.Void)))
Ejemplo n.º 48
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)
Ejemplo n.º 49
0
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)