Esempio n. 1
0
def test_switch_on_symbolic():
    symb1 = CDefinedIntSymbolic("1", 1)
    symb2 = CDefinedIntSymbolic("2", 2)
    symb3 = CDefinedIntSymbolic("3", 3)

    def fn(x):
        res = 0
        if x == symb1:
            res += x + 1
        elif x == symb2:
            res += x + 2
        elif x == symb3:
            res += x + 3
        res += 1
        return res

    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(fn, [int])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = t.graphs[0]
    remove_same_as(graph)
    res = merge_if_blocks_once(graph)
    assert not res
    checkgraph(graph)
Esempio n. 2
0
def call_final_function(translator, final_func, annhelper=None):
    """When the program finishes normally, call 'final_func()'."""
    from rpython.annotator import model as annmodel
    from rpython.rtyper.lltypesystem import lltype
    from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator

    own_annhelper = (annhelper is None)
    if own_annhelper:
        annhelper = MixLevelHelperAnnotator(translator.rtyper)
    c_final_func = annhelper.constfunc(final_func, [], annmodel.s_None)
    if own_annhelper:
        annhelper.finish()

    entry_point = translator.entry_point_graph
    v = entry_point.getreturnvar().copy()
    extrablock = Block([v])
    v_none = varoftype(lltype.Void)
    newop = SpaceOperation('direct_call', [c_final_func], v_none)
    extrablock.operations = [newop]
    extrablock.closeblock(Link([v], entry_point.returnblock))
    for block in entry_point.iterblocks():
        if block is not extrablock:
            for link in block.exits:
                if link.target is entry_point.returnblock:
                    link.target = extrablock
    checkgraph(entry_point)
Esempio n. 3
0
def checkgraphs(self, blocks):
    seen = set()
    for block in blocks:
        graph = self.annotated[block]
        if graph not in seen:
            checkgraph(graph)
            seen.add(graph)
Esempio n. 4
0
 def split_graph_and_record_jitdriver(self, graph, block, pos):
     op = block.operations[pos]
     jd = JitDriverStaticData()
     jd._jit_merge_point_in = graph
     args = op.args[2:]
     s_binding = self.translator.annotator.binding
     jd._portal_args_s = [s_binding(v) for v in args]
     graph = copygraph(graph)
     [jmpp] = find_jit_merge_points([graph])
     graph.startblock = support.split_before_jit_merge_point(*jmpp)
     # XXX this is incredibly obscure, but this is sometiems necessary
     #     so we don't explode in checkgraph. for reasons unknown this
     #     is not contanied within simplify_graph
     removenoops.remove_same_as(graph)
     # a crash in the following checkgraph() means that you forgot
     # to list some variable in greens=[] or reds=[] in JitDriver,
     # or that a jit_merge_point() takes a constant as an argument.
     checkgraph(graph)
     for v in graph.getargs():
         assert isinstance(v, Variable)
     assert len(dict.fromkeys(graph.getargs())) == len(graph.getargs())
     self.translator.graphs.append(graph)
     jd.portal_graph = graph
     # it's a bit unbelievable to have a portal without func
     assert hasattr(graph, "func")
     graph.func._dont_inline_ = True
     graph.func._jit_unroll_safe_ = True
     jd.jitdriver = block.operations[pos].args[1].value
     jd.portal_runner_ptr = "<not set so far>"
     jd.result_type = history.getkind(jd.portal_graph.getreturnvar()
                                      .concretetype)[0]
     self.jitdrivers_sd.append(jd)
Esempio n. 5
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 = op.newtuple(*starargs)
     newtup.result = argscopy[-1]
     newstartblock.operations.append(newtup)
     newstartblock.closeblock(Link(argscopy, graph.startblock))
     graph.startblock = newstartblock
     argnames = argnames + ['.star%d' % i for i in range(nb_extra_args)]
     graph.signature = Signature(argnames)
     # note that we can mostly ignore defaults: if nb_extra_args > 0,
     # then defaults aren't applied.  if nb_extra_args == 0, then this
     # just removes the *arg and the defaults keep their meaning.
     if nb_extra_args > 0:
         graph.defaults = None  # shouldn't be used in this case
     checkgraph(graph)
     return graph
Esempio n. 6
0
 def split_graph_and_record_jitdriver(self, graph, block, pos):
     op = block.operations[pos]
     jd = JitDriverStaticData()
     jd._jit_merge_point_in = graph
     args = op.args[2:]
     s_binding = self.translator.annotator.binding
     jd._portal_args_s = [s_binding(v) for v in args]
     graph = copygraph(graph)
     [jmpp] = find_jit_merge_points([graph])
     graph.startblock = support.split_before_jit_merge_point(*jmpp)
     # XXX this is incredibly obscure, but this is sometiems necessary
     #     so we don't explode in checkgraph. for reasons unknown this
     #     is not contanied within simplify_graph
     removenoops.remove_same_as(graph)
     # a crash in the following checkgraph() means that you forgot
     # to list some variable in greens=[] or reds=[] in JitDriver,
     # or that a jit_merge_point() takes a constant as an argument.
     checkgraph(graph)
     for v in graph.getargs():
         assert isinstance(v, Variable)
     assert len(dict.fromkeys(graph.getargs())) == len(graph.getargs())
     self.translator.graphs.append(graph)
     jd.portal_graph = graph
     # it's a bit unbelievable to have a portal without func
     assert hasattr(graph, "func")
     graph.func._dont_inline_ = True
     graph.func._jit_unroll_safe_ = True
     jd.jitdriver = block.operations[pos].args[1].value
     jd.portal_runner_ptr = "<not set so far>"
     jd.result_type = history.getkind(
         jd.portal_graph.getreturnvar().concretetype)[0]
     self.jitdrivers_sd.append(jd)
Esempio n. 7
0
def simplify_graph(graph, passes=True): # can take a list of passes to apply, True meaning all
    """inplace-apply all the existing optimisations to the graph."""
    if passes is True:
        passes = all_passes
    for pass_ in passes:
        pass_(graph)
    checkgraph(graph)
Esempio n. 8
0
def test_split_block_exceptions():
    for i in range(2):
        def raises(x):
            if x == 1:
                raise ValueError
            elif x == 2:
                raise KeyError
            return x
        def catches(x):
            try:
                y = x + 1
                raises(y)
            except ValueError:
                return 0
            except KeyError:
                return 1
            return x
        graph, t = translate(catches, [int])
        split_block(graph.startblock, i)
        checkgraph(graph)
        interp = LLInterpreter(t.rtyper)
        result = interp.eval_graph(graph, [0])
        assert result == 0
        result = interp.eval_graph(graph, [1])
        assert result == 1
        result = interp.eval_graph(graph, [2])
        assert result == 2
