Example #1
0
    def get_resume_point_link(self, block):
        try:
            return self.resumepoints[block]
        except KeyError:
            resumeblock = Block([])
            redcount   = 0
            greencount = 0
            newvars = []
            for v in block.inputargs:
                if v.concretetype is lltype.Void:
                    v1 = self.c_dummy
                elif self.hannotator.binding(v).is_green():
                    c = inputconst(lltype.Signed, greencount)
                    v1 = self.genop(resumeblock, 'restore_green', [c],
                                    result_like = v)
                    greencount += 1
                else:
                    c = inputconst(lltype.Signed, redcount)
                    v1 = self.genop(resumeblock, 'restore_local', [c],
                                    result_like = v)
                    redcount += 1
                newvars.append(v1)

            resumeblock.closeblock(Link(newvars, block))
            reenter_link = Link([], resumeblock)
            N = len(self.resumepoints)
            reenter_link.exitcase = N
            self.resumepoints[block] = reenter_link
            return reenter_link
Example #2
0
 def test_regalloc_exitswitch_2(self):
     v1 = Variable(); v1.concretetype = rclass.CLASSTYPE
     v2 = Variable(); v2.concretetype = rclass.CLASSTYPE
     v3 = Variable(); v3.concretetype = rclass.CLASSTYPE
     v4 = Variable(); v4.concretetype = rclass.CLASSTYPE
     block = Block([])
     block.operations = [
         SpaceOperation('res_call', [], v1),
         SpaceOperation('-live-', [], None),
         ]
     graph = FunctionGraph('f', block, v4)
     exclink = Link([v2], graph.returnblock)
     exclink.llexitcase = 123     # normally an exception class
     exclink.last_exception = v2
     exclink.last_exc_value = "unused"
     block.exitswitch = c_last_exception
     block.closeblock(Link([v1], graph.returnblock),
                      exclink)
     #
     self.check_assembler(graph, """
         res_call -> %i0
         -live-
         catch_exception L1
         int_return %i0
         ---
         L1:
         goto_if_exception_mismatch $123, L2
         last_exception -> %i0
         int_return %i0
         ---
         L2:
         reraise
     """)
Example #3
0
 def go_to_if(self, block, target, v_finished_flag):
     block.exitswitch = v_finished_flag
     [link_f] = block.exits
     link_t = Link([self.c_dummy], target)
     link_f.exitcase = False
     link_t.exitcase = True
     block.recloseblock(link_f, link_t)
Example #4
0
 def genswitch(self, block, v_exitswitch, false, true):
     block.exitswitch = v_exitswitch
     link_f = Link([], false)
     link_f.exitcase = False
     link_t = Link([], true)
     link_t.exitcase = True
     block.recloseblock(link_f, link_t)
Example #5
0
 def copy_link(self, link, prevblock):
     newargs = [self.get_new_name(a) for a in link.args] + self.passon_vars(prevblock)
     newlink = Link(newargs, self.copy_block(link.target), link.exitcase)
     newlink.last_exception = self.get_new_name(link.last_exception)
     newlink.last_exc_value = self.get_new_name(link.last_exc_value)
     if hasattr(link, 'llexitcase'):
         newlink.llexitcase = link.llexitcase
     return newlink
