Пример #1
0
def inputconst(reqtype, value):
    """Return a Constant with the given value, of the requested type,
    which can be a Repr instance or a low-level type.
    """
    if isinstance(reqtype, Repr):
        value = reqtype.convert_const(value)
        lltype = reqtype.lowleveltype
    elif isinstance(reqtype, LowLevelType):
        lltype = reqtype
    else:
        raise TypeError(repr(reqtype))
    # Void Constants can hold any value;
    # non-Void Constants must hold a correctly ll-typed value
    if lltype is not Void:
        try:
            realtype = typeOf(value)
        except (AssertionError, AttributeError):
            realtype = '???'
        if not isCompatibleType(realtype, lltype):
            raise TyperError("inputconst(reqtype = %s, value = %s):\n"
                             "expected a %r,\n"
                             "     got a %r" % (reqtype, value,
                                                lltype, realtype))
    c = Constant(value)
    c.concretetype = lltype
    return c
Пример #2
0
def test_func_simple():
    # -------------------- flowgraph building --------------------
    #     def f(x):
    #         return x+1
    x = Variable("x")
    x.concretetype = Signed
    result = Variable("result")
    result.concretetype = Signed
    one = Constant(1)
    one.concretetype = Signed
    op = SpaceOperation("int_add", [x, one], result)
    block = Block([x])
    graph = FunctionGraph("f", block)
    block.operations.append(op)
    block.closeblock(Link([result], graph.returnblock))
    graph.getreturnvar().concretetype = Signed
    # --------------------         end        --------------------

    F = FuncType([Signed], Signed)
    f = functionptr(F, "f", graph=graph)
    db = LowLevelDatabase()
    db.get(f)
    db.complete()
    dump_on_stdout(db)

    S = GcStruct('testing', ('fptr', Ptr(F)))
    s = malloc(S)
    s.fptr = f
    db = LowLevelDatabase()
    db.get(s)
    db.complete()
    dump_on_stdout(db)
Пример #3
0
 def flatten(self, S):
     start = 0
     if S._names and self.equivalent_substruct(S, S._names[0]):
         SUBTYPE = S._flds[S._names[0]]
         if isinstance(SUBTYPE, lltype.Struct):
             self.flatten(SUBTYPE)
             start = 1
         else:
             ARRAY = lltype.FixedSizeArray(SUBTYPE, 1)
             self.direct_fieldptr_key[ARRAY, 'item0'] = S, S._names[0]
     for name in S._names[start:]:
         key = S, name
         FIELDTYPE = S._flds[name]
         if key in self.accessed_substructs:
             self.needsubmallocs.append(key)
             self.flatnames.append(key)
             self.newvarstype[key] = lltype.Ptr(lltype.GcStruct('wrapper',
                                                       ('data', FIELDTYPE)))
         elif not isinstance(FIELDTYPE, lltype.ContainerType):
             example = FIELDTYPE._defl()
             constant = Constant(example)
             constant.concretetype = FIELDTYPE
             self.flatconstants[key] = constant
             self.flatnames.append(key)
             self.newvarstype[key] = FIELDTYPE
Пример #4
0
 def make_const_rt_result(self, v_result, value):
     newrtnode = RuntimeSpecNode(v_result, v_result.concretetype)
     self.setnode(v_result, newrtnode)
     if v_result.concretetype is not lltype.Void:
         assert v_result.concretetype == lltype.typeOf(value)
     c_value = Constant(value)
     c_value.concretetype = v_result.concretetype
     self.renamings[newrtnode] = c_value
Пример #5
0
def replace_we_are_jitted(graph):
    from rpython.rlib import jit

    replacement = Constant(0)
    replacement.concretetype = lltype.Signed
    did_replacement = replace_symbolic(graph, jit._we_are_jitted, replacement)
    if did_replacement:
        constant_fold_graph(graph)
    return did_replacement
Пример #6
0
def inputdesc(reqtype, desc):
    """Return a Constant for the given desc, of the requested type,
    which can only be a Repr.
    """
    assert isinstance(reqtype, Repr)
    value = reqtype.convert_desc(desc)
    lltype = reqtype.lowleveltype
    c = Constant(value)
    c.concretetype = lltype
    return c
Пример #7
0
 def handle_op_malloc(self, op):
     if op.result is self.v_expand_malloc:
         MALLOCTYPE = op.result.concretetype.TO
         typedesc = self.graphbuilder.mallocv.getmalloctypedesc(MALLOCTYPE)
         virtualnode = VirtualSpecNode(typedesc, [])
         self.setnode(op.result, virtualnode)
         for name, FIELDTYPE in typedesc.names_and_types:
             fieldnode = RuntimeSpecNode(name, FIELDTYPE)
             virtualnode.fields.append(fieldnode)
             c = Constant(FIELDTYPE._defl())
             c.concretetype = FIELDTYPE
             self.renamings[fieldnode] = c
         self.v_expand_malloc = None      # done
         return []
     else:
         return self.handle_default(op)
