invalidate the cache of all subtypes when updating a type's tp_dict (algorithm copied...
authorStefan Behnel <scoder@users.berlios.de>
Mon, 26 May 2008 22:12:36 +0000 (00:12 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Mon, 26 May 2008 22:12:36 +0000 (00:12 +0200)
Cython/Compiler/ExprNodes.py

index 6372ea777da1f8e0ab2c7b4ca343cddb9d26a04a..f6b59cdf20fd914b59d7615907a7bf6cab567c45 100644 (file)
@@ -847,6 +847,8 @@ class NameNode(AtomicExprNode):
         env.control_flow.set_state(self.pos, (self.name, 'source'), 'assignment')
         if self.entry.is_declared_generic:
             self.result_ctype = py_object_type
+        if self.entry.is_pyglobal and self.entry.is_member:
+            env.use_utility_code(type_cache_invalidation_code)
     
     def analyse_types(self, env):
         self.entry = env.lookup(self.name)
@@ -990,11 +992,8 @@ class NameNode(AtomicExprNode):
                         self.interned_cname,
                         rhs.py_result()))
                 # in Py2.6+, we need to invalidate the method cache
-                typeptr_cname = entry.scope.parent_type.typeptr_cname
-                code.putln("#if PY_VERSION_HEX >= 0x02060000")
-                code.putln("(%s)->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;" %
-                           typeptr_cname)
-                code.putln("#endif")
+                code.putln("__Pyx_TypeModified((PyTypeObject*)%s);" %
+                           entry.scope.parent_type.typeptr_cname)
             else: 
                 code.put_error_if_neg(self.pos,
                     'PyObject_SetAttr(%s, %s, %s)' % (
@@ -4102,3 +4101,39 @@ static INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
 }
 """,""
 ]
+
+#------------------------------------------------------------------------------------
+
+type_cache_invalidation_code = [
+"""
+#if PY_VERSION_HEX >= 0x02060000
+static void __Pyx_TypeModified(PyTypeObject* type); /*proto*/
+#else
+  #define __Pyx_TypeModified(t)
+#endif
+""","""
+#if PY_VERSION_HEX >= 0x02060000
+/* copied from typeobject.c in Python 3.0a5 */
+static void __Pyx_TypeModified(PyTypeObject* type) {
+    PyObject *raw, *ref;
+    Py_ssize_t i, n;
+
+    if (!PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG))
+        return;
+
+    raw = type->tp_subclasses;
+    if (raw != NULL) {
+        n = PyList_GET_SIZE(raw);
+        for (i = 0; i < n; i++) {
+            ref = PyList_GET_ITEM(raw, i);
+            ref = PyWeakref_GET_OBJECT(ref);
+            if (ref != Py_None) {
+                __Pyx_TypeModified((PyTypeObject *)ref);
+            }
+        }
+    }
+    type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
+}
+#endif
+"""
+]