def setup_init_functions(eci, translating): if translating: prefix = "PyPy" else: prefix = "cpyexttest" # jump through hoops to avoid releasing the GIL during initialization # of the cpyext module. The C functions are called with no wrapper, # but must not do anything like calling back PyType_Ready(). We # use them just to get a pointer to the PyTypeObjects defined in C. get_buffer_type = rffi.llexternal( "_%s_get_buffer_type" % prefix, [], PyTypeObjectPtr, compilation_info=eci, _nowrapper=True ) get_cobject_type = rffi.llexternal( "_%s_get_cobject_type" % prefix, [], PyTypeObjectPtr, compilation_info=eci, _nowrapper=True ) get_capsule_type = rffi.llexternal( "_%s_get_capsule_type" % prefix, [], PyTypeObjectPtr, compilation_info=eci, _nowrapper=True ) def init_types(space): from pypy.module.cpyext.typeobject import py_type_ready py_type_ready(space, get_buffer_type()) py_type_ready(space, get_cobject_type()) py_type_ready(space, get_capsule_type()) INIT_FUNCTIONS.append(init_types) from pypy.module.posix.interp_posix import add_fork_hook reinit_tls = rffi.llexternal("%sThread_ReInitTLS" % prefix, [], lltype.Void, compilation_info=eci) add_fork_hook("child", reinit_tls)
def setup(): if host_platform.machine() == 's390x': raise VMProfPlatformUnsupported("rvmprof not supported on" " s390x CPUs for now") compile_extra = ['-DRPYTHON_LL2CTYPES'] platform.verify_eci(ExternalCompilationInfo( compile_extra=compile_extra, **eci_kwds)) eci = global_eci vmprof_init = rffi.llexternal("vmprof_init", [rffi.INT, rffi.DOUBLE, rffi.CCHARP], rffi.CCHARP, compilation_info=eci) vmprof_enable = rffi.llexternal("vmprof_enable", [], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO) vmprof_disable = rffi.llexternal("vmprof_disable", [], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO) vmprof_register_virtual_function = rffi.llexternal( "vmprof_register_virtual_function", [rffi.CCHARP, rffi.LONG, rffi.INT], rffi.INT, compilation_info=eci) vmprof_ignore_signals = rffi.llexternal("vmprof_ignore_signals", [rffi.INT], lltype.Void, compilation_info=eci, _nowrapper=True) return CInterface(locals())
def setup(): from rpython.jit.backend import detect_cpu if detect_cpu.autodetect().startswith(detect_cpu.MODEL_S390_64): raise VMProfPlatformUnsupported("rvmprof not supported on" " s390x CPUs for now") compile_extra = ['-DRPYTHON_LL2CTYPES'] platform.verify_eci(ExternalCompilationInfo( compile_extra=compile_extra, **eci_kwds)) eci = global_eci vmprof_init = rffi.llexternal("vmprof_init", [rffi.INT, rffi.DOUBLE, rffi.CCHARP], rffi.CCHARP, compilation_info=eci) vmprof_enable = rffi.llexternal("vmprof_enable", [], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO) vmprof_disable = rffi.llexternal("vmprof_disable", [], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO) vmprof_register_virtual_function = rffi.llexternal( "vmprof_register_virtual_function", [rffi.CCHARP, rffi.LONG, rffi.INT], rffi.INT, compilation_info=eci) vmprof_ignore_signals = rffi.llexternal("vmprof_ignore_signals", [rffi.INT], lltype.Void, compilation_info=eci, _nowrapper=True) return CInterface(locals())
def test_cancollect_external(): fext1 = rffi.llexternal('fext1', [], lltype.Void, releasegil=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, releasegil=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, releasegil=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, **kwargs): unsafe = rffi.llexternal(name, args, result, compilation_info=CConfig._compilation_info_, **kwargs) safe = rffi.llexternal(name, args, result, compilation_info=CConfig._compilation_info_, sandboxsafe=True, releasegil=False, **kwargs) return unsafe, safe
def test_dict_eq_can_release_gil(self): from rpython.rtyper.lltypesystem import lltype, rffi if type(self.newdict()) is not dict: py.test.skip("this is an r_dict test") T = rffi.CArrayPtr(rffi.TIME_T) external = rffi.llexternal("time", [T], rffi.TIME_T, releasegil=True) myjitdriver = JitDriver(greens = [], reds = ['total', 'dct']) def key(x): return x % 2 def eq(x, y): external(lltype.nullptr(T.TO)) return (x % 2) == (y % 2) def f(n): dct = objectmodel.r_dict(eq, key) total = n x = 44444 y = 55555 z = 66666 while total: myjitdriver.jit_merge_point(total=total, dct=dct) dct[total] = total x = dct[total] y = dct[total] z = dct[total] total -= 1 return len(dct) + x + y + z res = self.meta_interp(f, [10], listops=True) assert res == 2 + 1 + 1 + 1 self.check_simple_loop(call_may_force=4, # ll_dict_lookup_trampoline call=1) # ll_dict_setitem_lookup_done_trampoline
def test_llexternal_with_callback(self): from rpython.rtyper.lltypesystem.rffi import llexternal from rpython.rtyper.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 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_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
def define_secondary_entrypoint_callback(cls): # XXX this is baaaad, cleanup global state try: del secondary_entrypoints["x42"] except KeyError: pass @entrypoint("x42", [lltype.Signed, lltype.Signed], c_name='callback') def mycallback(a, b): gc.collect() return a + b c_source = py.code.Source(""" int mystuff2() { return callback(40, 2) + callback(3, 4); } """) eci = ExternalCompilationInfo(separate_module_sources=[c_source]) z = rffi.llexternal('mystuff2', [], lltype.Signed, compilation_info=eci) S = lltype.GcStruct('S', ('x', lltype.Signed)) cls.secondary_entrypoints = secondary_entrypoints["x42"] def f(): p = lltype.malloc(S) p.x = 100 result = z() return result * p.x return f
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 rpython.rtyper.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 test_call_release_gil(): from rpython.jit.backend.llgraph.runner import LLGraphCPU T = rffi.CArrayPtr(rffi.TIME_T) external = rffi.llexternal("time", [T], rffi.TIME_T, releasegil=True, save_err=rffi.RFFI_SAVE_ERRNO) # no jit.dont_look_inside in this test def f(): return external(lltype.nullptr(T.TO)) rtyper = support.annotate(f, []) jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0]) cc = CallControl(LLGraphCPU(rtyper), jitdrivers_sd=[jitdriver_sd]) res = cc.find_all_graphs(FakePolicy()) [llext_graph] = [x for x in res if x.func is external] [block, _] = list(llext_graph.iterblocks()) [op] = block.operations tgt_tuple = op.args[0].value._obj.graph.func._call_aroundstate_target_ assert type(tgt_tuple) is tuple and len(tgt_tuple) == 2 call_target, saveerr = tgt_tuple assert saveerr == rffi.RFFI_SAVE_ERRNO call_target = llmemory.cast_ptr_to_adr(call_target) call_descr = cc.getcalldescr(op) assert call_descr.extrainfo.has_random_effects() assert call_descr.extrainfo.is_call_release_gil() is True assert call_descr.extrainfo.call_release_gil_target == ( call_target, rffi.RFFI_SAVE_ERRNO)
def test_bridge_from_guard_exception_may_force(self): myjitdriver = JitDriver(greens = [], reds = ['n']) c_time = rffi.llexternal("time", [lltype.Signed], lltype.Signed) def check(n): if n % 2: raise ValueError if n == 100000: c_time(0) def f(n): while n > 0: myjitdriver.can_enter_jit(n=n) myjitdriver.jit_merge_point(n=n) try: check(n) n -= 1 except ValueError: n -= 3 return n res = self.meta_interp(f, [20], policy=StopAtXPolicy(check)) assert res == f(20) res = self.meta_interp(f, [21], policy=StopAtXPolicy(check)) assert res == f(21)
def define_get_set_errno(self): eci = ExternalCompilationInfo( post_include_bits=[r''' #include <errno.h> static int test_get_set_errno(void) { int r = errno; //fprintf(stderr, "read saved errno: %d\n", r); errno = 42; return r; } ''']) c_test = rffi.llexternal('test_get_set_errno', [], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_FULL_ERRNO) def before(n, x): return (n, None, None, None, None, None, None, None, None, None, None, None) # def f(n, x, *args): rposix.set_saved_errno(24) result1 = c_test() result2 = rposix.get_saved_errno() assert result1 == 24 assert result2 == 42 n -= 1 return (n, x) + args return before, f, None
def define_simple(self): class Glob: def __init__(self): self.event = 0 glob = Glob() # c_strchr = rffi.llexternal('strchr', [rffi.CCHARP, lltype.Signed], rffi.CCHARP) def func(): glob.event += 1 def before(n, x): invoke_around_extcall(func, func) return (n, None, None, None, None, None, None, None, None, None, None, None) # def f(n, x, *args): a = rffi.str2charp(str(n)) c_strchr(a, ord('0')) lltype.free(a, flavor='raw') n -= 1 return (n, x) + args return before, f, None
def setup(): if not detect_cpu.autodetect().startswith(detect_cpu.MODEL_X86_64): raise VMProfPlatformUnsupported("rvmprof only supports" " x86-64 CPUs for now") ROOT = py.path.local(rpythonroot).join('rpython', 'rlib', 'rvmprof') SRC = ROOT.join('src') if sys.platform.startswith('linux'): libs = ['dl'] else: libs = [] eci_kwds = dict( include_dirs = [SRC], includes = ['rvmprof.h'], libraries = libs, separate_module_files = [SRC.join('rvmprof.c')], post_include_bits=['#define RPYTHON_VMPROF\n'], ) eci = ExternalCompilationInfo(**eci_kwds) platform.verify_eci(ExternalCompilationInfo( compile_extra=['-DRPYTHON_LL2CTYPES'], **eci_kwds)) vmprof_init = rffi.llexternal("vmprof_init", [rffi.INT, rffi.DOUBLE, rffi.CCHARP], rffi.CCHARP, compilation_info=eci) vmprof_enable = rffi.llexternal("vmprof_enable", [], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO) vmprof_disable = rffi.llexternal("vmprof_disable", [], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO) vmprof_register_virtual_function = rffi.llexternal( "vmprof_register_virtual_function", [rffi.CCHARP, rffi.LONG, rffi.INT], rffi.INT, compilation_info=eci) vmprof_ignore_signals = rffi.llexternal("vmprof_ignore_signals", [rffi.INT], lltype.Void, compilation_info=eci) return CInterface(locals())
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 llexternal(self, *args, **kwds): kwds = kwds.copy() from rpython.rtyper.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, 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 setup_init_functions(eci, translating): init_buffer = rffi.llexternal('init_bufferobject', [], lltype.Void, compilation_info=eci, _nowrapper=True) init_pycobject = rffi.llexternal('init_pycobject', [], lltype.Void, compilation_info=eci, _nowrapper=True) init_capsule = rffi.llexternal('init_capsule', [], lltype.Void, compilation_info=eci, _nowrapper=True) 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 if translating: reinit_tls = rffi.llexternal('PyThread_ReInitTLS', [], lltype.Void, compilation_info=eci) else: reinit_tls = rffi.llexternal('PyPyThread_ReInitTLS', [], lltype.Void, compilation_info=eci) add_fork_hook('child', reinit_tls)
def _fetch_addr_errno(): eci = ExternalCompilationInfo( separate_module_sources=[''' #include <errno.h> RPY_EXPORTED long fetch_addr_errno(void) { return (long)(&errno); } ''']) func1_ptr = rffi.llexternal('fetch_addr_errno', [], lltype.Signed, compilation_info=eci, _nowrapper=True) return func1_ptr()
def test_canrelease_external(): for rel in ['auto', True, False]: for sbxs in [True, False]: fext = rffi.llexternal('fext2', [], lltype.Void, releasegil=rel, sandboxsafe=sbxs) def g(): fext() t = rtype(g, []) gg = graphof(t, g) releases = (rel == 'auto' and not sbxs) or rel is True assert releases == gilanalysis.GilAnalyzer(t).analyze_direct_call(gg)
def test_llexternal(self): from rpython.rtyper.lltypesystem.rffi import llexternal z = llexternal('z', [lltype.Signed], lltype.Signed) def f(x): return z(x) 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 not result
def setup(): compile_extra = ['-DRPYTHON_LL2CTYPES'] platform.verify_eci(ExternalCompilationInfo( compile_extra=compile_extra, **eci_kwds)) eci = global_eci vmprof_init = rffi.llexternal("vmprof_init", [rffi.INT, rffi.DOUBLE, rffi.CCHARP], rffi.CCHARP, compilation_info=eci) vmprof_enable = rffi.llexternal("vmprof_enable", [], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO) vmprof_disable = rffi.llexternal("vmprof_disable", [], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO) vmprof_register_virtual_function = rffi.llexternal( "vmprof_register_virtual_function", [rffi.CCHARP, rffi.LONG, rffi.INT], rffi.INT, compilation_info=eci) vmprof_ignore_signals = rffi.llexternal("vmprof_ignore_signals", [rffi.INT], lltype.Void, compilation_info=eci, _nowrapper=True) vmprof_get_traceback = rffi.llexternal("vmprof_get_traceback", [PVMPROFSTACK, llmemory.Address, rffi.SIGNEDP, lltype.Signed], lltype.Signed, compilation_info=eci, _nowrapper=True) return CInterface(locals())
def _make_impl_attach_gdb(): # circular imports fun :-( import sys from rpython.rtyper.lltypesystem import rffi if sys.platform.startswith('linux'): # Only necessary on Linux eci = ExternalCompilationInfo(includes=['string.h', 'assert.h', 'sys/prctl.h'], post_include_bits=[""" /* If we have an old Linux kernel (or compile with old system headers), the following two macros are not defined. But we would still like a pypy translated on such a system to run on a more modern system. */ #ifndef PR_SET_PTRACER # define PR_SET_PTRACER 0x59616d61 #endif #ifndef PR_SET_PTRACER_ANY # define PR_SET_PTRACER_ANY ((unsigned long)-1) #endif static void pypy__allow_attach(void) { prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY); } """]) allow_attach = rffi.llexternal( "pypy__allow_attach", [], lltype.Void, compilation_info=eci, _nowrapper=True) else: # Do nothing, there's no prctl def allow_attach(): pass def impl_attach_gdb(): import os allow_attach() pid = os.getpid() gdbpid = os.fork() if gdbpid == 0: shell = os.environ.get("SHELL") or "/bin/sh" sepidx = shell.rfind(os.sep) + 1 if sepidx > 0: argv0 = shell[sepidx:] else: argv0 = shell try: os.execv(shell, [argv0, "-c", "gdb -p %d" % pid]) except OSError as e: os.write(2, "Could not start GDB: %s" % ( os.strerror(e.errno))) raise SystemExit else: time.sleep(1) # give the GDB time to attach return impl_attach_gdb
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 rpython.rtyper.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
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): y = -1 if x > 0: y = z(x) return y + x t,g = self.transform_func(f, [int], True) # llexternals normally should not raise, the graph should have no exception # checking assert summary(g) == {'int_gt': 1, 'int_add': 1, 'direct_call': 1}
def test_c_call(self): C = rffi.CArray(lltype.Signed) c = rffi.llexternal('x', [lltype.Ptr(C)], lltype.Signed) def g(): p = lltype.malloc(C, 3, flavor='raw') f(p) def f(p): c(rffi.ptradd(p, 0)) lltype.free(p, flavor='raw') r = self.analyze(g, [], f, backendopt=True) assert r
def define_close_stack(self): # class Glob(object): pass glob = Glob() class X(object): pass # def callback(p1, p2): for i in range(100): glob.lst.append(X()) return rffi.cast(rffi.INT, 1) CALLBACK = lltype.Ptr(lltype.FuncType([lltype.Signed, lltype.Signed], rffi.INT)) # @dont_look_inside def alloc1(): return llmemory.raw_malloc(16) @dont_look_inside def free1(p): llmemory.raw_free(p) c_qsort = rffi.llexternal('qsort', [rffi.VOIDP, rffi.SIZE_T, rffi.SIZE_T, CALLBACK], lltype.Void) # def f42(n): length = len(glob.lst) raw = alloc1() wrapper = rffi._make_wrapper_for(CALLBACK, callback, None, True) fn = llhelper(CALLBACK, wrapper) if n & 1: # to create a loop and a bridge, and also pass # to run the qsort() call in the blackhole interp c_qsort(rffi.cast(rffi.VOIDP, raw), rffi.cast(rffi.SIZE_T, 2), rffi.cast(rffi.SIZE_T, 8), fn) free1(raw) check(len(glob.lst) > length) del glob.lst[:] # def before(n, x): glob.lst = [] return (n, None, None, None, None, None, None, None, None, None, None, None) # def f(n, x, *args): f42(n) n -= 1 return (n, x) + args return before, f, None
# NOTE: for bridge functions which take arguments of type "HPy", one more hack # is needed. See the comment in bridge.h # Adding a new bridge function is annoying because it involves modifying few # different places: in theory it could be automated, but as long as the number # of bridge function remains manageable, it is better to avoid adding # unnecessary magic. To add a new bridge function you need: # # 1. add the @BRIDGE.func decorator to your RPython function # 2. add the corresponding field in _HPyBridge here # 3. inside src/bridge.h: # a) add the corresponding field in _HPyBridge # b) write a macro for the RPYTHON_LL2CTYPES case # c) write the function prototype for the non-RPYTHON_LL2CTYPES case # d) if the func recevies HPy arguments, write a macro to convert them llapi.cts.parse_source(""" typedef struct { void * hpy_err_Occurred_rpy; void * _hpy_err_SetString; } _HPyBridge; """) _HPyBridge = llapi.cts.gettype('_HPyBridge') hpy_get_bridge = rffi.llexternal('hpy_get_bridge', [], lltype.Ptr(_HPyBridge), compilation_info=llapi.eci, _nowrapper=True) BRIDGE = APISet(llapi.cts, prefix='^hpy_', force_c_name=True)
def external(name, args, result, **kwds): return rffi.llexternal(name, args, result, compilation_info=eci, **kwds)
from topaz.system import IS_WINDOWS if IS_WINDOWS: O_BINARY = os.O_BINARY eci = ExternalCompilationInfo(includes=["windows.h"]) class CConfig: _compilation_info_ = eci config = platform.configure(CConfig) _chsize = rffi.llexternal( "_chsize", [rffi.INT, rffi.LONG], rffi.INT, compilation_info=eci, ) def ftruncate(fd, size): _chsize(fd, size) def fchmod(fd, mode): raise NotImplementedError("chmod on windows") # This imports the definition of isdir that uses stat. On Windows # this is replaced in the path module with a version that isn't # RPython from genericpath import isdir else: O_BINARY = 0
def llexternal(*args, **kwargs): kwargs.setdefault('compilation_info', eci) kwargs.setdefault('sandboxsafe', True) kwargs.setdefault('_nowrapper', True) return rffi.llexternal(*args, **kwargs)
*(FARPROC*)&func = address; return func(key, isDisabled); } LONG pypy_RegDeleteKeyExA(FARPROC address, HKEY key, LPCSTR subkey, REGSAM sam, DWORD reserved) { LONG (WINAPI *func)(HKEY, LPCSTR, REGSAM, DWORD); *(FARPROC*)&func = address; return func(key, subkey, sam, reserved); } ''' ], ) pypy_RegChangeReflectionKey = rffi.llexternal('pypy_RegChangeReflectionKey', [rffi.VOIDP, rwinreg.HKEY], rffi.LONG, compilation_info=eci) pypy_RegQueryReflectionKey = rffi.llexternal( 'pypy_RegQueryReflectionKey', [rffi.VOIDP, rwinreg.HKEY, rwin32.LPBOOL], rffi.LONG, compilation_info=eci) pypy_RegDeleteKeyExA = rffi.llexternal( 'pypy_RegDeleteKeyExA', [rffi.VOIDP, rwinreg.HKEY, rffi.CCHARP, rwinreg.REGSAM, rwin32.DWORD], rffi.LONG, compilation_info=eci) def raiseWindowsError(space, errcode, context):
def expat_external(*a, **kw): kw['compilation_info'] = eci return rffi.llexternal(*a, **kw)
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. import sys from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.tool import rffi_platform as platform from rpython.translator.tool.cbuild import ExternalCompilationInfo from Builtins import * from Core import * DEFAULT_ENTRIES_ALLOC = 256 eci = ExternalCompilationInfo(includes=["string.h"]) memmove = rffi.llexternal("memmove", [rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T], rffi.CCHARP, compilation_info=eci) class CConfig: _compilation_info_ = eci cconfig = platform.configure(CConfig) def init(vm): return new_c_con_module(vm, "Array", "Array", __file__, import_, \ ["Array_Exception", "Array"])
def do_register(func): kwds.setdefault('_callable', func) kwds.setdefault('random_effects_on_gcobjs', False) kwds.setdefault('compilation_info', compilation_info) return rffi.llexternal(func.__name__, args, result, **kwds)
eci = ExternalCompilationInfo(includes=["sys/types.h", "dirent.h"]) class CConfig: _compilation_info_ = eci DIRENT = platform.Struct( "struct dirent", [("d_name", lltype.FixedSizeArray(rffi.CHAR, 1))]) config = platform.configure(CConfig) DIRP = rffi.COpaquePtr("DIR") DIRENT = config["DIRENT"] DIRENTP = lltype.Ptr(DIRENT) # XXX macro=True is hack to make sure we get the correct kind of # dirent struct (which depends on defines) os_opendir = rffi.llexternal("opendir", [rffi.CCHARP], DIRP, compilation_info=eci, macro=True) os_readdir = rffi.llexternal("readdir", [DIRP], DIRENTP, compilation_info=eci, macro=True) os_closedir = rffi.llexternal("closedir", [DIRP], rffi.INT, compilation_info=eci, macro=True) def opendir(path): dirp = os_opendir(path) if not dirp: raise OSError(rposix.get_errno(), "error in opendir") return dirp
assert not runner.sthread.is_empty_handle(h) runner.tasks[n].h = runner.sthread.get_null_handle() runner.comefrom = -42 runner.gointo = n assert runner.nextstep == -1 runner.status += 1 runner.nextstep = runner.status print "LEAVING %d to go to %d" % (self.n, n) return h QSORT_CALLBACK_PTR = lltype.Ptr( lltype.FuncType([llmemory.Address, llmemory.Address], rffi.INT)) qsort = rffi.llexternal( 'qsort', [llmemory.Address, rffi.SIZE_T, rffi.SIZE_T, QSORT_CALLBACK_PTR], lltype.Void) def cb_compare_callback(a, b): runner.steps.append(3) assert not runner.sthread.is_empty_handle(runner.main_h) runner.main_h = runner.sthread.switch(runner.main_h) assert not runner.sthread.is_empty_handle(runner.main_h) runner.steps.append(6) return rffi.cast(rffi.INT, 1) def cb_stacklet_callback(h, arg): runner.steps.append(1) while True:
# ____________________________________________________________ eci = ExternalCompilationInfo( include_dirs=[cdir], includes=['src/dtoa.h'], libraries=[], separate_module_sources=[source_file], ) # dtoa.c is limited to 'int', so we refuse to pass it # strings or integer arguments bigger than ~2GB _INT_LIMIT = 0x7ffff000 dg_strtod = rffi.llexternal('_PyPy_dg_strtod', [rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE, compilation_info=eci, sandboxsafe=True) dg_dtoa = rffi.llexternal( '_PyPy_dg_dtoa', [rffi.DOUBLE, rffi.INT, rffi.INT, rffi.INTP, rffi.INTP, rffi.CCHARPP], rffi.CCHARP, compilation_info=eci, sandboxsafe=True) dg_freedtoa = rffi.llexternal('_PyPy_dg_freedtoa', [rffi.CCHARP], lltype.Void, compilation_info=eci, sandboxsafe=True)
def external(name, argtypes, restype, **kw): kw['compilation_info'] = eci return rffi.llexternal( name, argtypes, restype, **kw)
def get_rpy_memory_usage(gc, gcref): return gc.get_size_incl_hash(llmemory.cast_ptr_to_adr(gcref)) def get_rpy_type_index(gc, gcref): typeid = gc.get_type_id(llmemory.cast_ptr_to_adr(gcref)) return gc.get_member_index(typeid) def is_rpy_instance(gc, gcref): typeid = gc.get_type_id(llmemory.cast_ptr_to_adr(gcref)) return gc.is_rpython_class(typeid) # ---------- raw_os_write = rffi.llexternal(UNDERSCORE_ON_WIN32 + 'write', [rffi.INT, llmemory.Address, rffi.SIZE_T], rffi.SIZE_T, sandboxsafe=True, _nowrapper=True) AddressStack = get_address_stack() class HeapDumper(object): _alloc_flavor_ = "raw" BUFSIZE = 8192 # words def __init__(self, gc, fd): self.gc = gc self.gcflag = gc.gcflag_extra self.fd = rffi.cast(rffi.INT, fd) self.writebuffer = lltype.malloc(rffi.SIGNEDP.TO, self.BUFSIZE, flavor='raw') self.buf_count = 0
def external(name, args, result): return rffi.llexternal(name, args, result, compilation_info=eci, releasegil=False)
class StreamError(Exception): def __init__(self, message): self.message = message StreamErrors = (OSError, StreamError) # errors that can generally be raised if sys.platform == "win32": from rpython.rlib.rwin32 import BOOL, HANDLE, get_osfhandle from rpython.rlib.rwin32 import GetLastError_saved from rpython.translator.tool.cbuild import ExternalCompilationInfo from rpython.rtyper.lltypesystem import rffi _eci = ExternalCompilationInfo() _setmode = rffi.llexternal('_setmode', [rffi.INT, rffi.INT], rffi.INT, compilation_info=_eci) SetEndOfFile = rffi.llexternal('SetEndOfFile', [HANDLE], BOOL, compilation_info=_eci, save_err=rffi.RFFI_SAVE_LASTERROR) def _setfd_binary(fd): # Allow this to succeed on invalid fd's with rposix.FdValidator(fd): _setmode(fd, os.O_BINARY) def ftruncate_win32(fd, size): curpos = os.lseek(fd, 0, 1) try: # move to the position to be truncated
releasegil=False, save_err=rffi.RFFI_SAVE_LASTERROR) CloseHandle_no_err = winexternal('CloseHandle', [HANDLE], BOOL, releasegil=False) FormatMessage = winexternal( 'FormatMessageA', [DWORD, rffi.VOIDP, DWORD, DWORD, rffi.CCHARP, DWORD, rffi.VOIDP], DWORD) FormatMessageW = winexternal( 'FormatMessageW', [DWORD, rffi.VOIDP, DWORD, DWORD, rffi.CWCHARP, DWORD, rffi.VOIDP], DWORD) _get_osfhandle = rffi.llexternal('_get_osfhandle', [rffi.INT], rffi.INTP) def get_osfhandle(fd): from rpython.rlib.rposix import FdValidator with FdValidator(fd): handle = rffi.cast(HANDLE, _get_osfhandle(fd)) if handle == INVALID_HANDLE_VALUE: raise WindowsError(ERROR_INVALID_HANDLE, "Invalid file handle") return handle def build_winerror_to_errno(): """Build a dictionary mapping windows error numbers to POSIX errno. The function returns the dict, and the default value for codes not in the dict.""" # Prior to Visual Studio 8, the MSVCRT dll doesn't export the # _dosmaperr() function, which is available only when compiled
('pw_gecos', rffi.CCHARP), ('pw_dir', rffi.CCHARP), ('pw_shell', rffi.CCHARP)]) group = platform.Struct('struct group', [('gr_name', rffi.CCHARP), ('gr_passwd', rffi.CCHARP), ('gr_gid', lltype.Signed), ('gr_mem', rffi.CCHARPP)]) PASSWD = platform.configure(CConfig)['passwd'] PASSWDPTR = lltype.Ptr(PASSWD) GROUP = platform.configure(CConfig)['group'] GROUPPTR = lltype.Ptr(GROUP) getpwnam = rffi.llexternal('getpwnam', [rffi.CCHARP], PASSWDPTR, compilation_info=eci) getpwuid = rffi.llexternal('getpwuid', [lltype.Signed], PASSWDPTR, compilation_info=eci) initgroups = rffi.llexternal('initgroups', [rffi.CCHARP, lltype.Signed], rffi.INT, compilation_info=eci) getgrgid = rffi.llexternal('getgrgid', [lltype.Signed], GROUPPTR, compilation_info=eci) getgrnam = rffi.llexternal('getgrnam', [rffi.CCHARP], GROUPPTR, compilation_info=eci)
_compilation_info_ = ExternalCompilationInfo( includes=["float.h", "math.h"], libraries=libraries) float_constants = ["DBL_MAX", "DBL_MIN", "DBL_EPSILON"] int_constants = ["DBL_MAX_EXP", "DBL_MAX_10_EXP", "DBL_MIN_EXP", "DBL_MIN_10_EXP", "DBL_DIG", "DBL_MANT_DIG", "FLT_RADIX", "FLT_ROUNDS"] for const in float_constants: setattr(CConfig, const, rffi_platform.DefinedConstantDouble(const)) for const in int_constants: setattr(CConfig, const, rffi_platform.DefinedConstantInteger(const)) del float_constants, int_constants, const nextafter = rffi.llexternal( 'nextafter', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE, compilation_info=CConfig._compilation_info_, sandboxsafe=True) globals().update(rffi_platform.configure(CConfig)) INVALID_MSG = "could not convert string to float" def string_to_float(s): """ Conversion of string to float. This version tries to only raise on invalid literals. Overflows should be converted to infinity whenever possible. Expects an unwrapped string and return an unwrapped float. """ from rpython.rlib.rstring import strip_spaces, ParseStringError
def llexternal(name, args, result, **kwds): kwds.setdefault('sandboxsafe', True) return rffi.llexternal(name, args, result, compilation_info=eci, **kwds)
return cdataobj.W_CData(space, ptr, self) else: raise oefmt(space.w_TypeError, "expected a cdata struct/union/array/pointer object") def _fget(self, attrchar): if attrchar == 'i': # item return self.ctitem return W_CTypePtrBase._fget(self, attrchar) # ____________________________________________________________ FILEP = rffi.COpaquePtr("FILE") rffi_fdopen = rffi.llexternal("fdopen", [rffi.INT, rffi.CCHARP], FILEP, save_err=rffi.RFFI_SAVE_ERRNO) rffi_setbuf = rffi.llexternal("setbuf", [FILEP, rffi.CCHARP], lltype.Void) rffi_fclose = rffi.llexternal("fclose", [FILEP], rffi.INT) class CffiFileObj(object): _immutable_ = True def __init__(self, fd, mode): self.llf = rffi_fdopen(fd, mode) if not self.llf: raise OSError(rposix.get_saved_errno(), "fdopen failed") rffi_setbuf(self.llf, lltype.nullptr(rffi.CCHARP.TO)) def close(self):
self.where = where eci = ExternalCompilationInfo(includes=['stdint.h', 'opagent.h'], library_dirs=['/usr/local/lib/oprofile/'], libraries=['bfd', 'opagent']) try: rffi_platform.verify_eci(eci) except rffi_platform.CompilationError: OPROFILE_AVAILABLE = False else: OPROFILE_AVAILABLE = True AGENT = rffi.VOIDP uint64_t = rffi.ULONGLONG op_open_agent = rffi.llexternal("op_open_agent", [], AGENT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO) op_close_agent = rffi.llexternal("op_close_agent", [AGENT], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO) # arguments are: # agent, symbol_name, address in memory, address in memory again, size op_write_native_code = rffi.llexternal( "op_write_native_code", [AGENT, rffi.CCHARP, uint64_t, rffi.VOIDP, rffi.UINT], rffi.INT, compilation_info=eci, save_err=rffi.RFFI_SAVE_ERRNO)
CLOCK_MONOTONIC_RAW = cconfig["CLOCK_MONOTONIC_RAW"] CLOCK_PROCESS_CPUTIME_ID = cconfig["CLOCK_PROCESS_CPUTIME_ID"] CLOCK_THREAD_CPUTIME_ID = cconfig["CLOCK_THREAD_CPUTIME_ID"] if HAS_CLOCK_GETTIME: #redo it for timespec CConfig.TIMESPEC = rffi_platform.Struct("struct timespec", [ ("tv_sec", rffi.TIME_T), ("tv_nsec", rffi.LONG), ]) cconfig = rffi_platform.configure(CConfig) TIMESPEC = cconfig['TIMESPEC'] c_clock_gettime = rffi.llexternal( "clock_gettime", [lltype.Signed, lltype.Ptr(TIMESPEC)], rffi.INT, compilation_info=CConfig._compilation_info_, releasegil=False, save_err=rffi.RFFI_SAVE_ERRNO) c_clock_getres = rffi.llexternal( "clock_getres", [lltype.Signed, lltype.Ptr(TIMESPEC)], rffi.INT, compilation_info=CConfig._compilation_info_, releasegil=False, save_err=rffi.RFFI_SAVE_ERRNO) @unwrap_spec(clk_id="c_int") def clock_gettime(space, clk_id): with lltype.scoped_alloc(TIMESPEC) as tp: ret = c_clock_gettime(clk_id, tp) if ret != 0: raise exception_from_saved_errno(space, space.w_IOError)
if key == 'main' than it's included by default """ def deco(func): secondary_entrypoints.setdefault(key, []).append((func, argtypes)) if c_name is not None: func.c_name = c_name if relax: func.relax_sig_check = True export_symbol(func) return func return deco pypy_debug_catch_fatal_exception = rffi.llexternal( 'pypy_debug_catch_fatal_exception', [], lltype.Void) def entrypoint(key, argtypes, c_name=None): """if key == 'main' than it's included by default """ def deco(func): source = py.code.Source( """ def wrapper(%(args)s): # the tuple has to be killed, but it's fine because this is # called from C rffi.stackcounter.stacks_counter += 1 llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py # this should not raise try:
def winexternal(name, args, result, **kwds): return rffi.llexternal(name, args, result, compilation_info=eci, calling_conv='win', **kwds)
LocalFree = winexternal('LocalFree', [HLOCAL], DWORD) CloseHandle = winexternal('CloseHandle', [HANDLE], BOOL, releasegil=False, save_err=rffi.RFFI_SAVE_LASTERROR) CloseHandle_no_err = winexternal('CloseHandle', [HANDLE], BOOL, releasegil=False) FormatMessage = winexternal( 'FormatMessageA', [DWORD, rffi.VOIDP, DWORD, DWORD, rffi.CCHARP, DWORD, rffi.VOIDP], DWORD) FormatMessageW = winexternal( 'FormatMessageW', [DWORD, rffi.VOIDP, DWORD, DWORD, rffi.CWCHARP, DWORD, rffi.VOIDP], DWORD) _get_osfhandle = rffi.llexternal('_get_osfhandle', [rffi.INT], HANDLE) def get_osfhandle(fd): from rpython.rlib.rposix import FdValidator with FdValidator(fd): handle = _get_osfhandle(fd) if handle == INVALID_HANDLE_VALUE: raise WindowsError(ERROR_INVALID_HANDLE, "Invalid file handle") return handle def build_winerror_to_errno(): """Build a dictionary mapping windows error numbers to POSIX errno. The function returns the dict, and the default value for codes not in the dict.""" # Prior to Visual Studio 8, the MSVCRT dll doesn't export the # _dosmaperr() function, which is available only when compiled
from pypy.interpreter.gateway import unwrap_spec from rpython.rtyper.lltypesystem import rffi from rpython.translator.tool.cbuild import ExternalCompilationInfo import sys if sys.platform.startswith('darwin'): eci = ExternalCompilationInfo() else: eci = ExternalCompilationInfo(libraries=['crypt']) c_crypt = rffi.llexternal('crypt', [rffi.CCHARP, rffi.CCHARP], rffi.CCHARP, compilation_info=eci, releasegil=False) @unwrap_spec(word=str, salt=str) def crypt(space, word, salt): """word will usually be a user's password. salt is a 2-character string which will be used to select one of 4096 variations of DES. The characters in salt must be either ".", "/", or an alphanumeric character. Returns the hashed password as a string, which will be composed of characters from the same alphabet as the salt.""" res = c_crypt(word, salt) if not res: return space.w_None str_res = rffi.charp2str(res) return space.wrap(str_res)
def external(name, args, result, **kwds): return rffi.llexternal(name, args, result, compilation_info= CConfig._compilation_info_, **kwds)
for TP, TPP in _prim_float_types: if size == rffi.sizeof(TP): _write_raw_float_data_tp(TP, TPP, target, source) return raise NotImplementedError("bad float size") def write_raw_longdouble_data(target, source): rffi.cast(rffi.LONGDOUBLEP, target)[0] = source # ____________________________________________________________ sprintf_longdouble = rffi.llexternal( "sprintf", [rffi.CCHARP, rffi.CCHARP, rffi.LONGDOUBLE], lltype.Void, _nowrapper=True, sandboxsafe=True) FORMAT_LONGDOUBLE = rffi.str2charp("%LE") def longdouble2str(lvalue): with lltype.scoped_alloc(rffi.CCHARP.TO, 128) as p: # big enough sprintf_longdouble(p, FORMAT_LONGDOUBLE, lvalue) return rffi.charp2str(p) # ____________________________________________________________
/* If we have an old Linux kernel (or compile with old system headers), the following two macros are not defined. But we would still like a pypy translated on such a system to run on a more modern system. */ #ifndef PR_SET_PTRACER # define PR_SET_PTRACER 0x59616d61 #endif #ifndef PR_SET_PTRACER_ANY # define PR_SET_PTRACER_ANY ((unsigned long)-1) #endif static void pypy__allow_attach(void) { prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY); } """ ]) allow_attach = rffi.llexternal("pypy__allow_attach", [], lltype.Void, compilation_info=eci, _nowrapper=True) else: # Do nothing, there's no prctl def allow_attach(): pass def impl_attach_gdb(): import os allow_attach() pid = os.getpid() gdbpid = os.fork() if gdbpid == 0: shell = os.environ.get("SHELL") or "/bin/sh" sepidx = shell.rfind(os.sep) + 1 if sepidx > 0:
def external(*args, **kwargs): kwargs['compilation_info'] = CConfig._compilation_info_ llfunc = rffi.llexternal(calling_conv='win', *args, **kwargs) return staticmethod(llfunc)