[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