Example #6
0
    def handle_after_residual_call_details(self, block, pos, newops, blockset,
                                           withexc, oop = False):
        dopts = {'withexc': withexc, 'oop': oop }
        copts = Constant(dopts, lltype.Void)
        v_flags = self.genop(newops, 'after_residual_call', [copts],
                             resulttype=lltype.Signed, red=True)
        residual_fetch_index = len(newops)
        self.genop(newops, 'residual_fetch', [v_flags, copts])
        residual_fetch_pos = pos+residual_fetch_index
        block.operations[pos:pos+1] = newops

        link_t = split_block(self.hannotator, block, residual_fetch_pos)
        nextblock = link_t.target
        blockset[nextblock] = False
        i_flags = link_t.args.index(v_flags)

        reds, greens = self.sort_by_color(link_t.args)
        self.genop(block, 'save_locals', reds)

        SPLIT_FOR_ZERO = False

        if SPLIT_FOR_ZERO:
            promoteblock = Block([copyvar(self.hannotator, v)
                                  for v in link_t.args])
            link_f = Link(link_t.args, promoteblock)
            promoteblock.recloseblock(Link(promoteblock.inputargs, nextblock))
            blockset[promoteblock] = False
            v_flags2 = promoteblock.inputargs[i_flags]
        else:
            promoteblock = block
            v_flags2 = v_flags
        # if there is no global merge point, this 'promote' will actually
        # always see a constant red box
        v_finished_flag = self.genop(promoteblock, 'promote', [v_flags2],
                                     resulttype = lltype.Bool)
        self.go_to_dispatcher_if(promoteblock, v_finished_flag)

        if SPLIT_FOR_ZERO:
            c_zero = inputconst(lltype.Signed, 0)
            link_t.args = link_t.args[:]
            link_t.args[i_flags] = c_zero

            resumepoint = self.get_resume_point(promoteblock)
            c_resumepoint = inputconst(lltype.Signed, resumepoint)
            v_is_zero = self.genop(block, 'int_eq', [v_flags, c_zero],
                                   resulttype=lltype.Bool, red=True)
            v_is_zero = self.genop(block, 'split',
                                   [v_is_zero, c_resumepoint] + greens,
                                   resulttype = lltype.Bool)
            block.exitswitch = v_is_zero
            link_t.exitcase = True
            link_f.exitcase = False
            block.recloseblock(link_f, link_t)
Example #7
0
    def transform_except_block(self, graph, block):
        # attach an except block -- let's hope that nobody uses it
        graph.exceptblock = Block([
            Variable('etype'),  # exception class
            Variable('evalue')
        ])  # exception value
        graph.exceptblock.operations = ()
        graph.exceptblock.closeblock()

        result = Variable()
        result.concretetype = lltype.Void
        block.operations = [
            SpaceOperation("direct_call",
                           [self.rpyexc_raise_ptr] + block.inputargs, result)
        ]
        l = Link([error_constant(graph.returnblock.inputargs[0].concretetype)],
                 graph.returnblock)
        block.recloseblock(l)
Example #8
0
def test_switch_no_default():
    from pypy.objspace.flow.model import FunctionGraph, Block, Constant, Link
    from pypy.rpython.lltypesystem.lltype import FuncType, Signed, functionptr
    from pypy.translator.unsimplify import varoftype
    block = Block([varoftype(Signed)])
    block.exitswitch = block.inputargs[0]
    graph = FunctionGraph("t", block, varoftype(Signed))
    links = []
    for i in range(10):
        links.append(Link([Constant(i*i, Signed)], graph.returnblock, i))
        links[-1].llexitcase = i
    block.closeblock(*links)
    fptr = functionptr(FuncType([Signed], Signed), "t", graph=graph)
    def func(x):
        return fptr(x)
    f = compile_function(func, [int])
    res = f(4)
    assert res == 16
Example #9
0
def test_promote_2():
    v1 = varoftype(lltype.Signed)
    v2 = varoftype(lltype.Signed)
    op = SpaceOperation('hint',
                        [v1, Constant({'promote': True}, lltype.Void)], v2)
    returnblock = Block([varoftype(lltype.Signed)])
    returnblock.operations = ()
    block = Block([v1])
    block.operations = [op]
    block.closeblock(Link([v2], returnblock))
    Transformer().optimize_block(block)
    assert len(block.operations) == 2
    assert block.operations[0].opname == '-live-'
    assert block.operations[0].args == []
    assert block.operations[1].opname == 'int_guard_value'
    assert block.operations[1].args == [v1]
    assert block.operations[1].result is None
    assert block.exits[0].args == [v1]
