Esempio n. 1
0
def insert_stackcheck(ann):
    from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles
    edges = []
    graphs_to_patch = {}
    for callposition, (caller, callee) in ann.translator.callgraph.items():
        if getattr(getattr(callee, 'func', None), 'insert_stack_check_here', False):
            graphs_to_patch[callee] = True
            continue
        edge = Edge(caller, callee)
        edge.callposition = callposition
        edges.append(edge)

    for graph in graphs_to_patch:
        v = Variable()
        ann.setbinding(v, annmodel.SomeImpossibleValue())
        unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v)
        graph.startblock.operations.insert(0, unwind_op)

    edgedict = make_edge_dict(edges)
    for edge in break_cycles(edgedict, edgedict):
        caller = edge.source
        _, _, call_tag = edge.callposition
        if call_tag:
            caller_block, _ = call_tag
        else:
            ann.warning("cycle detected but no information on where to insert "
                        "stack_check()")
            continue
        # caller block found, insert stack_check()
        v = Variable()
        # push annotation on v
        ann.setbinding(v, annmodel.SomeImpossibleValue())
        unwind_op = SpaceOperation('simple_call', [Constant(stack_check)], v)
        caller_block.operations.insert(0, unwind_op)
Esempio n. 2
0
 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
     """)
Esempio n. 3
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)
Esempio n. 4
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
Esempio n. 5
0
def test_decode_builtin_call_method():
    A = lltype.GcArray(lltype.Signed)
    def myfoobar(a, i, marker, c):
        assert marker == 'mymarker'
        return a[i] * ord(c)
    myfoobar.oopspec = 'spam.foobar(a, 2, c, i)'
    TYPE = lltype.FuncType([lltype.Ptr(A), lltype.Signed,
                            lltype.Void, lltype.Char],
                           lltype.Signed)
    fnobj = lltype.functionptr(TYPE, 'foobar', _callable=myfoobar)
    vi = Variable('i')
    vi.concretetype = lltype.Signed
    vc = Variable('c')
    vc.concretetype = lltype.Char
    v_result = Variable('result')
    v_result.concretetype = lltype.Signed
    myarray = lltype.malloc(A, 10)
    myarray[5] = 42
    op = SpaceOperation('direct_call', [newconst(fnobj),
                                        newconst(myarray),
                                        vi,
                                        voidconst('mymarker'),
                                        vc],
                        v_result)
    oopspec, opargs = decode_builtin_call(op)
    assert oopspec == 'spam.foobar'
    assert opargs == [newconst(myarray), newconst(2), vc, vi]
Esempio n. 6
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 = 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
Esempio n. 7
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
Esempio n. 8
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]
Esempio n. 9
0
    def test_guess_call_kind_and_calls_from_graphs(self):
        from pypy.objspace.flow.model import SpaceOperation, Constant, Variable

        portal_runner_ptr = object()
        g = object()
        g1 = object()
        cw = CodeWriter(None)
        cw.candidate_graphs = [g, g1]
        cw.portal_runner_ptr = portal_runner_ptr

        op = SpaceOperation('direct_call', [Constant(portal_runner_ptr)],
                            Variable())
        assert cw.guess_call_kind(op) == 'recursive'

        op = SpaceOperation('direct_call', [Constant(object())], Variable())
        assert cw.guess_call_kind(op) == 'residual'

        class funcptr:
            class graph:
                class func:
                    oopspec = "spec"

        op = SpaceOperation('direct_call', [Constant(funcptr)], Variable())
        assert cw.guess_call_kind(op) == 'builtin'

        class funcptr:
            graph = g

        op = SpaceOperation('direct_call', [Constant(funcptr)], Variable())
        res = cw.graphs_from(op)
        assert res == [g]
        assert cw.guess_call_kind(op) == 'regular'

        class funcptr:
            graph = object()

        op = SpaceOperation('direct_call', [Constant(funcptr)], Variable())
        res = cw.graphs_from(op)
        assert res is None
        assert cw.guess_call_kind(op) == 'residual'

        h = object()
        op = SpaceOperation('indirect_call',
                            [Variable(), Constant([g, g1, h])], Variable())
        res = cw.graphs_from(op)
        assert res == [g, g1]
        assert cw.guess_call_kind(op) == 'regular'

        op = SpaceOperation('indirect_call',
                            [Variable(), Constant([h])], Variable())
        res = cw.graphs_from(op)
        assert res is None
        assert cw.guess_call_kind(op) == 'residual'
Esempio n. 10
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)
Esempio n. 11
0
    def render_method(self, method_name, method, ilasm):
        args, retval = method.args, method.retval.name
        if len(args) == 0 or args[-1].name != 'callback':
            args.append(ArgDesc('callback', lambda: None))
        real_args = list(arg.name for arg in args)
        # FIXME: dirty JS here
        data = "{%s}" % ",".join(
            ["'%s':%s" % (i, i) for i in real_args if i != 'callback'])
        real_callback = Variable("callback").name
        if len(self.base_url) > 0 and not self.base_url.endswith("/"):
            url = self.base_url + "/" + method_name
        else:
            url = self.base_url + method_name

        METHOD_BODY = globals()[self.method + "_METHOD_BODY"]
        if USE_MOCHIKIT and self.use_xml:
            assert 0, "Cannot use mochikit and xml requests at the same time"
        if USE_MOCHIKIT and self.method == "POST":
            assert 0, "Cannot use mochikit with POST method"
        if USE_MOCHIKIT:
            ilasm.codegenerator.write(MOCHIKIT_BODY % {'class':self.name, 'method':method_name,\
                'args':','.join(real_args), 'data':data, 'call':url})
        else:
            if not self.use_xml:
                callback_body = CALLBACK_BODY
            else:
                callback_body = CALLBACK_XML_BODY
            ilasm.codegenerator.write(callback_body %
                                      {'real_callback': real_callback})
            ilasm.codegenerator.write(METHOD_BODY % {'class':self.name, 'method':method_name,\
                'args':",".join(real_args), 'data':data, 'call':url,\
                'real_callback':real_callback})
Esempio n. 12
0
def insert_ll_stackcheck(translator):
    from pypy.translator.backendopt.support import find_calls_from
    from pypy.rlib.rstack import stack_check
    from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles
    rtyper = translator.rtyper
    graph = rtyper.annotate_helper(stack_check, [])
    rtyper.specialize_more_blocks()
    stack_check_ptr = rtyper.getcallable(graph)
    stack_check_ptr_const = Constant(stack_check_ptr, lltype.typeOf(stack_check_ptr))
    edges = []
    graphs_to_patch = {}
    insert_in = {}
    for caller in translator.graphs:
        for block, callee in find_calls_from(translator, caller):
            if getattr(getattr(callee, 'func', None),
                       'insert_stack_check_here', False):
                insert_in[callee.startblock] = True
                continue
            edge = Edge(caller, callee)
            edge.block = block
            edges.append(edge)

    edgedict = make_edge_dict(edges)
    for edge in break_cycles(edgedict, edgedict):
        block = edge.block
        insert_in[block] = True
        
    for block in insert_in:
        v = Variable()
        v.concretetype = lltype.Void
        unwind_op = SpaceOperation('direct_call', [stack_check_ptr_const], v)
        block.operations.insert(0, unwind_op)
    return len(insert_in)
Esempio n. 13
0
    def rewrite_can_enter_jit(self, jd, can_enter_jits):
        FUNCPTR = jd._PTR_JIT_ENTER_FUNCTYPE
        jit_enter_fnptr = self.helper_func(FUNCPTR, jd._maybe_enter_jit_fn)

        if len(can_enter_jits) == 0:
            # see test_warmspot.test_no_loop_at_all
            operations = jd.portal_graph.startblock.operations
            op1 = operations[0]
            assert (op1.opname == 'jit_marker' and
                    op1.args[0].value == 'jit_merge_point')
            op0 = SpaceOperation(
                'jit_marker',
                [Constant('can_enter_jit', lltype.Void)] + op1.args[1:],
                None)
            operations.insert(0, op0)
            can_enter_jits = [(jd.portal_graph, jd.portal_graph.startblock, 0)]

        for graph, block, index in can_enter_jits:
            if graph is jd._jit_merge_point_in:
                continue

            op = block.operations[index]
            greens_v, reds_v = support.decode_hp_hint_args(op)
            args_v = greens_v + reds_v

            vlist = [Constant(jit_enter_fnptr, FUNCPTR)] + args_v

            v_result = Variable()
            v_result.concretetype = lltype.Void
            newop = SpaceOperation('direct_call', vlist, v_result)
            block.operations[index] = newop
Esempio n. 14
0
def instrument_inline_candidates(graphs, threshold):
    cache = {None: False}
    def candidate(graph):
        try:
            return cache[graph]
        except KeyError:
            res = static_instruction_count(graph) <= threshold
            cache[graph] = res
            return res
    n = 0
    for parentgraph in graphs:
        for block in parentgraph.iterblocks():
            ops = block.operations
            i = len(ops)-1
            while i >= 0:
                op = ops[i]
                i -= 1
                if op.opname == "direct_call":
                    funcobj = get_funcobj(op.args[0].value)
                    graph = getattr(funcobj, 'graph', None)
                    if graph is not None:
                        if getattr(getattr(funcobj, '_callable', None),
                                   '_dont_inline_', False):
                            continue
                    if candidate(graph):
                        tag = Constant('inline', Void)
                        label = Constant(n, Signed)
                        dummy = Variable()
                        dummy.concretetype = Void
                        count = SpaceOperation('instrument_count',
                                               [tag, label], dummy)
                        ops.insert(i+1, count)
                        n += 1
    log.inlining("%d call sites instrumented" % n)
Esempio n. 15
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
Esempio n. 16
0
def insert_ll_stackcheck(translator):
    from pypy.translator.backendopt.support import find_calls_from
    from pypy.rlib.rstack import stack_check
    from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles_v
    rtyper = translator.rtyper
    graph = rtyper.annotate_helper(stack_check, [])
    rtyper.specialize_more_blocks()
    stack_check_ptr = rtyper.getcallable(graph)
    stack_check_ptr_const = Constant(stack_check_ptr, lltype.typeOf(stack_check_ptr))
    edges = set()
    insert_in = set()
    for caller in translator.graphs:
        for block, callee in find_calls_from(translator, caller):
            if getattr(getattr(callee, 'func', None),
                       'insert_stack_check_here', False):
                insert_in.add(callee.startblock)
                continue
            if block is not caller.startblock:
                edges.add((caller.startblock, block))
            edges.add((block, callee.startblock))

    edgelist = [Edge(block1, block2) for (block1, block2) in edges]
    edgedict = make_edge_dict(edgelist)
    for block in break_cycles_v(edgedict, edgedict):
        insert_in.add(block)

    for block in insert_in:
        v = Variable()
        v.concretetype = lltype.Void
        unwind_op = SpaceOperation('direct_call', [stack_check_ptr_const], v)
        block.operations.insert(0, unwind_op)
    return len(insert_in)
Esempio n. 17
0
def prepare_constant_fold_link(link, constants, splitblocks):
    block = link.target
    if not block.operations:
        # when the target block has no operation, there is nothing we can do
        # except trying to fold an exitswitch
        if block.exitswitch is not None and block.exitswitch in constants:
            llexitvalue = constants[block.exitswitch].value
            rewire_link_for_known_exitswitch(link, llexitvalue)
        return

    folded_count = fold_op_list(block.operations, constants, exit_early=True)

    n = len(block.operations)
    if block.exitswitch == c_last_exception:
        n -= 1
    # is the next, non-folded operation an indirect_call?
    m = folded_count
    while m < n and block.operations[m].opname == 'keepalive':
        m += 1
    if m < n:
        nextop = block.operations[m]
        if nextop.opname == 'indirect_call' and nextop.args[0] in constants:
            # indirect_call -> direct_call
            callargs = [constants[nextop.args[0]]]
            constants1 = constants.copy()
            complete_constants(link, constants1)
            newkeepalives = []
            for i in range(folded_count, m):
                [v] = block.operations[i].args
                v = constants1.get(v, v)
                v_void = Variable()
                v_void.concretetype = lltype.Void
                newkeepalives.append(SpaceOperation('keepalive', [v], v_void))
            for v in nextop.args[1:-1]:
                callargs.append(constants1.get(v, v))
            v_result = Variable(nextop.result)
            v_result.concretetype = nextop.result.concretetype
            constants[nextop.result] = v_result
            callop = SpaceOperation('direct_call', callargs, v_result)
            newblock = insert_empty_block(None, link, newkeepalives + [callop])
            [link] = newblock.exits
            assert link.target is block
            folded_count = m + 1

    if folded_count > 0:
        splits = splitblocks.setdefault(block, [])
        splits.append((folded_count, link, constants))
Esempio n. 18
0
    def do_inline(self, block, index_operation):
        splitlink = split_block(None, block, index_operation)
        afterblock = splitlink.target
        # these variables have to be passed along all the links in the inlined
        # graph because the original function needs them in the blocks after
        # the inlined function
        # for every inserted block we need a new copy of these variables,
        # this copy is created with the method passon_vars
        self.original_passon_vars = [arg for arg in block.exits[0].args
                                         if isinstance(arg, Variable)]
        n = 0
        while afterblock.operations[n].opname == 'keepalive':
            n += 1
        assert afterblock.operations[n].opname == self.op.opname
        self.op = afterblock.operations.pop(n)
        #vars that need to be passed through the blocks of the inlined function
        linktoinlined = splitlink
        copiedstartblock = self.copy_block(self.graph_to_inline.startblock)
        copiedstartblock.isstartblock = False
        #find args passed to startblock of inlined function
        passon_args = []
        for arg in self.op.args[1:]:
            if isinstance(arg, Constant):
                passon_args.append(arg)
            else:
                index = afterblock.inputargs.index(arg)
                passon_args.append(linktoinlined.args[index])
        passon_args += self.original_passon_vars

        if self.op.opname == 'oosend' and not isinstance(self.op.args[1], Constant):
            # if we try to inline a graph defined in a superclass, the
            # type of 'self' on the graph differs from the current
            linkv = passon_args[0]
            inputv = copiedstartblock.inputargs[0]
            LINK_SELF = linkv.concretetype
            INPUT_SELF = inputv.concretetype
            if LINK_SELF != INPUT_SELF:
                # need to insert an upcast
                assert ootype.isSubclass(LINK_SELF, INPUT_SELF)
                v = Variable()
                v.concretetype = INPUT_SELF
                upcast = SpaceOperation('ooupcast', [linkv], v)
                block.operations.append(upcast)
                passon_args[0] = v

        #rewire blocks
        linktoinlined.target = copiedstartblock
        linktoinlined.args = passon_args
        afterblock.inputargs = [self.op.result] + afterblock.inputargs
        if self.graph_to_inline.returnblock in self.entrymap:
            self.rewire_returnblock(afterblock) 
        if self.graph_to_inline.exceptblock in self.entrymap:
            self.rewire_exceptblock(afterblock)
        if self.exception_guarded:
            assert afterblock.exits[0].exitcase is None
            afterblock.recloseblock(afterblock.exits[0])
            afterblock.exitswitch = None
        self.search_for_calls(afterblock)
        self.search_for_calls(block)
Esempio 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
Esempio n. 20
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)
Esempio n. 21
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)
Esempio n. 22
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)]
Esempio n. 23
0
def _insert_reads(block, varnames):
    assert len(varnames) == len(block.inputargs)
    v_entry1 = Variable('entry')
    for i, name in enumerate(varnames):
        block.operations.insert(
            i,
            SpaceOperation('getattr', [v_entry1, Constant(name)],
                           block.inputargs[i]))
    block.inputargs = [v_entry1]
Esempio n. 24
0
    def flowin(self, block, count, vars, newvarsmap):
        # in this 'block', follow where the 'var' goes to and replace
        # it by a flattened-out family of variables.  This family is given
        # by newvarsmap, whose keys are the 'flatnames'.
        self.last_removed_access = None

        def list_newvars():
            return [newvarsmap[key] for key in self.flatnames]

        assert block.operations != ()
        self.newops = []
        for op in block.operations:
            for arg in op.args[1:]:  # should be the first arg only
                assert arg not in vars
            if op.args and op.args[0] in vars:
                self.flowin_op(op, vars, newvarsmap)
            elif op.result in vars:
                assert op.opname == self.MALLOC_OP
                progress = True
                # drop the "malloc" operation
                newvarsmap = self.flatconstants.copy()  # zero initial values
                # if there are substructures, they are now individually
                # malloc'ed in an exploded way.  (They will typically be
                # removed again by the next malloc removal pass.)
                for key in self.needsubmallocs:
                    v = Variable()
                    v.concretetype = self.newvarstype[key]
                    c = Constant(v.concretetype.TO, lltype.Void)
                    if c.value == op.args[0].value:
                        progress = False  # replacing a malloc with
                        # the same malloc!
                    newop = self.recreate_malloc(c, v)
                    self.newops.append(newop)
                    newvarsmap[key] = v
                count[0] += progress
            else:
                self.newops.append(op)

        assert block.exitswitch not in vars

        for link in block.exits:
            appended = False
            newargs = []
            for arg in link.args:
                if arg in vars:
                    if not appended:
                        newargs += list_newvars()
                        appended = True
                else:
                    newargs.append(arg)
            link.args[:] = newargs

        self.insert_keepalives(list_newvars())
        block.operations[:] = self.newops
Esempio n. 25
0
 def insert_keepalives(self, newvars):
     if self.last_removed_access is not None:
         keepalives = []
         for v in newvars:
             T = v.concretetype
             if isinstance(T, lltype.Ptr) and T._needsgc():
                 v0 = Variable()
                 v0.concretetype = lltype.Void
                 newop = SpaceOperation('keepalive', [v], v0)
                 keepalives.append(newop)
         self.newops[self.last_removed_access:self.
                     last_removed_access] = keepalives
Esempio n. 26
0
    def transform_graph(self, graph):
        if graph in self.minimal_transform:
            if self.minimalgctransformer:
                self.minimalgctransformer.transform_graph(graph)
            del self.minimal_transform[graph]
            return
        if graph in self.seen_graphs:
            return
        self.seen_graphs[graph] = True

        self.links_to_split = {} # link -> vars to pop_alive across the link

        # for sanity, we need an empty block at the start of the graph
        inserted_empty_startblock = False
        if not starts_with_empty_block(graph):
            insert_empty_startblock(self.translator.annotator, graph)
            inserted_empty_startblock = True
        is_borrowed = self.compute_borrowed_vars(graph)

        for block in graph.iterblocks():
            self.transform_block(block, is_borrowed)

        for link, livecounts in self.links_to_split.iteritems():
            llops = LowLevelOpList()
            for var, livecount in livecounts.iteritems():
                for i in range(livecount):
                    self.pop_alive(var, llops)
                for i in range(-livecount):
                    self.push_alive(var, llops)
            if llops:
                if link.prevblock.exitswitch is None:
                    link.prevblock.operations.extend(llops)
                else:
                    insert_empty_block(self.translator.annotator, link, llops)

        # remove the empty block at the start of the graph, which should
        # still be empty (but let's check)
        if starts_with_empty_block(graph) and inserted_empty_startblock:
            old_startblock = graph.startblock
            graph.startblock.isstartblock = False
            graph.startblock = graph.startblock.exits[0].target
            graph.startblock.isstartblock = True

        checkgraph(graph)

        self.links_to_split = None
        v = Variable('vanishing_exc_value')
        v.concretetype = self.get_lltype_of_exception_value()
        llops = LowLevelOpList()
        self.pop_alive(v, llops)
        graph.exc_cleanup = (v, list(llops))
        return is_borrowed    # xxx for tests only
Esempio n. 27
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)
Esempio n. 28
0
def test_decode_builtin_call_nomethod():
    def myfoobar(i, marker, c):
        assert marker == 'mymarker'
        return i * ord(c)
    myfoobar.oopspec = 'foobar(2, c, i)'
    TYPE = lltype.FuncType([lltype.Signed, lltype.Void, lltype.Char],
                           lltype.Signed)
    fnobj = lltype.functionptr(TYPE, 'foobar', _callable=myfoobar)
    vi = Variable('i')
    vi.concretetype = lltype.Signed
    vc = Variable('c')
    vc.concretetype = lltype.Char
    v_result = Variable('result')
    v_result.concretetype = lltype.Signed
    op = SpaceOperation('direct_call', [newconst(fnobj),
                                        vi,
                                        voidconst('mymarker'),
                                        vc],
                        v_result)
    oopspec, opargs = decode_builtin_call(op)
    assert oopspec == 'foobar'
    assert opargs == [newconst(2), vc, vi]
Esempio n. 29
0
def generate_keepalive(vars, annotator=None):
    keepalive_ops = []
    for v in vars:
        if isinstance(v, Constant):
            continue
        if v.concretetype._is_atomic():
            continue
        v_keepalive = Variable()
        v_keepalive.concretetype = lltype.Void
        if annotator is not None:
            annotator.setbinding(v_keepalive, s_ImpossibleValue)
        keepalive_ops.append(SpaceOperation('keepalive', [v], v_keepalive))
    return keepalive_ops
Esempio n. 30
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]