[pypy-commit] cffi cffi-1.0: Resolve the F_EXTERNAL struct names by following the ffi.include chain

arigo noreply at buildbot.pypy.org
Mon Apr 27 23:48:57 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1866:8218d7a07822
Date: 2015-04-27 23:48 +0200
http://bitbucket.org/cffi/cffi/changeset/8218d7a07822/

Log:	Resolve the F_EXTERNAL struct names by following the ffi.include
	chain

diff --git a/_cffi1/cffi1_module.c b/_cffi1/cffi1_module.c
--- a/_cffi1/cffi1_module.c
+++ b/_cffi1/cffi1_module.c
@@ -114,7 +114,7 @@
     if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0)
         return -1;
 
-    if (make_included_tuples(ctx->includes, &ffi->included_ffis,
+    if (make_included_tuples(ctx->includes, &ffi->types_builder->included_ffis,
                              &lib->l_includes) < 0)
         return -1;
 
diff --git a/_cffi1/cffi_opcode.py b/_cffi1/cffi_opcode.py
--- a/_cffi1/cffi_opcode.py
+++ b/_cffi1/cffi_opcode.py
@@ -100,6 +100,7 @@
 F_UNION         = 0x01
 F_CHECK_FIELDS  = 0x02
 F_PACKED        = 0x04
+F_EXTERNAL      = 0x08
 
 CLASS_NAME = {}
 for _name, _value in globals().items():
diff --git a/_cffi1/ffi_obj.c b/_cffi1/ffi_obj.c
--- a/_cffi1/ffi_obj.c
+++ b/_cffi1/ffi_obj.c
@@ -26,7 +26,6 @@
     struct _cffi_parse_info_s info;
     int ctx_is_static;
     builder_c_t *types_builder;
-    PyObject *included_ffis;
 };
 
 static FFIObject *ffi_internal_new(PyTypeObject *ffitype,
@@ -56,7 +55,6 @@
     ffi->info.output = internal_output;
     ffi->info.output_size = FFI_COMPLEXITY_OUTPUT;
     ffi->ctx_is_static = (static_ctx != NULL);
-    ffi->included_ffis = NULL;
 #if 0
     ffi->dynamic_types = NULL;
 #endif
@@ -74,15 +72,14 @@
     if (!ffi->ctx_is_static)
         free_builder_c(ffi->types_builder);
 
-    Py_XDECREF(ffi->included_ffis);
     Py_TYPE(ffi)->tp_free((PyObject *)ffi);
 }
 
 static int ffi_traverse(FFIObject *ffi, visitproc visit, void *arg)
 {
     Py_VISIT(ffi->types_builder->types_dict);
+    Py_VISIT(ffi->types_builder->included_ffis);
     Py_VISIT(ffi->gc_wrefs);
-    Py_VISIT(ffi->included_ffis);
     return 0;
 }
 
@@ -809,3 +806,44 @@
     ffiobj_new,                                 /* tp_new */
     PyObject_GC_Del,                            /* tp_free */
 };
+
+
+static PyObject *
+_fetch_external_struct_or_union(const struct _cffi_struct_union_s *s,
+                                PyObject *included_ffis, int recursion)
+{
+    if (included_ffis == NULL)
+        return NULL;
+
+    if (recursion > 100) {
+        PyErr_SetString(PyExc_RuntimeError,
+                        "recursion overflow in ffi.include() delegations");
+        return NULL;
+    }
+
+    Py_ssize_t i;
+    for (i = 0; i < PyTuple_GET_SIZE(included_ffis); i++) {
+        FFIObject *ffi1;
+        const struct _cffi_struct_union_s *s1;
+        int sindex;
+        PyObject *x;
+
+        ffi1 = (FFIObject *)PyTuple_GET_ITEM(included_ffis, i);
+        sindex = search_in_struct_unions(&ffi1->types_builder->ctx, s->name,
+                                         strlen(s->name));
+        if (sindex < 0)  /* not found at all */
+            continue;
+        s1 = &ffi1->types_builder->ctx.struct_unions[sindex];
+        if ((s1->flags & (_CFFI_F_EXTERNAL | _CFFI_F_UNION))
+                == (s->flags & _CFFI_F_UNION)) {
+            /* s1 is not external, and the same kind (struct or union) as s */
+            return _realize_c_struct_or_union(ffi1->types_builder, sindex);
+        }
+        /* not found, look more recursively */
+        x = _fetch_external_struct_or_union(
+                s, ffi1->types_builder->included_ffis, recursion + 1);
+        if (x != NULL || PyErr_Occurred())
+            return x;   /* either found, or got an error */
+    }
+    return NULL;   /* not found at all, leave without an error */
+}
diff --git a/_cffi1/realize_c_type.c b/_cffi1/realize_c_type.c
--- a/_cffi1/realize_c_type.c
+++ b/_cffi1/realize_c_type.c
@@ -2,6 +2,7 @@
 typedef struct {
     struct _cffi_type_context_s ctx;   /* inlined substructure */
     PyObject *types_dict;
+    PyObject *included_ffis;
 } builder_c_t;
 
 
