Пример #1
0
def kill_assertion_link(graph, link):
    block = link.prevblock
    exits = list(block.exits)
    if len(exits) <= 1:
        return False
    remove_condition = len(exits) == 2
    if block.exitswitch == c_last_exception:
        if link is exits[0]:
            return False  # cannot remove the non-exceptional path
    else:
        if block.exitswitch.concretetype is not lltype.Bool:  # a switch
            remove_condition = False
        else:
            # common case: if <cond>: raise AssertionError
            # turn it into a debug_assert operation
            assert remove_condition
            newops = LowLevelOpList()
            if link.exitcase:
                v = newops.genop('bool_not', [block.exitswitch],
                                 resulttype=lltype.Bool)
            else:
                v = block.exitswitch
            msg = "assertion failed in %s" % (graph.name, )
            c_msg = inputconst(lltype.Void, msg)
            newops.genop('debug_assert', [v, c_msg])
            block.operations.extend(newops)

    exits.remove(link)
    if remove_condition:
        # condition no longer necessary
        block.exitswitch = None
        exits[0].exitcase = None
        exits[0].llexitcase = None
    block.recloseblock(*exits)
    return True
Пример #2
0
def kill_assertion_link(graph, link):
    block = link.prevblock
    exits = list(block.exits)
    if len(exits) <= 1:
        return False
    remove_condition = len(exits) == 2
    if block.canraise:
        if link is exits[0]:
            return False       # cannot remove the non-exceptional path
    else:
        if block.exitswitch.concretetype is not lltype.Bool:   # a switch
            remove_condition = False
        else:
            # common case: if <cond>: raise AssertionError
            # turn it into a debug_assert operation
            assert remove_condition
            newops = LowLevelOpList()
            if link.exitcase:
                v = newops.genop('bool_not', [block.exitswitch],
                                 resulttype=lltype.Bool)
            else:
                v = block.exitswitch
            msg = "assertion failed in %s" % (graph.name,)
            c_msg = inputconst(lltype.Void, msg)
            newops.genop('debug_assert', [v, c_msg])
            block.operations.extend(newops)

    exits.remove(link)
    if remove_condition:
        # condition no longer necessary
        block.exitswitch = None
        exits[0].exitcase = None
        exits[0].llexitcase = None
    block.recloseblock(*exits)
    return True
Пример #3
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
Пример #4
0
    def transform_block(self, block, is_borrowed):
        llops = LowLevelOpList()
        self.curr_block = block
        self.livevars = [
            var for var in block.inputargs
            if var_needsgc(var) and not is_borrowed(var)
        ]
        allvars = [var for var in block.getvariables() if var_needsgc(var)]
        self.var_last_needed_in = dict.fromkeys(allvars, 0)
        for i, op in enumerate(block.operations):
            for var in op.args:
                if not var_needsgc(var):
                    continue
                self.var_last_needed_in[var] = i
        for link in block.exits:
            for var in link.args:
                if not var_needsgc(var):
                    continue
                self.var_last_needed_in[var] = len(block.operations) + 1

        for i, op in enumerate(block.operations):
            hop = GcHighLevelOp(self, op, i, llops)
            hop.dispatch()

        if len(block.exits) != 0:  # i.e not the return block
            assert not block.canraise

            deadinallexits = set(self.livevars)
            for link in block.exits:
                deadinallexits.difference_update(set(link.args))

            for var in deadinallexits:
                self.pop_alive(var, llops)

            for link in block.exits:
                livecounts = dict.fromkeys(
                    set(self.livevars) - deadinallexits, 1)
                for v, v2 in zip(link.args, link.target.inputargs):
                    if is_borrowed(v2):
                        continue
                    if v in livecounts:
                        livecounts[v] -= 1
                    elif var_needsgc(v):
                        # 'v' is typically a Constant here, but it can be
                        # a borrowed variable going into a non-borrowed one
                        livecounts[v] = -1
                self.links_to_split[link] = livecounts

            block.operations[:] = llops
        self.livevars = None
        self.var_last_needed_in = None
        self.curr_block = None
Пример #5
0
def write_barrier_check(spaceop, needs_write_barrier=True):
    t = TranslationContext()
    t.buildannotator().build_types(lambda x:x, [SomeInteger()])
    t.buildrtyper().specialize()
    transformer = WriteBarrierTransformer(t)
    llops = LowLevelOpList()
    hop = GcHighLevelOp(transformer, spaceop, 0, llops)
    hop.dispatch()
    found = False
    print spaceop, '======>'
    for op in llops:
        print '\t', op
        if op.opname == 'direct_call':
            found = True
    assert found == needs_write_barrier
Пример #6
0
 def generate_exception_match(self, oplist, var_etype, const_etype):
     # generate the content of rclass.ll_issubclass(_const)
     from rpython.rtyper.rtyper import LowLevelOpList
     from rpython.rtyper.lltypesystem import lltype
     from rpython.flowspace.model import Constant, Variable, SpaceOperation
     llops = LowLevelOpList(None)
     field = llops.genop(
         'getfield',
         [var_etype, llops.genvoidconst('subclassrange_min')],
         lltype.Signed)
     res = llops.genop('int_between', [
         llops.genconst(const_etype.value.subclassrange_min),
         field,
         llops.genconst(const_etype.value.subclassrange_max),
     ], lltype.Bool)
     oplist.extend(llops)
     return res