Example #10
0
    def create_outgoing_link(self,
                             currentframe,
                             targetblock,
                             nodelist,
                             renamings,
                             v_expand_malloc=None):
        assert len(nodelist) == len(targetblock.inputargs)
        #
        if is_except(targetblock):
            v_expand_malloc = None
            while currentframe.callerframe is not None:
                currentframe = currentframe.callerframe
                newlink = self.handle_catch(currentframe, nodelist, renamings)
                if newlink:
                    return newlink
            else:
                targetblock = self.exception_escapes(nodelist, renamings)
                assert len(nodelist) == len(targetblock.inputargs)

        if (currentframe.callerframe is None
                and is_trivial_nodelist(nodelist)):
            # there is no more VirtualSpecNodes being passed around,
            # so we can stop specializing
            rtnodes = nodelist
            specblock = targetblock
        else:
            if is_return(targetblock):
                v_expand_malloc = None
                newframe = self.return_to_caller(currentframe, nodelist[0])
            else:
                targetnodes = dict(zip(targetblock.inputargs, nodelist))
                newframe = VirtualFrame(targetblock,
                                        0,
                                        targetnodes,
                                        callerframe=currentframe.callerframe,
                                        calledgraphs=currentframe.calledgraphs)
            rtnodes = newframe.find_rt_nodes()
            specblock = self.get_specialized_block(newframe, v_expand_malloc)

        linkargs = [renamings[rtnode] for rtnode in rtnodes]
        return Link(linkargs, specblock)
Example #11
0
 def build_callback_graph(self, graph, metadesccls=False):
     args_v = [copyvar(None, v) for v in graph.getargs()]
     v_res = copyvar(None, graph.getreturnvar())
     rtyper = self.bookkeeper.annotator.base_translator.rtyper  # fish
     fnptr = rtyper.getcallable(graph)
     v_ptr = Constant(fnptr, lltype.typeOf(fnptr))
     newstartblock = Block(args_v)
     if metadesccls:
         v_metadesccls = Constant(metadesccls, lltype.Void)
         args_v = [v_metadesccls] + args_v
         opname = 'ts_metacall'
         suffix = 'ts_metacall'
     else:
         opname = 'direct_call'
         suffix = 'ts_stub'
     newstartblock.operations.append(
         SpaceOperation(opname, [v_ptr] + args_v, v_res))
     newgraph = FunctionGraph('%s_%s' % (graph.name, suffix), newstartblock)
     newgraph.getreturnvar().concretetype = v_res.concretetype
     newstartblock.closeblock(Link([v_res], newgraph.returnblock))
     return newgraph
Example #12
0
def create_instantiate_function(annotator, classdef):
    # build the graph of a function that looks like
    # 
    # def my_instantiate():
    #     return instantiate(cls)
    #
    if hasattr(classdef, 'my_instantiate_graph'):
        return
    v = Variable()
    block = Block([])
    block.operations.append(SpaceOperation('instantiate1', [], v))
    name = valid_identifier('instantiate_'+classdef.name)
    graph = FunctionGraph(name, block)
    block.closeblock(Link([v], graph.returnblock))
    annotator.setbinding(v, annmodel.SomeInstance(classdef))
    annotator.annotated[block] = graph
    # force the result to be converted to a generic OBJECTPTR
    generalizedresult = annmodel.SomeInstance(classdef=None)
    annotator.setbinding(graph.getreturnvar(), generalizedresult)
    classdef.my_instantiate_graph = graph
    annotator.translator.graphs.append(graph)
Example #13
0
    def generic_exception_matching(self, afterblock, copiedexceptblock):
        #XXXXX don't look: insert blocks that do exception matching
        #for the cases where direct matching did not work        
        exc_match = Constant(
            self.translator.rtyper.getexceptiondata().fn_exception_match)
        exc_match.concretetype = typeOf(exc_match.value)
        blocks = []
        for i, link in enumerate(afterblock.exits[1:]):
            etype = copyvar(None, copiedexceptblock.inputargs[0])
            evalue = copyvar(None, copiedexceptblock.inputargs[1])
            passon_vars = self.passon_vars(i)
            block = Block([etype, evalue] + passon_vars)
            res = Variable()
            res.concretetype = Bool
            cexitcase = Constant(link.llexitcase)
            cexitcase.concretetype = typeOf(cexitcase.value)
            args = [exc_match, etype, cexitcase]
            block.operations.append(SpaceOperation("direct_call", args, res))
            block.exitswitch = res
            linkargs = self.find_args_in_exceptional_case(link, link.target,
                                                          etype, evalue, afterblock,
                                                          passon_vars)
            l = Link(linkargs, link.target)
            l.prevblock = block
            l.exitcase = True
            l.llexitcase = True
            block.closeblock(l)
            if i > 0:
                l = Link(blocks[-1].inputargs, block)
                l.exitcase = False
                l.llexitcase = False
                blocks[-1].recloseblock(l, *blocks[-1].exits)
            blocks.append(block)

        blocks[-1].recloseblock(*blocks[-1].exits[:1])
        blocks[-1].operations = []
        blocks[-1].exitswitch = None
        blocks[-1].exits[0].exitcase = None
        del blocks[-1].exits[0].llexitcase
        linkargs = copiedexceptblock.inputargs
        copiedexceptblock.recloseblock(Link(linkargs, blocks[0]))
        copiedexceptblock.operations += self.generate_keepalive(linkargs)
