Author: Antonio Cuni <[email protected]>
Branch: hpy
Changeset: r98164:3239497d9665
Date: 2019-11-28 01:17 +0100
http://bitbucket.org/pypy/pypy/changeset/3239497d9665/
Log: Merge branch hpy-ctypespace. Use CTypeSpace to declare HPy types
I think that the final result is much easier to read and to manage.
Currently, the C bits needs to be written by hand, but we can
probably hack more until it can read the real universal/hpy.h or an
autogen version which is easier to parse.
diff --git a/pypy/module/hpy_universal/_vendored/include/universal/hpy.h
b/pypy/module/hpy_universal/_vendored/include/universal/hpy.h
--- a/pypy/module/hpy_universal/_vendored/include/universal/hpy.h
+++ b/pypy/module/hpy_universal/_vendored/include/universal/hpy.h
@@ -6,7 +6,11 @@
#include <stdarg.h>
typedef intptr_t HPy_ssize_t;
-typedef struct { HPy_ssize_t _i; } HPy;
+
+// WARNING: the following change has been done inside the pypy hpy-ctypespace
+// branch. If/when the branch is merged, we should backport it to pyhandle/hpy
+struct _HPy_s { HPy_ssize_t _i; };
+typedef struct _HPy_s HPy;
typedef struct _HPyContext_s *HPyContext;
struct _object; /* that's PyObject inside CPython */
diff --git a/pypy/module/hpy_universal/interp_extfunc.py
b/pypy/module/hpy_universal/interp_extfunc.py
--- a/pypy/module/hpy_universal/interp_extfunc.py
+++ b/pypy/module/hpy_universal/interp_extfunc.py
@@ -14,15 +14,14 @@
def __init__(self, ml, w_self):
self.ml = ml
self.w_self = w_self
- self.name = rffi.charp2str(self.ml.c_ml_name)
+ self.name = rffi.constcharp2str(self.ml.c_ml_name)
self.flags = rffi.cast(lltype.Signed, self.ml.c_ml_flags)
# fetch the real HPy function pointer, by calling ml_meth, which
# is a function that returns it and also the CPython-only trampoline
with lltype.scoped_alloc(
- rffi.CArray(llapi._HPyCFunctionPtr), 1) as funcptr:
+ rffi.CArray(llapi._HPyCFunction), 1) as funcptr:
with lltype.scoped_alloc(
- rffi.CArray(llapi._HPy_CPyCFunctionPtr), 1) \
- as ignored_trampoline:
+ rffi.CArray(llapi._HPyCPyCFunction), 1) as
ignored_trampoline:
ml.c_ml_meth(funcptr, ignored_trampoline)
self.cfuncptr = funcptr[0]
diff --git a/pypy/module/hpy_universal/interp_hpy.py
b/pypy/module/hpy_universal/interp_hpy.py
--- a/pypy/module/hpy_universal/interp_hpy.py
+++ b/pypy/module/hpy_universal/interp_hpy.py
@@ -32,7 +32,7 @@
@apifunc([llapi.HPyContext, lltype.Ptr(llapi.HPyModuleDef)], llapi.HPy)
def HPyModule_Create(space, ctx, hpydef):
- modname = rffi.charp2str(hpydef.c_m_name)
+ modname = rffi.constcharp2str(hpydef.c_m_name)
w_mod = Module(space, space.newtext(modname))
#
# add all the functions defined in hpydef.c_m_methods
@@ -100,7 +100,7 @@
def create_hpy_module(space, name, origin, lib, initfunc):
state = space.fromcache(State)
- initfunc = rffi.cast(llapi.HPyInitFuncPtr, initfunc)
+ initfunc = rffi.cast(llapi.HPyInitFunc, initfunc)
h_module = generic_cpy_call_dont_convert_result(space, initfunc, state.ctx)
return handles.consume(space, h_module)
diff --git a/pypy/module/hpy_universal/llapi.py
b/pypy/module/hpy_universal/llapi.py
--- a/pypy/module/hpy_universal/llapi.py
+++ b/pypy/module/hpy_universal/llapi.py
@@ -3,12 +3,13 @@
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.translator import cdir
from pypy import pypydir
-from pypy.module.hpy_universal import _vendored
+from pypy.module.cpyext.cparser import CTypeSpace
PYPYDIR = py.path.local(pypydir)
INCLUDE_DIR = PYPYDIR.join('module', 'hpy_universal', '_vendored', 'include')
SRC_DIR = PYPYDIR.join('module', 'hpy_universal', 'src')
+
eci = ExternalCompilationInfo(
includes=["universal/hpy.h", "getargs.h"],
include_dirs=[
@@ -21,6 +22,11 @@
],
post_include_bits=["""
RPY_EXTERN void *_HPy_GetGlobalCtx(void);
+
+ // these are workarounds for a CTypeSpace limitation, since it can't
properly
+ // handle struct types which are not typedefs
+ typedef struct _HPyContext_s _struct_HPyContext_s;
+ typedef struct _HPy_s _struct_HPy_s;
"""],
separate_module_sources=["""
struct _HPyContext_s hpy_global_ctx;
@@ -30,71 +36,89 @@
}
"""])
+cts = CTypeSpace()
+# NOTE: the following C source is NOT seen by the C compiler during
+# translation: it is used only as a nice way to declare the lltype.* types
+# which are needed here
+cts.headers.append('stdint.h')
+cts.parse_source("""
+typedef intptr_t HPy_ssize_t;
-HPy_ssize_t = lltype.Signed # XXXXXXXXX?
+// see below for more info about HPy vs _struct_HPy_s
+typedef struct _HPy_s {
+ HPy_ssize_t _i;
+} _struct_HPy_s;
+typedef HPy_ssize_t HPy;
+
+typedef struct _HPyContext_s {
+ int ctx_version;
+ struct _HPy_s h_None;
+ struct _HPy_s h_True;
+ struct _HPy_s h_False;
+ struct _HPy_s h_ValueError;
+ void *ctx_Module_Create;
+ void *ctx_Dup;
+ void *ctx_Close;
+ void *ctx_Long_FromLong;
+ void *ctx_Long_AsLong;
+ void *ctx_Arg_Parse;
+ void *ctx_Number_Add;
+ void *ctx_Unicode_FromString;
+ void *ctx_Err_SetString;
+ void *ctx_FromPyObject;
+ void *ctx_AsPyObject;
+ void *ctx_CallRealFunctionFromTrampoline;
+} _struct_HPyContext_s;
+typedef struct _HPyContext_s *HPyContext;
+
+typedef HPy (*HPyInitFunc)(HPyContext ctx);
+
+typedef HPy (*_HPyCFunction)(HPyContext ctx, HPy self, HPy args);
+typedef void *_HPyCPyCFunction; // not used here
+typedef void (*_HPyMethodPairFunc)(_HPyCFunction *out_func,
+ _HPyCPyCFunction *out_trampoline);
+typedef HPy (*HPyMeth_VarArgs)(HPyContext ctx, HPy self, HPy *args,
HPy_ssize_t nargs);
+
+typedef struct {
+ const char *ml_name;
+ _HPyMethodPairFunc ml_meth;
+ int ml_flags;
+ const char *ml_doc;
+} HPyMethodDef;
+
+typedef struct {
+ void *dummy; // this is needed because we put a comma after
HPyModuleDef_HEAD_INIT :(
+ const char* m_name;
+ const char* m_doc;
+ HPy_ssize_t m_size;
+ HPyMethodDef *m_methods;
+} HPyModuleDef;
+""")
+
+HPy_ssize_t = cts.gettype('HPy_ssize_t')
+# XXX: HPyContext is equivalent to the old HPyContext which was defined
+# explicitly using rffi.CStruct: the only different is that this is missing
+# hints={'eci': eci}: however, the tests still pass (including
+# ztranslation). Why was the eci needed?
+HPyContext = cts.gettype('HPyContext')
# for practical reason, we use a primitive type to represent HPy almost
-# everywhere in RPython. HOWEVER, the "real" HPy C type which is defined in
-# universal/hpy.h is an anonymous struct: we need to use it e.g. to represent
-# fields inside HPyContextS
-HPy = HPy_ssize_t
-HPyS_real = rffi.CStruct('HPy',
- ('_i', HPy_ssize_t),
- hints={'eci': eci, 'typedef': True},
-)
+# everywhere in RPython: for example, rffi cannot handle functions returning
+# structs. HOWEVER, the "real" HPy C type is a struct, which is available as
+# "_struct_HPy_s"
+HPy = cts.gettype('HPy')
+HPyInitFunc = cts.gettype('HPyInitFunc')
+_HPyCFunction = cts.gettype('_HPyCFunction')
+_HPyCPyCFunction = cts.gettype('_HPyCPyCFunction')
+HPyMeth_VarArgs = cts.gettype('HPyMeth_VarArgs')
-HPyContextS = rffi.CStruct('_HPyContext_s',
- ('ctx_version', rffi.INT_real),
- ('h_None', HPyS_real),
- ('h_True', HPyS_real),
- ('h_False', HPyS_real),
- ('h_ValueError', HPyS_real),
- ('ctx_Module_Create', rffi.VOIDP),
- ('ctx_Dup', rffi.VOIDP),
- ('ctx_Close', rffi.VOIDP),
- ('ctx_Long_FromLong', rffi.VOIDP),
- ('ctx_Long_AsLong', rffi.VOIDP),
- ('ctx_Arg_Parse', rffi.VOIDP),
- ('ctx_Number_Add', rffi.VOIDP),
- ('ctx_Unicode_FromString', rffi.VOIDP),
- ('ctx_Err_SetString', rffi.VOIDP),
- ('ctx_FromPyObject', rffi.VOIDP),
- ('ctx_AsPyObject', rffi.VOIDP),
- ('ctx_CallRealFunctionFromTrampoline', rffi.VOIDP),
- hints={'eci': eci},
-)
-HPyContext = lltype.Ptr(HPyContextS)
-HPyInitFuncPtr = lltype.Ptr(lltype.FuncType([HPyContext], HPy))
-
-_HPyCFunctionPtr = lltype.Ptr(lltype.FuncType([HPyContext, HPy, HPy], HPy))
-_HPy_CPyCFunctionPtr = rffi.VOIDP # not used here
-
-HPyMeth_VarArgs = lltype.Ptr(
- lltype.FuncType([HPyContext, HPy, lltype.Ptr(rffi.CArray(HPy)),
HPy_ssize_t], HPy))
-
-
-_HPyMethodPairFuncPtr = lltype.Ptr(lltype.FuncType([
- rffi.CArrayPtr(_HPyCFunctionPtr),
- rffi.CArrayPtr(_HPy_CPyCFunctionPtr)],
- lltype.Void))
-
-HPyMethodDef = rffi.CStruct('HPyMethodDef',
- ('ml_name', rffi.CCHARP),
- ('ml_meth', _HPyMethodPairFuncPtr),
- ('ml_flags', rffi.INT_real),
- ('ml_doc', rffi.CCHARP),
- hints={'eci': eci, 'typedef': True},
-)
-
-HPyModuleDef = rffi.CStruct('HPyModuleDef',
- ('dummy', rffi.VOIDP),
- ('m_name', rffi.CCHARP),
- ('m_doc', rffi.CCHARP),
- ('m_size', lltype.Signed),
- ('m_methods', rffi.CArrayPtr(HPyMethodDef)),
- hints={'eci': eci, 'typedef': True},
-)
+HPyMethodDef = cts.gettype('HPyMethodDef')
+HPyModuleDef = cts.gettype('HPyModuleDef')
+# CTypeSpace converts "HPyMethodDef*" into lltype.Ptr(HPyMethodDef), but we
+# want a CArrayPtr instead, so that we can index the items inside
+# HPyModule_Create
+HPyModuleDef._flds['c_m_methods'] = rffi.CArrayPtr(HPyMethodDef)
METH_VARARGS = 0x0001
METH_KEYWORDS = 0x0002
diff --git a/rpython/jit/backend/llsupport/test/test_descr.py
b/rpython/jit/backend/llsupport/test/test_descr.py
--- a/rpython/jit/backend/llsupport/test/test_descr.py
+++ b/rpython/jit/backend/llsupport/test/test_descr.py
@@ -426,9 +426,10 @@
#
fielddescr = get_field_arraylen_descr(c0, rstr.STR)
ofs = fielddescr.offset
- assert repr(ofs) == ("< <FieldOffset <GcStruct rpy_string { hash, chars }>"
- " 'chars'> + < ArrayLengthOffset"
- " <Array of Char > > >")
+ assert repr(ofs) == (
+ "< <FieldOffset <GcStruct rpy_string { hash, chars }> 'chars'> "
+ "+ < ArrayLengthOffset <Array of Char "
+ "{'extra_item_after_alloc': 1, 'immutable': True} > > >")
# caching:
assert fielddescr is get_field_arraylen_descr(c0, rstr.STR)
diff --git a/rpython/rtyper/lltypesystem/lltype.py
b/rpython/rtyper/lltypesystem/lltype.py
--- a/rpython/rtyper/lltypesystem/lltype.py
+++ b/rpython/rtyper/lltypesystem/lltype.py
@@ -467,12 +467,16 @@
_str_fields = saferecursive(_str_fields, '...')
def __str__(self):
- return "%s of %s " % (self.__class__.__name__,
- self._str_fields(),)
+ hints = (' ' + str(self._hints)) if self._hints else ''
+ return "%s of %s%s " % (self.__class__.__name__,
+ self._str_fields(),
+ hints)
def _short_name(self):
- return "%s %s" % (self.__class__.__name__,
- self.OF._short_name(),)
+ hints = (' ' + str(self._hints)) if self._hints else ''
+ return "%s %s%s" % (self.__class__.__name__,
+ self.OF._short_name(),
+ hints)
_short_name = saferecursive(_short_name, '...')
def _container_example(self):
diff --git a/rpython/rtyper/lltypesystem/rffi.py
b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -1024,6 +1024,14 @@
) = make_string_mappings(unicode)
+def constcharp2str(cp):
+ """
+ Like charp2str, but takes a CONST_CCHARP instead
+ """
+ cp = cast(CCHARP, cp)
+ return charp2str(cp)
+constcharp2str._annenforceargs_ = [lltype.SomePtr(CONST_CCHARP)]
+
@not_rpython
def _deprecated_get_nonmovingbuffer(*args):
raise Exception(
diff --git a/rpython/rtyper/lltypesystem/test/test_rffi.py
b/rpython/rtyper/lltypesystem/test/test_rffi.py
--- a/rpython/rtyper/lltypesystem/test/test_rffi.py
+++ b/rpython/rtyper/lltypesystem/test/test_rffi.py
@@ -142,6 +142,33 @@
xf = self.compile(f, [], backendopt=False)
assert xf() == 3
+ def test_constcharp2str(self):
+ c_source = py.code.Source("""
+ const char *z(void)
+ {
+ return "hello world";
+ }
+ """)
+ eci = ExternalCompilationInfo(separate_module_sources=[c_source],
+ post_include_bits=['const char
*z(void);'])
+ z = llexternal('z', [], CONST_CCHARP, compilation_info=eci)
+
+ def f():
+ l_buf = lltype.malloc(CCHARP.TO, 5, flavor='raw')
+ l_buf[0] = 'A'
+ l_buf[1] = 'B'
+ l_buf[2] = 'C'
+ l_buf[3] = '\x00'
+ l_buf[4] = 'E'
+ l_constbuf = cast(CONST_CCHARP, l_buf)
+ res = constcharp2str(l_constbuf)
+ lltype.free(l_buf, flavor='raw')
+ return len(res)
+
+ assert f() == 3
+ xf = self.compile(f, [], backendopt=False)
+ assert xf() == 3
+
def test_stringstar(self):
c_source = """
#include <string.h>
@@ -813,7 +840,7 @@
interpret(test_ptradd, [])
def test_voidptr():
- assert repr(VOIDP) == "<* Array of void >"
+ assert repr(VOIDP) == "<* Array of void {'nolength': True,
'render_as_void': True} >"
class TestCRffi(BaseTestRffi):
def compile(self, func, args, **kwds):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit