def test_cancollect_external(): fext1 = rffi.llexternal('fext1', [], lltype.Void, threadsafe=False) def g(): fext1() t = rtype(g, []) gg = graphof(t, g) assert not CollectAnalyzer(t).analyze_direct_call(gg) fext2 = rffi.llexternal('fext2', [], lltype.Void, threadsafe=True) def g(): fext2() t = rtype(g, []) gg = graphof(t, g) assert CollectAnalyzer(t).analyze_direct_call(gg) S = lltype.GcStruct('S', ('x', lltype.Signed)) FUNC = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) fext3 = rffi.llexternal('fext3', [FUNC], lltype.Void, threadsafe=False) def h(x): lltype.malloc(S, zero=True) def g(): fext3(h) t = rtype(g, []) gg = graphof(t, g) assert CollectAnalyzer(t).analyze_direct_call(gg)
def external(name, args, result): unsafe = rffi.llexternal(name, args, result, compilation_info=CConfig._compilation_info_) safe = rffi.llexternal(name, args, result, compilation_info=CConfig._compilation_info_, sandboxsafe=True, threadsafe=False) return unsafe, safe
def test_different_signatures(self): fcntl_int = rffi.llexternal('fcntl', [rffi.INT, rffi.INT, rffi.INT], rffi.INT) fcntl_str = rffi.llexternal('fcntl', [rffi.INT, rffi.INT, rffi.CCHARP], rffi.INT) fcntl_int(12345, 1, 0) fcntl_str(12345, 3, "xxx") fcntl_int(12345, 1, 0)
def setup_init_functions(eci): init_buffer = rffi.llexternal('init_bufferobject', [], lltype.Void, compilation_info=eci) init_pycobject = rffi.llexternal('init_pycobject', [], lltype.Void, compilation_info=eci) init_capsule = rffi.llexternal('init_capsule', [], lltype.Void, compilation_info=eci) INIT_FUNCTIONS.extend([ lambda space: init_buffer(), lambda space: init_pycobject(), lambda space: init_capsule(), ])
def test_different_signatures(self): if sys.platform=='win32': py.test.skip("No fcntl on win32") fcntl_int = rffi.llexternal('fcntl', [rffi.INT, rffi.INT, rffi.INT], rffi.INT) fcntl_str = rffi.llexternal('fcntl', [rffi.INT, rffi.INT, rffi.CCHARP], rffi.INT) fcntl_int(12345, 1, 0) fcntl_str(12345, 3, "xxx") fcntl_int(12345, 1, 0)
def test_different_signatures(self): if sys.platform == 'win32': py.test.skip("No fcntl on win32") fcntl_int = rffi.llexternal('fcntl', [rffi.INT, rffi.INT, rffi.INT], rffi.INT) fcntl_str = rffi.llexternal('fcntl', [rffi.INT, rffi.INT, rffi.CCHARP], rffi.INT) fcntl_int(12345, 1, 0) fcntl_str(12345, 3, "xxx") fcntl_int(12345, 1, 0)
def test_llexternal_macro(self): eci = ExternalCompilationInfo( post_include_bits = ["#define fn(x) (42 + x)"], ) fn1 = rffi.llexternal('fn', [rffi.INT], rffi.INT, compilation_info=eci, macro=True) fn2 = rffi.llexternal('fn2', [rffi.DOUBLE], rffi.DOUBLE, compilation_info=eci, macro='fn') res = fn1(10) assert res == 52 res = fn2(10.5) assert res == 52.5
def test_opaque_obj_2(self): FILEP = rffi.COpaquePtr('FILE') fopen = rffi.llexternal('fopen', [rffi.CCHARP, rffi.CCHARP], FILEP) fclose = rffi.llexternal('fclose', [FILEP], rffi.INT) tmppath = udir.join('test_ll2ctypes.test_opaque_obj_2') ll_file = fopen(str(tmppath), "w") assert ll_file fclose(ll_file) assert tmppath.check(file=1) assert not ALLOCATED # detects memory leaks in the test assert rffi.cast(FILEP, -1) == rffi.cast(FILEP, -1)
def setup_init_functions(eci): init_buffer = rffi.llexternal('init_bufferobject', [], lltype.Void, compilation_info=eci) init_pycobject = rffi.llexternal('init_pycobject', [], lltype.Void, compilation_info=eci) init_capsule = rffi.llexternal('init_capsule', [], lltype.Void, compilation_info=eci) INIT_FUNCTIONS.extend([ lambda space: init_buffer(), lambda space: init_pycobject(), lambda space: init_capsule(), ]) from pypy.module.posix.interp_posix import add_fork_hook reinit_tls = rffi.llexternal('PyThread_ReInitTLS', [], lltype.Void, compilation_info=eci) add_fork_hook('child', reinit_tls)
def test_func_not_in_clib(): foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed) py.test.raises(NotImplementedError, foobar) foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed, libraries=['m']) # math library py.test.raises(NotImplementedError, foobar) foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed, libraries=['m', 'z']) # math and zlib libraries py.test.raises(NotImplementedError, foobar) foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed, libraries=['I_really_dont_exist_either']) py.test.raises(NotImplementedError, foobar)
def test_qsort(self): CMPFUNC = lltype.FuncType([rffi.VOIDP, rffi.VOIDP], rffi.INT) qsort = rffi.llexternal( 'qsort', [rffi.VOIDP, rffi.SIZE_T, rffi.SIZE_T, lltype.Ptr(CMPFUNC)], lltype.Void) lst = [23, 43, 24, 324, 242, 34, 78, 5, 3, 10] A = lltype.Array(lltype.Signed, hints={'nolength': True}) a = lltype.malloc(A, 10, flavor='raw') for i in range(10): a[i] = lst[i] SIGNEDPTR = lltype.Ptr(lltype.FixedSizeArray(lltype.Signed, 1)) def my_compar(p1, p2): p1 = rffi.cast(SIGNEDPTR, p1) p2 = rffi.cast(SIGNEDPTR, p2) print 'my_compar:', p1[0], p2[0] return rffi.cast(rffi.INT, cmp(p1[0], p2[0])) qsort(rffi.cast(rffi.VOIDP, a), rffi.cast(rffi.SIZE_T, 10), rffi.cast(rffi.SIZE_T, llmemory.sizeof(lltype.Signed)), llhelper(lltype.Ptr(CMPFUNC), my_compar)) for i in range(10): print a[i], print lst.sort() for i in range(10): assert a[i] == lst[i] lltype.free(a, flavor='raw') assert not ALLOCATED # detects memory leaks in the test
def test_llexternal_source(self): eci = ExternalCompilationInfo( separate_module_sources = ["int fn() { return 42; }"] ) fn = rffi.llexternal('fn', [], rffi.INT, compilation_info=eci) res = fn() assert res == 42
def define_callback_simple(cls): c_source = py.code.Source(""" int mystuff(int(*cb)(int, int)) { return cb(40, 2) + cb(3, 4); } """) eci = ExternalCompilationInfo(separate_module_sources=[c_source]) S = lltype.GcStruct('S', ('x', lltype.Signed)) CALLBACK = lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed) z = rffi.llexternal('mystuff', [lltype.Ptr(CALLBACK)], lltype.Signed, compilation_info=eci) def mycallback(a, b): gc.collect() return a + b def f(): p = lltype.malloc(S) p.x = 100 result = z(mycallback) return result * p.x return f
def install_dll(self, eci): """NOT_RPYTHON Called when the dll has been compiled""" if sys.platform == 'win32': self.get_pythonapi_handle = rffi.llexternal( 'pypy_get_pythonapi_handle', [], DLLHANDLE, compilation_info=eci)
def test_pass_around_t_object(self): from pypy.rpython.annlowlevel import base_ptr_lltype T = base_ptr_lltype() class X(object): _TYPE = T x = 10 def callback(x): return x.x c_source = py.code.Source(""" long eating_callback(void *arg, long(*call)(void*)) { return call(arg); } """) eci = ExternalCompilationInfo(separate_module_sources=[c_source], export_symbols=['eating_callback']) args = [T, rffi.CCallback([T], rffi.LONG)] eating_callback = rffi.llexternal('eating_callback', args, rffi.LONG, compilation_info=eci) res = eating_callback(X(), callback) assert res == 10
def external(name, args, result, eci=CConfig._compilation_info_): if _WIN and rffi.sizeof(rffi.TIME_T) == 8: # Recent Microsoft compilers use 64bit time_t and # the corresponding functions are named differently if rffi.TIME_T in args or rffi.TIME_TP in args or result in (rffi.TIME_T, rffi.TIME_TP): name = "_" + name + "64" return rffi.llexternal(name, args, result, compilation_info=eci, calling_conv=calling_conv, threadsafe=False)
def test_pass_around_t_object(self): from pypy.rpython.annlowlevel import base_ptr_lltype T = base_ptr_lltype() class X(object): _TYPE = T x = 10 def callback(x): return x.x c_source = py.code.Source(""" int eating_callback(void *arg, int(*call)(int)) { return call(arg); } """) eci = ExternalCompilationInfo(separate_module_sources=[c_source], export_symbols=['eating_callback']) args = [T, rffi.CCallback([T], rffi.INT)] eating_callback = rffi.llexternal('eating_callback', args, rffi.INT, compilation_info=eci) res = eating_callback(X(), callback) assert res == 10
def test_llexternal_with_callback(self): from pypy.rpython.lltypesystem.rffi import llexternal from pypy.rpython.lltypesystem import lltype class Abc: pass abc = Abc() FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) z = llexternal('z', [lltype.Ptr(FUNC)], lltype.Signed) def g(n): abc.foobar = n return n + 1 def f(x): return z(g) t, wa = self.translate(f, [int]) fgraph = graphof(t, f) backend_optimizations(t) assert fgraph.startblock.operations[0].opname == 'direct_call' result = wa.analyze(fgraph.startblock.operations[0]) assert len(result) == 1 (struct, T, name), = result assert struct == "struct" assert name.endswith("foobar")
def llexternal(name, args, result, **kwds): return rffi.llexternal(name, args, result, compilation_info=eci, _nowrapper=True, **kwds)
def test_llexternal(self): from pypy.rpython.lltypesystem.rffi import llexternal from pypy.rpython.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
def test_qsort(self): CMPFUNC = lltype.FuncType([rffi.VOIDP, rffi.VOIDP], rffi.INT) qsort = rffi.llexternal('qsort', [rffi.VOIDP, rffi.SIZE_T, rffi.SIZE_T, lltype.Ptr(CMPFUNC)], lltype.Void) lst = [23, 43, 24, 324, 242, 34, 78, 5, 3, 10] A = lltype.Array(lltype.Signed, hints={'nolength': True}) a = lltype.malloc(A, 10, flavor='raw') for i in range(10): a[i] = lst[i] SIGNEDPTR = lltype.Ptr(lltype.FixedSizeArray(lltype.Signed, 1)) def my_compar(p1, p2): p1 = rffi.cast(SIGNEDPTR, p1) p2 = rffi.cast(SIGNEDPTR, p2) print 'my_compar:', p1[0], p2[0] return rffi.cast(rffi.INT, cmp(p1[0], p2[0])) qsort(rffi.cast(rffi.VOIDP, a), rffi.cast(rffi.SIZE_T, 10), rffi.cast(rffi.SIZE_T, llmemory.sizeof(lltype.Signed)), llhelper(lltype.Ptr(CMPFUNC), my_compar)) for i in range(10): print a[i], print lst.sort() for i in range(10): assert a[i] == lst[i] lltype.free(a, flavor='raw') assert not ALLOCATED # detects memory leaks in the test
def external(name, args, result, **kwds): return rffi.llexternal(name, args, result, compilation_info=eci, sandboxsafe=True, **kwds)
def setup_va_functions(eci): for name, TP in VA_TP_LIST.iteritems(): name_no_star = process_va_name(name) func = rffi.llexternal('pypy_va_get_%s' % name_no_star, [VA_LIST_P], TP, compilation_info=eci) globals()['va_get_%s' % name_no_star] = func
def winexternal(name, args, result, **kwds): return rffi.llexternal(name, args, result, compilation_info=eci, calling_conv='win', **kwds)
def configure_boehm_once(cls): """ Configure boehm only once, since we don't cache failures """ if hasattr(cls, 'malloc_fn_ptr'): return cls.malloc_fn_ptr from pypy.rpython.tool import rffi_platform compilation_info = rffi_platform.configure_boehm() # Versions 6.x of libgc needs to use GC_local_malloc(). # Versions 7.x of libgc removed this function; GC_malloc() has # the same behavior if libgc was compiled with # THREAD_LOCAL_ALLOC. class CConfig: _compilation_info_ = compilation_info HAS_LOCAL_MALLOC = rffi_platform.Has("GC_local_malloc") config = rffi_platform.configure(CConfig) if config['HAS_LOCAL_MALLOC']: GC_MALLOC = "GC_local_malloc" else: GC_MALLOC = "GC_malloc" malloc_fn_ptr = rffi.llexternal(GC_MALLOC, [lltype.Signed], # size_t, but good enough llmemory.GCREF, compilation_info=compilation_info, sandboxsafe=True, _nowrapper=True) cls.malloc_fn_ptr = malloc_fn_ptr cls.compilation_info = compilation_info return malloc_fn_ptr
def test_gcc_options(self): # check that the env var CC is correctly interpreted, even if # it contains the compiler name followed by some options. if sys.platform == 'win32': py.test.skip("only for gcc") from pypy.rpython.lltypesystem import lltype, rffi dir = udir.ensure('test_gcc_options', dir=1) dir.join('someextraheader.h').write('#define someextrafunc() 42\n') eci = ExternalCompilationInfo(includes=['someextraheader.h']) someextrafunc = rffi.llexternal('someextrafunc', [], lltype.Signed, compilation_info=eci) def entry_point(argv): return someextrafunc() old_cc = os.environ.get('CC') try: os.environ['CC'] = 'gcc -I%s' % dir t, cbuilder = self.compile(entry_point) finally: if old_cc is None: del os.environ['CC'] else: os.environ['CC'] = old_cc
def winexternal(name, args, result, **kwargs): return rffi.llexternal(name, args, result, compilation_info=CConfig._compilation_info_, calling_conv='win', **kwargs)
def llexternal(name, ARGS, RESULT, **kwargs): return rffi.llexternal(name, ARGS, RESULT, compilation_info=eci, sandboxsafe=True, **kwargs)
def external(name, args, result): return rffi.llexternal(name, args, result, compilation_info=CConfig._compilation_info_, calling_conv=calling_conv, threadsafe=False)
def define_callback_simple(cls): import gc from pypy.rpython.lltypesystem import lltype, rffi from pypy.rpython.annlowlevel import llhelper from pypy.translator.tool.cbuild import ExternalCompilationInfo c_source = py.code.Source(""" int mystuff(int(*cb)(int, int)) { return cb(40, 2) + cb(3, 4); } """) eci = ExternalCompilationInfo(separate_module_sources=[c_source]) S = lltype.GcStruct('S', ('x', lltype.Signed)) CALLBACK = lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed) z = rffi.llexternal('mystuff', [lltype.Ptr(CALLBACK)], lltype.Signed, compilation_info=eci) def mycallback(a, b): gc.collect() return a + b def f(): p = lltype.malloc(S) p.x = 100 result = z(mycallback) return result * p.x return f
def register_stat_variant(name): if sys.platform.startswith('win'): _functions = { 'stat': '_stati64', 'fstat': '_fstati64', 'lstat': '_stati64' } # no lstat on Windows c_func_name = _functions[name] elif sys.platform.startswith('linux'): # because we always use _FILE_OFFSET_BITS 64 - this helps things work that are not a c compiler _functions = {'stat': 'stat64', 'fstat': 'fstat64', 'lstat': 'lstat64'} c_func_name = _functions[name] else: c_func_name = name arg_is_path = (name != 'fstat') if arg_is_path: ARG1 = rffi.CCHARP else: ARG1 = rffi.INT os_mystat = rffi.llexternal(c_func_name, [ARG1, STAT_STRUCT], rffi.INT, compilation_info=compilation_info) def os_mystat_llimpl(arg): stresult = lltype.malloc(STAT_STRUCT.TO, flavor='raw') try: if arg_is_path: arg = rffi.str2charp(arg) error = rffi.cast(rffi.LONG, os_mystat(arg, stresult)) if arg_is_path: rffi.free_charp(arg) if error != 0: raise OSError(rposix.get_errno(), "os_?stat failed") return build_stat_result(stresult) finally: lltype.free(stresult, flavor='raw') def fakeimpl(arg): st = getattr(os, name)(arg) fields = [TYPE for fieldname, TYPE in LL_STAT_FIELDS] TP = TUPLE_TYPE(fields) ll_tup = lltype.malloc(TP.TO) for i, (fieldname, TYPE) in enumerate(LL_STAT_FIELDS): val = getattr(st, fieldname) rffi.setintfield(ll_tup, 'item%d' % i, int(val)) return ll_tup if arg_is_path: s_arg = str else: s_arg = int register_external(getattr(os, name), [s_arg], s_StatResult, "ll_os.ll_os_%s" % (name, ), llimpl=func_with_new_name(os_mystat_llimpl, 'os_%s_llimpl' % (name, )), llfakeimpl=func_with_new_name(fakeimpl, 'os_%s_fake' % (name, )))
def test_llexternal_source(self): eci = ExternalCompilationInfo( separate_module_sources=["int fn() { return 42; }"], export_symbols=['fn'], ) fn = rffi.llexternal('fn', [], rffi.INT, compilation_info=eci) res = fn() assert res == 42
def llexternal(name, args, res, _callable=None): return rffi.llexternal(name, args, res, compilation_info=compilation_info, sandboxsafe=True, _nowrapper=True, _callable=_callable)
def __init__(self, rtyper, stats=None, translate_support_code=False, annmixlevel=None, gcdescr=None): self.rtyper = rtyper self.translate_support_code = translate_support_code self.compiled_functions = [] self.fail_ops = [] self.in_out_args = [] if translate_support_code: get_size = llmemory.sizeof else: get_size = rffi.sizeof self._arraydescrs = [ ArrayDescr(get_size(llmemory.GCREF), self.SIZE_GCPTR), # 0 ArrayDescr(get_size(lltype.Signed), self.SIZE_INT), # 1 ArrayDescr(get_size(lltype.Char), self.SIZE_CHAR), # 2 ArrayDescr(get_size(lltype.UniChar), self.SIZE_UNICHAR), # 3 ] self._descr_caches = {} self.fielddescr_vtable = self.fielddescrof(rclass.OBJECT, 'typeptr') if sys.maxint == 2147483647: self.size_of_int = 4 else: self.size_of_int = 8 if runicode.MAXUNICODE > 0xffff: self.size_of_unicode = 4 else: self.size_of_unicode = 2 self.gcarray_gcref = lltype.GcArray(llmemory.GCREF) self.gcarray_signed = lltype.GcArray(lltype.Signed) self.gcarray_char = lltype.GcArray(lltype.Char) self.gcarray_unichar = lltype.GcArray(lltype.UniChar) basesize, _, ofs_length = symbolic.get_array_token( self.gcarray_signed, self.translate_support_code) self.array_index_array = basesize self.array_index_length = ofs_length basesize, _, ofs_length = symbolic.get_array_token( rstr.STR, self.translate_support_code) self.string_index_array = basesize self.string_index_length = ofs_length basesize, _, ofs_length = symbolic.get_array_token( rstr.UNICODE, self.translate_support_code) self.unicode_index_array = basesize self.unicode_index_length = ofs_length self.vtable_descr = self.fielddescrof(rclass.OBJECT, 'typeptr') self._ovf_error_instance = self._get_prebuilt_error(OverflowError) self._zer_error_instance = self._get_prebuilt_error(ZeroDivisionError) # # temporary (Boehm only) from pypy.translator.tool.cbuild import ExternalCompilationInfo compilation_info = ExternalCompilationInfo(libraries=['gc']) self.malloc_fn_ptr = rffi.llexternal("GC_malloc", [rffi.SIZE_T], llmemory.GCREF, compilation_info=compilation_info, sandboxsafe=True, _nowrapper=True) assert rffi.sizeof(rffi.SIZE_T) == self.size_of_int
def proc_func(self, func): name = func.__name__ arg_tps = [self.proc_tp(arg) for arg in func.argtypes] ll_item = rffi.llexternal( name, arg_tps, self.proc_tp(func.restype), compilation_info=self.CConfig._compilation_info_) self.ns[name] = ll_item return ll_item
def test_rand(self): eci = ExternalCompilationInfo(includes=['stdlib.h']) rand = rffi.llexternal('rand', [], rffi.INT, compilation_info=eci) srand = rffi.llexternal('srand', [rffi.UINT], lltype.Void, compilation_info=eci) srand(rffi.r_uint(123)) res1 = rand() res2 = rand() res3 = rand() srand(rffi.r_uint(123)) res1b = rand() res2b = rand() res3b = rand() assert res1 == res1b assert res2 == res2b assert res3 == res3b assert not ALLOCATED # detects memory leaks in the test
def register_stat_variant(name): if sys.platform.startswith('win'): _functions = {'stat': '_stati64', 'fstat': '_fstati64', 'lstat': '_stati64'} # no lstat on Windows c_func_name = _functions[name] elif sys.platform.startswith('linux'): # because we always use _FILE_OFFSET_BITS 64 - this helps things work that are not a c compiler _functions = {'stat': 'stat64', 'fstat': 'fstat64', 'lstat': 'lstat64'} c_func_name = _functions[name] else: c_func_name = name arg_is_path = (name != 'fstat') if arg_is_path: ARG1 = rffi.CCHARP else: ARG1 = rffi.INT os_mystat = rffi.llexternal(c_func_name, [ARG1, STAT_STRUCT], rffi.INT, compilation_info=compilation_info) def os_mystat_llimpl(arg): stresult = lltype.malloc(STAT_STRUCT.TO, flavor='raw') try: if arg_is_path: arg = rffi.str2charp(arg) error = rffi.cast(rffi.LONG, os_mystat(arg, stresult)) if arg_is_path: rffi.free_charp(arg) if error != 0: raise OSError(rposix.get_errno(), "os_?stat failed") return build_stat_result(stresult) finally: lltype.free(stresult, flavor='raw') def fakeimpl(arg): st = getattr(os, name)(arg) fields = [TYPE for fieldname, TYPE in LL_STAT_FIELDS] TP = TUPLE_TYPE(fields) ll_tup = lltype.malloc(TP.TO) for i, (fieldname, TYPE) in enumerate(LL_STAT_FIELDS): val = getattr(st, fieldname) rffi.setintfield(ll_tup, 'item%d' % i, int(val)) return ll_tup if arg_is_path: s_arg = str else: s_arg = int register_external(getattr(os, name), [s_arg], s_StatResult, "ll_os.ll_os_%s" % (name,), llimpl=func_with_new_name(os_mystat_llimpl, 'os_%s_llimpl' % (name,)), llfakeimpl=func_with_new_name(fakeimpl, 'os_%s_fake' % (name,)))
def llexternal(self, *args, **kwds): kwds = kwds.copy() from pypy.rpython.lltypesystem import rffi if 'compilation_info' in kwds: kwds['compilation_info'] = self.compilation_info.merge( kwds['compilation_info']) else: kwds['compilation_info'] = self.compilation_info return rffi.llexternal(*args, **kwds)
def external(name, args, result, calling_conv="c", **kwds): return rffi.llexternal( name, args, result, compilation_info=CConfig._compilation_info_, calling_conv=calling_conv, sandboxsafe=True, **kwds )
def test_func_not_in_clib(self): eci = ExternalCompilationInfo(libraries=['m']) foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed) py.test.raises(NotImplementedError, foobar) foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed, compilation_info=eci) # math library py.test.raises(NotImplementedError, foobar) eci = ExternalCompilationInfo(libraries=['m', 'z']) foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed, compilation_info=eci) # math and zlib py.test.raises(NotImplementedError, foobar) eci = ExternalCompilationInfo(libraries=['I_really_dont_exist_either']) foobar = rffi.llexternal('I_really_dont_exist', [], lltype.Signed, compilation_info=eci) py.test.raises(NotImplementedError, foobar) assert not ALLOCATED # detects memory leaks in the test
def external(name, args, result, eci=CConfig._compilation_info_): if _WIN and rffi.sizeof(rffi.TIME_T) == 8: # Recent Microsoft compilers use 64bit time_t and # the corresponding functions are named differently if (rffi.TIME_T in args or rffi.TIME_TP in args or result in (rffi.TIME_T, rffi.TIME_TP)): name = '_' + name + '64' return rffi.llexternal(name, args, result, compilation_info=eci, calling_conv=calling_conv, threadsafe=False)
def test_strlen(): strlen = rffi.llexternal('strlen', [rffi.CCHARP], lltype.Signed, includes=['string.h']) s = rffi.str2charp("xxx") res = strlen(s) rffi.free_charp(s) assert res == 3 s = rffi.str2charp("") res = strlen(s) rffi.free_charp(s) assert res == 0
def __init__(self, translator, inline=False): super(BoehmGCTransformer, self).__init__(translator, inline=inline) self.finalizer_funcptrs = {} atomic_mh = mallocHelpers() atomic_mh.allocate = lambda size: llop.boehm_malloc_atomic(llmemory.Address, size) ll_malloc_fixedsize_atomic = atomic_mh._ll_malloc_fixedsize mh = mallocHelpers() mh.allocate = lambda size: llop.boehm_malloc(llmemory.Address, size) c_realloc = rffi.llexternal('GC_REALLOC', [rffi.VOIDP, rffi.INT], rffi.VOIDP, sandboxsafe=True) def _realloc(ptr, size): return llmemory.cast_ptr_to_adr(c_realloc(rffi.cast(rffi.VOIDP, ptr), size)) mh.realloc = _realloc ll_malloc_fixedsize = mh._ll_malloc_fixedsize # XXX, do we need/want an atomic version of this function? ll_malloc_varsize_no_length = mh.ll_malloc_varsize_no_length ll_malloc_varsize = mh.ll_malloc_varsize ll_realloc = mh.ll_realloc HDRPTR = lltype.Ptr(self.HDR) def ll_identityhash(addr): obj = llmemory.cast_adr_to_ptr(addr, HDRPTR) h = obj.hash if h == 0: obj.hash = h = ~llmemory.cast_adr_to_int(addr) return h if self.translator: self.malloc_fixedsize_ptr = self.inittime_helper( ll_malloc_fixedsize, [lltype.Signed], llmemory.Address) self.malloc_fixedsize_atomic_ptr = self.inittime_helper( ll_malloc_fixedsize_atomic, [lltype.Signed], llmemory.Address) self.malloc_varsize_no_length_ptr = self.inittime_helper( ll_malloc_varsize_no_length, [lltype.Signed]*3, llmemory.Address, inline=False) self.malloc_varsize_ptr = self.inittime_helper( ll_malloc_varsize, [lltype.Signed]*4, llmemory.Address, inline=False) self.weakref_create_ptr = self.inittime_helper( ll_weakref_create, [llmemory.Address], llmemory.WeakRefPtr, inline=False) self.weakref_deref_ptr = self.inittime_helper( ll_weakref_deref, [llmemory.WeakRefPtr], llmemory.Address) self.realloc_ptr = self.inittime_helper( ll_realloc, [llmemory.Address] + [lltype.Signed] * 4, llmemory.Address) self.identityhash_ptr = self.inittime_helper( ll_identityhash, [llmemory.Address], lltype.Signed, inline=False) self.mixlevelannotator.finish() # for now self.mixlevelannotator.backend_optimize()
def new_unary_math_function(name): c_func = rffi.llexternal(name, [rffi.DOUBLE], rffi.DOUBLE, compilation_info=eci, sandboxsafe=True) def ll_math(x): _error_reset() r = c_func(x) _check_error(r) return r return func_with_new_name(ll_math, 'll_math_' + name)
def configure_boehm_once(cls): """ Configure boehm only once, since we don't cache failures """ if hasattr(cls, 'malloc_fn_ptr'): return cls.malloc_fn_ptr from pypy.rpython.tool import rffi_platform compilation_info = rffi_platform.configure_boehm() # on some platform GC_init is required before any other # GC_* functions, call it here for the benefit of tests # XXX move this to tests init_fn_ptr = rffi.llexternal("GC_init", [], lltype.Void, compilation_info=compilation_info, sandboxsafe=True, _nowrapper=True) init_fn_ptr() # Versions 6.x of libgc needs to use GC_local_malloc(). # Versions 7.x of libgc removed this function; GC_malloc() has # the same behavior if libgc was compiled with # THREAD_LOCAL_ALLOC. class CConfig: _compilation_info_ = compilation_info HAS_LOCAL_MALLOC = rffi_platform.Has("GC_local_malloc") config = rffi_platform.configure(CConfig) if config['HAS_LOCAL_MALLOC']: GC_MALLOC = "GC_local_malloc" else: GC_MALLOC = "GC_malloc" malloc_fn_ptr = rffi.llexternal( GC_MALLOC, [lltype.Signed], # size_t, but good enough llmemory.GCREF, compilation_info=compilation_info, sandboxsafe=True, _nowrapper=True) cls.malloc_fn_ptr = malloc_fn_ptr return malloc_fn_ptr