Hi,
Guido van Rossum wrote:
> On Tue, May 27, 2008 at 9:47 AM, Stefan Behnel <[EMAIL PROTECTED]> wrote:
>> Could this function get a public interface? I do not think Cython is the only
>> case where C code wants to modify a type after its creation, and copying the
>> code over seems like a hack to me.
>>
> I'm fine with giving it a public interface. Please submit a patch with
> docs included.
Straight forward patch is attached (against 3.0a5). Works for me in Cython. I
thought about a name like "Taint(t)" or "ClearTypeCache(t)", but then went
with the coward solution of calling the function PyType_Modified() as it was
(almost) named internally.
BTW, I noticed that the code in typeobject.c uses "DECREF before set" two
times, like this:
method_cache[h].version = type->tp_version_tag;
method_cache[h].value = res; /* borrowed */
Py_INCREF(name);
Py_DECREF(method_cache[h].name);
method_cache[h].name = name;
During the call to Py_DECREF, the cache content is incorrect, so can't this
run into the same problem that Py_CLEAR() aims to solve? I attached a patch
for that, too, just in case.
Stefan
--- Include/object.h.ORIG 2008-05-27 21:34:30.000000000 +0200
+++ Include/object.h 2008-05-27 21:22:22.000000000 +0200
@@ -428,6 +428,7 @@
PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
PyAPI_FUNC(unsigned int) PyType_ClearCache(void);
+PyAPI_FUNC(void) PyType_Modified(PyTypeObject *);
/* Generic operations on objects */
PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
--- Objects/typeobject.c.ORIG 2008-05-27 21:35:05.000000000 +0200
+++ Objects/typeobject.c 2008-05-27 21:33:45.000000000 +0200
@@ -33,7 +33,6 @@
static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP];
static unsigned int next_version_tag = 0;
-static void type_modified(PyTypeObject *);
unsigned int
PyType_ClearCache(void)
@@ -48,12 +47,12 @@
}
next_version_tag = 0;
/* mark all version tags as invalid */
- type_modified(&PyBaseObject_Type);
+ PyType_Modified(&PyBaseObject_Type);
return cur_version_tag;
}
-static void
-type_modified(PyTypeObject *type)
+void
+PyType_Modified(PyTypeObject *type)
{
/* Invalidate any cached data for the specified type and all
subclasses. This function is called after the base
@@ -87,7 +86,7 @@
ref = PyList_GET_ITEM(raw, i);
ref = PyWeakref_GET_OBJECT(ref);
if (ref != Py_None) {
- type_modified((PyTypeObject *)ref);
+ PyType_Modified((PyTypeObject *)ref);
}
}
}
@@ -173,7 +172,7 @@
Py_INCREF(Py_None);
}
/* mark all version tags as invalid */
- type_modified(&PyBaseObject_Type);
+ PyType_Modified(&PyBaseObject_Type);
return 1;
}
bases = type->tp_bases;
@@ -313,7 +312,7 @@
return -1;
}
- type_modified(type);
+ PyType_Modified(type);
return PyDict_SetItemString(type->tp_dict, "__module__", value);
}
@@ -341,7 +340,7 @@
int res = PyDict_SetItemString(type->tp_dict,
"__abstractmethods__", value);
if (res == 0) {
- type_modified(type);
+ PyType_Modified(type);
if (value && PyObject_IsTrue(value)) {
type->tp_flags |= Py_TPFLAGS_IS_ABSTRACT;
}
@@ -1520,7 +1519,7 @@
from the custom MRO */
type_mro_modified(type, type->tp_bases);
- type_modified(type);
+ PyType_Modified(type);
return 0;
}
@@ -5734,7 +5733,7 @@
update_subclasses() recursion below, but carefully:
they each have their own conditions on which to stop
recursing into subclasses. */
- type_modified(type);
+ PyType_Modified(type);
init_slotdefs();
pp = ptrs;
--- Doc/c-api/type.rst.ORIG 2008-05-27 21:35:14.000000000 +0200
+++ Doc/c-api/type.rst 2008-05-27 21:44:20.000000000 +0200
@@ -38,6 +38,13 @@
Clears the internal lookup cache. Return the current version tag.
+.. cfunction:: void PyType_Modified(PyTypeObject *type)
+
+ Invalidates the internal lookup cache for the type and all of its
+ subtypes. This function must be called after any manual
+ modification of the attributes or base classes of the type.
+
+
.. cfunction:: int PyType_HasFeature(PyObject *o, int feature)
Return true if the type object *o* sets the feature *feature*. Type features
--- Objects/typeobject.c.NEW 2008-05-27 22:26:18.000000000 +0200
+++ Objects/typeobject.c 2008-05-27 22:28:55.000000000 +0200
@@ -148,7 +148,7 @@
cannot be done, 1 if Py_TPFLAGS_VALID_VERSION_TAG.
*/
Py_ssize_t i, n;
- PyObject *bases;
+ PyObject *bases, *tmp;
if (PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG))
return 1;
@@ -167,9 +167,10 @@
are borrowed reference */
for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) {
method_cache[i].value = NULL;
- Py_XDECREF(method_cache[i].name);
- method_cache[i].name = Py_None;
+ tmp = method_cache[i].name;
Py_INCREF(Py_None);
+ method_cache[i].name = Py_None;
+ Py_XDECREF(tmp);
}
/* mark all version tags as invalid */
PyType_Modified(&PyBaseObject_Type);
@@ -2254,7 +2255,7 @@
_PyType_Lookup(PyTypeObject *type, PyObject *name)
{
Py_ssize_t i, n;
- PyObject *mro, *res, *base, *dict;
+ PyObject *mro, *res, *base, *dict, *tmp;
unsigned int h;
if (MCACHE_CACHEABLE_NAME(name) &&
@@ -2292,9 +2293,10 @@
h = MCACHE_HASH_METHOD(type, name);
method_cache[h].version = type->tp_version_tag;
method_cache[h].value = res; /* borrowed */
+ tmp = method_cache[h].name;
Py_INCREF(name);
- Py_DECREF(method_cache[h].name);
method_cache[h].name = name;
+ Py_DECREF(tmp);
}
return res;
}
_______________________________________________
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com