Beispiel #1
0
 def passon_vars(self, cache_key):
     if cache_key in self._passon_vars:
         return self._passon_vars[cache_key]
     result = [copyvar(None, var)
                   for var in self.original_passon_vars]
     self._passon_vars[cache_key] = result
     return result
Beispiel #2
0
 def get_new_name(self, var):
     if var is None:
         return None
     if isinstance(var, Constant):
         return var
     if var not in self.varmap:
         self.varmap[var] = copyvar(None, var)
     return self.varmap[var]
Beispiel #3
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.exceptiondata.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]))
Beispiel #4
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)
Beispiel #5
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)
Beispiel #6
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 = copyvar(None, v)
         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)
Beispiel #7
0
    def gen_exc_check(self, block, returnblock, normalafterblock=None):
        #var_exc_occured = Variable()
        #var_exc_occured.concretetype = lltype.Bool
        #block.operations.append(SpaceOperation("safe_call", [self.rpyexc_occured_ptr], var_exc_occured))

        llops = rtyper.LowLevelOpList(None)

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

        if alloc_shortcut:
            var_no_exc = self.gen_nonnull(spaceop.result, llops)
        else:
            v_exc_type = self.gen_getfield('exc_type', llops)
            var_no_exc = self.gen_isnull(v_exc_type, llops)

        block.operations.extend(llops)

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

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

        block.recloseblock(l0, l)

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

        if insert_zeroing_op:
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            v_result = spaceop.result
            if v_result in l0.args:
                result_i = l0.args.index(v_result)
                v_result_after = normalafterblock.inputargs[result_i]
            else:
                v_result_after = copyvar(None, v_result)
                l0.args.append(v_result)
                normalafterblock.inputargs.append(v_result_after)
            normalafterblock.operations.insert(
                0, SpaceOperation('zero_gc_pointers_inside',
                                  [v_result_after],
                                  varoftype(lltype.Void)))
Beispiel #8
0
def SSA_to_SSI(graph_or_blocks, annotator=None):
    """Turn a number of blocks belonging to a flow graph into valid (i.e. SSI)
    form, assuming that they are only in SSA form (i.e. they can use each
    other's variables directly, without having to pass and rename them along
    links).

    'graph_or_blocks' can be a graph, or just a dict that lists some blocks
    from a graph, as follows: {block: reachable-from-outside-flag}.
    """
    from rpython.translator.unsimplify import copyvar

    entrymap = mkinsideentrymap(graph_or_blocks)
    builder = DataFlowFamilyBuilder(graph_or_blocks)
    variable_families = builder.get_variable_families()
    del builder

    pending = []     # list of (block, var-used-but-not-defined)

    for block in entrymap:
        variables_created = variables_created_in(block)
        variables_used = {}
        for op in block.operations:
            for v in op.args:
                variables_used[v] = True
        variables_used[block.exitswitch] = True
        for link in block.exits:
            for v in link.args:
                variables_used[v] = True

        for v in variables_used:
            if isinstance(v, Variable):
                if v not in variables_created:
                    pending.append((block, v))

    while pending:
        block, v = pending.pop()
        v_rep = variable_families.find_rep(v)
        variables_created = variables_created_in(block)
        if v in variables_created:
            continue     # already ok
        for w in variables_created:
            w_rep = variable_families.find_rep(w)
            if v_rep is w_rep:
                # 'w' is in the same family as 'v', so we can simply
                # reuse its value for 'v'
                block.renamevariables({v: w})
                break
        else:
            # didn't find it.  Add it to all incoming links.
            try:
                links = entrymap[block]
            except KeyError:
                raise Exception("SSA_to_SSI failed: no way to give a value to"
                                " %r in %r" % (v, block))
            w = copyvar(annotator, v)
            variable_families.union(v, w)
            block.renamevariables({v: w})
            block.inputargs.append(w)
            for link in links:
                link.args.append(v)
                pending.append((link.prevblock, v))