Ejemplo n.º 1
0
def getfunctionptr(graph, getconcretetype=None):
    """Return callable given a Python function."""
    if getconcretetype is None:
        getconcretetype = _getconcretetype
    llinputs = [getconcretetype(v) for v in graph.getargs()]
    lloutput = getconcretetype(graph.getreturnvar())

    FT = lltype.FuncType(llinputs, lloutput)
    name = graph.name
    if hasattr(graph, 'func') and callable(graph.func):
        # the Python function object can have _llfnobjattrs_, specifying
        # attributes that are forced upon the functionptr().  The idea
        # for not passing these extra attributes as arguments to
        # getcallable() itself is that multiple calls to getcallable()
        # for the same graph should return equal functionptr() objects.
        if hasattr(graph.func, '_llfnobjattrs_'):
            fnobjattrs = graph.func._llfnobjattrs_.copy()
            # can specify a '_name', but use graph.name by default
            name = fnobjattrs.pop('_name', name)
        else:
            fnobjattrs = {}
        # _callable is normally graph.func, but can be overridden:
        # see fakeimpl in extfunc.py
        _callable = fnobjattrs.pop('_callable', graph.func)
        return lltype.functionptr(FT, name, graph = graph,
                                  _callable = _callable, **fnobjattrs)
    else:
        return lltype.functionptr(FT, name, graph = graph)
Ejemplo n.º 2
0
def getfunctionptr(graph, getconcretetype=None):
    """Return callable given a Python function."""
    if getconcretetype is None:
        getconcretetype = _getconcretetype
    llinputs = [getconcretetype(v) for v in graph.getargs()]
    lloutput = getconcretetype(graph.getreturnvar())

    FT = lltype.FuncType(llinputs, lloutput)
    name = graph.name
    if hasattr(graph, 'func') and callable(graph.func):
        # the Python function object can have _llfnobjattrs_, specifying
        # attributes that are forced upon the functionptr().  The idea
        # for not passing these extra attributes as arguments to
        # getcallable() itself is that multiple calls to getcallable()
        # for the same graph should return equal functionptr() objects.
        if hasattr(graph.func, '_llfnobjattrs_'):
            fnobjattrs = graph.func._llfnobjattrs_.copy()
            # can specify a '_name', but use graph.name by default
            name = fnobjattrs.pop('_name', name)
        else:
            fnobjattrs = {}
        # _callable is normally graph.func, but can be overridden:
        # see fakeimpl in extfunc.py
        _callable = fnobjattrs.pop('_callable', graph.func)
        return lltype.functionptr(FT,
                                  name,
                                  graph=graph,
                                  _callable=_callable,
                                  **fnobjattrs)
    else:
        return lltype.functionptr(FT, name, graph=graph)
Ejemplo n.º 3
0
def test_caching_dynamic_deallocator():
    S = lltype.GcStruct("S", ('x', lltype.Signed), rtti=True)
    S1 = lltype.GcStruct("S1", ('s', S), ('y', lltype.Signed), rtti=True)
    T = lltype.GcStruct("T", ('x', lltype.Signed), rtti=True)

    def f_S(s):
        s.x = 1

    def f_S1(s1):
        s1.s.x = 1
        s1.y = 2

    def f_T(s):
        s.x = 1

    def type_info_S(p):
        return lltype.getRuntimeTypeInfo(S)

    def type_info_T(p):
        return lltype.getRuntimeTypeInfo(T)

    qp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
                                            lltype.Ptr(
                                                lltype.RuntimeTypeInfo)),
                            "type_info_S",
                            _callable=type_info_S)
    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)], lltype.Void),
                            "destructor_funcptr",
                            _callable=f_S)
    pinf = lltype.attachRuntimeTypeInfo(S, qp, destrptr=dp)
    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)], lltype.Void),
                            "destructor_funcptr",
                            _callable=f_S1)
    pinf = lltype.attachRuntimeTypeInfo(S1, qp, destrptr=dp)
    qp = lltype.functionptr(lltype.FuncType([lltype.Ptr(T)],
                                            lltype.Ptr(
                                                lltype.RuntimeTypeInfo)),
                            "type_info_S",
                            _callable=type_info_T)
    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(T)], lltype.Void),
                            "destructor_funcptr",
                            _callable=f_T)
    pinf = lltype.attachRuntimeTypeInfo(T, qp, destrptr=dp)

    def f():
        pass

    t = TranslationContext()
    t.buildannotator().build_types(f, [])
    t.buildrtyper().specialize()
    transformer = RefcountingGCTransformer(t)
    p_S = transformer.dynamic_deallocation_funcptr_for_type(S)
    p_S1 = transformer.dynamic_deallocation_funcptr_for_type(S1)
    p_T = transformer.dynamic_deallocation_funcptr_for_type(T)
    assert p_S is not p_T
    assert p_S is p_S1
Ejemplo n.º 4
0
def test_caching_dynamic_deallocator():
    S = lltype.GcStruct("S", ('x', lltype.Signed), rtti=True)
    S1 = lltype.GcStruct("S1", ('s', S), ('y', lltype.Signed), rtti=True)
    T = lltype.GcStruct("T", ('x', lltype.Signed), rtti=True)
    def f_S(s):
        s.x = 1
    def f_S1(s1):
        s1.s.x = 1
        s1.y = 2
    def f_T(s):
        s.x = 1
    def type_info_S(p):
        return lltype.getRuntimeTypeInfo(S)
    def type_info_T(p):
        return lltype.getRuntimeTypeInfo(T)
    qp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
                                            lltype.Ptr(lltype.RuntimeTypeInfo)),
                            "type_info_S",
                            _callable=type_info_S)
    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
                                            lltype.Void),
                            "destructor_funcptr",
                            _callable=f_S)
    pinf = lltype.attachRuntimeTypeInfo(S, qp, destrptr=dp)
    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
                                            lltype.Void),
                            "destructor_funcptr",
                            _callable=f_S1)
    pinf = lltype.attachRuntimeTypeInfo(S1, qp, destrptr=dp)
    qp = lltype.functionptr(lltype.FuncType([lltype.Ptr(T)],
                                            lltype.Ptr(lltype.RuntimeTypeInfo)),
                            "type_info_S",
                            _callable=type_info_T)
    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(T)],
                                            lltype.Void),
                            "destructor_funcptr",
                            _callable=f_T)
    pinf = lltype.attachRuntimeTypeInfo(T, qp, destrptr=dp)
    def f():
        pass
    t = TranslationContext()
    t.buildannotator().build_types(f, [])
    t.buildrtyper().specialize()
    transformer = RefcountingGCTransformer(t)
    p_S = transformer.dynamic_deallocation_funcptr_for_type(S)
    p_S1 = transformer.dynamic_deallocation_funcptr_for_type(S1)
    p_T = transformer.dynamic_deallocation_funcptr_for_type(T)
    assert p_S is not p_T
    assert p_S is p_S1
Ejemplo n.º 5
0
 def _setup_repr_final(self):
     AbstractInstanceRepr._setup_repr_final(self)
     if self.gcflavor == 'gc':
         if (self.classdef is not None
                 and self.classdef.classdesc.lookup('__del__') is not None):
             s_func = self.classdef.classdesc.s_read_attribute('__del__')
             source_desc = self.classdef.classdesc.lookup('__del__')
             source_classdef = source_desc.getclassdef(None)
             source_repr = getinstancerepr(self.rtyper, source_classdef)
             assert len(s_func.descriptions) == 1
             funcdesc, = s_func.descriptions
             graph = funcdesc.getuniquegraph()
             self.check_graph_of_del_does_not_call_too_much(graph)
             FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
             destrptr = functionptr(FUNCTYPE,
                                    graph.name,
                                    graph=graph,
                                    _callable=graph.func)
         else:
             destrptr = None
         OBJECT = OBJECT_BY_FLAVOR[LLFLAVOR[self.gcflavor]]
         self.rtyper.attachRuntimeTypeInfoFunc(self.object_type,
                                               ll_runtime_type_info, OBJECT,
                                               destrptr)
         vtable = self.rclass.getvtable()
         self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO)
Ejemplo n.º 6
0
Archivo: rclass.py Proyecto: sota/pypy
 def _setup_repr_final(self):
     AbstractInstanceRepr._setup_repr_final(self)
     if self.gcflavor == 'gc':
         if (self.classdef is not None and
             self.classdef.classdesc.lookup('__del__') is not None):
             s_func = self.classdef.classdesc.s_read_attribute('__del__')
             source_desc = self.classdef.classdesc.lookup('__del__')
             source_classdef = source_desc.getclassdef(None)
             source_repr = getinstancerepr(self.rtyper, source_classdef)
             assert len(s_func.descriptions) == 1
             funcdesc, = s_func.descriptions
             graph = funcdesc.getuniquegraph()
             self.check_graph_of_del_does_not_call_too_much(graph)
             FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
             destrptr = functionptr(FUNCTYPE, graph.name,
                                    graph=graph,
                                    _callable=graph.func)
         else:
             destrptr = None
         OBJECT = OBJECT_BY_FLAVOR[LLFLAVOR[self.gcflavor]]
         self.rtyper.attachRuntimeTypeInfoFunc(self.object_type,
                                               ll_runtime_type_info,
                                               OBJECT, destrptr)
         vtable = self.rclass.getvtable()
         self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO)
