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

Reply via email to