Esempio n. 9
0
def call_final_function(translator, final_func, annhelper=None):
    """When the program finishes normally, call 'final_func()'."""
    from rpython.annotator import model as annmodel
    from rpython.rtyper.lltypesystem import lltype
    from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator

    own_annhelper = (annhelper is None)
    if own_annhelper:
        annhelper = MixLevelHelperAnnotator(translator.rtyper)
    c_final_func = annhelper.constfunc(final_func, [], annmodel.s_None)
    if own_annhelper:
        annhelper.finish()

    entry_point = translator.entry_point_graph
    v = copyvar(translator.annotator, entry_point.getreturnvar())
    extrablock = Block([v])
    v_none = varoftype(lltype.Void)
    newop = SpaceOperation('direct_call', [c_final_func], v_none)
    extrablock.operations = [newop]
    extrablock.closeblock(Link([v], entry_point.returnblock))
    for block in entry_point.iterblocks():
        if block is not extrablock:
            for link in block.exits:
                if link.target is entry_point.returnblock:
                    link.target = extrablock
    checkgraph(entry_point)
Esempio n. 10
0
def test_split_block_exceptions():
    for i in range(2):

        def raises(x):
            if x == 1:
                raise ValueError
            elif x == 2:
                raise KeyError
            return x

        def catches(x):
            try:
                y = x + 1
                raises(y)
            except ValueError:
                return 0
            except KeyError:
                return 1
            return x

        graph, t = translate(catches, [int])
        split_block(t.annotator, graph.startblock, i)
        checkgraph(graph)
        interp = LLInterpreter(t.rtyper)
        result = interp.eval_graph(graph, [0])
        assert result == 0
        result = interp.eval_graph(graph, [1])
        assert result == 1
        result = interp.eval_graph(graph, [2])
        assert result == 2
Esempio n. 11
0
def check_graph(graph, args, expected_result, t):
    if option.view:
        t.view()
    checkgraph(graph)
    interp = LLInterpreter(t.rtyper)
    res = interp.eval_graph(graph, args)
    assert res == expected_result
Esempio n. 12
0
def check_graph(graph, args, expected_result, t):
    if option.view:
        t.view()
    checkgraph(graph)
    interp = LLInterpreter(t.rtyper)
    res = interp.eval_graph(graph, args)
    assert res == expected_result
Esempio n. 13
0
def checkgraphs(self, blocks):
    seen = set()
    for block in blocks:
        graph = self.annotated[block]
        if graph not in seen:
            checkgraph(graph)
            seen.add(graph)
Esempio n. 14
0
def simplify_graph(
        graph,
        passes=True):  # can take a list of passes to apply, True meaning all
    """inplace-apply all the existing optimisations to the graph."""
    if passes is True:
        passes = all_passes
    for pass_ in passes:
        pass_(graph)
    checkgraph(graph)
Esempio n. 15
0
def virtualize_mallocs(translator, graphs, verbose=False):
    newgraphs = graphs[:]
    mallocv = MallocVirtualizer(newgraphs, translator.rtyper, verbose)
    while mallocv.remove_mallocs_once():
        pass
    for graph in newgraphs:
        checkgraph(graph)
        join_blocks(graph)
    assert newgraphs[:len(graphs)] == graphs
    del newgraphs[:len(graphs)]
    translator.graphs.extend(newgraphs)
Esempio n. 16
0
    def transform_graph(self, graph):
        if graph in self.minimal_transform:
            if self.minimalgctransformer:
                self.minimalgctransformer.transform_graph(graph)
            self.minimal_transform.remove(graph)
            return
        if graph in self.seen_graphs:
            return
        self.seen_graphs.add(graph)

        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(graph)
            inserted_empty_startblock = True
        is_borrowed = self.compute_borrowed_vars(graph)

        try:
            for block in graph.iterblocks():
                self.transform_block(block, is_borrowed)
        except GCTransformError as e:
            e.args = ('[function %s]: %s' % (graph.name, e.message),)
            raise

        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(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 = graph.startblock.exits[0].target

        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. 17
0
def virtualize_mallocs(translator, graphs, verbose=False):
    newgraphs = graphs[:]
    mallocv = MallocVirtualizer(newgraphs, translator.rtyper, verbose)
    while mallocv.remove_mallocs_once():
        pass
    for graph in newgraphs:
        checkgraph(graph)
        join_blocks(graph)
    assert newgraphs[:len(graphs)] == graphs
    del newgraphs[:len(graphs)]
    translator.graphs.extend(newgraphs)
Esempio n. 18
0
    def build_graph_types(self, flowgraph, inputcells, complete_now=True):
        checkgraph(flowgraph)

        nbarg = len(flowgraph.getargs())
        assert len(inputcells) == nbarg # wrong number of args

        # register the entry point
        self.addpendinggraph(flowgraph, inputcells)
        # recursively proceed until no more pending block is left
        if complete_now:
            self.complete()
        return self.annotation(flowgraph.getreturnvar())
Esempio n. 19
0
    def build_graph_types(self, flowgraph, inputcells, complete_now=True):
        checkgraph(flowgraph)

        nbarg = len(flowgraph.getargs())
        assert len(inputcells) == nbarg  # wrong number of args

        # register the entry point
        self.addpendinggraph(flowgraph, inputcells)
        # recursively proceed until no more pending block is left
        if complete_now:
            self.complete()
        return self.annotation(flowgraph.getreturnvar())
Esempio n. 20
0
def test_split_blocks_simple():
    for i in range(4):
        def f(x, y):
            z = x + y
            w = x * y
            return z + w
        graph, t = translate(f, [int, int])
        split_block(graph.startblock, i)
        checkgraph(graph)
        interp = LLInterpreter(t.rtyper)
        result = interp.eval_graph(graph, [1, 2])
        assert result == 5
Esempio n. 21
0
def postprocess_graph(graph, c_gcdata):
    """Collect information about the gc_push_roots and gc_pop_roots
    added in this complete graph, and replace them with real operations.
    """
    regalloc = allocate_registers(graph)
    expand_push_roots(graph, regalloc)
    move_pushes_earlier(graph, regalloc)
    expand_pop_roots(graph, regalloc)
    add_enter_leave_roots_frame(graph, regalloc, c_gcdata)
    checkgraph(graph)
    postprocess_double_check(graph)
    return (regalloc is not None)
Esempio n. 22
0
 def check_malloc_removed(cls, graph):
     remover = cls.MallocRemover()
     checkgraph(graph)
     count1 = count2 = 0
     for node in graph.iterblocks():
             for op in node.operations:
                 if op.opname == cls.MallocRemover.MALLOC_OP:
                     S = op.args[0].value
                     if not remover.union_wrapper(S):   # union wrappers are fine
                         count1 += 1
                 if op.opname in ('direct_call', 'indirect_call'):
                     count2 += 1
     assert count1 == 0   # number of mallocs left
     assert count2 == 0   # number of calls left
Esempio n. 23
0
def test_split_blocks_simple():
    for i in range(4):

        def f(x, y):
            z = x + y
            w = x * y
            return z + w

        graph, t = translate(f, [int, int])
        split_block(t.annotator, graph.startblock, i)
        checkgraph(graph)
        interp = LLInterpreter(t.rtyper)
        result = interp.eval_graph(graph, [1, 2])
        assert result == 5
Esempio n. 24
0
 def check_malloc_removed(cls, graph):
     remover = cls.MallocRemover()
     checkgraph(graph)
     count1 = count2 = 0
     for node in graph.iterblocks():
             for op in node.operations:
                 if op.opname == cls.MallocRemover.MALLOC_OP:
                     S = op.args[0].value
                     if not remover.union_wrapper(S):   # union wrappers are fine
                         count1 += 1
                 if op.opname in ('direct_call', 'indirect_call'):
                     count2 += 1
     assert count1 == 0   # number of mallocs left
     assert count2 == 0   # number of calls left
Esempio n. 25
0
    def transform_graph(self, graph):
        if graph in self.minimal_transform:
            if self.minimalgctransformer:
                self.minimalgctransformer.transform_graph(graph)
            self.minimal_transform.remove(graph)
            return
        if graph in self.seen_graphs:
            return
        self.seen_graphs.add(graph)

        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 = graph.startblock.exits[0].target

        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. 26
0
def test_replace_we_are_jitted():
    from rpython.rlib import jit
    def fn():
        if jit.we_are_jitted():
            return 1
        return 2 + jit.we_are_jitted()
    graph, t = get_graph(fn, [])
    result = replace_we_are_jitted(graph)
    assert result
    checkgraph(graph)
    # check shape of graph
    assert len(graph.startblock.operations) == 0
    assert graph.startblock.exitswitch is None
    assert graph.startblock.exits[0].target.exits[0].args[0].value == 2
Esempio n. 27
0
def remove_asserts(translator, graphs):
    rtyper = translator.rtyper
    excdata = rtyper.exceptiondata
    clsdef = translator.annotator.bookkeeper.getuniqueclassdef(AssertionError)
    ll_AssertionError = excdata.get_standard_ll_exc_instance(rtyper, clsdef)
    total_count = [0, 0]

    for graph in graphs:
        count = 0
        morework = True
        while morework:
            morework = False
            eliminate_empty_blocks(graph)
            join_blocks(graph)
            for link in graph.iterlinks():
                if (link.target is graph.exceptblock
                        and isinstance(link.args[1], Constant)
                        and link.args[1].value == ll_AssertionError):
                    if kill_assertion_link(graph, link):
                        count += 1
                        morework = True
                        break
                    else:
                        total_count[0] += 1
                        if translator.config.translation.verbose:
                            log.removeassert(
                                "cannot remove an assert from %s" %
                                (graph.name, ))
        if count:
            # now melt away the (hopefully) dead operation that compute
            # the condition
            total_count[1] += count
            if translator.config.translation.verbose:
                log.removeassert("removed %d asserts in %s" %
                                 (count, graph.name))
            checkgraph(graph)
    total_count = tuple(total_count)
    if total_count[0] == 0:
        if total_count[1] == 0:
            msg = None
        else:
            msg = "Removed %d asserts" % (total_count[1], )
    else:
        if total_count[1] == 0:
            msg = "Could not remove %d asserts" % (total_count[0], )
        else:
            msg = "Could not remove %d asserts, but removed %d asserts." % total_count
    if msg is not None:
        log.removeassert(msg)
Esempio n. 28
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))
            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
Esempio n. 29
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))
            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
Esempio n. 30
0
def test_split_blocks_conditional():
    for i in range(3):
        def f(x, y):
            if x + 12:
                return y + 1
            else:
                return y + 2
        graph, t = translate(f, [int, int])
        split_block(graph.startblock, i)
        checkgraph(graph)
        interp = LLInterpreter(t.rtyper)
        result = interp.eval_graph(graph, [-12, 2])
        assert result == 4
        result = interp.eval_graph(graph, [0, 2])
        assert result == 3
Esempio n. 31
0
def test_replace_we_are_jitted():
    from rpython.rlib import jit

    def fn():
        if jit.we_are_jitted():
            return 1
        return 2 + jit.we_are_jitted()

    graph, t = get_graph(fn, [])
    result = replace_we_are_jitted(graph)
    assert result
    checkgraph(graph)
    # check shape of graph
    assert len(graph.startblock.operations) == 0
    assert graph.startblock.exitswitch is None
    assert graph.startblock.exits[0].target.exits[0].args[0].value == 2
Esempio n. 32
0
def test_split_blocks_conditional():
    for i in range(3):

        def f(x, y):
            if x + 12:
                return y + 1
            else:
                return y + 2

        graph, t = translate(f, [int, int])
        split_block(t.annotator, graph.startblock, i)
        checkgraph(graph)
        interp = LLInterpreter(t.rtyper)
        result = interp.eval_graph(graph, [-12, 2])
        assert result == 4
        result = interp.eval_graph(graph, [0, 2])
        assert result == 3
Esempio n. 33
0
 def check(self, f, argtypes, no_getfields=0):
     t = self.translate(f, argtypes)
     getfields = 0
     graph = graphof(t, f)
     removenoops.remove_same_as(graph)
     checkgraph(graph)
     storesink_graph(graph)
     checkgraph(graph)
     if option.view:
         t.view()
     for block in graph.iterblocks():
         for op in block.operations:
             if op.opname == 'getfield':
                 getfields += 1
     if no_getfields != getfields:
         py.test.fail("Expected %d, got %d getfields" %
                      (no_getfields, getfields))
Esempio n. 34
0
def build_flow(func):
    """
    Create the flow graph for the function.
    """
    _assert_rpythonic(func)
    if (isgeneratorfunction(func) and
            not hasattr(func, '_generator_next_method_of_')):
        return make_generator_entry_graph(func)
    code = HostCode._from_code(func.func_code)
    graph = PyGraph(func, code)
    ctx = FlowContext(graph, code)
    ctx.build_flow()
    fixeggblocks(graph)
    checkgraph(graph)
    if code.is_generator:
        tweak_generator_graph(graph)
    return graph
Esempio n. 35
0
 def check(self, f, argtypes, no_getfields=0):
     t = self.translate(f, argtypes)
     getfields = 0
     graph = graphof(t, f)
     removenoops.remove_same_as(graph)
     checkgraph(graph)
     storesink_graph(graph)
     checkgraph(graph)
     if option.view:
         t.view()
     for block in graph.iterblocks():
         for op in block.operations:
             if op.opname == 'getfield':
                 getfields += 1
     if no_getfields != getfields:
         py.test.fail("Expected %d, got %d getfields" %
                      (no_getfields, getfields))
Esempio n. 36
0
def remove_asserts(translator, graphs):
    rtyper = translator.rtyper
    excdata = rtyper.exceptiondata
    clsdef = translator.annotator.bookkeeper.getuniqueclassdef(AssertionError)
    ll_AssertionError = excdata.get_standard_ll_exc_instance(rtyper, clsdef)
    total_count = [0, 0]

    for graph in graphs:
        count = 0
        morework = True
        while morework:
            morework = False
            eliminate_empty_blocks(graph)
            join_blocks(graph)
            for link in graph.iterlinks():
                if (link.target is graph.exceptblock
                    and isinstance(link.args[1], Constant)
                    and link.args[1].value == ll_AssertionError):
                    if kill_assertion_link(graph, link):
                        count += 1
                        morework = True
                        break
                    else:
                        total_count[0] += 1
                        if translator.config.translation.verbose:
                            log.removeassert("cannot remove an assert from %s" % (graph.name,))
        if count:
            # now melt away the (hopefully) dead operation that compute
            # the condition
            total_count[1] += count
            if translator.config.translation.verbose:
                log.removeassert("removed %d asserts in %s" % (count, graph.name))
            checkgraph(graph)
    total_count = tuple(total_count)
    if total_count[0] == 0:
        if total_count[1] == 0:
            msg = None
        else:
            msg = "Removed %d asserts" % (total_count[1],)
    else:
        if total_count[1] == 0:
            msg = "Could not remove %d asserts" % (total_count[0],)
        else:
            msg = "Could not remove %d asserts, but removed %d asserts." % total_count
    if msg is not None:
        log.removeassert(msg)
Esempio n. 37
0
def remove_tail_calls_to_self(translator, graph):
    entrymap = mkentrymap(graph)
    changed = False
    for link in entrymap[graph.returnblock]:
        block = link.prevblock
        if (len(block.exits) == 1 and len(block.operations) > 0
                and block.operations[-1].opname == 'direct_call'
                and block.operations[-1].result == link.args[0]):
            print "getgraph", graph
            if graph is graph:
                _remove_tail_call(translator, graph, block)
                changed = True
    if changed:
        from rpython.translator import simplify
        checkgraph(graph)
        simplify.remove_identical_vars(graph)
        simplify.eliminate_empty_blocks(graph)
        simplify.join_blocks(graph)
Esempio n. 38
0
def remove_tail_calls_to_self(translator, graph):
    entrymap = mkentrymap(graph)
    changed = False
    for link in entrymap[graph.returnblock]:
        block = link.prevblock
        if (len(block.exits) == 1 and
            len(block.operations) > 0 and
            block.operations[-1].opname == 'direct_call' and
            block.operations[-1].result == link.args[0]):
            print "getgraph", graph
            if graph is graph:
                _remove_tail_call(translator, graph, block)
                changed = True
    if changed:
        from rpython.translator import simplify
        checkgraph(graph)
        simplify.remove_identical_vars(graph)
        simplify.eliminate_empty_blocks(graph)
        simplify.join_blocks(graph)
Esempio n. 39
0
def sanity_check(t):
    # look for missing '.concretetype'
    for graph in t.graphs:
        checkgraph(graph)
        for node in graph.iterblocks():
            for v in node.inputargs:
                assert hasattr(v, 'concretetype')
            for op in node.operations:
                for v in op.args:
                    assert hasattr(v, 'concretetype')
                assert hasattr(op.result, 'concretetype')
        for node in graph.iterlinks():
            if node.exitcase is not None:
                assert hasattr(node, 'llexitcase')
            for v in node.args:
                assert hasattr(v, 'concretetype')
            if isinstance(node.last_exception, (Variable, Constant)):
                assert hasattr(node.last_exception, 'concretetype')
            if isinstance(node.last_exc_value, (Variable, Constant)):
                assert hasattr(node.last_exc_value, 'concretetype')
Esempio n. 40
0
def sanity_check(t):
    # look for missing '.concretetype'
    for graph in t.graphs:
        checkgraph(graph)
        for node in graph.iterblocks():
            for v in node.inputargs:
                assert hasattr(v, "concretetype")
            for op in node.operations:
                for v in op.args:
                    assert hasattr(v, "concretetype")
                assert hasattr(op.result, "concretetype")
        for node in graph.iterlinks():
            if node.exitcase is not None:
                assert hasattr(node, "llexitcase")
            for v in node.args:
                assert hasattr(v, "concretetype")
            if isinstance(node.last_exception, (Variable, Constant)):
                assert hasattr(node.last_exception, "concretetype")
            if isinstance(node.last_exc_value, (Variable, Constant)):
                assert hasattr(node.last_exc_value, "concretetype")
Esempio n. 41
0
def call_initial_function(translator, initial_func, annhelper=None):
    """Before the program starts, call 'initial_func()'."""
    from rpython.annotator import model as annmodel
    from rpython.rtyper.lltypesystem import lltype
    from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator

    own_annhelper = (annhelper is None)
    if own_annhelper:
        annhelper = MixLevelHelperAnnotator(translator.rtyper)
    c_initial_func = annhelper.constfunc(initial_func, [], annmodel.s_None)
    if own_annhelper:
        annhelper.finish()

    entry_point = translator.entry_point_graph
    args = [copyvar(translator.annotator, v) for v in entry_point.getargs()]
    extrablock = Block(args)
    v_none = varoftype(lltype.Void)
    newop = SpaceOperation('direct_call', [c_initial_func], v_none)
    extrablock.operations = [newop]
    extrablock.closeblock(Link(args, entry_point.startblock))
    entry_point.startblock = extrablock
    checkgraph(entry_point)
Esempio n. 42
0
def build_flow(func, space=FlowObjSpace()):
    """
    Create the flow graph for the function.
    """
    _assert_rpythonic(func)
    code = HostCode._from_code(func.func_code)
    if (code.is_generator and
            not hasattr(func, '_generator_next_method_of_')):
        graph = PyGraph(func, code)
        block = graph.startblock
        for name, w_value in zip(code.co_varnames, block.framestate.mergeable):
            if isinstance(w_value, Variable):
                w_value.rename(name)
        return bootstrap_generator(graph)
    graph = PyGraph(func, code)
    frame = space.frame = FlowSpaceFrame(space, graph, code)
    frame.build_flow()
    fixeggblocks(graph)
    checkgraph(graph)
    if code.is_generator:
        tweak_generator_graph(graph)
    return graph
Esempio n. 43
0
def postprocess_inlining(graph):
    """We first write calls to GC functions with gc_push_roots(...) and
    gc_pop_roots(...) around.  Then we inline some of these functions.
    As a result, the gc_push_roots and gc_pop_roots are no longer in
    the same block.  Fix that by moving the gc_push_roots/gc_pop_roots
    inside the inlined portion of the graph, around every call.

    We could also get a correct result by doing things in a different
    order, e.g. first postprocess_graph() and then inlining.  However,
    this order brings an important benefit: if the inlined graph has a
    fast-path, like malloc_fixedsize(), then there are no gc_push_roots
    and gc_pop_roots left along the fast-path.
    """
    for block in graph.iterblocks():
        for i in range(len(block.operations)-1, -1, -1):
            op = block.operations[i]
            if op.opname == 'gc_pop_roots':
                break
            if op.opname == 'gc_push_roots':
                _fix_graph_after_inlining(graph, block, i)
                break
    checkgraph(graph)