Example #14
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)
Example #15
0
 def test_regalloc_call(self):
     v1 = Variable()
     v1.concretetype = lltype.Signed
     v2 = Variable()
     v2.concretetype = lltype.Signed
     v3 = Variable()
     v3.concretetype = lltype.Signed
     v4 = Variable()
     v4.concretetype = lltype.Signed
     block = Block([v1])
     block.operations = [
         SpaceOperation('int_add', [v1, Constant(1, lltype.Signed)], v2),
         SpaceOperation('rescall', [ListOfKind('int', [v1, v2])], v3),
     ]
     graph = FunctionGraph('f', block, v4)
     block.closeblock(Link([v3], graph.returnblock))
     #
     self.check_assembler(
         graph, """
         int_add %i0, $1 -> %i1
         rescall I[%i0, %i1] -> %i0
         int_return %i0
     """)
Example #16
0
def cutoff_alwaysraising_block(self, block):
    "Fix a block whose end can never be reached at run-time."
    # search the operation that cannot succeed
    can_succeed = [op for op in block.operations if op.result in self.bindings]
    cannot_succeed = [
        op for op in block.operations if op.result not in self.bindings
    ]
    n = len(can_succeed)
    # check consistency
    assert can_succeed == block.operations[:n]
    assert cannot_succeed == block.operations[n:]
    assert 0 <= n < len(block.operations)
    # chop off the unreachable end of the block
    del block.operations[n + 1:]
    s_impossible = annmodel.SomeImpossibleValue()
    self.bindings[block.operations[n].result] = s_impossible
    # insert the equivalent of 'raise AssertionError'
    graph = self.annotated[block]
    msg = "Call to %r should have raised an exception" % (getattr(
        graph, 'func', None), )
    c1 = Constant(AssertionError)
    c2 = Constant(AssertionError(msg))
    errlink = Link([c1, c2], graph.exceptblock)
    block.recloseblock(errlink, *block.exits)
    # record new link to make the transformation idempotent
    self.links_followed[errlink] = True
    # fix the annotation of the exceptblock.inputargs
    etype, evalue = graph.exceptblock.inputargs
    s_type = annmodel.SomeObject()
    s_type.knowntype = type
    s_type.is_type_of = [evalue]
    s_value = annmodel.SomeInstance(
        self.bookkeeper.getuniqueclassdef(Exception))
    self.setbinding(etype, s_type)
    self.setbinding(evalue, s_value)
    # make sure the bookkeeper knows about AssertionError
    self.bookkeeper.getuniqueclassdef(AssertionError)
Example #17
0
 def test_regalloc_exitswitch_2(self):
     v1 = Variable()
     v1.concretetype = rclass.CLASSTYPE
     v2 = Variable()
     v2.concretetype = rclass.CLASSTYPE
     v3 = Variable()
     v3.concretetype = rclass.CLASSTYPE
     v4 = Variable()
     v4.concretetype = rclass.CLASSTYPE
     block = Block([])
     block.operations = [
         SpaceOperation('res_call', [], v1),
         SpaceOperation('-live-', [], None),
     ]
     graph = FunctionGraph('f', block, v4)
     exclink = Link([v2], graph.returnblock)
     exclink.llexitcase = 123  # normally an exception class
     exclink.last_exception = v2
     exclink.last_exc_value = "unused"
     block.exitswitch = c_last_exception
     block.closeblock(Link([v1], graph.returnblock), exclink)
     #
     self.check_assembler(
         graph, """
         res_call -> %i0
         -live-
         catch_exception L1
         int_return %i0
         ---
         L1:
         goto_if_exception_mismatch $123, L2
         last_exception -> %i0
         int_return %i0
         ---
         L2:
         reraise
     """)