Ejemplo n.º 7
0
    def _setup_repr_final(self):
        self._setup_immutable_field_list()
        self._check_for_immutable_conflicts()
        if self.gcflavor == 'gc':
            if (self.classdef is not None
                    and self.classdef.classdesc.lookup('__del__') is not None):
                s_func = self.classdef.classdesc.s_read_attribute('__del__')
                source_desc = self.classdef.classdesc.lookup('__del__')
                source_classdef = source_desc.getclassdef(None)
                source_repr = getinstancerepr(self.rtyper, source_classdef)
                assert len(s_func.descriptions) == 1
                funcdesc, = s_func.descriptions
                graph = funcdesc.getuniquegraph()
                self.check_graph_of_del_does_not_call_too_much(
                    self.rtyper, graph)
                FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
                destrptr = functionptr(FUNCTYPE,
                                       graph.name,
                                       graph=graph,
                                       _callable=graph.func)
            else:
                destrptr = None
            self.rtyper.call_all_setups()  # compute ForwardReferences now
            args_s = [SomePtr(Ptr(OBJECT))]
            graph = self.rtyper.annotate_helper(ll_runtime_type_info, args_s)
            s = self.rtyper.annotation(graph.getreturnvar())
            if (not isinstance(s, SomePtr)
                    or s.ll_ptrtype != Ptr(RuntimeTypeInfo)):
                raise TyperError("runtime type info function returns %r, "
                                 "expected Ptr(RuntimeTypeInfo)" % (s))
            funcptr = self.rtyper.getcallable(graph)
            attachRuntimeTypeInfo(self.object_type, funcptr, destrptr)

            vtable = self.rclass.getvtable()
            self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO)
Ejemplo n.º 8
0
def test_assemble_cast_consts():
    ssarepr = SSARepr("test")
    S = lltype.GcStruct('S')
    s = lltype.malloc(S)
    F = lltype.FuncType([], lltype.Signed)
    f = lltype.functionptr(F, 'f')
    ssarepr.insns = [
        ('int_return', Constant('X', lltype.Char)),
        ('int_return', Constant(unichr(0x1234), lltype.UniChar)),
        ('int_return', Constant(f, lltype.Ptr(F))),
        ('ref_return', Constant(s, lltype.Ptr(S))),
        ]
    assembler = Assembler()
    jitcode = assembler.assemble(ssarepr)
    assert jitcode.code == ("\x00\x58"
                            "\x01\xFF"
                            "\x01\xFE"
                            "\x02\xFF")
    assert assembler.insns == {'int_return/c': 0,
                               'int_return/i': 1,
                               'ref_return/r': 2}
    f_int = heaptracker.adr2int(llmemory.cast_ptr_to_adr(f))
    assert jitcode.constants_i == [0x1234, f_int]
    s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
    assert jitcode.constants_r == [s_gcref]
Ejemplo n.º 9
0
def test_decode_builtin_call_method():
    A = lltype.GcArray(lltype.Signed)
    def myfoobar(a, i, marker, c):
        assert marker == 'mymarker'
        return a[i] * ord(c)
    myfoobar.oopspec = 'spam.foobar(a, 2, c, i)'
    TYPE = lltype.FuncType([lltype.Ptr(A), lltype.Signed,
                            lltype.Void, lltype.Char],
                           lltype.Signed)
    fnobj = lltype.functionptr(TYPE, 'foobar', _callable=myfoobar)
    vi = Variable('i')
    vi.concretetype = lltype.Signed
    vc = Variable('c')
    vc.concretetype = lltype.Char
    v_result = Variable('result')
    v_result.concretetype = lltype.Signed
    myarray = lltype.malloc(A, 10)
    myarray[5] = 42
    op = SpaceOperation('direct_call', [newconst(fnobj),
                                        newconst(myarray),
                                        vi,
                                        voidconst('mymarker'),
                                        vc],
                        v_result)
    oopspec, opargs = decode_builtin_call(op)
    assert oopspec == 'spam.foobar'
    assert opargs == [newconst(myarray), newconst(2), vc, vi]
Ejemplo n.º 10
0
    def test_llexternal(self):
        from rpython.rtyper.lltypesystem.rffi import llexternal
        from rpython.rtyper.lltypesystem import lltype
        z = llexternal('z', [lltype.Signed], lltype.Signed)
        def f(x):
            return z(x)
        t, ra = self.translate(f, [int])
        fgraph = graphof(t, f)
        backend_optimizations(t)
        assert fgraph.startblock.operations[0].opname == 'direct_call'

        result = ra.can_raise(fgraph.startblock.operations[0])
        assert not result

        z = lltype.functionptr(lltype.FuncType([lltype.Signed], lltype.Signed),
                               'foobar')
        def g(x):
            return z(x)
        t, ra = self.translate(g, [int])
        ggraph = graphof(t, g)

        assert ggraph.startblock.operations[0].opname == 'direct_call'

        result = ra.can_raise(ggraph.startblock.operations[0])
        assert result
Ejemplo n.º 11
0
    def test_llexternal(self):
        from rpython.rtyper.lltypesystem.rffi import llexternal
        from rpython.rtyper.lltypesystem import lltype
        z = llexternal('z', [lltype.Signed], lltype.Signed)
        def f(x):
            return z(x)
        t, ra = self.translate(f, [int])
        fgraph = graphof(t, f)
        backend_optimizations(t)
        assert fgraph.startblock.operations[0].opname == 'direct_call'

        result = ra.can_raise(fgraph.startblock.operations[0])
        assert not result

        z = lltype.functionptr(lltype.FuncType([lltype.Signed], lltype.Signed),
                               'foobar')
        def g(x):
            return z(x)
        t, ra = self.translate(g, [int])
        ggraph = graphof(t, g)

        assert ggraph.startblock.operations[0].opname == 'direct_call'

        result = ra.can_raise(ggraph.startblock.operations[0])
        assert result
Ejemplo n.º 12
0
    def _setup_repr_final(self):
        self._setup_immutable_field_list()
        self._check_for_immutable_conflicts()
        if self.gcflavor == 'gc':
            if (self.classdef is not None and
                    self.classdef.classdesc.lookup('__del__') is not None):
                s_func = self.classdef.classdesc.s_read_attribute('__del__')
                source_desc = self.classdef.classdesc.lookup('__del__')
                source_classdef = source_desc.getclassdef(None)
                source_repr = getinstancerepr(self.rtyper, source_classdef)
                assert len(s_func.descriptions) == 1
                funcdesc, = s_func.descriptions
                graph = funcdesc.getuniquegraph()
                self.check_graph_of_del_does_not_call_too_much(graph)
                FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
                destrptr = functionptr(FUNCTYPE, graph.name,
                                       graph=graph,
                                       _callable=graph.func)
            else:
                destrptr = None
            self.rtyper.call_all_setups()  # compute ForwardReferences now
            args_s = [SomePtr(Ptr(OBJECT))]
            graph = self.rtyper.annotate_helper(ll_runtime_type_info, args_s)
            s = self.rtyper.annotation(graph.getreturnvar())
            if (not isinstance(s, SomePtr) or
                s.ll_ptrtype != Ptr(RuntimeTypeInfo)):
                raise TyperError("runtime type info function returns %r, "
                                "expected Ptr(RuntimeTypeInfo)" % (s))
            funcptr = self.rtyper.getcallable(graph)
            attachRuntimeTypeInfo(self.object_type, funcptr, destrptr)

            vtable = self.rclass.getvtable()
            self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO)
Ejemplo n.º 13
0
def test_deallocator_with_destructor():
    S = lltype.GcStruct("S", ('x', lltype.Signed), rtti=True)
    def f(s):
        s.x = 1
    def type_info_S(p):
        return lltype.getRuntimeTypeInfo(S)
    qp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
                                            lltype.Ptr(lltype.RuntimeTypeInfo)),
                            "type_info_S",
                            _callable=type_info_S)
    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
                                            lltype.Void),
                            "destructor_funcptr",
                            _callable=f)
    pinf = lltype.attachRuntimeTypeInfo(S, qp, destrptr=dp)
    graph, t = make_deallocator(S)
Ejemplo n.º 14
0
def test_decode_builtin_call_method():
    A = lltype.GcArray(lltype.Signed)

    def myfoobar(a, i, marker, c):
        assert marker == 'mymarker'
        return a[i] * ord(c)

    myfoobar.oopspec = 'spam.foobar(a, 2, c, i)'
    TYPE = lltype.FuncType(
        [lltype.Ptr(A), lltype.Signed, lltype.Void, lltype.Char],
        lltype.Signed)
    fnobj = lltype.functionptr(TYPE, 'foobar', _callable=myfoobar)
    vi = Variable('i')
    vi.concretetype = lltype.Signed
    vc = Variable('c')
    vc.concretetype = lltype.Char
    v_result = Variable('result')
    v_result.concretetype = lltype.Signed
    myarray = lltype.malloc(A, 10)
    myarray[5] = 42
    op = SpaceOperation(
        'direct_call',
        [newconst(fnobj),
         newconst(myarray), vi,
         voidconst('mymarker'), vc], v_result)
    oopspec, opargs = decode_builtin_call(op)
    assert oopspec == 'spam.foobar'
    assert opargs == [newconst(myarray), newconst(2), vc, vi]