Пример #8
0
def inputconst(reqtype, value):
    """Return a Constant with the given value, of the requested type,
    which can be a Repr instance or a low-level type.
    """
    if isinstance(reqtype, Repr):
        value = reqtype.convert_const(value)
        lltype = reqtype.lowleveltype
    elif isinstance(reqtype, LowLevelType):
        lltype = reqtype
    else:
        raise TypeError(repr(reqtype))
    if not lltype._contains_value(value):
        raise TyperError("inputconst(): expected a %r, got %r" %
                         (lltype, value))
    c = Constant(value)
    c.concretetype = lltype
    return c
Пример #9
0
 def get_exc_reconstruction_block(self, typedesc):
     exceptblock = self.graph.exceptblock
     self.mallocv.fixup_except_block(exceptblock)
     TEXC = exceptblock.inputargs[0].concretetype
     TVAL = exceptblock.inputargs[1].concretetype
     #
     v_ignored_type = varoftype(TEXC)
     v_incoming_value = varoftype(TVAL)
     block = Block([v_ignored_type, v_incoming_value])
     #
     c_EXCTYPE = Constant(typedesc.MALLOCTYPE, lltype.Void)
     v = varoftype(lltype.Ptr(typedesc.MALLOCTYPE))
     c_flavor = Constant({'flavor': 'gc'}, lltype.Void)
     op = SpaceOperation('malloc', [c_EXCTYPE, c_flavor], v)
     block.operations.append(op)
     #
     for name, FIELDTYPE in typedesc.names_and_types:
         EXACTPTR = lltype.Ptr(typedesc.name2subtype[name])
         c_name = Constant(name)
         c_name.concretetype = lltype.Void
         #
         v_in = varoftype(EXACTPTR)
         op = SpaceOperation('cast_pointer', [v_incoming_value], v_in)
         block.operations.append(op)
         #
         v_field = varoftype(FIELDTYPE)
         op = SpaceOperation('getfield', [v_in, c_name], v_field)
         block.operations.append(op)
         #
         v_out = varoftype(EXACTPTR)
         op = SpaceOperation('cast_pointer', [v], v_out)
         block.operations.append(op)
         #
         v0 = varoftype(lltype.Void)
         op = SpaceOperation('setfield', [v_out, c_name, v_field], v0)
         block.operations.append(op)
     #
     v_exc_value = varoftype(TVAL)
     op = SpaceOperation('cast_pointer', [v], v_exc_value)
     block.operations.append(op)
     #
     exc_type = self.mallocv.EXCTYPE_to_vtable[typedesc.MALLOCTYPE]
     c_exc_type = Constant(exc_type, TEXC)
     block.closeblock(Link([c_exc_type, v_exc_value], exceptblock))
     return block
Пример #10
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]))
Пример #11
0
        def make_closure(jd, fullfuncname, is_string):
            if jd is None:

                def closure(i):
                    if is_string:
                        i = hlstr(i)
                    for jd in self.jitdrivers_sd:
                        getattr(jd.warmstate, fullfuncname)(i)
            else:
                state = jd.warmstate

                def closure(i):
                    if is_string:
                        i = hlstr(i)
                    getattr(state, fullfuncname)(i)

            if is_string:
                TP = PTR_SET_PARAM_STR_FUNCTYPE
            else:
                TP = PTR_SET_PARAM_FUNCTYPE
            funcptr = self.helper_func(TP, closure)
            return Constant(funcptr, TP)
Пример #12
0
def transform_ovfcheck(graph):
    """The special function calls ovfcheck needs to
    be translated into primitive operations. ovfcheck is called directly
    after an operation that should be turned into an overflow-checked
    version. It is considered a syntax error if the resulting <op>_ovf
    is not defined in objspace/flow/objspace.py.
    """
    covf = Constant(rarithmetic.ovfcheck)

    for block in graph.iterblocks():
        for i in range(len(block.operations) - 1, -1, -1):
            op = block.operations[i]
            if op.opname != 'simple_call':
                continue
            if op.args[0] == covf:
                if i == 0:
                    # hard case: ovfcheck() on an operation that occurs
                    # in the previous block, like 'floordiv'.  The generic
                    # exception handling around the ovfcheck() is enough
                    # to cover all cases; kill the one around the previous op.
                    entrymap = mkentrymap(graph)
                    links = entrymap[block]
                    assert len(links) == 1
                    prevblock = links[0].prevblock
                    assert prevblock.exits[0].target is block
                    prevblock.exitswitch = None
                    prevblock.exits = (links[0], )
                    join_blocks(graph)  # merge the two blocks together
                    transform_ovfcheck(graph)  # ...and try again
                    return
                op1 = block.operations[i - 1]
                if not isinstance(op1, OverflowingOperation):
                    raise Exception("ovfcheck in %s: Operation %s has no "
                                    "overflow variant" %
                                    (graph.name, op1.opname))
                op1_ovf = op1.ovfchecked()
                block.operations[i - 1] = op1_ovf
                del block.operations[i]
                block.renamevariables({op.result: op1_ovf.result})
