Author: Armin Rigo <ar...@tunes.org> Branch: cffi-1.0 Changeset: r1855:04e073297436 Date: 2015-04-27 15:33 +0200 http://bitbucket.org/cffi/cffi/changeset/04e073297436/
Log: Move the guarantee of uniqueness of types to the core _cffi_backend.c. Gets rid of USES_LOCAL which is not really compatible with ffi.include(). diff --git a/_cffi1/ffi_obj.c b/_cffi1/ffi_obj.c --- a/_cffi1/ffi_obj.c +++ b/_cffi1/ffi_obj.c @@ -400,7 +400,6 @@ } z = new_pointer_type(ct); - z = get_unique_type(self->types_builder, z); if (z == NULL) return NULL; 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 @@ -7,7 +7,6 @@ static PyObject *all_primitives[_CFFI__NUM_PRIM]; -static PyObject *global_types_dict; static CTypeDescrObject *g_ct_voidp, *g_ct_chararray; static PyObject *build_primitive_type(int num); /* forward */ @@ -16,14 +15,6 @@ (all_primitives[num] != NULL ? all_primitives[num] \ : build_primitive_type(num)) -static int _add_to_global_types_dict(PyObject *ct) -{ - if (ct == NULL) - return -1; - return PyDict_SetItemString(global_types_dict, - ((CTypeDescrObject *)ct)->ct_name, ct); -} - static int init_global_types_dict(PyObject *ffi_type_dict) { int err; @@ -32,29 +23,25 @@ MemoryErrors during importing an extension module are kind of bad anyway */ - global_types_dict = PyDict_New(); - if (global_types_dict == NULL) - return -1; - ct_void = get_primitive_type(_CFFI_PRIM_VOID); // 'void' - if (_add_to_global_types_dict(ct_void) < 0) + if (ct_void == NULL) return -1; ct2 = new_pointer_type((CTypeDescrObject *)ct_void); // 'void *' - if (_add_to_global_types_dict(ct2) < 0) + if (ct2 == NULL) return -1; g_ct_voidp = (CTypeDescrObject *)ct2; ct_char = get_primitive_type(_CFFI_PRIM_CHAR); // 'char' - if (_add_to_global_types_dict(ct_char) < 0) + if (ct_char == NULL) return -1; ct2 = new_pointer_type((CTypeDescrObject *)ct_char); // 'char *' - if (_add_to_global_types_dict(ct2) < 0) + if (ct2 == NULL) return -1; ct2 = new_array_type((CTypeDescrObject *)ct2, -1); // 'char[]' - if (_add_to_global_types_dict(ct2) < 0) + if (ct2 == NULL) return -1; g_ct_chararray = (CTypeDescrObject *)ct2; @@ -117,66 +104,6 @@ return builder; } -static PyObject *get_unique_type(builder_c_t *builder, PyObject *x) -{ - /* Replace the CTypeDescrObject 'x' with a standardized one. - This either just returns x, or x is decrefed and a new reference - to the standard equivalent is returned. - - In this function, 'x' always contains a reference that must be - decrefed, and 'y' never does. - */ - CTypeDescrObject *ct = (CTypeDescrObject *)x; - if (ct == NULL) - return NULL; - - /* XXX maybe change the type of ct_name to be a real 'PyObject *'? */ - PyObject *name = PyString_FromString(ct->ct_name); - if (name == NULL) - goto no_memory; - - PyObject *y = PyDict_GetItem(builder->types_dict, name); - if (y != NULL) { - /* Already found the same ct_name in the dict. Return the old one. */ - Py_INCREF(y); - Py_DECREF(x); - x = y; - goto done; - } - - if (!(ct->ct_flags & CT_USES_LOCAL)) { - /* The type is not "local", i.e. does not make use of any struct, - union or enum. This means it should be shared across independent - ffi instances. Look it up and possibly add it to the global - types dict. - */ - y = PyDict_GetItem(global_types_dict, name); - if (y != NULL) { - Py_INCREF(y); - Py_DECREF(x); - x = y; - } - else { - /* Not found in the global dictionary. Put it there. */ - if (PyDict_SetItem(global_types_dict, name, x) < 0) - goto no_memory; - } - } - - /* Set x in the local dict. */ - if (PyDict_SetItem(builder->types_dict, name, x) < 0) - goto no_memory; - - done: - Py_DECREF(name); - return x; - - no_memory: - Py_XDECREF(name); - Py_DECREF(x); - return NULL; -} - static PyObject *build_primitive_type(int num) { /* XXX too many translations between here and new_primitive_type() */ @@ -365,7 +292,6 @@ return NULL; if (CTypeDescr_Check(y)) { x = new_pointer_type((CTypeDescrObject *)y); - x = get_unique_type(builder, x); } else { assert(PyTuple_Check(y)); /* from _CFFI_OP_FUNCTION */ @@ -383,12 +309,10 @@ if (y == NULL) return NULL; z = new_pointer_type((CTypeDescrObject *)y); - z = get_unique_type(builder, z); Py_DECREF(y); if (z == NULL) return NULL; x = new_array_type((CTypeDescrObject *)z, length); - x = get_unique_type(builder, x); Py_DECREF(z); break; @@ -573,7 +497,6 @@ z = new_function_type(fargs, (CTypeDescrObject *)y, ellipsis, FFI_DEFAULT_ABI); - z = get_unique_type(builder, z); Py_DECREF(fargs); Py_DECREF(y); if (z == NULL) diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -132,7 +132,6 @@ #define CT_WITH_VAR_ARRAY 1048576 #define CT_IS_UNSIZED_CHAR_A 2097152 #define CT_LAZY_FIELD_LIST 4194304 -#define CT_USES_LOCAL 8388608 #define CT_PRIMITIVE_ANY (CT_PRIMITIVE_SIGNED | \ CT_PRIMITIVE_UNSIGNED | \ CT_PRIMITIVE_CHAR | \ @@ -3381,6 +3380,57 @@ /************************************************************/ +static PyObject *unique_cache; + +static PyObject *get_unique_type(CTypeDescrObject *x, + const void *unique_key[], long keylength) +{ + /* Replace the CTypeDescrObject 'x' with a standardized one. + This either just returns x, or x is decrefed and a new reference + to the already-existing equivalent is returned. + + In this function, 'x' always contains a reference that must be + either decrefed or returned. + + Keys: + void ["void"] + primitive [&static_struct] + pointer [ctype] + array [ctype, length] + funcptr [ctresult, ellipsis+abi, num_args, ctargs...] + */ + long i; + PyObject *key, *y; + const void **pkey; + int err; + + key = PyString_FromStringAndSize(NULL, keylength * sizeof(void *)); + if (key == NULL) + goto error; + + pkey = (const void **)PyString_AS_STRING(key); + for (i = 0; i < keylength; i++) + pkey[i] = unique_key[i]; + + y = PyDict_GetItem(unique_cache, key); + if (y != NULL) { + Py_DECREF(key); + Py_INCREF(y); + Py_DECREF(x); + return y; + } + err = PyDict_SetItem(unique_cache, key, (PyObject *)x); + Py_DECREF(key); + if (err < 0) + goto error; + + return (PyObject *)x; + + error: + Py_DECREF(x); + return NULL; +} + static PyObject *new_primitive_type(const char *name) { #define ENUM_PRIMITIVE_TYPES \ @@ -3461,6 +3511,7 @@ { NULL } }; const struct descr_s *ptypes; + const void *unique_key[1]; int name_size; ffi_type *ffitype; @@ -3526,7 +3577,8 @@ td->ct_flags |= CT_PRIMITIVE_FITS_LONG; } td->ct_name_position = strlen(td->ct_name); - return (PyObject *)td; + unique_key[0] = ptypes; + return get_unique_type(td, unique_key, 1); bad_ffi_type: PyErr_Format(PyExc_NotImplementedError, @@ -3548,6 +3600,7 @@ { CTypeDescrObject *td; const char *extra; + const void *unique_key[1]; if (ctitem->ct_flags & CT_ARRAY) extra = "(*)"; /* obscure case: see test_array_add */ @@ -3559,7 +3612,7 @@ td->ct_size = sizeof(void *); td->ct_length = -1; - td->ct_flags = CT_POINTER | (ctitem->ct_flags & CT_USES_LOCAL); + td->ct_flags = CT_POINTER; if (ctitem->ct_flags & (CT_STRUCT|CT_UNION)) td->ct_flags |= CT_IS_PTR_TO_OWNED; if (ctitem->ct_flags & CT_VOID) @@ -3568,7 +3621,8 @@ ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) && ctitem->ct_size == sizeof(char))) td->ct_flags |= CT_CAST_ANYTHING; /* 'void *' or 'char *' only */ - return (PyObject *)td; + unique_key[0] = ctitem; + return get_unique_type(td, unique_key, 1); } static PyObject *b_new_pointer_type(PyObject *self, PyObject *args) @@ -3611,6 +3665,7 @@ char extra_text[32]; Py_ssize_t arraysize; int flags = CT_ARRAY; + const void *unique_key[2]; if (!(ctptr->ct_flags & CT_POINTER)) { PyErr_SetString(PyExc_TypeError, "first arg must be a pointer ctype"); @@ -3648,13 +3703,16 @@ td->ct_stuff = (PyObject *)ctptr; td->ct_size = arraysize; td->ct_length = length; - td->ct_flags = flags | (ctptr->ct_flags & CT_USES_LOCAL); - return (PyObject *)td; + td->ct_flags = flags; + unique_key[0] = ctptr; + unique_key[1] = (void *)length; + return get_unique_type(td, unique_key, 2); } static PyObject *new_void_type(void) { int name_size = strlen("void") + 1; + const void *unique_key[1]; CTypeDescrObject *td = ctypedescr_new(name_size); if (td == NULL) return NULL; @@ -3663,7 +3721,8 @@ td->ct_size = -1; td->ct_flags = CT_VOID | CT_IS_OPAQUE; td->ct_name_position = strlen("void"); - return (PyObject *)td; + unique_key[0] = "void"; + return get_unique_type(td, unique_key, 1); } static PyObject *b_new_void_type(PyObject *self, PyObject *args) @@ -3680,7 +3739,7 @@ td->ct_size = -1; td->ct_length = -1; - td->ct_flags = flag | CT_IS_OPAQUE | CT_USES_LOCAL; + td->ct_flags = flag | CT_IS_OPAQUE; td->ct_extra = NULL; memcpy(td->ct_name, name, namelen + 1); td->ct_name_position = namelen; @@ -4406,8 +4465,6 @@ int ellipsis) { CTypeDescrObject *fct; - Py_ssize_t i, nargs; - int all_flags; fb->nb_bytes = 0; fb->bufferp = NULL; @@ -4429,16 +4486,9 @@ goto error; assert(fb->bufferp == fct->ct_name + fb->nb_bytes); - all_flags = fresult->ct_flags; - nargs = PyTuple_GET_SIZE(fargs); - for (i = 0; i < nargs; i++) { - CTypeDescrObject *farg = (CTypeDescrObject *)PyTuple_GET_ITEM(fargs, i); - all_flags |= farg->ct_flags; - } - fct->ct_extra = NULL; fct->ct_size = sizeof(void(*)(void)); - fct->ct_flags = CT_FUNCTIONPTR | (all_flags & CT_USES_LOCAL); + fct->ct_flags = CT_FUNCTIONPTR; return fct; error: @@ -4496,6 +4546,7 @@ CTypeDescrObject *fct; struct funcbuilder_s funcbuilder; Py_ssize_t i; + const void **unique_key; if ((fresult->ct_size < 0 && !(fresult->ct_flags & CT_VOID)) || (fresult->ct_flags & CT_ARRAY)) { @@ -4551,7 +4602,15 @@ Py_INCREF(o); PyTuple_SET_ITEM(fct->ct_stuff, 2 + i, o); } - return (PyObject *)fct; + + /* [ctresult, ellipsis+abi, num_args, ctargs...] */ + unique_key = alloca((3 + funcbuilder.nargs) * sizeof(void *)); + unique_key[0] = fresult; + unique_key[1] = (const void *)(Py_ssize_t)((fabi << 1) | !!ellipsis); + unique_key[2] = (const void *)(Py_ssize_t)(funcbuilder.nargs); + for (i=0; i<funcbuilder.nargs; i++) + unique_key[3 + i] = PyTuple_GET_ITEM(fct->ct_stuff, 2 + i); + return get_unique_type(fct, unique_key, 3 + funcbuilder.nargs); error: Py_DECREF(fct); @@ -4890,7 +4949,7 @@ td->ct_size = basetd->ct_size; td->ct_length = basetd->ct_length; /* alignment */ td->ct_extra = basetd->ct_extra; /* ffi type */ - td->ct_flags = basetd->ct_flags | CT_IS_ENUM | CT_USES_LOCAL; + td->ct_flags = basetd->ct_flags | CT_IS_ENUM; td->ct_name_position = name_size - 1; return (PyObject *)td; @@ -5914,6 +5973,11 @@ if (m == NULL) INITERROR; + + unique_cache = PyDict_New(); + if (unique_cache == NULL) + INITERROR; + if (PyType_Ready(&dl_type) < 0) INITERROR; if (PyType_Ready(&CTypeDescr_Type) < 0) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit