[pypy-commit] cffi default: Make the type objects mortal
arigo
noreply at buildbot.pypy.org
Wed Sep 30 17:20:40 CEST 2015
Author: Armin Rigo <arigo at 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()
More information about the pypy-commit
mailing list