Esempio n. 44
0
def call_initial_function(translator, initial_func, annhelper=None):
    """Before the program starts, call 'initial_func()'."""
    from rpython.annotator import model as annmodel
    from rpython.rtyper.lltypesystem import lltype
    from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator

    own_annhelper = (annhelper is None)
    if own_annhelper:
        annhelper = MixLevelHelperAnnotator(translator.rtyper)
    c_initial_func = annhelper.constfunc(initial_func, [], annmodel.s_None)
    if own_annhelper:
        annhelper.finish()

    entry_point = translator.entry_point_graph
    args = [v.copy() for v in entry_point.getargs()]
    extrablock = Block(args)
    v_none = varoftype(lltype.Void)
    newop = SpaceOperation('direct_call', [c_initial_func], v_none)
    extrablock.operations = [newop]
    extrablock.closeblock(Link(args, entry_point.startblock))
    entry_point.startblock = extrablock
    checkgraph(entry_point)
Esempio n. 45
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 = op.newtuple(*starargs)
     newtup.result = argscopy[-1]
     newstartblock.operations.append(newtup)
     newstartblock.closeblock(Link(argscopy, graph.startblock))
     graph.startblock = newstartblock
     argnames = argnames + ['.star%d' % i for i in range(nb_extra_args)]
     graph.signature = Signature(argnames)
     # note that we can mostly ignore defaults: if nb_extra_args > 0,
     # then defaults aren't applied.  if nb_extra_args == 0, then this
     # just removes the *arg and the defaults keep their meaning.
     if nb_extra_args > 0:
         graph.defaults = None   # shouldn't be used in this case
     checkgraph(graph)
     return graph
Esempio n. 46
0
def test_switch_on_symbolic():
    symb1 = CDefinedIntSymbolic("1", 1)
    symb2 = CDefinedIntSymbolic("2", 2)
    symb3 = CDefinedIntSymbolic("3", 3)
    def fn(x):
        res = 0
        if x == symb1:
            res += x + 1
        elif x == symb2:
            res += x + 2
        elif x == symb3:
            res += x + 3
        res += 1
        return res
    t = TranslationContext()
    a = t.buildannotator()
    a.build_types(fn, [int])
    rtyper = t.buildrtyper()
    rtyper.specialize()
    graph = t.graphs[0]
    remove_same_as(graph)
    res = merge_if_blocks_once(graph)
    assert not res
    checkgraph(graph)
Esempio n. 47
0
def tweak_generator_body_graph(Entry, graph):
    # First, always run simplify_graph in order to reduce the number of
    # variables passed around
    simplify_graph(graph)
    insert_empty_startblock(None, graph)
    _insert_reads(graph.startblock, Entry.varnames)
    Entry.block = graph.startblock
    #
    mappings = [Entry]
    #
    stopblock = Block([])
    op0 = op.simple_call(const(StopIteration))
    op1 = op.type(op0.result)
    stopblock.operations = [op0, op1]
    stopblock.closeblock(Link([op1.result, op0.result], graph.exceptblock))
    #
    for block in list(graph.iterblocks()):
        for exit in block.exits:
            if exit.target is graph.returnblock:
                exit.args = []
                exit.target = stopblock
        assert block is not stopblock
        for index in range(len(block.operations)-1, -1, -1):
            hlop = block.operations[index]
            if hlop.opname == 'yield_':
                [v_yielded_value] = hlop.args
                del block.operations[index]
                newlink = split_block(None, block, index)
                newblock = newlink.target
                #
                class Resume(AbstractPosition):
                    _immutable_ = True
                    block = newblock
                Resume.__name__ = 'Resume%d' % len(mappings)
                mappings.append(Resume)
                varnames = get_variable_names(newlink.args)
                #
                _insert_reads(newblock, varnames)
                #
                op_resume = op.simple_call(const(Resume))
                block.operations.append(op_resume)
                v_resume = op_resume.result
                for i, name in enumerate(varnames):
                    block.operations.append(
                        op.setattr(v_resume, const(name), newlink.args[i]))
                op_pair = op.newtuple(v_resume, v_yielded_value)
                block.operations.append(op_pair)
                newlink.args = [op_pair.result]
                newlink.target = graph.returnblock
    #
    regular_entry_block = Block([Variable('entry')])
    block = regular_entry_block
    for Resume in mappings:
        op_check = op.simple_call(
            const(isinstance), block.inputargs[0], const(Resume))
        block.operations.append(op_check)
        block.exitswitch = op_check.result
        link1 = Link([block.inputargs[0]], Resume.block)
        link1.exitcase = True
        nextblock = Block([Variable('entry')])
        link2 = Link([block.inputargs[0]], nextblock)
        link2.exitcase = False
        block.closeblock(link1, link2)
        block = nextblock
    block.closeblock(Link([Constant(AssertionError),
                           Constant(AssertionError("bad generator class"))],
                          graph.exceptblock))
    graph.startblock = regular_entry_block
    graph.signature = Signature(['entry'])
    graph.defaults = ()
    checkgraph(graph)
    eliminate_empty_blocks(graph)
Esempio n. 48
0
        greens_v, reds_v = support.decode_hp_hint_args(op)
        vlist = [Constant(jd.portal_runner_ptr, jd._PTR_PORTAL_FUNCTYPE)]
        vlist += greens_v
        vlist += reds_v
        v_result = Variable()
        v_result.concretetype = PORTALFUNC.RESULT
        newop = SpaceOperation('direct_call', vlist, v_result)
        del origblock.operations[origindex:]
        origblock.operations.append(newop)
        origblock.exitswitch = None
        origblock.recloseblock(Link([v_result], origportalgraph.returnblock))
        # the origportal now can raise (even if it did not raise before),
        # which means that we cannot inline it anywhere any more, but that's
        # fine since any forced inlining has been done before
        #
        checkgraph(origportalgraph)

    def add_finish(self):
        def finish():
            if self.metainterp_sd.profiler.initialized:
                self.metainterp_sd.profiler.finish()
            self.metainterp_sd.cpu.finish_once()

        if self.cpu.translate_support_code:
            call_final_function(self.translator, finish,
                                annhelper=self.annhelper)

    def rewrite_set_param_and_get_stats(self):
        from rpython.rtyper.lltypesystem.rstr import STR

        closures = {}