Ejemplo n.º 15
0
def test_assemble_cast_consts():
    ssarepr = SSARepr("test")
    S = lltype.GcStruct('S')
    s = lltype.malloc(S)
    np = lltype.nullptr(S)
    F = lltype.FuncType([], lltype.Signed)
    f = lltype.functionptr(F, 'f')
    ssarepr.insns = [
        ('int_return', Constant('X', lltype.Char)),
        ('int_return', Constant(unichr(0x1234), lltype.UniChar)),
        ('int_return', Constant(f, lltype.Ptr(F))),
        ('ref_return', Constant(s, lltype.Ptr(S))),
        ('ref_return', Constant(np, lltype.Ptr(S))),
        ('ref_return', Constant(s, lltype.Ptr(S))),
        ('ref_return', Constant(np, lltype.Ptr(S))),
    ]
    assembler = Assembler()
    jitcode = assembler.assemble(ssarepr)
    assert jitcode.code == ("\x00\x58"
                            "\x01\xFF"
                            "\x01\xFE"
                            "\x02\xFF"
                            "\x02\xFE"
                            "\x02\xFF"
                            "\x02\xFE")
    assert assembler.insns == {
        'int_return/c': 0,
        'int_return/i': 1,
        'ref_return/r': 2
    }
    f_int = ptr2int(f)
    assert jitcode.constants_i == [0x1234, f_int]
    s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
    np_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, np)
    assert jitcode.constants_r == [s_gcref, np_gcref]
Ejemplo n.º 16
0
 def specialize_call(self, hop):
     rtyper = hop.rtyper
     signature_args = self.normalize_args(*hop.args_s)
     args_r = [rtyper.getrepr(s_arg) for s_arg in signature_args]
     args_ll = [r_arg.lowleveltype for r_arg in args_r]
     s_result = hop.s_result
     r_result = rtyper.getrepr(s_result)
     ll_result = r_result.lowleveltype
     name = getattr(self, 'name', None) or self.instance.__name__
     impl = getattr(self, 'lltypeimpl', None)
     fakeimpl = getattr(self, 'lltypefakeimpl', self.instance)
     if impl:
         if hasattr(self, 'lltypefakeimpl'):
             # If we have both an llimpl and an llfakeimpl,
             # we need a wrapper that selects the proper one and calls it
             from rpython.tool.sourcetools import func_with_new_name
             # Using '*args' is delicate because this wrapper is also
             # created for init-time functions like llarena.arena_malloc
             # which are called before the GC is fully initialized
             args = ', '.join(['arg%d' % i for i in range(len(args_ll))])
             d = {'original_impl': impl,
                  's_result': s_result,
                  'fakeimpl': fakeimpl,
                  '__name__': __name__,
                  }
             exec py.code.compile("""
                 from rpython.rlib.objectmodel import running_on_llinterp
                 from rpython.rlib.debug import llinterpcall
                 from rpython.rlib.jit import dont_look_inside
                 # note: we say 'dont_look_inside' mostly because the
                 # JIT does not support 'running_on_llinterp', but in
                 # theory it is probably right to stop jitting anyway.
                 @dont_look_inside
                 def ll_wrapper(%s):
                     if running_on_llinterp:
                         return llinterpcall(s_result, fakeimpl, %s)
                     else:
                         return original_impl(%s)
             """ % (args, args, args)) in d
             impl = func_with_new_name(d['ll_wrapper'], name + '_wrapper')
         if rtyper.annotator.translator.config.translation.sandbox:
             impl._dont_inline_ = True
         # store some attributes to the 'impl' function, where
         # the eventual call to rtyper.getcallable() will find them
         # and transfer them to the final lltype.functionptr().
         impl._llfnobjattrs_ = {
             '_name': self.name,
             '_safe_not_sandboxed': self.safe_not_sandboxed,
             }
         obj = rtyper.getannmixlevel().delayedfunction(
             impl, signature_args, hop.s_result)
     else:
         FT = FuncType(args_ll, ll_result)
         obj = functionptr(FT, name, _external_name=self.name,
                           _callable=fakeimpl,
                           _safe_not_sandboxed=self.safe_not_sandboxed)
     vlist = [hop.inputconst(typeOf(obj), obj)] + hop.inputargs(*args_r)
     hop.exception_is_here()
     return hop.genop('direct_call', vlist, r_result)
Ejemplo n.º 17
0
def test_boehm_finalizer___del__():
    S = lltype.GcStruct("S", ('x', lltype.Signed), rtti=True)
    def f(s):
        s.x = 1
    def type_info_S(p):
        return lltype.getRuntimeTypeInfo(S)
    qp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
                                            lltype.Ptr(lltype.RuntimeTypeInfo)),
                            "type_info_S",
                            _callable=type_info_S)
    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
                                            lltype.Void),
                            "destructor_funcptr",
                            _callable=f)
    lltype.attachRuntimeTypeInfo(S, qp, destrptr=dp)
    f, t = make_boehm_finalizer(S)
    assert f is not None
Ejemplo n.º 18
0
def annotate(translator, func, result, args):
    args = [arg.concretetype for arg in args]
    graph = translator.rtyper.annotate_helper(func, args)
    fptr = lltype.functionptr(lltype.FuncType(args, result.concretetype),
                              func.func_name,
                              graph=graph)
    c = inputconst(lltype.typeOf(fptr), fptr)
    return c
Ejemplo n.º 19
0
 def genexternalcall(self, fnname, args_v, resulttype=None, **flags):
     if isinstance(resulttype, Repr):
         resulttype = resulttype.lowleveltype
     argtypes = [v.concretetype for v in args_v]
     FUNCTYPE = FuncType(argtypes, resulttype or Void)
     f = functionptr(FUNCTYPE, fnname, **flags)
     cf = inputconst(typeOf(f), f)
     return self.genop('direct_call', [cf] + list(args_v), resulttype)
Ejemplo n.º 20
0
 def genexternalcall(self, fnname, args_v, resulttype=None, **flags):
     if isinstance(resulttype, Repr):
         resulttype = resulttype.lowleveltype
     argtypes = [v.concretetype for v in args_v]
     FUNCTYPE = FuncType(argtypes, resulttype or Void)
     f = functionptr(FUNCTYPE, fnname, **flags)
     cf = inputconst(typeOf(f), f)
     return self.genop('direct_call', [cf]+list(args_v), resulttype)
Ejemplo n.º 21
0
def get_direct_call_op(argtypes, restype):
    FUNC = lltype.FuncType(argtypes, restype)
    fnptr = lltype.functionptr(FUNC, "g")  # no graph
    c_fnptr = const(fnptr)
    vars = [varoftype(TYPE) for TYPE in argtypes]
    v_result = varoftype(restype)
    op = SpaceOperation("direct_call", [c_fnptr] + vars, v_result)
    return op
Ejemplo n.º 22
0
def test_half_exceptiontransformed_graphs():
    from rpython.translator import exceptiontransform

    def f1(x):
        if x < 0:
            raise ValueError
        return 754

    def g1(x):
        try:
            return f1(x)
        except ValueError:
            return 5

    def f2(x):
        if x < 0:
            raise ValueError
        return 21

    def g2(x):
        try:
            return f2(x)
        except ValueError:
            return 6

    f3 = lltype.functionptr(lltype.FuncType([lltype.Signed], lltype.Signed),
                            'f3',
                            _callable=f1)

    def g3(x):
        try:
            return f3(x)
        except ValueError:
            return 7

    def f(flag, x):
        if flag == 1:
            return g1(x)
        elif flag == 2:
            return g2(x)
        else:
            return g3(x)

    t = TranslationContext()
    t.buildannotator().build_types(f, [int, int])
    t.buildrtyper().specialize()
    etrafo = exceptiontransform.ExceptionTransformer(t)
    etrafo.create_exception_handling(graphof(t, f1))
    etrafo.create_exception_handling(graphof(t, g2))
    etrafo.create_exception_handling(graphof(t, g3))
    graph = graphof(t, f)
    interp = LLInterpreter(t.rtyper)
    res = interp.eval_graph(graph, [1, -64])
    assert res == 5
    res = interp.eval_graph(graph, [2, -897])
    assert res == 6
    res = interp.eval_graph(graph, [3, -9831])
    assert res == 7
Ejemplo n.º 23
0
def test_half_exceptiontransformed_graphs():
    from rpython.translator import exceptiontransform

    def f1(x):
        if x < 0:
            raise ValueError
        return 754

    def g1(x):
        try:
            return f1(x)
        except ValueError:
            return 5

    def f2(x):
        if x < 0:
            raise ValueError
        return 21

    def g2(x):
        try:
            return f2(x)
        except ValueError:
            return 6

    f3 = lltype.functionptr(lltype.FuncType([lltype.Signed], lltype.Signed), "f3", _callable=f1)

    def g3(x):
        try:
            return f3(x)
        except ValueError:
            return 7

    def f(flag, x):
        if flag == 1:
            return g1(x)
        elif flag == 2:
            return g2(x)
        else:
            return g3(x)

    t = TranslationContext()
    t.buildannotator().build_types(f, [int, int])
    t.buildrtyper().specialize()
    etrafo = exceptiontransform.ExceptionTransformer(t)
    etrafo.create_exception_handling(graphof(t, f1))
    etrafo.create_exception_handling(graphof(t, g2))
    etrafo.create_exception_handling(graphof(t, g3))
    graph = graphof(t, f)
    interp = LLInterpreter(t.rtyper)
    res = interp.eval_graph(graph, [1, -64])
    assert res == 5
    res = interp.eval_graph(graph, [2, -897])
    assert res == 6
    res = interp.eval_graph(graph, [3, -9831])
    assert res == 7
Ejemplo n.º 24
0
def test_deallocator_with_destructor():
    S = lltype.GcStruct("S", ('x', lltype.Signed), rtti=True)

    def f(s):
        s.x = 1

    def type_info_S(p):
        return lltype.getRuntimeTypeInfo(S)

    qp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)],
                                            lltype.Ptr(
                                                lltype.RuntimeTypeInfo)),
                            "type_info_S",
                            _callable=type_info_S)
    dp = lltype.functionptr(lltype.FuncType([lltype.Ptr(S)], lltype.Void),
                            "destructor_funcptr",
                            _callable=f)
    pinf = lltype.attachRuntimeTypeInfo(S, qp, destrptr=dp)
    graph, t = make_deallocator(S)