Example #18
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)

        # XXX: does alloc_shortcut make sense also for ootype?
        if alloc_shortcut:
            T = spaceop.result.concretetype
            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
        # XXX this is not right. it also inserts zero_gc_pointers_inside
        # XXX on a path that malloc_nonmovable returns null, but does not raise
        # XXX which might end up with a segfault. But we don't have such gc now
        if spaceop.opname == 'malloc' or spaceop.opname == 'malloc_nonmovable':
            flavor = spaceop.args[1].value['flavor']
            if flavor == 'gc':
                insert_zeroing_op = True

        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)))

        if self.always_exc_clear:
            # insert code that clears the exception even in the non-exceptional
            # case...  this is a hint for the JIT, but pointless otherwise
            if normalafterblock is None:
                normalafterblock = insert_empty_block(None, l0)
            llops = rtyper.LowLevelOpList(None)
            self.gen_setfield('exc_value', self.c_null_evalue, llops)
            self.gen_setfield('exc_type', self.c_null_etype, llops)
            normalafterblock.operations[:0] = llops
Example #19
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)
    #
    assert graph.startblock.operations[0].opname == 'generator_mark'
    graph.startblock.operations.pop(0)
    #
    insert_empty_startblock(None, graph)
    _insert_reads(graph.startblock, Entry.varnames)
    Entry.block = graph.startblock
    #
    mappings = [Entry]
    #
    stopblock = Block([])
    v0 = Variable(); v1 = Variable()
    stopblock.operations = [
        SpaceOperation('simple_call', [Constant(StopIteration)], v0),
        SpaceOperation('type', [v0], v1),
        ]
    stopblock.closeblock(Link([v1, v0], 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):
            op = block.operations[index]
            if op.opname == 'yield':
                [v_yielded_value] = op.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)
                #
                v_resume = Variable('resume')
                block.operations.append(
                    SpaceOperation('simple_call', [Constant(Resume)],
                                   v_resume))
                for i, name in enumerate(varnames):
                    block.operations.append(
                        SpaceOperation('setattr', [v_resume, Constant(name),
                                                   newlink.args[i]],
                                       Variable()))
                v_pair = Variable('pair')
                block.operations.append(
                    SpaceOperation('newtuple', [v_resume, v_yielded_value],
                                   v_pair))
                newlink.args = [v_pair]
                newlink.target = graph.returnblock
    #
    regular_entry_block = Block([Variable('entry')])
    block = regular_entry_block
    for Resume in mappings:
        v_check = Variable()
        block.operations.append(
            SpaceOperation('simple_call', [Constant(isinstance),
                                           block.inputargs[0],
                                           Constant(Resume)],
                           v_check))
        block.exitswitch = v_check
        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)