Esempio n. 49
0
 def _transform_hint_close_stack(self, fnptr):
     # We cannot easily pass variable amount of arguments of the call
     # across the call to the pypy_asm_stackwalk helper.  So we store
     # them away and restore them.  More precisely, we need to
     # replace 'graph' with code that saves the arguments, and make
     # a new graph that starts with restoring the arguments.
     if self._asmgcc_save_restore_arguments is None:
         self._asmgcc_save_restore_arguments = {}
     sradict = self._asmgcc_save_restore_arguments
     sra = []  # list of pointers to raw-malloced containers for args
     seen = {}
     FUNC1 = lltype.typeOf(fnptr).TO
     for TYPE in FUNC1.ARGS:
         if isinstance(TYPE, lltype.Ptr):
             TYPE = llmemory.Address
         num = seen.get(TYPE, 0)
         seen[TYPE] = num + 1
         key = (TYPE, num)
         if key not in sradict:
             CONTAINER = lltype.FixedSizeArray(TYPE, 1)
             p = lltype.malloc(CONTAINER,
                               flavor='raw',
                               zero=True,
                               immortal=True)
             sradict[key] = Constant(p, lltype.Ptr(CONTAINER))
         sra.append(sradict[key])
     #
     # make a copy of the graph that will reload the values
     graph = fnptr._obj.graph
     graph2 = copygraph(graph)
     #
     # edit the original graph to only store the value of the arguments
     block = Block(graph.startblock.inputargs)
     c_item0 = Constant('item0', lltype.Void)
     assert len(block.inputargs) == len(sra)
     for v_arg, c_p in zip(block.inputargs, sra):
         if isinstance(v_arg.concretetype, lltype.Ptr):
             v_adr = varoftype(llmemory.Address)
             block.operations.append(
                 SpaceOperation("cast_ptr_to_adr", [v_arg], v_adr))
             v_arg = v_adr
         v_void = varoftype(lltype.Void)
         block.operations.append(
             SpaceOperation("bare_setfield", [c_p, c_item0, v_arg], v_void))
     #
     # call asm_stackwalk(graph2)
     FUNC2 = lltype.FuncType([], FUNC1.RESULT)
     fnptr2 = lltype.functionptr(FUNC2,
                                 fnptr._obj._name + '_reload',
                                 graph=graph2)
     c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2))
     HELPERFUNC = lltype.FuncType(
         [lltype.Ptr(FUNC2), ASM_FRAMEDATA_HEAD_PTR], FUNC1.RESULT)
     v_asm_stackwalk = varoftype(lltype.Ptr(HELPERFUNC), "asm_stackwalk")
     block.operations.append(
         SpaceOperation("cast_pointer", [c_asm_stackwalk], v_asm_stackwalk))
     v_result = varoftype(FUNC1.RESULT)
     block.operations.append(
         SpaceOperation("indirect_call", [
             v_asm_stackwalk, c_fnptr2, c_gcrootanchor,
             Constant(None, lltype.Void)
         ], v_result))
     block.closeblock(Link([v_result], graph.returnblock))
     graph.startblock = block
     #
     # edit the copy of the graph to reload the values
     block2 = graph2.startblock
     block1 = Block([])
     reloadedvars = []
     for v, c_p in zip(block2.inputargs, sra):
         v = v.copy()
         if isinstance(v.concretetype, lltype.Ptr):
             w = varoftype(llmemory.Address)
         else:
             w = v
         block1.operations.append(
             SpaceOperation('getfield', [c_p, c_item0], w))
         if w is not v:
             block1.operations.append(
                 SpaceOperation('cast_adr_to_ptr', [w], v))
         reloadedvars.append(v)
     block1.closeblock(Link(reloadedvars, block2))
     graph2.startblock = block1
     #
     checkgraph(graph)
     checkgraph(graph2)
Esempio n. 50
0
def cleanup_graph(graph):
    checkgraph(graph)
    eliminate_empty_blocks(graph)
    join_blocks(graph)
    remove_identical_vars(graph)
    checkgraph(graph)
Esempio n. 51
0
def tweak_generator_body_graph(Entry, graph):
    # First, always run simplify_graph in order to reduce the number of
    # variables passed around
    simplify_graph(graph)
    insert_empty_startblock(graph)
    _insert_reads(graph.startblock, Entry.varnames)
    Entry.block = graph.startblock
    #
    mappings = [Entry]
    #
    stopblock = Block([])
    op0 = op.simple_call(const(StopIteration))
    op1 = op.type(op0.result)
    stopblock.operations = [op0, op1]
    stopblock.closeblock(Link([op1.result, op0.result], graph.exceptblock))
    #
    for block in list(graph.iterblocks()):
        for exit in block.exits:
            if exit.target is graph.returnblock:
                exit.args = []
                exit.target = stopblock
        assert block is not stopblock
        for index in range(len(block.operations) - 1, -1, -1):
            hlop = block.operations[index]
            if hlop.opname == 'yield_':
                [v_yielded_value] = hlop.args
                del block.operations[index]
                newlink = split_block(block, index)
                newblock = newlink.target

                #
                class Resume(AbstractPosition):
                    _immutable_ = True
                    block = newblock

                Resume.__name__ = 'Resume%d' % len(mappings)
                mappings.append(Resume)
                varnames = get_variable_names(newlink.args)
                #
                _insert_reads(newblock, varnames)
                #
                op_resume = op.simple_call(const(Resume))
                block.operations.append(op_resume)
                v_resume = op_resume.result
                for i, name in enumerate(varnames):
                    block.operations.append(
                        op.setattr(v_resume, const(name), newlink.args[i]))
                op_pair = op.newtuple(v_resume, v_yielded_value)
                block.operations.append(op_pair)
                newlink.args = [op_pair.result]
                newlink.target = graph.returnblock
    #
    regular_entry_block = Block([Variable('entry')])
    block = regular_entry_block
    for Resume in mappings:
        op_check = op.isinstance(block.inputargs[0], const(Resume))
        block.operations.append(op_check)
        block.exitswitch = op_check.result
        link1 = Link([block.inputargs[0]], Resume.block)
        link1.exitcase = True
        nextblock = Block([Variable('entry')])
        link2 = Link([block.inputargs[0]], nextblock)
        link2.exitcase = False
        block.closeblock(link1, link2)
        block = nextblock
    block.closeblock(
        Link([
            Constant(AssertionError),
            Constant(AssertionError("bad generator class"))
        ], graph.exceptblock))
    graph.startblock = regular_entry_block
    graph.signature = Signature(['entry'])
    graph.defaults = ()
    checkgraph(graph)
    eliminate_empty_blocks(graph)
