[pypy-commit] cffi cffi-1.0: in-progress: declare structs on FFIs after a cdef()

arigo noreply at buildbot.pypy.org
Wed Apr 22 15:51:43 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1775:8acbc3c22b22
Date: 2015-04-22 15:52 +0200
http://bitbucket.org/cffi/cffi/changeset/8acbc3c22b22/

Log:	in-progress: declare structs on FFIs after a cdef()

diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -97,6 +97,7 @@
             if override:
                 for cache in self._function_caches:
                     cache.clear()
+        _set_cdef_types(self)
 
     def dlopen(self, name, flags=0):
         """Load and return a dynamic library identified by 'name'.
@@ -565,3 +566,27 @@
     else:
         with ffi._lock:
             return ffi._get_cached_btype(tp)
+
+def _set_cdef_types(ffi):
+    struct_unions = []
+    pending_completion = []
+    for name, tp in sorted(ffi._parser._declarations.items()):
+        if name.startswith('struct '):
+            tp.check_not_partial()
+            basename = name[7:]
+            BType = _cffi1_backend.new_struct_type(basename)
+            struct_unions.append(basename)
+            struct_unions.append(BType)
+            if tp.fldtypes is not None:
+                pending_completion.append((tp, BType))
+    #
+    ffi.__set_types(struct_unions)
+    #
+    for tp, BType in pending_completion:
+        fldtypes = [ffi.typeof(ftp._get_c_name()) for ftp in tp.fldtypes]
+        lst = list(zip(tp.fldnames, fldtypes, tp.fldbitsize))
+        sflags = 0
+        if tp.packed:
+            sflags = 8    # SF_PACKED
+        _cffi1_backend.complete_struct_or_union(BType, lst, ffi,
+                                                -1, -1, sflags)
diff --git a/new/cffi1_module.c b/new/cffi1_module.c
--- a/new/cffi1_module.c
+++ b/new/cffi1_module.c
@@ -51,7 +51,7 @@
     if (m == NULL)
         return -1;
 
-    FFIObject *ffi = ffi_internal_new(&FFI_Type, ctx, 1);
+    FFIObject *ffi = ffi_internal_new(&FFI_Type, ctx);
     Py_XINCREF(ffi);    /* make the ffi object really immortal */
     if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0)
         return -1;
diff --git a/new/ffi_obj.c b/new/ffi_obj.c
--- a/new/ffi_obj.c
+++ b/new/ffi_obj.c
@@ -24,15 +24,15 @@
     struct _cffi_parse_info_s info;
     int ctx_is_static;
     builder_c_t *types_builder;
+    PyObject *dynamic_types;
     _cffi_opcode_t internal_output[FFI_COMPLEXITY_OUTPUT];
 };
 
 static FFIObject *ffi_internal_new(PyTypeObject *ffitype,
-                                   const struct _cffi_type_context_s *ctx,
-                                   int ctx_is_static)
+                                 const struct _cffi_type_context_s *static_ctx)
 {
     FFIObject *ffi;
-    if (ctx_is_static) {
+    if (static_ctx != NULL) {
         ffi = (FFIObject *)PyObject_GC_New(FFIObject, ffitype);
         /* we don't call PyObject_GC_Track() here: from _cffi_init_module()
            it is not needed, because in this case the ffi object is immortal */
@@ -43,16 +43,17 @@
     if (ffi == NULL)
         return NULL;
 
-    ffi->types_builder = new_builder_c(ctx);
+    ffi->types_builder = new_builder_c(static_ctx);
     if (ffi->types_builder == NULL) {
         Py_DECREF(ffi);
         return NULL;
     }
     ffi->gc_wrefs = NULL;
-    ffi->info.ctx = ctx;
+    ffi->info.ctx = &ffi->types_builder->ctx;
     ffi->info.output = ffi->internal_output;
     ffi->info.output_size = FFI_COMPLEXITY_OUTPUT;
-    ffi->ctx_is_static = ctx_is_static;
+    ffi->ctx_is_static = (static_ctx != NULL);
+    ffi->dynamic_types = NULL;
     return ffi;
 }
 
@@ -60,6 +61,7 @@
 {
     PyObject_GC_UnTrack(ffi);
     Py_XDECREF(ffi->gc_wrefs);
+    Py_XDECREF(ffi->dynamic_types);
 
     if (!ffi->ctx_is_static)
         free_builder_c(ffi->types_builder);
@@ -77,22 +79,7 @@
 static PyObject *ffiobj_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
     /* user-facing initialization code, for explicit FFI() calls */
-    struct _cffi_type_context_s *ctx;
-    PyObject *result;
-
-    ctx = PyMem_Malloc(sizeof(struct _cffi_type_context_s));
-    if (ctx == NULL) {
-        PyErr_NoMemory();
-        return NULL;
-    }
-    memset(ctx, 0, sizeof(struct _cffi_type_context_s));
-
-    result = (PyObject *)ffi_internal_new(type, ctx, 0);
-    if (result == NULL) {
-        PyMem_Free(ctx);
-        return NULL;
-    }
-    return result;
+    return (PyObject *)ffi_internal_new(type, NULL);
 }
 
 static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds)
@@ -548,7 +535,72 @@
     return 0;
 }
 
+static PyObject *ffi__set_types(FFIObject *self, PyObject *args)
+{
+    PyObject *lst1;
+    _cffi_opcode_t *types = NULL;
+    struct _cffi_struct_union_s *struct_unions = NULL;
+
+    if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &lst1))
+        return NULL;
+
+    if (self->ctx_is_static) {
+     bad_usage:
+        PyMem_Free(struct_unions);
+        PyMem_Free(types);
+        if (!PyErr_Occurred())
+            PyErr_SetString(PyExc_RuntimeError, "internal error");
+        return NULL;
+    }
+
+    cleanup_builder_c(self->types_builder);
+
+    int i, lst_length = PyList_GET_SIZE(lst1) / 2;
+    Py_ssize_t new_size_1 = sizeof(_cffi_opcode_t) * lst_length;
+    Py_ssize_t new_size_2 = sizeof(struct _cffi_struct_union_s) * lst_length;
+    types = PyMem_Malloc(new_size_1);
+    struct_unions = PyMem_Malloc(new_size_2);
+    if (!types || !struct_unions) {
+        PyErr_NoMemory();
+        goto bad_usage;
+    }
+    memset(types, 0, new_size_1);
+    memset(struct_unions, 0, new_size_2);
+
+    for (i = 0; i < lst_length; i++) {
+        PyObject *x = PyList_GET_ITEM(lst1, i * 2);
+        if (!PyString_Check(x))
+            goto bad_usage;
+        struct_unions[i].name = PyString_AS_STRING(x);
+        struct_unions[i].type_index = i;
+        //struct_unions[i].flags = ...;
+        struct_unions[i].size = (size_t)-2;
+        struct_unions[i].alignment = -2;
+
+        x = PyList_GET_ITEM(lst1, i * 2 + 1);
+        if (!CTypeDescr_Check(x))
+            goto bad_usage;
+        types[i] = x;
+    }
+    for (i = 0; i < lst_length; i++) {
+        PyObject *x = (PyObject *)types[i];
+        Py_INCREF(x);
+    }
+
+    Py_INCREF(lst1);     /* to keep alive the strings in '.name' */
+    Py_XDECREF(self->dynamic_types);
+    self->dynamic_types = lst1;
+    self->types_builder->ctx.types = types;
+    self->types_builder->num_types_imported = lst_length;
+    self->types_builder->ctx.struct_unions = struct_unions;
+    self->types_builder->ctx.num_struct_unions = lst_length;
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
 static PyMethodDef ffi_methods[] = {
+    {"__set_types",   (PyCFunction)ffi__set_types,METH_VARARGS},
 #if 0
     {"addressof",     (PyCFunction)ffi_addressof, METH_VARARGS},
 #endif
diff --git a/new/realize_c_type.c b/new/realize_c_type.c
--- a/new/realize_c_type.c
+++ b/new/realize_c_type.c
@@ -2,6 +2,7 @@
 typedef struct {
     struct _cffi_type_context_s ctx;   /* inlined substructure */
     PyObject *types_dict;
+    int num_types_imported;
 } builder_c_t;
 
 
@@ -44,9 +45,15 @@
     return err;
 }
 
-static void free_builder_c(builder_c_t *builder)
+static void cleanup_builder_c(builder_c_t *builder)
 {
-    Py_XDECREF(builder->types_dict);
+    int i;
+    for (i = builder->num_types_imported; (--i) >= 0; ) {
+        _cffi_opcode_t x = builder->ctx.types[i];
+        if ((((uintptr_t)x) & 1) == 0) {
+            Py_XDECREF((PyObject *)x);
+        }
+    }
 
     const void *mem[] = {builder->ctx.types,
                          builder->ctx.globals,
@@ -54,11 +61,16 @@
                          builder->ctx.fields,
                          builder->ctx.enums,
                          builder->ctx.typenames};
-    int i;
     for (i = 0; i < sizeof(mem) / sizeof(*mem); i++) {
         if (mem[i] != NULL)
             PyMem_Free((void *)mem[i]);
     }
+}
+
+static void free_builder_c(builder_c_t *builder)
+{
+    Py_XDECREF(builder->types_dict);
+    cleanup_builder_c(builder);
     PyMem_Free(builder);
 }
 
@@ -74,8 +86,13 @@
         PyErr_NoMemory();
         return NULL;
     }
-    builder->ctx = *ctx;
+    if (ctx)
+        builder->ctx = *ctx;
+    else
+        memset(&builder->ctx, 0, sizeof(builder->ctx));
+
     builder->types_dict = ldict;
+    builder->num_types_imported = 0;
     return builder;
 }
 
diff --git a/new/test_dlopen.py b/new/test_dlopen.py
--- a/new/test_dlopen.py
+++ b/new/test_dlopen.py
@@ -3,6 +3,11 @@
 import math
 
 
+def test_cdef_struct():
+    ffi = FFI()
+    ffi.cdef("struct foo_s { int a, b; };")
+    assert ffi.sizeof("struct foo_s") == 8
+
 def test_math_sin():
     py.test.skip("XXX redo!")
     ffi = FFI()


More information about the pypy-commit mailing list