Example #20
0
 def insert_integer_search(self, block, cases, defaultlink, blockset,
                           range_start, range_stop):
     # fix the exit of the 'block' to check for the given remaining
     # 'cases', knowing that if we get there then the value must
     # be contained in range(range_start, range_stop).
     if not cases:
         assert defaultlink is not None
         block.exitswitch = None
         block.recloseblock(Link(defaultlink.args, defaultlink.target))
     elif len(cases) == 1 and (defaultlink is None or
                               range_start == range_stop-1):
         block.exitswitch = None
         block.recloseblock(cases.values()[0])
     else:
         intvalues = cases.keys()
         intvalues.sort()
         if len(intvalues) <= 3:
             # not much point in being clever with no more than 3 cases
             intval = intvalues[-1]
             remainingcases = cases.copy()
             link = remainingcases.pop(intval)
             c_intval = inputconst(lltype.Signed, intval)
             v = self.genop(block, 'int_eq', [block.exitswitch, c_intval],
                            resulttype=lltype.Bool, red=True)
             link.exitcase = True
             link.llexitcase = True
             falseblock = Block([])
             falseblock.exitswitch = block.exitswitch
             blockset[falseblock] = False
             falselink = Link([], falseblock)
             falselink.exitcase = False
             falselink.llexitcase = False
             block.exitswitch = v
             block.recloseblock(falselink, link)
             if defaultlink is None or intval == range_stop-1:
                 range_stop = intval
             self.insert_integer_search(falseblock, remainingcases,
                                        defaultlink, blockset,
                                        range_start, range_stop)
         else:
             intval = intvalues[len(intvalues) // 2]
             c_intval = inputconst(lltype.Signed, intval)
             v = self.genop(block, 'int_ge', [block.exitswitch, c_intval],
                            resulttype=lltype.Bool, red=True)
             falseblock = Block([])
             falseblock.exitswitch = block.exitswitch
             trueblock  = Block([])
             trueblock.exitswitch = block.exitswitch
             blockset[falseblock] = False
             blockset[trueblock]  = False
             falselink = Link([], falseblock)
             falselink.exitcase = False
             falselink.llexitcase = False
             truelink = Link([], trueblock)
             truelink.exitcase = True
             truelink.llexitcase = True
             block.exitswitch = v
             block.recloseblock(falselink, truelink)
             falsecases = {}
             truecases = {}
             for intval1, link1 in cases.items():
                 if intval1 < intval:
                     falsecases[intval1] = link1
                 else:
                     truecases[intval1] = link1
             self.insert_integer_search(falseblock, falsecases,
                                        defaultlink, blockset,
                                        range_start, intval)
             self.insert_integer_search(trueblock, truecases,
                                        defaultlink, blockset,
                                        intval, range_stop)
Example #21
0
    def handle_red_call(self, block, pos, withexc, color='red'):
        link = split_block(self.hannotator, block, pos+1)
        op = block.operations.pop(pos)
        #if op.opname == 'direct_call':
        #    f = open('LOG', 'a')
        #    print >> f, color, op.args[0].value
        #    f.close()
        assert len(block.operations) == pos
        nextblock = link.target
        linkargs = link.args
        varsalive = list(linkargs)

        if color != 'gray':
            # the result will be either passed as an extra local 0
            # by the caller, or restored by a restore_local
            try:
                index = varsalive.index(op.result)
            except ValueError:
                linkargs.insert(0, op.result)
                v_result = copyvar(self.hannotator, op.result)
                nextblock.inputargs.insert(0, v_result)
            else:
                del varsalive[index]
                old_v_result = linkargs.pop(index)
                linkargs.insert(0, old_v_result)
                v_result = nextblock.inputargs.pop(index)
                nextblock.inputargs.insert(0, v_result)
        else:
            if op.result in varsalive:
                index = varsalive.index(op.result)
                del varsalive[index]
                linkargs.pop(index)
                c_void = Constant(None, lltype.Void)
                linkargs.insert(0, c_void)
                v_result = nextblock.inputargs.pop(index)
                nextblock.inputargs.insert(0, v_result)                                
        reds, greens = self.sort_by_color(varsalive)

        blockset = {}
        blockset[block] = True     # reachable from outside
        blockset[nextblock] = False

        v_func = op.args[0]
        hs_func = self.hannotator.binding(v_func)
        if hs_func.is_green():
            constantblock = block
            nonconstantblock = None
        else:
            constantblock = Block([])
            nonconstantblock = Block([])
            blockset[constantblock] = False
            blockset[nonconstantblock] = False
            v_is_constant = self.genop(block, 'is_constant', [v_func],
                                       resulttype = lltype.Bool)
            self.genswitch(block, v_is_constant, true  = constantblock,
                                                 false = nonconstantblock)

        postconstantblock = self.naive_split_block(constantblock,
                                                 len(constantblock.operations))
        blockset[postconstantblock] = False
        self.make_call(constantblock, op, reds, color)

        conversionblock = nextblock
        if color == 'red':
            assert not self.hannotator.binding(op.result).is_green()
        elif color == 'yellow':
            conversionblock = Block([copyvar(self.hannotator, v)
                                     for v in nextblock.inputargs])
            v0 = conversionblock.inputargs[0]
            already_green = self.hannotator.binding(op.result).is_green()
            assert already_green == self.hannotator.binding(v0).is_green()
            if not already_green:
                RESULT = self.hannotator.binding(v0).concretetype
                hs = hintmodel.SomeLLAbstractConstant(RESULT, {})
                self.hannotator.bindings[v0] = hs
            conversionblock.closeblock(Link(conversionblock.inputargs,
                                            nextblock))
            blockset[conversionblock] = False
            # to merge some of the possibly many return jitstates
            self.mergepoint_set[nextblock] = 'local'

        resumepoint = self.get_resume_point(conversionblock)
        c_resumepoint = inputconst(lltype.Signed, resumepoint)
        self.genop(postconstantblock, 'collect_split', [c_resumepoint] + greens)
        resumeblock = self.get_resume_point_link(conversionblock).target
        postconstantblock.recloseblock(Link([], resumeblock))
        blockset[resumeblock] = True    # reachable from outside

        if nonconstantblock is not None:
            nonconstantblock.recloseblock(Link(linkargs, nextblock))
            v_res = self.handle_residual_call_details(
                                            nonconstantblock, 0, op,
                                            color, blockset, preserve_res =
                                            (color != 'gray'),
                                            withexc=withexc)

        SSA_to_SSI(blockset, self.hannotator)
Example #22
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_stst = shape
    assert not shape_star, "XXX not implemented"
    assert not shape_stst, "XXX not implemented"

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

    did_something = False
    NODEFAULT = object()

    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 = [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 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 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
Example #23
0
def new_wrapper(func, translator, newname=None):
    # The basic idea is to produce a flow graph from scratch, using the
    # help of the rtyper for the conversion of the arguments after they
    # have been decoded.
    
    bk = translator.annotator.bookkeeper
    graph = bk.getdesc(func).getuniquegraph()

    f = getfunctionptr(graph)
    FUNCTYPE = typeOf(f).TO

    newops = LowLevelOpList(translator.rtyper)

    varguments = []
    for var in graph.startblock.inputargs:
        v = Variable(var)
        v.concretetype = PyObjPtr
        varguments.append(v)

    wrapper_inputargs = varguments[:]
    # use the rtyper to produce the conversions
    inputargs = f._obj.graph.getargs()
    for i in range(len(varguments)):
        if FUNCTYPE.ARGS[i] != PyObjPtr:
            rtyper = translator.rtyper
            r_arg = rtyper.bindingrepr(inputargs[i])
            # give the rtyper a chance to know which function we are wrapping
            rtyper.set_wrapper_context(func)
            varguments[i] = newops.convertvar(varguments[i],
                                              r_from = pyobj_repr,
                                              r_to = r_arg)
            rtyper.set_wrapper_context(None)

    vlist = [inputconst(typeOf(f), f)] + varguments
    vresult = newops.genop('direct_call', vlist, resulttype=FUNCTYPE.RESULT)

    if FUNCTYPE.RESULT != PyObjPtr:
        # convert "result" back to a PyObject
        rtyper = translator.rtyper
        assert rtyper is not None, (
            "needs the rtyper to perform function result conversions")
        r_result = rtyper.bindingrepr(f._obj.graph.getreturnvar())
        vresult = newops.convertvar(vresult,
                                    r_from = r_result,
                                    r_to = pyobj_repr)

    # "return result"
    block = Block(wrapper_inputargs)
    wgraph = FunctionGraph('pyfn_' + (newname or func.func_name), block)
    translator.update_call_graph(wgraph, graph, object())
    translator.graphs.append(wgraph)
    block.operations[:] = newops
    block.closeblock(Link([vresult], wgraph.returnblock))
    wgraph.getreturnvar().concretetype = PyObjPtr
    checkgraph(wgraph)

    # the above convertvar()s may have created and annotated new helpers
    # that need to be specialized now
    translator.rtyper.specialize_more_blocks()

    return functionptr(FuncType([PyObjPtr] * len(wrapper_inputargs),
                                PyObjPtr),
                       wgraph.name,
                       graph = wgraph,
                       exception_policy = "CPython")
Example #24
0
        #
        _, origblock, origindex = self.jit_merge_point_pos
        op = origblock.operations[origindex]
        assert op.opname == 'jit_marker'
        assert op.args[0].value == 'jit_merge_point'
        greens_v, reds_v = decode_hp_hint_args(op)
        vlist = [Constant(self.portal_runner_ptr, self.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))
        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(self):
        closures = {}
        graphs = self.translator.graphs
Example #25
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)

        # XXX: does alloc_shortcut make sense also for ootype?
        if alloc_shortcut:
            T = spaceop.result.concretetype
            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)))
Example #26
0
 def handle_call_with_close_stack(self, hop):
     fnptr = hop.spaceop.args[0].value
     # 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.  We need to 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)
             sradict[key] = Constant(p, lltype.Ptr(CONTAINER))
         sra.append(sradict[key])
     #
     # store the value of the arguments
     livevars = self.push_roots(hop)
     c_item0 = Constant('item0', lltype.Void)
     for v_arg, c_p in zip(hop.spaceop.args[1:], sra):
         if isinstance(v_arg.concretetype, lltype.Ptr):
             v_arg = hop.genop("cast_ptr_to_adr", [v_arg],
                               resulttype=llmemory.Address)
         hop.genop("bare_setfield", [c_p, c_item0, v_arg])
     #
     # make a copy of the graph that will reload the values
     graph2 = copygraph(fnptr._obj.graph)
     block2 = graph2.startblock
     block2.isstartblock = False
     block1 = Block([])
     reloadedvars = []
     for v, c_p in zip(block2.inputargs, sra):
         v = copyvar(None, v)
         if isinstance(v.concretetype, lltype.Ptr):
             w = Variable('tmp')
             w.concretetype = 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))
     block1.isstartblock = True
     graph2.startblock = block1
     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)], FUNC1.RESULT)
     #
     v_asm_stackwalk = hop.genop("cast_pointer", [c_asm_stackwalk],
                                 resulttype=lltype.Ptr(HELPERFUNC))
     hop.genop("indirect_call",
               [v_asm_stackwalk, c_fnptr2, Constant(None, lltype.Void)],
               resultvar=hop.spaceop.result)
     self.pop_roots(hop, livevars)