Esempio n. 52
0
def partial_escape(translator, graph):
    """
    Main function.
    Blocks, which we'll work on, are in a dequeue, called "worklist", and are
    indexing link-state tuples in "statemap".
    """
    insert_links(graph)
    worklist = deque([graph.startblock])
    statemap = defaultdict(list)
    statemap[graph.startblock] = [(None, {})]
    finished = set()
    entrymap = mkentrymap(graph)
    backedges = find_backedges(graph)

    number_getfield_removed = 0

    while worklist:
        block = worklist.popleft()
        must_be_materialized = block.is_final_block()
        for link in entrymap[block]:
            if link in backedges:
                must_be_materialized = True
        state = get_current_state(statemap[block],
                                  must_be_materialized=must_be_materialized)
        if block.is_final_block():
            continue

        new_operations = []
        # Going through the operations
        for op in block.operations:
            if op.opname == 'malloc':
                # Create new entry for every allocation that is not returned
                if can_remove(op):
                    vobj = VirtualObject(op.result.concretetype, op.args)
                    state[op.result] = vobj
                    vobj.aliases.add(op.result)
                else:
                    new_operations.append(op)
            elif op.opname == 'cast_pointer':
                if op.args[0] in state:
                    # Creating something like an 'alias' for the casting
                    state[op.result] = vobj = state[op.args[0]]
                    vobj.aliases.add(op.result)
                else:
                    new_operations.append(op)
            elif op.opname == 'setfield':
                if op.args[0] in state:
                    state[op.args[0]].vars[op.args[1].value,
                                           op.args[0].concretetype] = op.args[2]
                else:
                    materialize_object(op.args[2], state, new_operations)
                    new_operations.append(op)
            elif op.opname == 'getfield':
                key = op.args[1].value, op.args[0].concretetype
                if op.args[0] in state and key in state[op.args[0]].vars:
                    targ = state[op.args[0]].vars[key]
                    number_getfield_removed += 1
                    if targ in state:
                        state[op.result] = vobj = state[targ]
                        state[targ].aliases.add(vobj)
                    else:
                        new_operations.append(SpaceOperation('same_as',
                                                             [targ],
                                                             op.result))
                else:
                    materialize_object(op.args[0], state, new_operations)
                    new_operations.append(op)
            else:
                for arg in op.args:
                    materialize_object(arg, state, new_operations)
                new_operations.append(op)
        # for all backedges, materialize all arguments (loops aren't supported
        # properly yet)
        for exit in block.exits:
            if exit in backedges or exit.target.is_final_block():
                for arg in exit.args:
                    materialize_object(arg, state, new_operations)
        block.operations = new_operations

        # We're done with the internals of the block. Editing the lists:
        finished.add(block)
        for exit in block.exits:
            # Only adding to the worklist if all its ancestors are processed
            for lnk in entrymap[exit.target]:
                if lnk.prevblock not in finished and lnk not in backedges:
                    break
            else:
                if exit.target not in finished and exit.target not in worklist: # XXX
                    worklist.append(exit.target)
            # setting statemaps:
            statemap[exit.target].append((exit, state))
    if number_getfield_removed:
        if translator.config.translation.verbose:
            log.cse("partial escape analysis removed %s getfields in graph %s" % (number_getfield_removed, graph))
        else:
            log.dot()

    # Done. Cleaning up.
    remove_same_as(graph)
    transform_dead_op_vars(graph)
    eliminate_empty_blocks(graph)
    join_blocks(graph)
    checkgraph(graph)

    return number_getfield_removed
Esempio n. 53
0
def normalize_calltable_row_signature(annotator, shape, row):
    graphs = row.values()
    assert graphs, "no graph??"
    sig0 = graphs[0].signature
    defaults0 = graphs[0].defaults
    for graph in graphs[1:]:
        if graph.signature != sig0:
            break
        if graph.defaults != defaults0:
            break
    else:
        return False   # nothing to do, all signatures already match

    shape_cnt, shape_keys, shape_star = shape
    if shape_star:
        raise TyperError(
            "not implemented: a call is done with a '*' argument, and the"
            " multiple functions or methods that it can go to don't have"
            " all the same signature (different argument names or defaults)."
            " The call can go to:\n%s" % '\n'.join(map(repr, graphs)))

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

    did_something = False

    for graph in graphs:
        argnames, varargname, kwargname = graph.signature
        assert not varargname, "XXX not implemented"
        assert not kwargname, "XXX not implemented" # ?
        inputargs_s = [annotator.binding(v) for v in graph.getargs()]
        argorder = range(shape_cnt)
        for key in shape_keys:
            i = list(argnames).index(key)
            assert i not in argorder
            argorder.append(i)
        need_reordering = (argorder != range(call_nbargs))
        if need_reordering or len(graph.getargs()) != call_nbargs:
            oldblock = graph.startblock
            inlist = []
            defaults = graph.defaults or ()
            num_nondefaults = len(inputargs_s) - len(defaults)
            defaults = [description.NODEFAULT] * num_nondefaults + list(defaults)
            newdefaults = []
            for j in argorder:
                v = Variable(graph.getargs()[j])
                annotator.setbinding(v, inputargs_s[j])
                inlist.append(v)
                newdefaults.append(defaults[j])
            newblock = Block(inlist)
            # prepare the output args of newblock:
            # 1. collect the positional arguments
            outlist = inlist[:shape_cnt]
            # 2. add defaults and keywords
            for j in range(shape_cnt, len(inputargs_s)):
                try:
                    i = argorder.index(j)
                    v = inlist[i]
                except ValueError:
                    default = defaults[j]
                    if default is description.NODEFAULT:
                        raise TyperError(
                            "call pattern has %d positional arguments, "
                            "but %r takes at least %d arguments" % (
                                shape_cnt, graph.name, num_nondefaults))
                    v = Constant(default)
                outlist.append(v)
            newblock.closeblock(Link(outlist, oldblock))
            graph.startblock = newblock
            for i in range(len(newdefaults)-1,-1,-1):
                if newdefaults[i] is description.NODEFAULT:
                    newdefaults = newdefaults[i:]
                    break
            graph.defaults = tuple(newdefaults)
            graph.signature = Signature([argnames[j] for j in argorder],
                                        None, None)
            # finished
            checkgraph(graph)
            annotator.annotated[newblock] = annotator.annotated[oldblock]
            did_something = True
    return did_something
Esempio n. 54
0
def cleanup_graph(graph):
    checkgraph(graph)
    eliminate_empty_blocks(graph)
    join_blocks(graph)
    remove_identical_vars(graph)
    checkgraph(graph)
Esempio n. 55
0
        greens_v, reds_v = support.decode_hp_hint_args(op)
        vlist = [Constant(jd.portal_runner_ptr, jd._PTR_PORTAL_FUNCTYPE)]
        vlist += greens_v
        vlist += reds_v
        v_result = Variable()
        v_result.concretetype = PORTALFUNC.RESULT
        newop = SpaceOperation('direct_call', vlist, v_result)
        del origblock.operations[origindex:]
        origblock.operations.append(newop)
        origblock.exitswitch = None
        origblock.recloseblock(Link([v_result], origportalgraph.returnblock))
        # the origportal now can raise (even if it did not raise before),
        # which means that we cannot inline it anywhere any more, but that's
        # fine since any forced inlining has been done before
        #
        checkgraph(origportalgraph)

    def add_finish(self):
        def finish():
            if self.metainterp_sd.profiler.initialized:
                self.metainterp_sd.profiler.finish()
            self.metainterp_sd.cpu.finish_once()

        if self.cpu.translate_support_code:
            call_final_function(self.translator,
                                finish,
                                annhelper=self.annhelper)

    def rewrite_set_param_and_get_stats(self):
        from rpython.rtyper.lltypesystem.rstr import STR