Ejemplo n.º 25
0
def test_graphs_from_direct_call():
    cc = CallControl()
    F = lltype.FuncType([], lltype.Signed)
    f = lltype.functionptr(F, 'f', graph='fgraph')
    v = varoftype(lltype.Signed)
    op = SpaceOperation('direct_call', [Constant(f, lltype.Ptr(F))], v)
    #
    lst = cc.graphs_from(op, {}.__contains__)
    assert lst is None  # residual call
    #
    lst = cc.graphs_from(op, {'fgraph': True}.__contains__)
    assert lst == ['fgraph']  # normal call
Ejemplo n.º 26
0
def test_graphs_from_direct_call():
    cc = CallControl()
    F = lltype.FuncType([], lltype.Signed)
    f = lltype.functionptr(F, 'f', graph='fgraph')
    v = varoftype(lltype.Signed)
    op = SpaceOperation('direct_call', [Constant(f, lltype.Ptr(F))], v)
    #
    lst = cc.graphs_from(op, {}.__contains__)
    assert lst is None     # residual call
    #
    lst = cc.graphs_from(op, {'fgraph': True}.__contains__)
    assert lst == ['fgraph']     # normal call
Ejemplo n.º 27
0
 def get_funcptr(self, rtyper, args_r, r_result):
     from rpython.rtyper.rtyper import llinterp_backend
     args_ll = [r_arg.lowleveltype for r_arg in args_r]
     ll_result = r_result.lowleveltype
     name = self.s_func.name
     if self.fakeimpl and rtyper.backend is llinterp_backend:
         FT = FuncType(args_ll, ll_result)
         return functionptr(
             FT, name, _external_name=name, _callable=self.fakeimpl)
     elif self.impl:
         if isinstance(self.impl, _ptr):
             return self.impl
         else:
             # store some attributes to the 'impl' function, where
             # the eventual call to rtyper.getcallable() will find them
             # and transfer them to the final lltype.functionptr().
             self.impl._llfnobjattrs_ = {'_name': name}
             return rtyper.getannmixlevel().delayedfunction(
                 self.impl, self.s_func.args_s, self.s_func.s_result)
     else:
         fakeimpl = self.fakeimpl or self.s_func.const
         FT = FuncType(args_ll, ll_result)
         return functionptr(
             FT, name, _external_name=name, _callable=fakeimpl)
Ejemplo n.º 28
0
def test_str2unicode():
    # test that the oopspec is present and correctly transformed
    PSTR = lltype.Ptr(rstr.STR)
    PUNICODE = lltype.Ptr(rstr.UNICODE)
    FUNC = lltype.FuncType([PSTR], PUNICODE)
    func = lltype.functionptr(FUNC, "ll_str2unicode", _callable=rstr.LLHelpers.ll_str2unicode)
    v1 = varoftype(PSTR)
    v2 = varoftype(PUNICODE)
    op = SpaceOperation("direct_call", [const(func), v1], v2)
    tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
    op1 = tr.rewrite_operation(op)
    assert op1.opname == "residual_call_r_r"
    assert op1.args[0].value == func
    assert op1.args[1] == ListOfKind("ref", [v1])
    assert op1.args[2] == "calldescr-%d" % effectinfo.EffectInfo.OS_STR2UNICODE
    assert op1.result == v2
Ejemplo n.º 29
0
def test_math_sqrt():
    # test that the oopspec is present and correctly transformed
    FLOAT = lltype.Float
    FUNC = lltype.FuncType([FLOAT], FLOAT)
    func = lltype.functionptr(FUNC, "ll_math", _callable=ll_math.sqrt_nonneg)
    v1 = varoftype(FLOAT)
    v2 = varoftype(FLOAT)
    op = SpaceOperation("direct_call", [const(func), v1], v2)
    tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
    op1 = tr.rewrite_operation(op)
    assert op1.opname == "residual_call_irf_f"
    assert op1.args[0].value == func
    assert op1.args[1] == ListOfKind("int", [])
    assert op1.args[2] == ListOfKind("ref", [])
    assert op1.args[3] == ListOfKind("float", [v1])
    assert op1.args[4] == "calldescr-%d" % effectinfo.EffectInfo.OS_MATH_SQRT
    assert op1.result == v2
Ejemplo n.º 30
0
def test_malloc_new_with_destructor():
    vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
    S = lltype.GcStruct("S", ("parent", rclass.OBJECT), rtti=True)
    DESTRUCTOR = lltype.FuncType([lltype.Ptr(S)], lltype.Void)
    destructor = lltype.functionptr(DESTRUCTOR, "destructor")
    lltype.attachRuntimeTypeInfo(S, destrptr=destructor)
    heaptracker.set_testing_vtable_for_gcstruct(S, vtable, "S")
    v = varoftype(lltype.Ptr(S))
    op = SpaceOperation("malloc", [Constant(S, lltype.Void), Constant({"flavor": "gc"}, lltype.Void)], v)
    tr = Transformer(FakeCPU(), FakeResidualCallControl())
    oplist = tr.rewrite_operation(op)
    op0, op1 = oplist
    assert op0.opname == "residual_call_r_r"
    assert op0.args[0].value == "alloc_with_del"  # pseudo-function as a str
    assert list(op0.args[1]) == []
    assert op1.opname == "-live-"
    assert op1.args == []
Ejemplo n.º 31
0
def test_unicode_slice():
    # test that the oopspec is present and correctly transformed
    PUNICODE = lltype.Ptr(rstr.UNICODE)
    INT = lltype.Signed
    FUNC = lltype.FuncType([PUNICODE, INT, INT], PUNICODE)
    func = lltype.functionptr(FUNC, "_ll_stringslice", _callable=rstr.LLHelpers._ll_stringslice)
    v1 = varoftype(PUNICODE)
    v2 = varoftype(INT)
    v3 = varoftype(INT)
    v4 = varoftype(PUNICODE)
    op = SpaceOperation("direct_call", [const(func), v1, v2, v3], v4)
    tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
    op1 = tr.rewrite_operation(op)
    assert op1.opname == "residual_call_ir_r"
    assert op1.args[0].value == func
    assert op1.args[1] == ListOfKind("int", [v2, v3])
    assert op1.args[2] == ListOfKind("ref", [v1])
    assert op1.args[3] == "calldescr-%d" % effectinfo.EffectInfo.OS_UNI_SLICE
    assert op1.result == v4
Ejemplo n.º 32
0
def test_call_ptr():
    def f(x, y, z):
        return x+y+z
    FTYPE = lltype.FuncType([lltype.Signed, lltype.Signed, lltype.Signed], lltype.Signed)
    fptr = lltype.functionptr(FTYPE, "f", _callable=f)

    def g(x, y, z):
        tot = 0
        tot += fptr(x, y, z)
        tot += fptr(*(x, y, z))
        tot += fptr(x, *(x, z))
        return tot

    res = interpret(g, [1, 2, 4])
    assert res == g(1, 2, 4)

    def wrong(x, y):
        fptr(*(x, y))

    py.test.raises(TypeError, "interpret(wrong, [1, 2])")
Ejemplo n.º 33
0
def llhelper(F, f):
    """Gives a low-level function pointer of type F which, when called,
    invokes the RPython function f().
    """
    # Example - the following code can be either run or translated:
    #
    #   def my_rpython_code():
    #       g = llhelper(F, my_other_rpython_function)
    #       assert typeOf(g) == F
    #       ...
    #       g()
    #
    # however the following doesn't translate (xxx could be fixed with hacks):
    #
    #   prebuilt_g = llhelper(F, f)
    #   def my_rpython_code():
    #       prebuilt_g()

    # the next line is the implementation for the purpose of direct running
    return lltype.functionptr(F.TO, f.func_name, _callable=f)
Ejemplo n.º 34
0
def llhelper(F, f):
    """Gives a low-level function pointer of type F which, when called,
    invokes the RPython function f().
    """
    # Example - the following code can be either run or translated:
    #
    #   def my_rpython_code():
    #       g = llhelper(F, my_other_rpython_function)
    #       assert typeOf(g) == F
    #       ...
    #       g()
    #
    # however the following doesn't translate (xxx could be fixed with hacks):
    #
    #   prebuilt_g = llhelper(F, f)
    #   def my_rpython_code():
    #       prebuilt_g()

    # the next line is the implementation for the purpose of direct running
    return lltype.functionptr(F.TO, f.func_name, _callable=f)
Ejemplo n.º 35
0
def test_decode_builtin_call_nomethod():
    def myfoobar(i, marker, c):
        assert marker == 'mymarker'
        return i * ord(c)

    myfoobar.oopspec = 'foobar(2, c, i)'
    TYPE = lltype.FuncType([lltype.Signed, lltype.Void, lltype.Char],
                           lltype.Signed)
    fnobj = lltype.functionptr(TYPE, 'foobar', _callable=myfoobar)
    vi = Variable('i')
    vi.concretetype = lltype.Signed
    vc = Variable('c')
    vc.concretetype = lltype.Char
    v_result = Variable('result')
    v_result.concretetype = lltype.Signed
    op = SpaceOperation(
        'direct_call',
        [newconst(fnobj), vi, voidconst('mymarker'), vc], v_result)
    oopspec, opargs = decode_builtin_call(op)
    assert oopspec == 'foobar'
    assert opargs == [newconst(2), vc, vi]
Ejemplo n.º 36
0
def test_unicode_eq_checknull_char():
    # test that the oopspec is present and correctly transformed
    PUNICODE = lltype.Ptr(rstr.UNICODE)
    FUNC = lltype.FuncType([PUNICODE, PUNICODE], lltype.Bool)
    func = lltype.functionptr(FUNC, "ll_streq", _callable=rstr.LLHelpers.ll_streq)
    v1 = varoftype(PUNICODE)
    v2 = varoftype(PUNICODE)
    v3 = varoftype(lltype.Bool)
    op = SpaceOperation("direct_call", [const(func), v1, v2], v3)
    cc = FakeBuiltinCallControl()
    tr = Transformer(FakeCPU(), cc)
    op1 = tr.rewrite_operation(op)
    assert op1.opname == "residual_call_r_i"
    assert op1.args[0].value == func
    assert op1.args[1] == ListOfKind("ref", [v1, v2])
    assert op1.args[2] == "calldescr-%d" % effectinfo.EffectInfo.OS_UNI_EQUAL
    assert op1.result == v3
    # test that the OS_UNIEQ_* functions are registered
    cic = cc.callinfocollection
    assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_SLICE_NONNULL)
    assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_CHECKNULL_CHAR)
Ejemplo n.º 37
0
def test_decode_builtin_call_nomethod():
    def myfoobar(i, marker, c):
        assert marker == 'mymarker'
        return i * ord(c)
    myfoobar.oopspec = 'foobar(2, c, i)'
    TYPE = lltype.FuncType([lltype.Signed, lltype.Void, lltype.Char],
                           lltype.Signed)
    fnobj = lltype.functionptr(TYPE, 'foobar', _callable=myfoobar)
    vi = Variable('i')
    vi.concretetype = lltype.Signed
    vc = Variable('c')
    vc.concretetype = lltype.Char
    v_result = Variable('result')
    v_result.concretetype = lltype.Signed
    op = SpaceOperation('direct_call', [newconst(fnobj),
                                        vi,
                                        voidconst('mymarker'),
                                        vc],
                        v_result)
    oopspec, opargs = decode_builtin_call(op)
    assert oopspec == 'foobar'
    assert opargs == [newconst(2), vc, vi]
Ejemplo n.º 38
0
def test_call_ptr():
    def f(x, y, z):
        return x + y + z

    FTYPE = lltype.FuncType([lltype.Signed, lltype.Signed, lltype.Signed],
                            lltype.Signed)
    fptr = lltype.functionptr(FTYPE, "f", _callable=f)

    def g(x, y, z):
        tot = 0
        tot += fptr(x, y, z)
        tot += fptr(*(x, y, z))
        tot += fptr(x, *(x, z))
        return tot

    res = interpret(g, [1, 2, 4])
    assert res == g(1, 2, 4)

    def wrong(x, y):
        fptr(*(x, y))

    py.test.raises(TypeError, "interpret(wrong, [1, 2])")
Ejemplo n.º 39
0
def test_list_ll_arraycopy():
    from rpython.rlib.rgc import ll_arraycopy

    LIST = lltype.GcArray(lltype.Signed)
    PLIST = lltype.Ptr(LIST)
    INT = lltype.Signed
    FUNC = lltype.FuncType([PLIST] * 2 + [INT] * 3, lltype.Void)
    func = lltype.functionptr(FUNC, "ll_arraycopy", _callable=ll_arraycopy)
    v1 = varoftype(PLIST)
    v2 = varoftype(PLIST)
    v3 = varoftype(INT)
    v4 = varoftype(INT)
    v5 = varoftype(INT)
    v6 = varoftype(lltype.Void)
    op = SpaceOperation("direct_call", [const(func), v1, v2, v3, v4, v5], v6)
    tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
    op1 = tr.rewrite_operation(op)
    assert op1.opname == "residual_call_ir_v"
    assert op1.args[0].value == func
    assert op1.args[1] == ListOfKind("int", [v3, v4, v5])
    assert op1.args[2] == ListOfKind("ref", [v1, v2])
    assert op1.args[3] == "calldescr-%d" % effectinfo.EffectInfo.OS_ARRAYCOPY
Ejemplo n.º 40
0
def test_unicode_concat():
    # test that the oopspec is present and correctly transformed
    PSTR = lltype.Ptr(rstr.UNICODE)
    FUNC = lltype.FuncType([PSTR, PSTR], PSTR)
    func = lltype.functionptr(FUNC, "ll_strconcat", _callable=rstr.LLHelpers.ll_strconcat)
    v1 = varoftype(PSTR)
    v2 = varoftype(PSTR)
    v3 = varoftype(PSTR)
    op = SpaceOperation("direct_call", [const(func), v1, v2], v3)
    cc = FakeBuiltinCallControl()
    tr = Transformer(FakeCPU(), cc)
    op1 = tr.rewrite_operation(op)
    assert op1.opname == "residual_call_r_r"
    assert op1.args[0].value == func
    assert op1.args[1] == ListOfKind("ref", [v1, v2])
    assert op1.args[2] == "calldescr-%d" % effectinfo.EffectInfo.OS_UNI_CONCAT
    assert op1.result == v3
    #
    # check the callinfo_for_oopspec
    got = cc.callinfocollection.seen[0]
    assert got[0] == effectinfo.EffectInfo.OS_UNI_CONCAT
    assert got[1] == op1.args[2]  # the calldescr
    assert heaptracker.int2adr(got[2]) == llmemory.cast_ptr_to_adr(func)
Ejemplo n.º 41
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))
Ejemplo n.º 42
0
 def __getitem__(self, key):
     F = lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed)
     f = lltype.functionptr(F, key[0])
     c_func = Constant(f, lltype.typeOf(f))
     return c_func, lltype.Signed
Ejemplo n.º 43
0
 def _transform_hint_close_stack(self, fnptr):
     # We cannot easily pass variable amount of arguments of the call
     # across the call to the pypy_asm_stackwalk helper.  So we store
     # them away and restore them.  More precisely, we need to
     # replace 'graph' with code that saves the arguments, and make
     # a new graph that starts with restoring the arguments.
     if self._asmgcc_save_restore_arguments is None:
         self._asmgcc_save_restore_arguments = {}
     sradict = self._asmgcc_save_restore_arguments
     sra = []     # list of pointers to raw-malloced containers for args
     seen = {}
     FUNC1 = lltype.typeOf(fnptr).TO
     for TYPE in FUNC1.ARGS:
         if isinstance(TYPE, lltype.Ptr):
             TYPE = llmemory.Address
         num = seen.get(TYPE, 0)
         seen[TYPE] = num + 1
         key = (TYPE, num)
         if key not in sradict:
             CONTAINER = lltype.FixedSizeArray(TYPE, 1)
             p = lltype.malloc(CONTAINER, flavor='raw', zero=True,
                               immortal=True)
             sradict[key] = Constant(p, lltype.Ptr(CONTAINER))
         sra.append(sradict[key])
     #
     # make a copy of the graph that will reload the values
     graph = fnptr._obj.graph
     graph2 = copygraph(graph)
     #
     # edit the original graph to only store the value of the arguments
     block = Block(graph.startblock.inputargs)
     c_item0 = Constant('item0', lltype.Void)
     assert len(block.inputargs) == len(sra)
     for v_arg, c_p in zip(block.inputargs, sra):
         if isinstance(v_arg.concretetype, lltype.Ptr):
             v_adr = varoftype(llmemory.Address)
             block.operations.append(
                 SpaceOperation("cast_ptr_to_adr", [v_arg], v_adr))
             v_arg = v_adr
         v_void = varoftype(lltype.Void)
         block.operations.append(
             SpaceOperation("bare_setfield", [c_p, c_item0, v_arg], v_void))
     #
     # call asm_stackwalk(graph2)
     FUNC2 = lltype.FuncType([], FUNC1.RESULT)
     fnptr2 = lltype.functionptr(FUNC2,
                                 fnptr._obj._name + '_reload',
                                 graph=graph2)
     c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2))
     HELPERFUNC = lltype.FuncType([lltype.Ptr(FUNC2),
                                   ASM_FRAMEDATA_HEAD_PTR], FUNC1.RESULT)
     v_asm_stackwalk = varoftype(lltype.Ptr(HELPERFUNC), "asm_stackwalk")
     block.operations.append(
         SpaceOperation("cast_pointer", [c_asm_stackwalk], v_asm_stackwalk))
     v_result = varoftype(FUNC1.RESULT)
     block.operations.append(
         SpaceOperation("indirect_call", [v_asm_stackwalk, c_fnptr2,
                                          c_gcrootanchor,
                                          Constant(None, lltype.Void)],
                        v_result))
     block.closeblock(Link([v_result], graph.returnblock))
     graph.startblock = block
     #
     # edit the copy of the graph to reload the values
     block2 = graph2.startblock
     block1 = Block([])
     reloadedvars = []
     for v, c_p in zip(block2.inputargs, sra):
         v = v.copy()
         if isinstance(v.concretetype, lltype.Ptr):
             w = varoftype(llmemory.Address)
         else:
             w = v
         block1.operations.append(SpaceOperation('getfield',
                                                 [c_p, c_item0], w))
         if w is not v:
             block1.operations.append(SpaceOperation('cast_adr_to_ptr',
                                                     [w], v))
         reloadedvars.append(v)
     block1.closeblock(Link(reloadedvars, block2))
     graph2.startblock = block1
     #
     checkgraph(graph)
     checkgraph(graph2)
Ejemplo n.º 44
0
 def getcallable(graph):
     F = lltype.FuncType([], lltype.Signed)
     return lltype.functionptr(F, 'bar')
Ejemplo n.º 45
0
 def _transform_hint_close_stack(self, fnptr):
     # We cannot easily pass variable amount of arguments of the call
     # across the call to the pypy_asm_stackwalk helper.  So we store
     # them away and restore them.  More precisely, we need to
     # replace 'graph' with code that saves the arguments, and make
     # a new graph that starts with restoring the arguments.
     if self._asmgcc_save_restore_arguments is None:
         self._asmgcc_save_restore_arguments = {}
     sradict = self._asmgcc_save_restore_arguments
     sra = []  # list of pointers to raw-malloced containers for args
     seen = {}
     FUNC1 = lltype.typeOf(fnptr).TO
     for TYPE in FUNC1.ARGS:
         if isinstance(TYPE, lltype.Ptr):
             TYPE = llmemory.Address
         num = seen.get(TYPE, 0)
         seen[TYPE] = num + 1
         key = (TYPE, num)
         if key not in sradict:
             CONTAINER = lltype.FixedSizeArray(TYPE, 1)
             p = lltype.malloc(CONTAINER,
                               flavor='raw',
                               zero=True,
                               immortal=True)
             sradict[key] = Constant(p, lltype.Ptr(CONTAINER))
         sra.append(sradict[key])
     #
     # make a copy of the graph that will reload the values
     graph = fnptr._obj.graph
     graph2 = copygraph(graph)
     #
     # edit the original graph to only store the value of the arguments
     block = Block(graph.startblock.inputargs)
     c_item0 = Constant('item0', lltype.Void)
     assert len(block.inputargs) == len(sra)
     for v_arg, c_p in zip(block.inputargs, sra):
         if isinstance(v_arg.concretetype, lltype.Ptr):
             v_adr = varoftype(llmemory.Address)
             block.operations.append(
                 SpaceOperation("cast_ptr_to_adr", [v_arg], v_adr))
             v_arg = v_adr
         v_void = varoftype(lltype.Void)
         block.operations.append(
             SpaceOperation("bare_setfield", [c_p, c_item0, v_arg], v_void))
     #
     # call asm_stackwalk(graph2)
     FUNC2 = lltype.FuncType([], FUNC1.RESULT)
     fnptr2 = lltype.functionptr(FUNC2,
                                 fnptr._obj._name + '_reload',
                                 graph=graph2)
     c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2))
     HELPERFUNC = lltype.FuncType(
         [lltype.Ptr(FUNC2), ASM_FRAMEDATA_HEAD_PTR], FUNC1.RESULT)
     v_asm_stackwalk = varoftype(lltype.Ptr(HELPERFUNC), "asm_stackwalk")
     block.operations.append(
         SpaceOperation("cast_pointer", [c_asm_stackwalk], v_asm_stackwalk))
     v_result = varoftype(FUNC1.RESULT)
     block.operations.append(
         SpaceOperation("indirect_call", [
             v_asm_stackwalk, c_fnptr2, c_gcrootanchor,
             Constant(None, lltype.Void)
         ], v_result))
     block.closeblock(Link([v_result], graph.returnblock))
     graph.startblock = block
     #
     # edit the copy of the graph to reload the values
     block2 = graph2.startblock
     block1 = Block([])
     reloadedvars = []
     for v, c_p in zip(block2.inputargs, sra):
         v = v.copy()
         if isinstance(v.concretetype, lltype.Ptr):
             w = varoftype(llmemory.Address)
         else:
             w = v
         block1.operations.append(
             SpaceOperation('getfield', [c_p, c_item0], w))
         if w is not v:
             block1.operations.append(
                 SpaceOperation('cast_adr_to_ptr', [w], v))
         reloadedvars.append(v)
     block1.closeblock(Link(reloadedvars, block2))
     graph2.startblock = block1
     #
     checkgraph(graph)
     checkgraph(graph2)
Ejemplo n.º 46
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))
Ejemplo n.º 47
0
def llexternal(name, args, result, _callable=None,
               compilation_info=ExternalCompilationInfo(),
               sandboxsafe=False, releasegil='auto',
               _nowrapper=False, calling_conv='c',
               elidable_function=False, macro=None,
               random_effects_on_gcobjs='auto'):
    """Build an external function that will invoke the C function 'name'
    with the given 'args' types and 'result' type.

    You get by default a wrapper that casts between number types as needed
    to match the arguments.  You can also pass an RPython string when a
    CCHARP argument is expected, and the C function receives a 'const char*'
    pointing to a read-only null-terminated character of arrays, as usual
    for C.

    The C function can have callbacks, but they must be specified explicitly
    as constant RPython functions.  We don't support yet C functions that
    invoke callbacks passed otherwise (e.g. set by a previous C call).

    releasegil: whether it's ok to release the GIL around the call.
                Default is yes, unless sandboxsafe is set, in which case
                we consider that the function is really short-running and
                don't bother releasing the GIL.  An explicit True or False
                overrides this logic.
    """
    if _callable is not None:
        assert callable(_callable)
    ext_type = lltype.FuncType(args, result)
    if _callable is None:
        if macro is not None:
            if macro is True:
                macro = name
            _callable = generate_macro_wrapper(
                name, macro, ext_type, compilation_info)
        else:
            _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv)
    if elidable_function:
        _callable._elidable_function_ = True
    kwds = {}

    has_callback = False
    for ARG in args:
        if _isfunctype(ARG):
            has_callback = True
    if has_callback:
        kwds['_callbacks'] = callbackholder = CallbackHolder()
    else:
        callbackholder = None

    if releasegil in (False, True):
        # invoke the around-handlers, which release the GIL, if and only if
        # the C function is thread-safe.
        invoke_around_handlers = releasegil
    else:
        # default case:
        # invoke the around-handlers only for "not too small" external calls;
        # sandboxsafe is a hint for "too-small-ness" (e.g. math functions).
        # Also, _nowrapper functions cannot release the GIL, by default.
        invoke_around_handlers = not sandboxsafe and not _nowrapper

    if random_effects_on_gcobjs not in (False, True):
        random_effects_on_gcobjs = (
            invoke_around_handlers or   # because it can release the GIL
            has_callback)               # because the callback can do it
    assert not (elidable_function and random_effects_on_gcobjs)

    funcptr = lltype.functionptr(ext_type, name, external='C',
                                 compilation_info=compilation_info,
                                 _callable=_callable,
                                 _safe_not_sandboxed=sandboxsafe,
                                 _debugexc=True, # on top of llinterp
                                 canraise=False,
                                 random_effects_on_gcobjs=
                                     random_effects_on_gcobjs,
                                 calling_conv=calling_conv,
                                 **kwds)
    if isinstance(_callable, ll2ctypes.LL2CtypesCallable):
        _callable.funcptr = funcptr

    if _nowrapper:
        return funcptr


    if invoke_around_handlers:
        # The around-handlers are releasing the GIL in a threaded pypy.
        # We need tons of care to ensure that no GC operation and no
        # exception checking occurs while the GIL is released.

        # The actual call is done by this small piece of non-inlinable
        # generated code in order to avoid seeing any GC pointer:
        # neither '*args' nor the GC objects originally passed in as
        # argument to wrapper(), if any (e.g. RPython strings).

        argnames = ', '.join(['a%d' % i for i in range(len(args))])
        source = py.code.Source("""
            def call_external_function(%(argnames)s):
                before = aroundstate.before
                if before: before()
                # NB. it is essential that no exception checking occurs here!
                res = funcptr(%(argnames)s)
                after = aroundstate.after
                if after: after()
                return res
        """ % locals())
        miniglobals = {'aroundstate': aroundstate,
                       'funcptr':     funcptr,
                       '__name__':    __name__, # for module name propagation
                       }
        exec source.compile() in miniglobals
        call_external_function = miniglobals['call_external_function']
        call_external_function._dont_inline_ = True
        call_external_function._annspecialcase_ = 'specialize:ll'
        call_external_function._gctransformer_hint_close_stack_ = True
        call_external_function._call_aroundstate_target_ = funcptr
        call_external_function = func_with_new_name(call_external_function,
                                                    'ccall_' + name)
        # don't inline, as a hack to guarantee that no GC pointer is alive
        # anywhere in call_external_function
    else:
        # if we don't have to invoke the aroundstate, we can just call
        # the low-level function pointer carelessly
        call_external_function = funcptr

    unrolling_arg_tps = unrolling_iterable(enumerate(args))
    def wrapper(*args):
        real_args = ()
        to_free = ()
        for i, TARGET in unrolling_arg_tps:
            arg = args[i]
            freeme = None
            if TARGET == CCHARP:
                if arg is None:
                    arg = lltype.nullptr(CCHARP.TO)   # None => (char*)NULL
                    freeme = arg
                elif isinstance(arg, str):
                    arg = str2charp(arg)
                    # XXX leaks if a str2charp() fails with MemoryError
                    # and was not the first in this function
                    freeme = arg
            elif TARGET == CWCHARP:
                if arg is None:
                    arg = lltype.nullptr(CWCHARP.TO)   # None => (wchar_t*)NULL
                    freeme = arg
                elif isinstance(arg, unicode):
                    arg = unicode2wcharp(arg)
                    # XXX leaks if a unicode2wcharp() fails with MemoryError
                    # and was not the first in this function
                    freeme = arg
            elif TARGET is VOIDP:
                if arg is None:
                    arg = lltype.nullptr(VOIDP.TO)
                elif isinstance(arg, str):
                    arg = str2charp(arg)
                    freeme = arg
                elif isinstance(arg, unicode):
                    arg = unicode2wcharp(arg)
                    freeme = arg
            elif _isfunctype(TARGET) and not _isllptr(arg):
                # XXX pass additional arguments
                if invoke_around_handlers:
                    arg = llhelper(TARGET, _make_wrapper_for(TARGET, arg,
                                                             callbackholder,
                                                             aroundstate))
                else:
                    arg = llhelper(TARGET, _make_wrapper_for(TARGET, arg,
                                                             callbackholder))
            else:
                SOURCE = lltype.typeOf(arg)
                if SOURCE != TARGET:
                    if TARGET is lltype.Float:
                        arg = float(arg)
                    elif ((isinstance(SOURCE, lltype.Number)
                           or SOURCE is lltype.Bool)
                      and (isinstance(TARGET, lltype.Number)
                           or TARGET is lltype.Bool)):
                        arg = cast(TARGET, arg)
            real_args = real_args + (arg,)
            to_free = to_free + (freeme,)
        res = call_external_function(*real_args)
        for i, TARGET in unrolling_arg_tps:
            if to_free[i]:
                lltype.free(to_free[i], flavor='raw')
        if rarithmetic.r_int is not r_int:
            if result is INT:
                return cast(lltype.Signed, res)
            elif result is UINT:
                return cast(lltype.Unsigned, res)
        return res
    wrapper._annspecialcase_ = 'specialize:ll'
    wrapper._always_inline_ = 'try'
    # for debugging, stick ll func ptr to that
    wrapper._ptr = funcptr
    wrapper = func_with_new_name(wrapper, name)

    if calling_conv != "c":
        wrapper = jit.dont_look_inside(wrapper)

    return wrapper
Ejemplo n.º 48
0
def llexternal(name, args, result, _callable=None,
               compilation_info=ExternalCompilationInfo(),
               sandboxsafe=False, releasegil='auto',
               _nowrapper=False, calling_conv='c',
               elidable_function=False, macro=None,
               random_effects_on_gcobjs='auto',
               save_err=RFFI_ERR_NONE):
    """Build an external function that will invoke the C function 'name'
    with the given 'args' types and 'result' type.

    You get by default a wrapper that casts between number types as needed
    to match the arguments.  You can also pass an RPython string when a
    CCHARP argument is expected, and the C function receives a 'const char*'
    pointing to a read-only null-terminated character of arrays, as usual
    for C.

    The C function can have callbacks, but they must be specified explicitly
    as constant RPython functions.  We don't support yet C functions that
    invoke callbacks passed otherwise (e.g. set by a previous C call).

    releasegil: whether it's ok to release the GIL around the call.
                Default is yes, unless sandboxsafe is set, in which case
                we consider that the function is really short-running and
                don't bother releasing the GIL.  An explicit True or False
                overrides this logic.
    """
    if _callable is not None:
        assert callable(_callable)
    ext_type = lltype.FuncType(args, result)
    if _callable is None:
        if macro is not None:
            if macro is True:
                macro = name
            _callable = generate_macro_wrapper(
                name, macro, ext_type, compilation_info)
        else:
            _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv)
    else:
        assert macro is None, "'macro' is useless if you specify '_callable'"
    if elidable_function:
        _callable._elidable_function_ = True
    kwds = {}

    has_callback = False
    for ARG in args:
        if _isfunctype(ARG):
            has_callback = True
    if has_callback:
        kwds['_callbacks'] = callbackholder = CallbackHolder()
    else:
        callbackholder = None

    if releasegil in (False, True):
        # invoke the around-handlers, which release the GIL, if and only if
        # the C function is thread-safe.
        invoke_around_handlers = releasegil
    else:
        # default case:
        # invoke the around-handlers only for "not too small" external calls;
        # sandboxsafe is a hint for "too-small-ness" (e.g. math functions).
        # Also, _nowrapper functions cannot release the GIL, by default.
        invoke_around_handlers = not sandboxsafe and not _nowrapper

    if random_effects_on_gcobjs not in (False, True):
        random_effects_on_gcobjs = (
            invoke_around_handlers or   # because it can release the GIL
            has_callback)               # because the callback can do it
    assert not (elidable_function and random_effects_on_gcobjs)

    funcptr = lltype.functionptr(ext_type, name, external='C',
                                 compilation_info=compilation_info,
                                 _callable=_callable,
                                 _safe_not_sandboxed=sandboxsafe,
                                 _debugexc=True, # on top of llinterp
                                 canraise=False,
                                 random_effects_on_gcobjs=
                                     random_effects_on_gcobjs,
                                 calling_conv=calling_conv,
                                 **kwds)
    if isinstance(_callable, ll2ctypes.LL2CtypesCallable):
        _callable.funcptr = funcptr

    if _nowrapper:
        assert save_err == RFFI_ERR_NONE
        return funcptr

    if invoke_around_handlers:
        # The around-handlers are releasing the GIL in a threaded pypy.
        # We need tons of care to ensure that no GC operation and no
        # exception checking occurs while the GIL is released.

        # The actual call is done by this small piece of non-inlinable
        # generated code in order to avoid seeing any GC pointer:
        # neither '*args' nor the GC objects originally passed in as
        # argument to wrapper(), if any (e.g. RPython strings).

        argnames = ', '.join(['a%d' % i for i in range(len(args))])
        source = py.code.Source("""
            from rpython.rlib import rgil
            def call_external_function(%(argnames)s):
                rgil.release()
                # NB. it is essential that no exception checking occurs here!
                if %(save_err)d:
                    from rpython.rlib import rposix
                    rposix._errno_before(%(save_err)d)
                res = funcptr(%(argnames)s)
                if %(save_err)d:
                    from rpython.rlib import rposix
                    rposix._errno_after(%(save_err)d)
                rgil.acquire()
                return res
        """ % locals())
        miniglobals = {'funcptr':     funcptr,
                       '__name__':    __name__, # for module name propagation
                       }
        exec source.compile() in miniglobals
        call_external_function = miniglobals['call_external_function']
        call_external_function._dont_inline_ = True
        call_external_function._annspecialcase_ = 'specialize:ll'
        call_external_function._gctransformer_hint_close_stack_ = True
        #
        # '_call_aroundstate_target_' is used by the JIT to generate a
        # CALL_RELEASE_GIL directly to 'funcptr'.  This doesn't work if
        # 'funcptr' might be a C macro, though.
        if macro is None:
            call_external_function._call_aroundstate_target_ = funcptr, save_err
        #
        call_external_function = func_with_new_name(call_external_function,
                                                    'ccall_' + name)
        # don't inline, as a hack to guarantee that no GC pointer is alive
        # anywhere in call_external_function
    else:
        # if we don't have to invoke the GIL handling, we can just call
        # the low-level function pointer carelessly
        if macro is None and save_err == RFFI_ERR_NONE:
            call_external_function = funcptr
        else:
            # ...well, unless it's a macro, in which case we still have
            # to hide it from the JIT...
            argnames = ', '.join(['a%d' % i for i in range(len(args))])
            source = py.code.Source("""
                def call_external_function(%(argnames)s):
                    if %(save_err)d:
                        from rpython.rlib import rposix
                        rposix._errno_before(%(save_err)d)
                    res = funcptr(%(argnames)s)
                    if %(save_err)d:
                        from rpython.rlib import rposix
                        rposix._errno_after(%(save_err)d)
                    return res
            """ % locals())
            miniglobals = {'funcptr':     funcptr,
                           '__name__':    __name__,
                           }
            exec source.compile() in miniglobals
            call_external_function = miniglobals['call_external_function']
            call_external_function = func_with_new_name(call_external_function,
                                                        'ccall_' + name)
            call_external_function = jit.dont_look_inside(
                call_external_function)

    unrolling_arg_tps = unrolling_iterable(enumerate(args))
    def wrapper(*args):
        real_args = ()
        to_free = ()
        for i, TARGET in unrolling_arg_tps:
            arg = args[i]
            freeme = None
            if TARGET == CCHARP:
                if arg is None:
                    arg = lltype.nullptr(CCHARP.TO)   # None => (char*)NULL
                    freeme = arg
                elif isinstance(arg, str):
                    arg = str2charp(arg)
                    # XXX leaks if a str2charp() fails with MemoryError
                    # and was not the first in this function
                    freeme = arg
            elif TARGET == CWCHARP:
                if arg is None:
                    arg = lltype.nullptr(CWCHARP.TO)   # None => (wchar_t*)NULL
                    freeme = arg
                elif isinstance(arg, unicode):
                    arg = unicode2wcharp(arg)
                    # XXX leaks if a unicode2wcharp() fails with MemoryError
                    # and was not the first in this function
                    freeme = arg
            elif TARGET is VOIDP:
                if arg is None:
                    arg = lltype.nullptr(VOIDP.TO)
                elif isinstance(arg, str):
                    arg = str2charp(arg)
                    freeme = arg
                elif isinstance(arg, unicode):
                    arg = unicode2wcharp(arg)
                    freeme = arg
            elif _isfunctype(TARGET) and not _isllptr(arg):
                # XXX pass additional arguments
                use_gil = invoke_around_handlers
                arg = llhelper(TARGET, _make_wrapper_for(TARGET, arg,
                                                         callbackholder,
                                                         use_gil))
            else:
                SOURCE = lltype.typeOf(arg)
                if SOURCE != TARGET:
                    if TARGET is lltype.Float:
                        arg = float(arg)
                    elif ((isinstance(SOURCE, lltype.Number)
                           or SOURCE is lltype.Bool)
                      and (isinstance(TARGET, lltype.Number)
                           or TARGET is lltype.Bool)):
                        arg = cast(TARGET, arg)
            real_args = real_args + (arg,)
            to_free = to_free + (freeme,)
        res = call_external_function(*real_args)
        for i, TARGET in unrolling_arg_tps:
            if to_free[i]:
                lltype.free(to_free[i], flavor='raw')
        if rarithmetic.r_int is not r_int:
            if result is INT:
                return cast(lltype.Signed, res)
            elif result is UINT:
                return cast(lltype.Unsigned, res)
        return res
    wrapper._annspecialcase_ = 'specialize:ll'
    wrapper._always_inline_ = 'try'
    # for debugging, stick ll func ptr to that
    wrapper._ptr = funcptr
    wrapper = func_with_new_name(wrapper, name)

    if calling_conv != "c":
        wrapper = jit.dont_look_inside(wrapper)

    return wrapper
    def _run(self,
             atypes,
             rtype,
             avalues,
             rvalue,
             expected_call_release_gil=1,
             supports_floats=True,
             supports_longlong=False,
             supports_singlefloats=False):

        cif_description = get_description(atypes, rtype)

        def verify(*args):
            for a, exp_a in zip(args, avalues):
                if (lltype.typeOf(exp_a) == rffi.ULONG
                        and lltype.typeOf(a) == lltype.Signed):
                    a = rffi.cast(rffi.ULONG, a)
                assert a == exp_a
            return rvalue

        FUNC = lltype.FuncType([lltype.typeOf(avalue) for avalue in avalues],
                               lltype.typeOf(rvalue))
        func = lltype.functionptr(FUNC, 'verify', _callable=verify)
        func_addr = rffi.cast(rffi.VOIDP, func)

        for i in range(len(avalues)):
            cif_description.exchange_args[i] = (i + 1) * 16
        cif_description.exchange_result = (len(avalues) + 1) * 16

        unroll_avalues = unrolling_iterable(avalues)

        def fake_call_impl_any(cif_description, func_addr, exchange_buffer):
            ofs = 16
            for avalue in unroll_avalues:
                TYPE = rffi.CArray(lltype.typeOf(avalue))
                data = rffi.ptradd(exchange_buffer, ofs)
                got = rffi.cast(lltype.Ptr(TYPE), data)[0]
                if lltype.typeOf(avalue) is lltype.SingleFloat:
                    got = float(got)
                    avalue = float(avalue)
                elif (lltype.typeOf(avalue) is rffi.SIGNEDCHAR
                      or lltype.typeOf(avalue) is rffi.UCHAR):
                    got = intmask(got)
                    avalue = intmask(avalue)
                assert got == avalue
                ofs += 16
            if rvalue is not None:
                write_rvalue = rvalue
            else:
                write_rvalue = 12923  # ignored
            TYPE = rffi.CArray(lltype.typeOf(write_rvalue))
            data = rffi.ptradd(exchange_buffer, ofs)
            rffi.cast(lltype.Ptr(TYPE), data)[0] = write_rvalue

        def f(i):
            exbuf = lltype.malloc(rffi.CCHARP.TO, (len(avalues) + 2) * 16,
                                  flavor='raw')

            targetptr = rffi.ptradd(exbuf, 16)
            for avalue in unroll_avalues:
                TYPE = rffi.CArray(lltype.typeOf(avalue))
                if i >= 9:  # a guard that can fail
                    pass
                rffi.cast(lltype.Ptr(TYPE), targetptr)[0] = avalue
                targetptr = rffi.ptradd(targetptr, 16)

            jit_ffi_call(cif_description, func_addr, exbuf)

            if rvalue is None:
                res = 654321
            else:
                TYPE = rffi.CArray(lltype.typeOf(rvalue))
                res = rffi.cast(lltype.Ptr(TYPE), targetptr)[0]
            lltype.free(exbuf, flavor='raw')
            if lltype.typeOf(res) is lltype.SingleFloat:
                res = float(res)
            return res

        def matching_result(res, rvalue):
            if rvalue is None:
                return res == 654321
            if isinstance(rvalue, r_singlefloat):
                rvalue = float(rvalue)
            if lltype.typeOf(rvalue) is rffi.ULONG:
                res = intmask(res)
                rvalue = intmask(rvalue)
            return res == rvalue

        with FakeFFI(fake_call_impl_any):
            res = f(-42)
            assert matching_result(res, rvalue)
            res = self.interp_operations(
                f, [-42],
                supports_floats=supports_floats,
                supports_longlong=supports_longlong,
                supports_singlefloats=supports_singlefloats)
            if is_longlong(FUNC.RESULT):
                # longlongs are returned as floats, but that's just
                # an inconvenience of interp_operations().  Normally both
                # longlong and floats are passed around as longlongs.
                res = float2longlong(res)
            assert matching_result(res, rvalue)
            self.check_operations_history(
                call_may_force=0, call_release_gil=expected_call_release_gil)

            ##################################################
            driver = jit.JitDriver(reds=['i'], greens=[])

            def main():
                i = 0
                while 1:
                    driver.jit_merge_point(i=i)
                    res = f(i)
                    i += 1
                    if i == 12:
                        return res

            self.meta_interp(main, [])