Пример #13
0
 def gct_fv_gc_malloc(self, hop, flags, TYPE, c_size):
     # XXX same behavior for zero=True: in theory that's wrong
     if TYPE._is_atomic():
         funcptr = self.malloc_fixedsize_atomic_ptr
         opname = 'boehm_malloc_atomic'
     else:
         funcptr = self.malloc_fixedsize_ptr
         opname = 'boehm_malloc'
     tr = self.translator
     if tr and tr.config.translation.reverse_debugger:
         # Don't check for NULLs after the operation (it crashes anyway
         # with an explicit error message in case of out-of-memory).
         # Avoiding a direct_call lets _RPY_REVDB_PRUID() prints the
         # right file/line, at least for fixed-size mallocs.
         v_raw = hop.genop(opname, [c_size], resulttype=llmemory.GCREF)
     else:
         v_raw = hop.genop("direct_call", [funcptr, c_size],
                           resulttype=llmemory.GCREF)
     finalizer_ptr = self.finalizer_funcptr_for_type(TYPE)
     if finalizer_ptr:
         c_finalizer_ptr = Constant(finalizer_ptr, self.FINALIZER_PTR)
         hop.genop("boehm_register_finalizer", [v_raw, c_finalizer_ptr])
     return v_raw
Пример #14
0
 def get_exc_reconstruction_block(self, typedesc):
     exceptblock = self.graph.exceptblock
     self.mallocv.fixup_except_block(exceptblock)
     TEXC = exceptblock.inputargs[0].concretetype
     TVAL = exceptblock.inputargs[1].concretetype
     #
     v_ignored_type = varoftype(TEXC)
     v_incoming_value = varoftype(TVAL)
     block = Block([v_ignored_type, v_incoming_value])
     #
     c_EXCTYPE = Constant(typedesc.MALLOCTYPE, lltype.Void)
     v = varoftype(lltype.Ptr(typedesc.MALLOCTYPE))
     c_flavor = Constant({'flavor': 'gc'}, lltype.Void)
     op = SpaceOperation('malloc', [c_EXCTYPE, c_flavor], v)
     block.operations.append(op)
     #
     for name, FIELDTYPE in typedesc.names_and_types:
         EXACTPTR = lltype.Ptr(typedesc.name2subtype[name])
         c_name = Constant(name)
         c_name.concretetype = lltype.Void
         #
         v_in = varoftype(EXACTPTR)
         op = SpaceOperation('cast_pointer', [v_incoming_value], v_in)
         block.operations.append(op)
         #
         v_field = varoftype(FIELDTYPE)
         op = SpaceOperation('getfield', [v_in, c_name], v_field)
         block.operations.append(op)
         #
         v_out = varoftype(EXACTPTR)
         op = SpaceOperation('cast_pointer', [v], v_out)
         block.operations.append(op)
         #
         v0 = varoftype(lltype.Void)
         op = SpaceOperation('setfield', [v_out, c_name, v_field], v0)
         block.operations.append(op)
     #
     v_exc_value = varoftype(TVAL)
     op = SpaceOperation('cast_pointer', [v], v_exc_value)
     block.operations.append(op)
     #
     exc_type = self.mallocv.EXCTYPE_to_vtable[typedesc.MALLOCTYPE]
     c_exc_type = Constant(exc_type, TEXC)
     block.closeblock(Link([c_exc_type, v_exc_value], exceptblock))
     return block