@@ -74,6 +75,9 @@
         if (mem[i] != NULL)
             PyMem_Free((void *)mem[i]);
     }
+
+    Py_XDECREF(builder->included_ffis);
+    builder->included_ffis = NULL;
 }
 
 static void free_builder_c(builder_c_t *builder)
@@ -101,6 +105,7 @@
         memset(&builder->ctx, 0, sizeof(builder->ctx));
 
     builder->types_dict = ldict;
+    builder->included_ffis = NULL;
 #if 0
     builder->num_types_imported = 0;
 #endif
@@ -268,6 +273,79 @@
     }
 }
 
+static PyObject *                                              /* forward */
+_fetch_external_struct_or_union(const struct _cffi_struct_union_s *s,
+                                PyObject *included_ffis, int recursion);
+
+static PyObject *
+_realize_c_struct_or_union(builder_c_t *builder, int sindex)
+{
+    PyObject *x;
+    _cffi_opcode_t op2;
+    const struct _cffi_struct_union_s *s;
+
+    s = &builder->ctx.struct_unions[sindex];
+    op2 = builder->ctx.types[s->type_index];
+    if ((((uintptr_t)op2) & 1) == 0) {
+        x = (PyObject *)op2;     /* found already in the "primary" slot */
+        Py_INCREF(x);
+    }
+    else {
+        CTypeDescrObject *ct = NULL;
+
+        if (!(s->flags & _CFFI_F_EXTERNAL)) {
+            int flags = (s->flags & _CFFI_F_UNION) ? CT_UNION : CT_STRUCT;
+            char *name = alloca(8 + strlen(s->name));
+            _realize_name(name,
+                          (s->flags & _CFFI_F_UNION) ? "union " : "struct ",
+                          s->name);
+            if (strcmp(name, "struct _IO_FILE") == 0)
+                flags |= CT_IS_FILE;
+
+            x = new_struct_or_union_type(name, flags);
+            if (x == NULL)
+                return NULL;
+
+            if (s->first_field_index >= 0) {
+                ct = (CTypeDescrObject *)x;
+                ct->ct_size = (Py_ssize_t)s->size;
+                ct->ct_length = s->alignment;
+                ct->ct_flags &= ~CT_IS_OPAQUE;
+                ct->ct_flags |= CT_LAZY_FIELD_LIST;
+                ct->ct_extra = builder;
+            }
+        }
+        else {
+            x = _fetch_external_struct_or_union(s, builder->included_ffis, 0);
+            if (x == NULL) {
+                if (!PyErr_Occurred())
+                    PyErr_Format(FFIError, "'%s %.200s' should come from "
+                                 "ffi.include() but was not found",
+                                 (s->flags & _CFFI_F_UNION) ? "union"
+                                 : "struct", s->name);
+                return NULL;
+            }
+        }
+
+        /* Update the "primary" OP_STRUCT_UNION slot */
+        assert((((uintptr_t)x) & 1) == 0);
+        assert(builder->ctx.types[s->type_index] == op2);
+        Py_INCREF(x);
+        builder->ctx.types[s->type_index] = x;
+
+        if (ct != NULL && s->size == (size_t)-2) {
+            /* oops, this struct is unnamed and we couldn't generate
+               a C expression to get its size.  We have to rely on
+               complete_struct_or_union() to compute it now. */
+            if (do_realize_lazy_struct(ct) < 0) {
+                builder->ctx.types[s->type_index] = op2;
+                return NULL;
+            }
+        }
+    }
+    return x;
+}
+
 static PyObject *
 _realize_c_type_or_func(builder_c_t *builder,
                         _cffi_opcode_t opcodes[], int index)
@@ -320,62 +398,8 @@
         break;
 
     case _CFFI_OP_STRUCT_UNION:
-    {
-        const struct _cffi_struct_union_s *s;
-        _cffi_opcode_t op2;
-
-        s = &builder->ctx.struct_unions[_CFFI_GETARG(op)];
-        op2 = builder->ctx.types[s->type_index];
-        if ((((uintptr_t)op2) & 1) == 0) {
-            x = (PyObject *)op2;
-            Py_INCREF(x);
-        }
-        else {
-            int flags = (s->flags & _CFFI_F_UNION) ? CT_UNION : CT_STRUCT;
-            char *name = alloca(8 + strlen(s->name));
-            _realize_name(name,
-                          (s->flags & _CFFI_F_UNION) ? "union " : "struct ",
-                          s->name);
-            if (strcmp(name, "struct _IO_FILE") == 0)
-                flags |= CT_IS_FILE;
-
-            x = new_struct_or_union_type(name, flags);
-
-            CTypeDescrObject *ct = NULL;
-            if (s->first_field_index >= 0) {
-                ct = (CTypeDescrObject *)x;
-                ct->ct_size = (Py_ssize_t)s->size;
-                ct->ct_length = s->alignment;
-                ct->ct_flags &= ~CT_IS_OPAQUE;
-                ct->ct_flags |= CT_LAZY_FIELD_LIST;
-                ct->ct_extra = builder;
-            }
-
-            /* Update the "primary" OP_STRUCT_UNION slot, which
-               may be the same or a different slot than the "current" one */
-            assert((((uintptr_t)x) & 1) == 0);
-            assert(builder->ctx.types[s->type_index] == op2);
-            Py_INCREF(x);
-            builder->ctx.types[s->type_index] = x;
-
-            if (s->size == (size_t)-2) {
-                /* oops, this struct is unnamed and we couldn't generate
-                   a C expression to get its size.  We have to rely on
-                   complete_struct_or_union() to compute it now. */
-                assert(ct != NULL);
-                if (do_realize_lazy_struct(ct) < 0) {
-                    builder->ctx.types[s->type_index] = op2;
-                    return NULL;
-                }
-            }
-
-            /* Done, leave without updating the "current" slot because
-               it may be done already above.  If not, never mind, the
-               next call to realize_c_type() will do it. */
-            return x;
-        }
+        x = _realize_c_struct_or_union(builder, _CFFI_GETARG(op));
         break;
-    }
 
     case _CFFI_OP_ENUM:
     {
@@ -530,7 +554,7 @@
         return NULL;
     }
 
-    if (x != NULL && opcodes == builder->ctx.types) {
+    if (x != NULL && opcodes == builder->ctx.types && opcodes[index] != x) {
         assert((((uintptr_t)x) & 1) == 0);
         assert((((uintptr_t)opcodes[index]) & 1) == 1);
         Py_INCREF(x);
diff --git a/_cffi1/test_recompiler.py b/_cffi1/test_recompiler.py
--- a/_cffi1/test_recompiler.py
+++ b/_cffi1/test_recompiler.py
@@ -484,7 +484,7 @@
     ffi.include(ffi1)
     ffi.cdef("struct foo_s *ff2(struct foo_s *);")
     lib = verify(ffi, "test_include_2",
-                 "struct foo_s { int x, y; };\n"
+                 "struct foo_s { int x, y; }; //usually from a #include\n"
                  "struct foo_s *ff2(struct foo_s *p) { p->y++; return p; }")
     p = ffi.new("struct foo_s *")
     p.y = 41


More information about the pypy-commit mailing list