Example #27
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)
    #
    assert graph.startblock.operations[0].opname == 'generator_mark'
    graph.startblock.operations.pop(0)
    #
    insert_empty_startblock(None, graph)
    _insert_reads(graph.startblock, Entry.varnames)
    Entry.block = graph.startblock
    #
    mappings = [Entry]
    #
    stopblock = Block([])
    v0 = Variable()
    v1 = Variable()
    stopblock.operations = [
        SpaceOperation('simple_call', [Constant(StopIteration)], v0),
        SpaceOperation('type', [v0], v1),
    ]
    stopblock.closeblock(Link([v1, v0], 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):
            op = block.operations[index]
            if op.opname == 'yield':
                [v_yielded_value] = op.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)
                #
                v_resume = Variable('resume')
                block.operations.append(
                    SpaceOperation('simple_call', [Constant(Resume)],
                                   v_resume))
                for i, name in enumerate(varnames):
                    block.operations.append(
                        SpaceOperation(
                            'setattr',
                            [v_resume,
                             Constant(name), newlink.args[i]], Variable()))
                v_pair = Variable('pair')
                block.operations.append(
                    SpaceOperation('newtuple', [v_resume, v_yielded_value],
                                   v_pair))
                newlink.args = [v_pair]
                newlink.target = graph.returnblock
    #
    regular_entry_block = Block([Variable('entry')])
    block = regular_entry_block
    for Resume in mappings:
        v_check = Variable()
        block.operations.append(
            SpaceOperation(
                'simple_call',
                [Constant(isinstance), block.inputargs[0],
                 Constant(Resume)], v_check))
        block.exitswitch = v_check
        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)