[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