Пример #1
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 = newstartblock
     argnames = argnames + ['.star%d' % i for i in range(nb_extra_args)]
     graph.signature = Signature(argnames)
     # note that we can mostly ignore defaults: if nb_extra_args > 0,
     # then defaults aren't applied.  if nb_extra_args == 0, then this
     # just removes the *arg and the defaults keep their meaning.
     if nb_extra_args > 0:
         graph.defaults = None  # shouldn't be used in this case
     checkgraph(graph)
     return graph
Пример #2
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)]
        assert afterblock.operations[0].opname == self.op.opname
        self.op = afterblock.operations.pop(0)
        #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
                if ootype.isSubclass(LINK_SELF, INPUT_SELF):
                    opname = 'ooupcast'
                else:
                    assert ootype.isSubclass(INPUT_SELF, LINK_SELF)
                    opname = 'oodowncast'
                v = Variable()
                v.concretetype = INPUT_SELF
                upcast = SpaceOperation(opname, [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)
Пример #3
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
Пример #4
0
    def rewrite_can_enter_jit(self, jd, can_enter_jits):
        FUNC = jd._JIT_ENTER_FUNCTYPE
        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_pos[0]:
                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
Пример #5
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)
Пример #6
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)
Пример #7
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)
Пример #8
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)
Пример #9
0
def insert_ll_stackcheck(translator):
    from pypy.translator.backendopt.support import find_calls_from
    from pypy.rpython.module.ll_stack import ll_stack_check
    from pypy.tool.algo.graphlib import Edge, make_edge_dict, break_cycles
    rtyper = translator.rtyper
    graph = rtyper.annotate_helper(ll_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)
Пример #10
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)
Пример #11
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)
Пример #12
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)
Пример #13
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]
Пример #14
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
Пример #15
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
Пример #16
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
Пример #17
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
Пример #18
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
Пример #19
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)
Пример #20
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
Пример #21
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
Пример #22
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]
Пример #23
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)
Пример #24
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
Пример #25
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]
Пример #26
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
Пример #27
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
     """)
Пример #28
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
Пример #29
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
Пример #30
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'
Пример #31
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) 
 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)
Пример #33
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})
Пример #34
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
Пример #35
0
def test_is_pure():
    from pypy.objspace.flow.model import Variable, Constant
    from pypy.rpython import rclass
    assert llop.bool_not.is_pure([Variable()])
    assert llop.debug_assert.is_pure([Variable()])
    assert not llop.int_add_ovf.is_pure([Variable(), Variable()])
    #
    S1 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed))
    v_s1 = Variable()
    v_s1.concretetype = lltype.Ptr(S1)
    assert not llop.setfield.is_pure([v_s1, Constant('x'), Variable()])
    assert not llop.getfield.is_pure([v_s1, Constant('y')])
    #
    A1 = lltype.GcArray(lltype.Signed)
    v_a1 = Variable()
    v_a1.concretetype = lltype.Ptr(A1)
    assert not llop.setarrayitem.is_pure([v_a1, Variable(), Variable()])
    assert not llop.getarrayitem.is_pure([v_a1, Variable()])
    assert llop.getarraysize.is_pure([v_a1])
    #
    S2 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed),
                         hints={'immutable': True})
    v_s2 = Variable()
    v_s2.concretetype = lltype.Ptr(S2)
    assert not llop.setfield.is_pure([v_s2, Constant('x'), Variable()])
    assert llop.getfield.is_pure([v_s2, Constant('y')])
    #
    A2 = lltype.GcArray(lltype.Signed, hints={'immutable': True})
    v_a2 = Variable()
    v_a2.concretetype = lltype.Ptr(A2)
    assert not llop.setarrayitem.is_pure([v_a2, Variable(), Variable()])
    assert llop.getarrayitem.is_pure([v_a2, Variable()])
    assert llop.getarraysize.is_pure([v_a2])
    #
    for kind in [rclass.IR_MUTABLE, rclass.IR_IMMUTABLE,
                 rclass.IR_IMMUTABLE_ARRAY, rclass.IR_QUASIIMMUTABLE,
                 rclass.IR_QUASIIMMUTABLE_ARRAY]:
        accessor = rclass.FieldListAccessor()
        S3 = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed),
                             hints={'immutable_fields': accessor})
        accessor.initialize(S3, {'x': kind})
        v_s3 = Variable()
        v_s3.concretetype = lltype.Ptr(S3)
        assert not llop.setfield.is_pure([v_s3, Constant('x'), Variable()])
        assert not llop.setfield.is_pure([v_s3, Constant('y'), Variable()])
        assert llop.getfield.is_pure([v_s3, Constant('x')]) is kind
        assert not llop.getfield.is_pure([v_s3, Constant('y')])
Пример #36
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))
Пример #37
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
Пример #38
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)]
Пример #39
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)
Пример #40
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]
Пример #41
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)]
Пример #42
0
 def genop(self, opname, args_v, resulttype=None):
     try:
         for v in args_v:
             v.concretetype
     except AttributeError:
         raise AssertionError("wrong level!  you must call hop.inputargs()"
                              " and pass its result to genop(),"
                              " never hop.args_v directly.")
     vresult = Variable()
     self.append(SpaceOperation(opname, args_v, vresult))
     if resulttype is None:
         vresult.concretetype = Void
         return None
     else:
         if isinstance(resulttype, Repr):
             resulttype = resulttype.lowleveltype
         assert isinstance(resulttype, LowLevelType)
         vresult.concretetype = resulttype
         return vresult
Пример #43
0
 def genop(self, opname, args_v, resulttype=None):
     try:
         for v in args_v:
             v.concretetype
     except AttributeError:
         raise AssertionError("wrong level!  you must call hop.inputargs()"
                              " and pass its result to genop(),"
                              " never hop.args_v directly.")
     vresult = Variable()
     self.append(SpaceOperation(opname, args_v, vresult))
     if resulttype is None:
         vresult.concretetype = Void
         return None
     else:
         if isinstance(resulttype, Repr):
             resulttype = resulttype.lowleveltype
         assert isinstance(resulttype, LowLevelType)
         vresult.concretetype = resulttype
         return vresult
Пример #44
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)
Пример #45
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)
Пример #46
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
     """)
Пример #47
0
    def rewrite_can_enter_jit(self):
        FUNC = self.JIT_ENTER_FUNCTYPE
        FUNCPTR = self.PTR_JIT_ENTER_FUNCTYPE
        jit_enter_fnptr = self.helper_func(FUNCPTR, self.maybe_enter_jit_fn)

        graphs = self.translator.graphs
        can_enter_jits = find_can_enter_jit(graphs)
        for graph, block, index in can_enter_jits:
            if graph is self.jit_merge_point_pos[0]:
                continue

            op = block.operations[index]
            greens_v, reds_v = 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
Пример #48
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()
    block2graph = {}
    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)
                block2graph[callee.startblock] = callee
                continue
            if block is not caller.startblock:
                edges.add((caller.startblock, block))
                block2graph[caller.startblock] = caller
            edges.add((block, callee.startblock))
            block2graph[block] = caller

    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)
        # prevents cycles of tail calls from occurring -- such cycles would
        # not consume any stack, so would turn into potentially infinite loops
        graph = block2graph[block]
        graph.inhibit_tail_call = True
    return len(insert_in)
Пример #49
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)
Пример #50
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]
Пример #51
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()
    block2graph = {}
    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)
                block2graph[callee.startblock] = callee
                continue
            if block is not caller.startblock:
                edges.add((caller.startblock, block))
                block2graph[caller.startblock] = caller
            edges.add((block, callee.startblock))
            block2graph[block] = caller

    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)
        # prevents cycles of tail calls from occurring -- such cycles would
        # not consume any stack, so would turn into potentially infinite loops
        graph = block2graph[block]
        graph.inhibit_tail_call = True
    return len(insert_in)
Пример #52
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]
Пример #53
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
Пример #54
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]
Пример #55
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)
Пример #56
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?
    if folded_count < n:
        nextop = block.operations[folded_count]
        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)
            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, [callop])
            [link] = newblock.exits
            assert link.target is block
            folded_count += 1

    if folded_count > 0:
        splits = splitblocks.setdefault(block, [])
        splits.append((folded_count, link, constants))
Пример #57
0
    def handle_raisingop(self, block, i, opdesc):
        op = block.operations[i]
        if self.hannotator.binding(op.result).is_green():
            # case not really well supported
            v_red = Variable(op.result)
            v_red.concretetype = op.result.concretetype
            hs_red = hintmodel.SomeLLAbstractVariable(op.result.concretetype)
            self.hannotator.setbinding(v_red, hs_red)
            spaceop = SpaceOperation('revealconst', [v_red], op.result)
            op.result = v_red
            i += 1
            block.operations.insert(i, spaceop)

        link = split_block(self.hannotator, block, i+1)

        reds, greens = self.sort_by_color(link.args)
        self.genop(block, 'save_locals', reds)
        resumepoint = self.get_resume_point(link.target)
        c_resumepoint = inputconst(lltype.Signed, resumepoint)

        assert len(opdesc.canraise) == 1    # for now
        c_canraise = inputconst(lltype.Void, opdesc.canraise[0])
        self.genop(block, 'split_raisingop',
                   [self.c_dummy, c_resumepoint, c_canraise] + greens)
Пример #58
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