Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r2296:9ad33a44f60f Date: 2015-09-30 17:17 +0200 http://bitbucket.org/cffi/cffi/changeset/9ad33a44f60f/
Log: Make the type objects mortal diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -155,6 +155,9 @@ PyObject *ct_weakreflist; /* weakref support */ + PyObject *ct_unique_key; /* key in unique_cache (a string, but not + human-readable) */ + Py_ssize_t ct_size; /* size of instances, or -1 if unknown */ Py_ssize_t ct_length; /* length of arrays, or -1 if unknown; or alignment of primitive and struct types; @@ -286,6 +289,7 @@ typedef PyObject *const cffi_allocator_t[3]; static cffi_allocator_t default_allocator = { NULL, NULL, NULL }; static PyObject *FFIError; +static PyObject *unique_cache; /************************************************************/ @@ -301,6 +305,7 @@ ct->ct_itemdescr = NULL; ct->ct_stuff = NULL; ct->ct_weakreflist = NULL; + ct->ct_unique_key = NULL; PyObject_GC_Track(ct); return ct; } @@ -343,6 +348,15 @@ PyObject_GC_UnTrack(ct); if (ct->ct_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) ct); + + if (ct->ct_unique_key != NULL) { + /* revive dead object temporarily for DelItem */ + Py_REFCNT(ct) = 43; + PyDict_DelItem(unique_cache, ct->ct_unique_key); + assert(Py_REFCNT(ct) == 42); + Py_REFCNT(ct) = 0; + Py_DECREF(ct->ct_unique_key); + } Py_XDECREF(ct->ct_itemdescr); Py_XDECREF(ct->ct_stuff); if (ct->ct_flags & CT_FUNCTIONPTR) @@ -3612,8 +3626,6 @@ /************************************************************/ -static PyObject *unique_cache; - static PyObject *get_unique_type(CTypeDescrObject *x, const void *unique_key[], long keylength) { @@ -3633,7 +3645,6 @@ */ PyObject *key, *y; const void **pkey; - int err; key = PyBytes_FromStringAndSize(NULL, keylength * sizeof(void *)); if (key == NULL) @@ -3649,11 +3660,14 @@ Py_DECREF(x); return y; } - err = PyDict_SetItem(unique_cache, key, (PyObject *)x); - Py_DECREF(key); - if (err < 0) + if (PyDict_SetItem(unique_cache, key, (PyObject *)x) < 0) { + Py_DECREF(key); goto error; - + } + + assert(x->ct_unique_key == NULL); + x->ct_unique_key = key; /* the key will be freed in ctypedescr_dealloc() */ + Py_DECREF(x); /* the 'value' in unique_cache doesn't count as 1 */ return (PyObject *)x; error: diff --git a/testing/cffi1/test_ffi_obj.py b/testing/cffi1/test_ffi_obj.py --- a/testing/cffi1/test_ffi_obj.py +++ b/testing/cffi1/test_ffi_obj.py @@ -29,6 +29,32 @@ assert ffi.typeof("int[][10]") is ffi.typeof("int[][10]") assert ffi.typeof("int(*)()") is ffi.typeof("int(*)()") +def test_ffi_type_not_immortal(): + import weakref, gc + ffi = _cffi1_backend.FFI() + t1 = ffi.typeof("int **") + t2 = ffi.typeof("int *") + w1 = weakref.ref(t1) + w2 = weakref.ref(t2) + del t1, ffi + gc.collect() + assert w1() is None + assert w2() is t2 + ffi = _cffi1_backend.FFI() + assert ffi.typeof(ffi.new("int **")[0]) is t2 + # + ffi = _cffi1_backend.FFI() + t1 = ffi.typeof("int ***") + t2 = ffi.typeof("int **") + w1 = weakref.ref(t1) + w2 = weakref.ref(t2) + del t2, ffi + gc.collect() + assert w1() is t1 + assert w2() is not None # kept alive by t1 + ffi = _cffi1_backend.FFI() + assert ffi.typeof("int * *") is t1.item + def test_ffi_cache_type_globally(): ffi1 = _cffi1_backend.FFI() ffi2 = _cffi1_backend.FFI() _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit