def test_func_simple(): # -------------------- flowgraph building -------------------- # def f(x): # return x+1 x = Variable("x") x.concretetype = Signed result = Variable("result") result.concretetype = Signed one = Constant(1) one.concretetype = Signed op = SpaceOperation("int_add", [x, one], result) block = Block([x]) graph = FunctionGraph("f", block) block.operations.append(op) block.closeblock(Link([result], graph.returnblock)) graph.getreturnvar().concretetype = Signed # -------------------- end -------------------- F = FuncType([Signed], Signed) f = functionptr(F, "f", graph=graph) db = LowLevelDatabase() db.get(f) db.complete() dump_on_stdout(db) S = GcStruct('testing', ('fptr', Ptr(F))) s = malloc(S) s.fptr = f db = LowLevelDatabase() db.get(s) db.complete() dump_on_stdout(db)
def generate_macro_wrapper(name, macro, functype, eci): """Wraps a function-like macro inside a real function, and expose it with llexternal.""" # Generate the function call from pypy.translator.c.database import LowLevelDatabase from pypy.translator.c.support import cdecl wrapper_name = 'pypy_macro_wrapper_%s' % (name,) argnames = ['arg%d' % (i,) for i in range(len(functype.ARGS))] db = LowLevelDatabase() implementationtypename = db.gettype(functype, argnames=argnames) if functype.RESULT is lltype.Void: pattern = '%s { %s(%s); }' else: pattern = '%s { return %s(%s); }' source = pattern % ( cdecl(implementationtypename, wrapper_name), macro, ', '.join(argnames)) # Now stuff this source into a "companion" eci that will be used # by ll2ctypes. We replace eci._with_ctypes, so that only one # shared library is actually compiled (when ll2ctypes calls the # first function) ctypes_eci = eci.merge(ExternalCompilationInfo( separate_module_sources=[source], export_symbols=[wrapper_name], )) if hasattr(eci, '_with_ctypes'): ctypes_eci = eci._with_ctypes.merge(ctypes_eci) eci._with_ctypes = ctypes_eci func = llexternal(wrapper_name, functype.ARGS, functype.RESULT, compilation_info=eci, _nowrapper=True) # _nowrapper=True returns a pointer which is not hashable return lambda *args: func(*args)
def test_array_of_char(): A = GcArray(Char) a = malloc(A, 11) for i, c in zip(range(11), 'hello world'): a[i] = c db = LowLevelDatabase() db.get(a) db.complete() dump_on_stdout(db)
def test_recursive_struct(): S = GcForwardReference() S.become(GcStruct('testing', ('p', Ptr(S)))) p = malloc(S) p.p = p db = LowLevelDatabase() db.get(p) db.complete() dump_on_stdout(db)
def test_struct(): db = LowLevelDatabase() pfx = db.namespace.global_prefix + 'g_' S = GcStruct('test', ('x', Signed)) s = malloc(S) s.x = 42 assert db.get(s).startswith('(&'+pfx) assert db.containernodes.keys() == [s._obj] assert db.structdefnodes.keys() == [S]
def test_struct(): db = LowLevelDatabase() pfx = db.namespace.global_prefix + 'g_' S = GcStruct('test', ('x', Signed)) s = malloc(S) s.x = 42 assert db.get(s).startswith('(&' + pfx) assert db.containernodes.keys() == [s._obj] assert db.structdefnodes.keys() == [S]
def test_typedef(): A = Typedef(Signed, 'test4') db = LowLevelDatabase() assert db.gettype(A) == "test4 @" PA = CArrayPtr(A) assert db.gettype(PA) == "test4 *@" F = FuncType((A,), A) assert db.gettype(F) == "test4 (@)(test4)"
def test_typedef(): A = Typedef(Signed, 'test4') db = LowLevelDatabase() assert db.gettype(A) == "test4 @" PA = CArrayPtr(A) assert db.gettype(PA) == "test4 *@" F = FuncType((A, ), A) assert db.gettype(F) == "test4 (@)(test4)"
def build_database(self): translator = self.translator gcpolicyclass = self.get_gcpolicyclass() if self.config.translation.gcrootfinder == "asmgcc": if not self.standalone: raise NotImplementedError("--gcrootfinder=asmgcc requires standalone") if self.config.translation.stackless: if not self.standalone: raise Exception("stackless: only for stand-alone builds") from pypy.translator.stackless.transform import StacklessTransformer stacklesstransformer = StacklessTransformer( translator, self.originalentrypoint, stackless_gc=gcpolicyclass.requires_stackless) self.entrypoint = stacklesstransformer.slp_entry_point else: stacklesstransformer = None db = LowLevelDatabase(translator, standalone=self.standalone, gcpolicyclass=gcpolicyclass, stacklesstransformer=stacklesstransformer, thread_enabled=self.config.translation.thread, sandbox=self.config.translation.sandbox) self.db = db # give the gc a chance to register interest in the start-up functions it # need (we call this for its side-effects of db.get()) list(db.gcpolicy.gc_startup_code()) # build entrypoint and eventually other things to expose pf = self.getentrypointptr() if isinstance(pf, list): for one_pf in pf: db.get(one_pf) self.c_entrypoint_name = None else: pfname = db.get(pf) for func, _ in self.secondary_entrypoints: bk = translator.annotator.bookkeeper db.get(getfunctionptr(bk.getdesc(func).getuniquegraph())) self.c_entrypoint_name = pfname for obj in exports.EXPORTS_obj2name.keys(): db.getcontainernode(obj) exports.clear() db.complete() self.collect_compilation_info(db) return db
def test_inlined_struct(): db = LowLevelDatabase() pfx = db.namespace.global_prefix + 'g_' S = GcStruct('test', ('x', Struct('subtest', ('y', Signed)))) s = malloc(S) s.x.y = 42 assert db.get(s).startswith('(&' + pfx) assert db.containernodes.keys() == [s._obj] db.complete() assert len(db.structdefnodes) == 2 assert S in db.structdefnodes assert S.x in db.structdefnodes
def test_inlined_struct(): db = LowLevelDatabase() pfx = db.namespace.global_prefix + 'g_' S = GcStruct('test', ('x', Struct('subtest', ('y', Signed)))) s = malloc(S) s.x.y = 42 assert db.get(s).startswith('(&'+pfx) assert db.containernodes.keys() == [s._obj] db.complete() assert len(db.structdefnodes) == 2 assert S in db.structdefnodes assert S.x in db.structdefnodes
def test_function_call(): def g(x, y): return x-y def f(x): return g(1, x) t, graph = makegraph(f, [int]) F = FuncType([Signed], Signed) f = functionptr(F, "f", graph=graph) db = LowLevelDatabase(t) db.get(f) db.complete() dump_on_stdout(db)
def test_malloc(): S = GcStruct('testing', ('x', Signed), ('y', Signed)) def ll_f(x): p = malloc(S) p.x = x p.y = x+1 return p.x * p.y t, graph = makegraph(ll_f, [int]) db = LowLevelDatabase(t) db.get(getfunctionptr(graph)) db.complete() dump_on_stdout(db)
def test_codegen(): db = LowLevelDatabase() U = Struct('inlined', ('z', Signed)) T = Struct('subtest', ('y', Signed)) S = Struct('test', ('x', Ptr(T)), ('u', U), ('p', Ptr(U))) s = malloc(S, immortal=True) s.x = malloc(T, immortal=True) s.x.y = 42 s.u.z = -100 s.p = s.u db.get(s) db.complete() dump_on_stdout(db)
def test_codegen_2(): db = LowLevelDatabase() A = GcArray(('x', Signed)) S = GcStruct('test', ('aptr', Ptr(A))) a = malloc(A, 3) a[0].x = 100 a[1].x = 101 a[2].x = 102 s = malloc(S) s.aptr = a db.get(s) db.complete() dump_on_stdout(db)
def test_name_gcref(): from pypy.rpython.lltypesystem import lltype, llmemory, rclass from pypy.translator.c import primitive from pypy.translator.c.database import LowLevelDatabase x = lltype.cast_int_to_ptr(rclass.OBJECTPTR, 19) y = lltype.cast_opaque_ptr(llmemory.GCREF, x) db = LowLevelDatabase() assert primitive.name_gcref(y, db) == "((void*) 19)"
def test_codegen_3(): db = LowLevelDatabase() A = Struct('varsizedstuff', ('x', Signed), ('y', Array(('i', Signed)))) S = Struct('test', ('aptr', Ptr(A)), ('anitem', Ptr(A.y.OF)), ('anarray', Ptr(A.y))) a = malloc(A, 3, immortal=True) a.x = 99 a.y[0].i = 100 a.y[1].i = 101 a.y[2].i = 102 s = malloc(S, immortal=True) s.aptr = a s.anitem = a.y[1] s.anarray = a.y db.get(s) db.complete() dump_on_stdout(db)
def test_multiple_malloc(): S1 = GcStruct('testing1', ('x', Signed), ('y', Signed)) S = GcStruct('testing', ('ptr1', Ptr(S1)), ('ptr2', Ptr(S1)), ('z', Signed)) def ll_f(x): ptr1 = malloc(S1) ptr1.x = x ptr2 = malloc(S1) ptr2.x = x+1 s = malloc(S) s.ptr1 = ptr1 s.ptr2 = ptr2 return s.ptr1.x * s.ptr2.x t, graph = makegraph(ll_f, [int]) db = LowLevelDatabase(t) db.get(getfunctionptr(graph)) db.complete() dump_on_stdout(db)
def test_func_as_pyobject(): def f(x): return x*2 t = TranslationContext() t.buildannotator().build_types(f, [int]) t.buildrtyper().specialize() db = LowLevelDatabase(t) entrypoint = db.get(pyobjectptr(f)) db.complete() module = compile_db(db) f1 = getattr(module, entrypoint) assert f1(5) == 10 assert f1(x=5) == 10 assert f1(-123) == -246 assert module.malloc_counters() == (0, 0) py.test.raises(Exception, f1, "world") # check that it's really typed py.test.raises(Exception, f1) py.test.raises(Exception, f1, 2, 3) py.test.raises(Exception, f1, 2, x=2)
def build_database(self): translator = self.translator gcpolicyclass = self.get_gcpolicyclass() if self.config.translation.gcrootfinder == "asmgcc": if not self.standalone: raise NotImplementedError("--gcrootfinder=asmgcc requires standalone") if self.config.translation.stackless: if not self.standalone: raise Exception("stackless: only for stand-alone builds") from pypy.translator.stackless.transform import StacklessTransformer stacklesstransformer = StacklessTransformer( translator, self.originalentrypoint, stackless_gc=gcpolicyclass.requires_stackless) self.entrypoint = stacklesstransformer.slp_entry_point else: stacklesstransformer = None db = LowLevelDatabase(translator, standalone=self.standalone, gcpolicyclass=gcpolicyclass, stacklesstransformer=stacklesstransformer, thread_enabled=self.config.translation.thread, sandbox=self.config.translation.sandbox) self.db = db # give the gc a chance to register interest in the start-up functions it # need (we call this for its side-effects of db.get()) list(db.gcpolicy.gc_startup_code()) # build entrypoint and eventually other things to expose pf = self.getentrypointptr() pfname = db.get(pf) self.c_entrypoint_name = pfname db.complete() self.collect_compilation_info(db) return db
def test_typedef(self, space): from pypy.translator.c.database import LowLevelDatabase db = LowLevelDatabase() assert (api.c_function_signature(db, api.FUNCTIONS['PyPy_TypedefTest1']) == ('Py_ssize_t', 'Py_ssize_t arg0')) assert (api.c_function_signature(db, api.FUNCTIONS['PyPy_TypedefTest2']) == ('Py_ssize_t *', 'Py_ssize_t *arg0')) PyPy_TypedefTest1(space, 0) ppos = lltype.malloc(api.Py_ssize_tP.TO, 1, flavor='raw') ppos[0] = 0 PyPy_TypedefTest2(space, ppos) lltype.free(ppos, flavor='raw')
def test_runtime_type_info(): S = GcStruct('s', ('is_actually_s1', Bool)) S1 = GcStruct('s1', ('sub', S)) attachRuntimeTypeInfo(S) attachRuntimeTypeInfo(S1) def rtti_S(p): if p.is_actually_s1: return getRuntimeTypeInfo(S1) else: return getRuntimeTypeInfo(S) def rtti_S1(p): return getRuntimeTypeInfo(S1) def does_stuff(): p = malloc(S) p.is_actually_s1 = False p1 = malloc(S1) p1.sub.is_actually_s1 = True # and no crash when p and p1 are decref'ed return sys t = TranslationContext() t.buildannotator().build_types(does_stuff, []) rtyper = t.buildrtyper() rtyper.attachRuntimeTypeInfoFunc(S, rtti_S) rtyper.attachRuntimeTypeInfoFunc(S1, rtti_S1) rtyper.specialize() #t.view() db = LowLevelDatabase(t) entrypoint = db.get(pyobjectptr(does_stuff)) db.complete() module = compile_db(db) f1 = getattr(module, entrypoint) f1() mallocs, frees = module.malloc_counters() assert mallocs == frees
def setup_library(space): "NOT_RPYTHON" from pypy.module.cpyext.pyobject import make_ref export_symbols = list(FUNCTIONS) + SYMBOLS_C + list(GLOBALS) from pypy.translator.c.database import LowLevelDatabase db = LowLevelDatabase() generate_macros(export_symbols, rename=False, do_deref=False) functions = generate_decls_and_callbacks(db, [], api_struct=False) code = "#include <Python.h>\n" + "\n".join(functions) eci = build_eci(False, export_symbols, code) space.fromcache(State).install_dll(eci) run_bootstrap_functions(space) setup_va_functions(eci) # populate static data for name, (typ, expr) in GLOBALS.iteritems(): name = name.replace("#", "") if name.startswith('PyExc_'): name = '_' + name from pypy.module import cpyext w_obj = eval(expr) if typ in ('PyObject*', 'PyTypeObject*'): struct_ptr = make_ref(space, w_obj) elif typ == 'PyDateTime_CAPI*': continue else: assert False, "Unknown static data: %s %s" % (typ, name) struct = rffi.cast(get_structtype_for_ctype(typ), struct_ptr)._obj struct._compilation_info = eci export_struct(name, struct) for name, func in FUNCTIONS.iteritems(): deco = entrypoint("cpyext", func.argtypes, name, relax=True) deco(func.get_wrapper(space)) setup_init_functions(eci) trunk_include = pypydir.dirpath() / 'include' copy_header_files(trunk_include)
def test_malloc(): S = GcStruct('testing', ('x', Signed), ('y', Signed)) def ll_f(x): p = malloc(S) p.x = x p.y = x + 1 return p.x * p.y t, graph = makegraph(ll_f, [int]) db = LowLevelDatabase(t) db.get(getfunctionptr(graph)) db.complete() dump_on_stdout(db)
def test_function_call(): def g(x, y): return x - y def f(x): return g(1, x) t, graph = makegraph(f, [int]) F = FuncType([Signed], Signed) f = functionptr(F, "f", graph=graph) db = LowLevelDatabase(t) db.get(f) db.complete() dump_on_stdout(db)
def test_multiple_malloc(): S1 = GcStruct('testing1', ('x', Signed), ('y', Signed)) S = GcStruct('testing', ('ptr1', Ptr(S1)), ('ptr2', Ptr(S1)), ('z', Signed)) def ll_f(x): ptr1 = malloc(S1) ptr1.x = x ptr2 = malloc(S1) ptr2.x = x + 1 s = malloc(S) s.ptr1 = ptr1 s.ptr2 = ptr2 return s.ptr1.x * s.ptr2.x t, graph = makegraph(ll_f, [int]) db = LowLevelDatabase(t) db.get(getfunctionptr(graph)) db.complete() dump_on_stdout(db)
def test_voidp(): A = VOIDP db = LowLevelDatabase() assert db.gettype(A) == "void *@"
def test_intlong_unique(): A = INT_real B = Signed db = LowLevelDatabase() assert db.gettype(A) == "int @" assert db.gettype(B) == "long @"
def test_primitive(): db = LowLevelDatabase() assert db.get(5) == '5L' assert db.get(True) == '1'
def build_bridge(space): "NOT_RPYTHON" from pypy.module.cpyext.pyobject import make_ref export_symbols = list(FUNCTIONS) + SYMBOLS_C + list(GLOBALS) from pypy.translator.c.database import LowLevelDatabase db = LowLevelDatabase() generate_macros(export_symbols, rename=True, do_deref=True) # Structure declaration code members = [] structindex = {} for name, func in sorted(FUNCTIONS.iteritems()): restype, args = c_function_signature(db, func) members.append('%s (*%s)(%s);' % (restype, name, args)) structindex[name] = len(structindex) structmembers = '\n'.join(members) struct_declaration_code = """\ struct PyPyAPI { %(members)s } _pypyAPI; struct PyPyAPI* pypyAPI = &_pypyAPI; """ % dict(members=structmembers) functions = generate_decls_and_callbacks(db, export_symbols) global_objects = [] for name, (typ, expr) in GLOBALS.iteritems(): if "#" in name: continue if typ == 'PyDateTime_CAPI*': continue elif name.startswith('PyExc_'): global_objects.append('%s _%s;' % (typ[:-1], name)) else: global_objects.append('%s %s = NULL;' % (typ, name)) global_code = '\n'.join(global_objects) prologue = "#include <Python.h>\n" code = (prologue + struct_declaration_code + global_code + '\n' + '\n'.join(functions)) eci = build_eci(True, export_symbols, code) eci = eci.compile_shared_lib(outputfilename=str(udir / "module_cache" / "pypyapi")) modulename = py.path.local(eci.libraries[-1]) run_bootstrap_functions(space) # load the bridge, and init structure import ctypes bridge = ctypes.CDLL(str(modulename), mode=ctypes.RTLD_GLOBAL) space.fromcache(State).install_dll(eci) # populate static data for name, (typ, expr) in GLOBALS.iteritems(): from pypy.module import cpyext w_obj = eval(expr) if name.endswith('#'): name = name[:-1] isptr = False else: isptr = True if name.startswith('PyExc_'): isptr = False INTERPLEVEL_API[name] = w_obj name = name.replace('Py', 'PyPy') if isptr: ptr = ctypes.c_void_p.in_dll(bridge, name) if typ == 'PyObject*': value = make_ref(space, w_obj) elif typ == 'PyDateTime_CAPI*': value = w_obj else: assert False, "Unknown static pointer: %s %s" % (typ, name) ptr.value = ctypes.cast(ll2ctypes.lltype2ctypes(value), ctypes.c_void_p).value elif typ in ('PyObject*', 'PyTypeObject*'): if name.startswith('PyPyExc_'): # we already have the pointer in_dll = ll2ctypes.get_ctypes_type(PyObject).in_dll( bridge, name) py_obj = ll2ctypes.ctypes2lltype(PyObject, in_dll) else: # we have a structure, get its address in_dll = ll2ctypes.get_ctypes_type(PyObject.TO).in_dll( bridge, name) py_obj = ll2ctypes.ctypes2lltype(PyObject, ctypes.pointer(in_dll)) from pypy.module.cpyext.pyobject import (track_reference, get_typedescr) w_type = space.type(w_obj) typedescr = get_typedescr(w_type.instancetypedef) py_obj.c_ob_refcnt = 1 py_obj.c_ob_type = rffi.cast(PyTypeObjectPtr, make_ref(space, w_type)) typedescr.attach(space, py_obj, w_obj) track_reference(space, py_obj, w_obj) else: assert False, "Unknown static object: %s %s" % (typ, name) pypyAPI = ctypes.POINTER(ctypes.c_void_p).in_dll(bridge, 'pypyAPI') # implement structure initialization code for name, func in FUNCTIONS.iteritems(): if name.startswith('cpyext_'): # XXX hack continue pypyAPI[structindex[name]] = ctypes.cast( ll2ctypes.lltype2ctypes(func.get_llhelper(space)), ctypes.c_void_p) setup_va_functions(eci) setup_init_functions(eci) return modulename.new(ext='')
def translator2database(translator, entrypoint): pf = lltype.pyobjectptr(entrypoint) db = LowLevelDatabase(translator) db.get(pf) db.complete() return db, pf
def build_database(self, exports=[], pyobj_options=None): translator = self.translator gcpolicyclass = self.get_gcpolicyclass() if self.config.translation.stackless: if not self.standalone: raise Exception("stackless: only for stand-alone builds") from pypy.translator.stackless.transform import StacklessTransformer stacklesstransformer = StacklessTransformer( translator, self.originalentrypoint, stackless_gc=gcpolicyclass.requires_stackless) self.entrypoint = stacklesstransformer.slp_entry_point else: stacklesstransformer = None db = LowLevelDatabase(translator, standalone=self.standalone, gcpolicyclass=gcpolicyclass, stacklesstransformer=stacklesstransformer, thread_enabled=self.config.translation.thread) # pass extra options into pyobjmaker if pyobj_options: for key, value in pyobj_options.items(): setattr(db.pyobjmaker, key, value) # we need a concrete gcpolicy to do this self.libraries += db.gcpolicy.gc_libraries() # give the gc a chance to register interest in the start-up functions it # need (we call this for its side-effects of db.get()) list(db.gcpolicy.gc_startup_code()) # build entrypoint and eventually other things to expose pf = self.getentrypointptr() pfname = db.get(pf) self.exports[self.entrypoint.func_name] = pf for obj in exports: if type(obj) is tuple: objname, obj = obj elif hasattr(obj, '__name__'): objname = obj.__name__ else: objname = None po = self.getentrypointptr(obj) poname = db.get(po) objname = objname or poname if objname in self.exports: raise NameError, 'duplicate name in export: %s is %s and %s' % ( objname, db.get(self.exports[objname]), poname) self.exports[objname] = po db.complete() # add library dependencies seen = dict.fromkeys(self.libraries) for node in db.globalcontainers(): if hasattr(node, 'libraries'): for library in node.libraries: if library not in seen: self.libraries.append(library) seen[library] = True return db
def build_database(self): translator = self.translator gcpolicyclass = self.get_gcpolicyclass() if self.config.translation.gcrootfinder == "asmgcc": if not self.standalone: raise NotImplementedError("--gcrootfinder=asmgcc requires standalone") db = LowLevelDatabase(translator, standalone=self.standalone, gcpolicyclass=gcpolicyclass, thread_enabled=self.config.translation.thread, sandbox=self.config.translation.sandbox) self.db = db # give the gc a chance to register interest in the start-up functions it # need (we call this for its side-effects of db.get()) list(db.gcpolicy.gc_startup_code()) # build entrypoint and eventually other things to expose pf = self.getentrypointptr() if isinstance(pf, list): for one_pf in pf: db.get(one_pf) self.c_entrypoint_name = None else: pfname = db.get(pf) for func, _ in self.secondary_entrypoints: bk = translator.annotator.bookkeeper db.get(getfunctionptr(bk.getdesc(func).getuniquegraph())) self.c_entrypoint_name = pfname for obj in exports.EXPORTS_obj2name.keys(): db.getcontainernode(obj) exports.clear() db.complete() self.collect_compilation_info(db) return db