Ejemplo n.º 50
0
    def _run(self, atypes, rtype, avalues, rvalue,
             expected_call_release_gil=1,
             supports_floats=True,
             supports_longlong=False,
             supports_singlefloats=False):

        cif_description = get_description(atypes, rtype)

        def verify(*args):
            for a, exp_a in zip(args, avalues):
                if (lltype.typeOf(exp_a) == rffi.ULONG and
                    lltype.typeOf(a) == lltype.Signed):
                    a = rffi.cast(rffi.ULONG, a)
                assert a == exp_a
            return rvalue
        FUNC = lltype.FuncType([lltype.typeOf(avalue) for avalue in avalues],
                               lltype.typeOf(rvalue))
        func = lltype.functionptr(FUNC, 'verify', _callable=verify)
        func_addr = rffi.cast(rffi.VOIDP, func)

        for i in range(len(avalues)):
            cif_description.exchange_args[i] = (i+1) * 16
        cif_description.exchange_result = (len(avalues)+1) * 16

        unroll_avalues = unrolling_iterable(avalues)

        def fake_call_impl_any(cif_description, func_addr, exchange_buffer):
            ofs = 16
            for avalue in unroll_avalues:
                TYPE = rffi.CArray(lltype.typeOf(avalue))
                data = rffi.ptradd(exchange_buffer, ofs)
                got = rffi.cast(lltype.Ptr(TYPE), data)[0]
                if lltype.typeOf(avalue) is lltype.SingleFloat:
                    got = float(got)
                    avalue = float(avalue)
                elif (lltype.typeOf(avalue) is rffi.SIGNEDCHAR or
                      lltype.typeOf(avalue) is rffi.UCHAR):
                    got = intmask(got)
                    avalue = intmask(avalue)
                assert got == avalue
                ofs += 16
            if rvalue is not None:
                write_rvalue = rvalue
            else:
                write_rvalue = 12923  # ignored
            TYPE = rffi.CArray(lltype.typeOf(write_rvalue))
            data = rffi.ptradd(exchange_buffer, ofs)
            rffi.cast(lltype.Ptr(TYPE), data)[0] = write_rvalue

        def f(i):
            exbuf = lltype.malloc(rffi.CCHARP.TO, (len(avalues)+2) * 16,
                                  flavor='raw')

            targetptr = rffi.ptradd(exbuf, 16)
            for avalue in unroll_avalues:
                TYPE = rffi.CArray(lltype.typeOf(avalue))
                if i >= 9:    # a guard that can fail
                    pass
                rffi.cast(lltype.Ptr(TYPE), targetptr)[0] = avalue
                targetptr = rffi.ptradd(targetptr, 16)

            jit_ffi_call(cif_description, func_addr, exbuf)

            if rvalue is None:
                res = 654321
            else:
                TYPE = rffi.CArray(lltype.typeOf(rvalue))
                res = rffi.cast(lltype.Ptr(TYPE), targetptr)[0]
            lltype.free(exbuf, flavor='raw')
            if lltype.typeOf(res) is lltype.SingleFloat:
                res = float(res)
            return res

        def matching_result(res, rvalue):
            if rvalue is None:
                return res == 654321
            if isinstance(rvalue, r_singlefloat):
                rvalue = float(rvalue)
            if lltype.typeOf(rvalue) is rffi.ULONG:
                res = intmask(res)
                rvalue = intmask(rvalue)
            return res == rvalue

        with FakeFFI(fake_call_impl_any):
            res = f(-42)
            assert matching_result(res, rvalue)
            res = self.interp_operations(f, [-42],
                            supports_floats = supports_floats,
                          supports_longlong = supports_longlong,
                      supports_singlefloats = supports_singlefloats)
            if is_longlong(FUNC.RESULT):
                # longlongs are returned as floats, but that's just
                # an inconvenience of interp_operations().  Normally both
                # longlong and floats are passed around as longlongs.
                res = float2longlong(res)
            assert matching_result(res, rvalue)
            self.check_operations_history(call_may_force=0,
                                          call_release_gil=expected_call_release_gil)

            ##################################################
            driver = jit.JitDriver(reds=['i'], greens=[])
            def main():
                i = 0
                while 1:
                    driver.jit_merge_point(i=i)
                    res = f(i)
                    i += 1
                    if i == 12:
                        return res
            self.meta_interp(main, [])
Ejemplo n.º 51
0
 def getfunctionptr(graph):
     F = lltype.FuncType([], lltype.Signed)
     return lltype.functionptr(F, 'bar')
Ejemplo n.º 52
0
 def getexternalcallable(self, ll_args, ll_result, name, **kwds):
     FT = lltype.FuncType(ll_args, ll_result)
     return lltype.functionptr(FT, name, **kwds)