Esempio n. 56
0
 def checkgraphs(self):
     for graph in self.graphs:
         checkgraph(graph)
Esempio n. 57
0
 def _transform_hint_close_stack(self, fnptr):
     # We cannot easily pass variable amount of arguments of the call
     # across the call to the pypy_asm_stackwalk helper.  So we store
     # them away and restore them.  More precisely, we need to
     # replace 'graph' with code that saves the arguments, and make
     # a new graph that starts with restoring the arguments.
     if self._asmgcc_save_restore_arguments is None:
         self._asmgcc_save_restore_arguments = {}
     sradict = self._asmgcc_save_restore_arguments
     sra = []     # list of pointers to raw-malloced containers for args
     seen = {}
     FUNC1 = lltype.typeOf(fnptr).TO
     for TYPE in FUNC1.ARGS:
         if isinstance(TYPE, lltype.Ptr):
             TYPE = llmemory.Address
         num = seen.get(TYPE, 0)
         seen[TYPE] = num + 1
         key = (TYPE, num)
         if key not in sradict:
             CONTAINER = lltype.FixedSizeArray(TYPE, 1)
             p = lltype.malloc(CONTAINER, flavor='raw', zero=True,
                               immortal=True)
             sradict[key] = Constant(p, lltype.Ptr(CONTAINER))
         sra.append(sradict[key])
     #
     # make a copy of the graph that will reload the values
     graph = fnptr._obj.graph
     graph2 = copygraph(graph)
     #
     # edit the original graph to only store the value of the arguments
     block = Block(graph.startblock.inputargs)
     c_item0 = Constant('item0', lltype.Void)
     assert len(block.inputargs) == len(sra)
     for v_arg, c_p in zip(block.inputargs, sra):
         if isinstance(v_arg.concretetype, lltype.Ptr):
             v_adr = varoftype(llmemory.Address)
             block.operations.append(
                 SpaceOperation("cast_ptr_to_adr", [v_arg], v_adr))
             v_arg = v_adr
         v_void = varoftype(lltype.Void)
         block.operations.append(
             SpaceOperation("bare_setfield", [c_p, c_item0, v_arg], v_void))
     #
     # call asm_stackwalk(graph2)
     FUNC2 = lltype.FuncType([], FUNC1.RESULT)
     fnptr2 = lltype.functionptr(FUNC2,
                                 fnptr._obj._name + '_reload',
                                 graph=graph2)
     c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2))
     HELPERFUNC = lltype.FuncType([lltype.Ptr(FUNC2),
                                   ASM_FRAMEDATA_HEAD_PTR], FUNC1.RESULT)
     v_asm_stackwalk = varoftype(lltype.Ptr(HELPERFUNC), "asm_stackwalk")
     block.operations.append(
         SpaceOperation("cast_pointer", [c_asm_stackwalk], v_asm_stackwalk))
     v_result = varoftype(FUNC1.RESULT)
     block.operations.append(
         SpaceOperation("indirect_call", [v_asm_stackwalk, c_fnptr2,
                                          c_gcrootanchor,
                                          Constant(None, lltype.Void)],
                        v_result))
     block.closeblock(Link([v_result], graph.returnblock))
     graph.startblock = block
     #
     # edit the copy of the graph to reload the values
     block2 = graph2.startblock
     block1 = Block([])
     reloadedvars = []
     for v, c_p in zip(block2.inputargs, sra):
         v = v.copy()
         if isinstance(v.concretetype, lltype.Ptr):
             w = varoftype(llmemory.Address)
         else:
             w = v
         block1.operations.append(SpaceOperation('getfield',
                                                 [c_p, c_item0], w))
         if w is not v:
             block1.operations.append(SpaceOperation('cast_adr_to_ptr',
                                                     [w], v))
         reloadedvars.append(v)
     block1.closeblock(Link(reloadedvars, block2))
     graph2.startblock = block1
     #
     checkgraph(graph)
     checkgraph(graph2)
Esempio n. 58
0
def merge_if_blocks_once(graph):
    """Convert consecutive blocks that all compare a variable (of Primitive type)
    with a constant into one block with multiple exits. The backends can in
    turn output this block as a switch statement.
    """
    candidates = [block for block in graph.iterblocks()
                      if is_chain_block(block, first=True)]
    entrymap = mkentrymap(graph)
    for firstblock in candidates:
        chain = []
        checkvars = []
        varmap = {}  # {var in a block in the chain: var in the first block}
        for var in firstblock.exits[0].args:
            varmap[var] = var
        for var in firstblock.exits[1].args:
            varmap[var] = var
        def add_to_varmap(var, newvar):
            if isinstance(var, Variable):
                varmap[newvar] = varmap[var]
            else:
                varmap[newvar] = var
        current = firstblock
        while 1:
            # check whether the chain can be extended with the block that follows the
            # False link
            checkvar = [var for var in current.operations[-1].args
                           if isinstance(var, Variable)][0]
            resvar = current.operations[-1].result
            case = [var for var in current.operations[-1].args
                       if isinstance(var, Constant)][0]
            checkvars.append(checkvar)
            falseexit = current.exits[0]
            assert not falseexit.exitcase
            trueexit = current.exits[1]
            targetblock = falseexit.target
            # if the result of the check is also passed through the link, we
            # cannot construct the chain
            if resvar in falseexit.args or resvar in trueexit.args:
                break
            chain.append((current, case))
            if len(entrymap[targetblock]) != 1:
                break
            if checkvar not in falseexit.args:
                break
            newcheckvar = targetblock.inputargs[falseexit.args.index(checkvar)]
            if not is_chain_block(targetblock):
                break
            if newcheckvar not in targetblock.operations[0].args:
                break
            for i, var in enumerate(trueexit.args):
                add_to_varmap(var, trueexit.target.inputargs[i])
            for i, var in enumerate(falseexit.args):
                add_to_varmap(var, falseexit.target.inputargs[i])
            current = targetblock
        if len(chain) > 1:
            break
    else:
        return False
    merge_chain(chain, checkvars[0], varmap, graph)
    checkgraph(graph)
    return True
Esempio n. 59
0
def normalize_calltable_row_signature(annotator, shape, row):
    graphs = row.values()
    assert graphs, "no graph??"
    sig0 = graphs[0].signature
    defaults0 = graphs[0].defaults
    for graph in graphs[1:]:
        if graph.signature != sig0:
            break
        if graph.defaults != defaults0:
            break
    else:
        return False  # nothing to do, all signatures already match

    shape_cnt, shape_keys, shape_star = shape
    assert not shape_star, "should have been removed at this stage"

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

    did_something = False

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