Пример #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
     """)
Пример #16
0
    def rewrite_access_helper(self, op):
        # make sure we make a copy of function so it no longer belongs
        # to extregistry
        func = op.args[1].value
        if func.func_name.startswith('stats_'):
            # get special treatment since we rewrite it to a call that accepts
            # jit driver
            assert len(op.args) >= 3, ("%r must have a first argument "
                                       "(which is None)" % (func, ))
            func = func_with_new_name(func, func.func_name + '_compiled')

            def new_func(ignored, *args):
                return func(self, *args)

            ARGS = [lltype.Void] + [arg.concretetype for arg in op.args[3:]]
        else:
            ARGS = [arg.concretetype for arg in op.args[2:]]
            new_func = func_with_new_name(func, func.func_name + '_compiled')
        RESULT = op.result.concretetype
        FUNCPTR = lltype.Ptr(lltype.FuncType(ARGS, RESULT))
        ptr = self.helper_func(FUNCPTR, new_func)
        op.opname = 'direct_call'
        op.args = [Constant(ptr, FUNCPTR)] + op.args[2:]
Пример #17
0
 def convert_const(self, weakdict):
     if weakdict is None:
         return lltype.nullptr(self.WEAKDICT)
     if not isinstance(weakdict, RWeakValueDictionary):
         raise TyperError("expected an RWeakValueDictionary: %r" %
                          (weakdict, ))
     try:
         key = Constant(weakdict)
         return self.dict_cache[key]
     except KeyError:
         self.setup()
         l_dict = self.ll_new_weakdict()
         self.dict_cache[key] = l_dict
         bk = self.rtyper.annotator.bookkeeper
         classdef = bk.getuniqueclassdef(weakdict._valueclass)
         r_value = getinstancerepr(self.rtyper, classdef)
         for dictkey, dictvalue in weakdict._dict.items():
             llkey = self.r_key.convert_const(dictkey)
             llvalue = r_value.convert_const(dictvalue)
             if llvalue:
                 llvalue = lltype.cast_pointer(rclass.OBJECTPTR, llvalue)
                 self.ll_set_nonnull(l_dict, llkey, llvalue)
         return l_dict
Пример #18
0
 def no_more_blocks_to_annotate(pol, annotator):
     bk = annotator.bookkeeper
     # hint to all pending specializers that we are done
     for callback in bk.pending_specializations:
         callback()
     del bk.pending_specializations[:]
     if annotator.added_blocks is not None:
         all_blocks = annotator.added_blocks
     else:
         all_blocks = annotator.annotated
     for block in list(all_blocks):
         for i, instr in enumerate(block.operations):
             if not isinstance(instr, (op.simple_call, op.call_args)):
                 continue
             v_func = instr.args[0]
             s_func = annotator.annotation(v_func)
             if not hasattr(s_func, 'needs_sandboxing'):
                 continue
             key = ('sandboxing', s_func.const)
             if key not in bk.emulated_pbc_calls:
                 params_s = s_func.args_s
                 s_result = s_func.s_result
                 from rpython.translator.sandbox.rsandbox import make_sandbox_trampoline
                 sandbox_trampoline = make_sandbox_trampoline(
                     s_func.name, params_s, s_result)
                 sandbox_trampoline._signature_ = [
                     SomeTuple(items=params_s)
                 ], s_result
                 bk.emulate_pbc_call(key,
                                     bk.immutablevalue(sandbox_trampoline),
                                     params_s)
             else:
                 s_trampoline = bk.emulated_pbc_calls[key][0]
                 sandbox_trampoline = s_trampoline.const
             new = instr.replace(
                 {instr.args[0]: Constant(sandbox_trampoline)})
             block.operations[i] = new
Пример #19
0
 def unformat_arg(s):
     if s.endswith(','):
         s = s[:-1].rstrip()
     if s[0] == '%':
         try:
             return registers[s]
         except KeyError:
             num = int(s[2:])
             if s[1] == 'i': reg = Register('int', num)
             elif s[1] == 'r': reg = Register('ref', num)
             elif s[1] == 'f': reg = Register('float', num)
             else: raise AssertionError("bad register type")
             registers[s] = reg
             return reg
     elif s[0] == '$':
         intvalue = int(s[1:])
         return Constant(intvalue, lltype.Signed)
     elif s[0] == 'L':
         return TLabel(s)
     elif s[0] in 'IRF' and s[1] == '[' and s[-1] == ']':
         items = split_words(s[2:-1])
         items = map(unformat_arg, items)
         return ListOfKind({'I': 'int', 'R': 'ref', 'F': 'float'}[s[0]],
                           items)
     elif s.startswith('<SwitchDictDescr '):
         assert s.endswith('>')
         switchdict = SwitchDictDescr()
         switchdict._labels = []
         items = split_words(s[len('<SwitchDictDescr '):-1])
         for item in items:
             key, value = item.split(':')
             value = value.rstrip(',')
             switchdict._labels.append((int(key), TLabel(value)))
         return switchdict
     else:
         raise AssertionError("unsupported argument: %r" % (s,))
Пример #20
0
 def new_instance(self, llops, classcallhop=None):
     """Build a new instance, without calling __init__."""
     flavor = self.gcflavor
     flags = {'flavor': flavor}
     ctype = inputconst(Void, self.object_type)
     cflags = inputconst(Void, flags)
     vlist = [ctype, cflags]
     cnonmovable = self.classdef.classdesc.read_attribute(
         '_alloc_nonmovable_', Constant(False))
     if cnonmovable.value:
         opname = 'malloc_nonmovable'
     else:
         opname = 'malloc'
     vptr = llops.genop(opname, vlist, resulttype=Ptr(self.object_type))
     ctypeptr = inputconst(CLASSTYPE, self.rclass.getvtable())
     self.setfield(vptr, '__class__', ctypeptr, llops)
     # initialize instance attributes from their defaults from the class
     if self.classdef is not None:
         flds = self.allinstancefields.keys()
         flds.sort()
         for fldname in flds:
             if fldname == '__class__':
                 continue
             mangled_name, r = self.allinstancefields[fldname]
             if r.lowleveltype is Void:
                 continue
             value = self.classdef.classdesc.read_attribute(fldname, None)
             if value is not None:
                 cvalue = inputconst(r.lowleveltype,
                                     r.convert_desc_or_const(value))
                 self.setfield(vptr,
                               fldname,
                               cvalue,
                               llops,
                               flags={'access_directly': True})
     return vptr
Пример #21
0
    def collect_var_and_types(self):
        #
        # collect all variables and constants used in the body,
        # and get their types now
        #
        # NOTE: cannot use dictionaries with Constants as keys, because
        #       Constants may hash and compare equal but have different lltypes
        self.all_cached_consts = None  # will be filled after implementation_end
        mix = [self.graph.getreturnvar()]
        self.more_ll_values = []
        for block in self.graph.iterblocks():
            mix.extend(block.inputargs)
            for op in block.operations:
                mix.extend(op.args)
                mix.append(op.result)
            for link in block.exits:
                mix.extend(link.getextravars())
                mix.extend(link.args)
                if hasattr(link, 'llexitcase'):
                    self.more_ll_values.append(link.llexitcase)
                elif link.exitcase is not None:
                    mix.append(Constant(link.exitcase))
        if self.exception_policy == "CPython":
            v, exc_cleanup_ops = self.graph.exc_cleanup
            mix.append(v)
            for cleanupop in exc_cleanup_ops:
                mix.extend(cleanupop.args)
                mix.append(cleanupop.result)

        uniquemix = []
        seen = identity_dict()
        for v in mix:
            if v not in seen:
                uniquemix.append(v)
                seen[v] = True
        self.vars = uniquemix
Пример #22
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 = copiedexceptblock.inputargs[0].copy()
            evalue = copiedexceptblock.inputargs[1].copy()
            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]))
Пример #23
0
def test_guess_call_kind_and_calls_from_graphs():
    class portal_runner_obj:
        graph = object()

    class FakeJitDriverSD:
        portal_runner_ptr = portal_runner_obj

    g = object()
    g1 = object()
    cc = CallControl(jitdrivers_sd=[FakeJitDriverSD()])
    cc.candidate_graphs = [g, g1]

    op = SpaceOperation('direct_call', [Constant(portal_runner_obj)],
                        Variable())
    assert cc.guess_call_kind(op) == 'recursive'

    class fakeresidual:
        _obj = object()

    op = SpaceOperation('direct_call', [Constant(fakeresidual)], Variable())
    assert cc.guess_call_kind(op) == 'residual'

    class funcptr:
        class _obj:
            class graph:
                class func:
                    oopspec = "spec"

    op = SpaceOperation('direct_call', [Constant(funcptr)], Variable())
    assert cc.guess_call_kind(op) == 'builtin'

    class funcptr:
        class _obj:
            graph = g

    op = SpaceOperation('direct_call', [Constant(funcptr)], Variable())
    res = cc.graphs_from(op)
    assert res == [g]
    assert cc.guess_call_kind(op) == 'regular'

    class funcptr:
        class _obj:
            graph = object()

    op = SpaceOperation('direct_call', [Constant(funcptr)], Variable())
    res = cc.graphs_from(op)
    assert res is None
    assert cc.guess_call_kind(op) == 'residual'

    h = object()
    op = SpaceOperation('indirect_call',
                        [Variable(), Constant([g, g1, h])], Variable())
    res = cc.graphs_from(op)
    assert res == [g, g1]
    assert cc.guess_call_kind(op) == 'regular'

    op = SpaceOperation('indirect_call',
                        [Variable(), Constant([h])], Variable())
    res = cc.graphs_from(op)
    assert res is None
    assert cc.guess_call_kind(op) == 'residual'
Пример #24
0
 def constant_func(self, name, inputtypes, rettype, graph, **kwds):
     FUNC_TYPE = lltype.FuncType(inputtypes, rettype)
     fn_ptr = lltype.functionptr(FUNC_TYPE, name, graph=graph, **kwds)
     return Constant(fn_ptr, lltype.Ptr(FUNC_TYPE))
Пример #25
0
def constant_value(llvalue):
    return Constant(llvalue, lltype.typeOf(llvalue))
Пример #26
0
def sc_we_are_translated(ctx):
    return Constant(True)
Пример #27
0
def error_constant(T):
    return Constant(error_value(T), T)
Пример #28
0
 def specialize_call(self, hop):
     hop.exception_cannot_occur()
     retval = Constant(hop.r_result.convert_const(hop.args_v[0].value))
     retval.concretetype = hop.r_result.lowleveltype
     return retval
Пример #29
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
Пример #30
0
 def getname_w(self, index):
     return Constant(self.pycode.names[index])
Пример #31
0
class __extend__(pairtype(MultipleFrozenPBCRepr, FunctionRepr)):
    def convert_from_to((r_frozen1, r_fn2), v, llops):
        if r_fn2.lowleveltype is Void:
            value = r_fn2.s_pbc.const
            return Constant(value, Void)
        return NotImplemented
Пример #32
0
def adjust_shape(hop2, s_shape):
    new_shape = (s_shape.const[0] + 1, ) + s_shape.const[1:]
    c_shape = Constant(new_shape)
    s_shape = hop2.rtyper.annotator.bookkeeper.immutablevalue(new_shape)
    hop2.v_s_insertfirstarg(c_shape, s_shape)  # reinsert adjusted shape
Пример #33
0
 def inittime_helper(self, ll_helper, ll_args, ll_result, inline=True):
     ptr = self.annotate_helper(ll_helper, ll_args, ll_result, inline=inline)
     return Constant(ptr, lltype.typeOf(ptr))
Пример #34
0
 def flowin_op(self, op, vars, newvarsmap):
     if op.opname in ("getfield", "getarrayitem"):
         S = op.args[0].concretetype.TO
         fldname = op.args[1].value
         key = self.key_for_field_access(S, fldname)
         if key not in newvarsmap:
             newop = self.handle_unreachable(op.result)
         elif key in self.accessed_substructs:
             c_name = Constant('data', lltype.Void)
             newop = SpaceOperation("getfield",
                                    [newvarsmap[key], c_name],
                                    op.result)
         else:
             newop = SpaceOperation("same_as",
                                    [newvarsmap[key]],
                                    op.result)
         self.newops.append(newop)
     elif op.opname in ("setfield", "setarrayitem"):
         S = op.args[0].concretetype.TO
         fldname = op.args[1].value
         key = self.key_for_field_access(S, fldname)
         if key not in newvarsmap:
             newop = self.handle_unreachable(op.result)
             self.newops.append(newop)
         elif key in self.accessed_substructs:
             c_name = Constant('data', lltype.Void)
             newop = SpaceOperation("setfield",
                              [newvarsmap[key], c_name, op.args[2]],
                                        op.result)
             self.newops.append(newop)
         else:
             newvarsmap[key] = op.args[2]
     elif op.opname in ("same_as", "cast_pointer"):
         vars.add(op.result)
         # Consider the two pointers (input and result) as
         # equivalent.  We can, and indeed must, use the same
         # flattened list of variables for both, as a "setfield"
         # via one pointer must be reflected in the other.
     elif op.opname in ("getsubstruct", "getarraysubstruct",
                        "direct_fieldptr"):
         S = op.args[0].concretetype.TO
         fldname = op.args[1].value
         if op.opname == "getarraysubstruct":
             fldname = 'item%d' % fldname
         equiv = self.equivalent_substruct(S, fldname)
         if equiv:
             # exactly like a cast_pointer
             assert op.result not in vars
             vars.add(op.result)
         else:
             # do it with a getsubstruct on the independently
             # malloc'ed GcStruct
             if op.opname == "direct_fieldptr":
                 opname = "direct_fieldptr"
             else:
                 opname = "getsubstruct"
             try:
                 v = newvarsmap[S, fldname]
             except KeyError:
                 newop = self.handle_unreachable(op.result)
             else:
                 cname = Constant('data', lltype.Void)
                 newop = SpaceOperation(opname,
                                        [v, cname],
                                        op.result)
             self.newops.append(newop)
     elif op.opname in ("ptr_iszero", "ptr_nonzero"):
         # we know the pointer is not NULL if it comes from
         # a successful malloc
         c = Constant(op.opname == "ptr_nonzero", lltype.Bool)
         newop = SpaceOperation('same_as', [c], op.result)
         self.newops.append(newop)
     else:
         raise AssertionError(op.opname)
Пример #35
0
 def recreate_malloc(self, c, v):
     return SpaceOperation(self.MALLOC_OP, [c,
                                            Constant({'flavor': 'gc'},
                                                     lltype.Void)],
                           v)
Пример #36
0
 def insert_exits(self, block):
     if len(block.exits) == 1:
         # A single link, fall-through
         link = block.exits[0]
         assert link.exitcase in (None, False, True)
         # the cases False or True should not really occur, but can show
         # up in the manually hacked graphs for generators...
         self.make_link(link)
     #
     elif block.exitswitch is c_last_exception:
         # An exception block. See test_exc_exitswitch in test_flatten.py
         # for an example of what kind of code this makes.
         index = -1
         while True:
             lastopname = block.operations[index].opname
             if lastopname != '-live-':
                 break
             index -= 1
         assert block.exits[0].exitcase is None  # is this always True?
         #
         if not self._include_all_exc_links:
             if index == -1:
                 # cannot raise: the last instruction is not
                 # actually a '-live-'
                 self.make_link(block.exits[0])
                 return
         #
         self.emitline('catch_exception', TLabel(block.exits[0]))
         self.make_link(block.exits[0])
         self.emitline(Label(block.exits[0]))
         for link in block.exits[1:]:
             if (link.exitcase is Exception
                     or (link.exitcase is OverflowError
                         and lastopname.startswith('int_')
                         and lastopname.endswith('_ovf'))):
                 # this link captures all exceptions
                 self.make_exception_link(link)
                 break
             self.emitline(
                 'goto_if_exception_mismatch',
                 Constant(link.llexitcase, lltype.typeOf(link.llexitcase)),
                 TLabel(link))
             self.make_exception_link(link)
             self.emitline(Label(link))
         else:
             # no link captures all exceptions, so we have to put a reraise
             # for the other exceptions
             self.emitline("reraise")
             self.emitline("---")
     #
     elif len(block.exits) == 2 and (isinstance(block.exitswitch, tuple)
                                     or block.exitswitch.concretetype
                                     == lltype.Bool):
         # Two exit links with a boolean condition
         linkfalse, linktrue = block.exits
         if linkfalse.llexitcase == True:
             linkfalse, linktrue = linktrue, linkfalse
         opname = 'goto_if_not'
         livebefore = False
         if isinstance(block.exitswitch, tuple):
             # special case produced by jtransform.optimize_goto_if_not()
             opname = 'goto_if_not_' + block.exitswitch[0]
             opargs = block.exitswitch[1:]
             if opargs[-1] == '-live-before':
                 livebefore = True
                 opargs = opargs[:-1]
         else:
             assert block.exitswitch.concretetype == lltype.Bool
             opargs = [block.exitswitch]
         #
         lst = self.flatten_list(opargs) + [TLabel(linkfalse)]
         if livebefore:
             self.emitline('-live-')
         self.emitline(opname, *lst)
         if not livebefore:
             self.emitline('-live-', TLabel(linkfalse))
         # true path:
         self.make_link(linktrue)
         # false path:
         self.emitline(Label(linkfalse))
         self.make_link(linkfalse)
     #
     else:
         # A switch.
         #
         switches = [
             link for link in block.exits if link.exitcase != 'default'
         ]
         switches.sort(key=lambda link: link.llexitcase)
         kind = getkind(block.exitswitch.concretetype)
         assert kind == 'int'  # XXX
         #
         # A switch on an integer, implementable efficiently with the
         # help of a SwitchDictDescr.  We use this even if there are
         # very few cases: in pyjitpl.py, opimpl_switch() will promote
         # the int only if it matches one of the cases.
         from rpython.jit.codewriter.jitcode import SwitchDictDescr
         switchdict = SwitchDictDescr()
         switchdict._labels = []
         self.emitline('-live-')  # for 'guard_value'
         self.emitline('switch', self.getcolor(block.exitswitch),
                       switchdict)
         # emit the default path
         if block.exits[-1].exitcase == 'default':
             self.make_link(block.exits[-1])
         else:
             self.emitline("unreachable")
             self.emitline("---")
         #
         for switch in switches:
             key = lltype.cast_primitive(lltype.Signed, switch.llexitcase)
             switchdict._labels.append((key, TLabel(switch)))
             # emit code for that path
             # note: we need a -live- for all the 'guard_false' we produce
             # if the switched value doesn't match any case.
             self.emitline(Label(switch))
             self.emitline('-live-')
             self.make_link(switch)
Пример #37
0
 def handle_unreachable(self, v_result):
     from rpython.rtyper.lltypesystem.rstr import string_repr
     msg = "unreachable operation (from malloc.py)"
     ll_msg = string_repr.convert_const(msg)
     c_msg = Constant(ll_msg, lltype.typeOf(ll_msg))
     return SpaceOperation("debug_fatalerror", [c_msg], v_result)
Пример #38
0
                bhcaller._setup_return_value_r(result)
            elif result_kind == 'float':
                bhcaller._setup_return_value_f(result)
            else:
                assert False

        jd.handle_jitexc_from_bh = handle_jitexception_from_blackhole

        # ____________________________________________________________
        # Now mutate origportalgraph to end with a call to portal_runner_ptr
        #
        origblock, origindex, op = locate_jit_merge_point(origportalgraph)
        assert op.opname == 'jit_marker'
        assert op.args[0].value == 'jit_merge_point'
        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)
Пример #39
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)
Пример #40
0
 def immutablevalue(self, x):
     """The most precise SomeValue instance that contains the
     immutable value x."""
     # convert unbound methods to the underlying function
     if hasattr(x, 'im_self') and x.im_self is None:
         x = x.im_func
         assert not hasattr(x, 'im_self')
     tp = type(x)
     if issubclass(tp, Symbolic):  # symbolic constants support
         result = x.annotation()
         result.const_box = Constant(x)
         return result
     if tp is bool:
         result = SomeBool()
     elif tp is int:
         result = SomeInteger(nonneg=x >= 0)
     elif tp is long:
         if -sys.maxint - 1 <= x <= sys.maxint:
             x = int(x)
             result = SomeInteger(nonneg=x >= 0)
         else:
             raise Exception("seeing a prebuilt long (value %s)" % hex(x))
     elif issubclass(tp, str):  # py.lib uses annotated str subclasses
         no_nul = not '\x00' in x
         if len(x) == 1:
             result = SomeChar(no_nul=no_nul)
         else:
             result = SomeString(no_nul=no_nul)
     elif tp is unicode:
         if len(x) == 1:
             result = SomeUnicodeCodePoint()
         else:
             result = SomeUnicodeString()
     elif tp is bytearray:
         result = SomeByteArray()
     elif tp is tuple:
         result = SomeTuple(items=[self.immutablevalue(e) for e in x])
     elif tp is float:
         result = SomeFloat()
     elif tp is list:
         key = Constant(x)
         try:
             return self.immutable_cache[key]
         except KeyError:
             result = SomeList(ListDef(self, s_ImpossibleValue))
             self.immutable_cache[key] = result
             for e in x:
                 result.listdef.generalize(self.immutablevalue(e))
             result.const_box = key
             return result
     elif (tp is dict or tp is r_dict or tp is SomeOrderedDict.knowntype
           or tp is r_ordereddict):
         key = Constant(x)
         try:
             return self.immutable_cache[key]
         except KeyError:
             if tp is SomeOrderedDict.knowntype or tp is r_ordereddict:
                 cls = SomeOrderedDict
             else:
                 cls = SomeDict
             is_r_dict = issubclass(tp, r_dict)
             result = cls(
                 DictDef(self,
                         s_ImpossibleValue,
                         s_ImpossibleValue,
                         is_r_dict=is_r_dict))
             self.immutable_cache[key] = result
             if is_r_dict:
                 s_eqfn = self.immutablevalue(x.key_eq)
                 s_hashfn = self.immutablevalue(x.key_hash)
                 result.dictdef.dictkey.update_rdict_annotations(
                     s_eqfn, s_hashfn)
             seen_elements = 0
             while seen_elements != len(x):
                 items = x.items()
                 for ek, ev in items:
                     result.dictdef.generalize_key(self.immutablevalue(ek))
                     result.dictdef.generalize_value(
                         self.immutablevalue(ev))
                     result.dictdef.seen_prebuilt_key(ek)
                 seen_elements = len(items)
                 # if the dictionary grew during the iteration,
                 # start over again
             result.const_box = key
             return result
     elif tp is weakref.ReferenceType:
         x1 = x()
         if x1 is None:
             result = SomeWeakRef(None)  # dead weakref
         else:
             s1 = self.immutablevalue(x1)
             assert isinstance(s1, SomeInstance)
             result = SomeWeakRef(s1.classdef)
     elif tp is property:
         return SomeProperty(x)
     elif ishashable(x) and x in BUILTIN_ANALYZERS:
         _module = getattr(x, "__module__", "unknown")
         result = SomeBuiltin(BUILTIN_ANALYZERS[x],
                              methodname="%s.%s" % (_module, x.__name__))
     elif extregistry.is_registered(x):
         entry = extregistry.lookup(x)
         result = entry.compute_annotation_bk(self)
     elif tp is type:
         result = SomeConstantType(x, self)
     elif callable(x):
         if hasattr(x, 'im_self') and hasattr(x, 'im_func'):
             # on top of PyPy, for cases like 'l.append' where 'l' is a
             # global constant list, the find_method() returns non-None
             s_self = self.immutablevalue(x.im_self)
             result = s_self.find_method(x.im_func.__name__)
         elif hasattr(x, '__self__') and x.__self__ is not None:
             # for cases like 'l.append' where 'l' is a global constant list
             s_self = self.immutablevalue(x.__self__)
             result = s_self.find_method(x.__name__)
             assert result is not None
         else:
             result = None
         if result is None:
             result = SomePBC([self.getdesc(x)])
     elif hasattr(x, '_freeze_'):
         assert x._freeze_() is True
         # user-defined classes can define a method _freeze_(), which
         # is called when a prebuilt instance is found.  If the method
         # returns True, the instance is considered immutable and becomes
         # a SomePBC().  Otherwise it's just SomeInstance().
         result = SomePBC([self.getdesc(x)])
     elif hasattr(x, '__class__') \
              and x.__class__.__module__ != '__builtin__':
         if hasattr(x, '_cleanup_'):
             x._cleanup_()
         self.see_mutable(x)
         result = SomeInstance(self.getuniqueclassdef(x.__class__))
     elif x is None:
         return s_None
     else:
         raise Exception("Don't know how to represent %r" % (x, ))
     result.const = x
     return result