55
66#include <ctype.h>
77
8-
9- /* Support type attribute cache */
10-
11- /* The cache can keep references to the names alive for longer than
12- they normally would. This is why the maximum size is limited to
13- MCACHE_MAX_ATTR_SIZE, since it might be a problem if very large
14- strings are used as attribute names. */
15- #define MCACHE_MAX_ATTR_SIZE 100
16- #define MCACHE_SIZE_EXP 10
17- #define MCACHE_HASH (version , name_hash ) \
18- (((unsigned int)(version) * (unsigned int)(name_hash)) \
19- >> (8*sizeof(unsigned int) - MCACHE_SIZE_EXP))
20- #define MCACHE_HASH_METHOD (type , name ) \
21- MCACHE_HASH((type)->tp_version_tag, \
22- ((PyStringObject *)(name))->ob_shash)
23- #define MCACHE_CACHEABLE_NAME (name ) \
24- PyString_CheckExact(name) && \
25- PyString_GET_SIZE(name) <= MCACHE_MAX_ATTR_SIZE
26-
27- struct method_cache_entry {
28- unsigned int version ;
29- PyObject * name ; /* reference to exactly a str or None */
30- PyObject * value ; /* borrowed */
31- };
32-
33- static struct method_cache_entry method_cache [1 << MCACHE_SIZE_EXP ];
34- static unsigned int next_version_tag = 0 ;
35-
36- static void
37- type_modified (PyTypeObject * type )
38- {
39- /* Invalidate any cached data for the specified type and all
40- subclasses. This function is called after the base
41- classes, mro, or attributes of the type are altered.
42-
43- Invariants:
44-
45- - Py_TPFLAGS_VALID_VERSION_TAG is never set if
46- Py_TPFLAGS_HAVE_VERSION_TAG is not set (e.g. on type
47- objects coming from non-recompiled extension modules)
48-
49- - before Py_TPFLAGS_VALID_VERSION_TAG can be set on a type,
50- it must first be set on all super types.
51-
52- This function clears the Py_TPFLAGS_VALID_VERSION_TAG of a
53- type (so it must first clear it on all subclasses). The
54- tp_version_tag value is meaningless unless this flag is set.
55- We don't assign new version tags eagerly, but only as
56- needed.
57- */
58- PyObject * raw , * ref ;
59- Py_ssize_t i , n ;
60-
61- if (!PyType_HasFeature (type , Py_TPFLAGS_VALID_VERSION_TAG ))
62- return ;
63-
64- raw = type -> tp_subclasses ;
65- if (raw != NULL ) {
66- n = PyList_GET_SIZE (raw );
67- for (i = 0 ; i < n ; i ++ ) {
68- ref = PyList_GET_ITEM (raw , i );
69- ref = PyWeakref_GET_OBJECT (ref );
70- if (ref != Py_None ) {
71- type_modified ((PyTypeObject * )ref );
72- }
73- }
74- }
75- type -> tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG ;
76- }
77-
78- static void
79- type_mro_modified (PyTypeObject * type , PyObject * bases ) {
80- /*
81- Check that all base classes or elements of the mro of type are
82- able to be cached. This function is called after the base
83- classes or mro of the type are altered.
84-
85- Unset HAVE_VERSION_TAG and VALID_VERSION_TAG if the type
86- inherits from an old-style class, either directly or if it
87- appears in the MRO of a new-style class. No support either for
88- custom MROs that include types that are not officially super
89- types.
90-
91- Called from mro_internal, which will subsequently be called on
92- each subclass when their mro is recursively updated.
93- */
94- Py_ssize_t i , n ;
95- int clear = 0 ;
96-
97- if (!PyType_HasFeature (type , Py_TPFLAGS_HAVE_VERSION_TAG ))
98- return ;
99-
100- n = PyTuple_GET_SIZE (bases );
101- for (i = 0 ; i < n ; i ++ ) {
102- PyObject * b = PyTuple_GET_ITEM (bases , i );
103- PyTypeObject * cls ;
104-
105- if (!PyType_Check (b ) ) {
106- clear = 1 ;
107- break ;
108- }
109-
110- cls = (PyTypeObject * )b ;
111-
112- if (!PyType_HasFeature (cls , Py_TPFLAGS_HAVE_VERSION_TAG ) ||
113- !PyType_IsSubtype (type , cls )) {
114- clear = 1 ;
115- break ;
116- }
117- }
118-
119- if (clear )
120- type -> tp_flags &= ~(Py_TPFLAGS_HAVE_VERSION_TAG |
121- Py_TPFLAGS_VALID_VERSION_TAG );
122- }
123-
124- static int
125- assign_version_tag (PyTypeObject * type )
126- {
127- /* Ensure that the tp_version_tag is valid and set
128- Py_TPFLAGS_VALID_VERSION_TAG. To respect the invariant, this
129- must first be done on all super classes. Return 0 if this
130- cannot be done, 1 if Py_TPFLAGS_VALID_VERSION_TAG.
131- */
132- Py_ssize_t i , n ;
133- PyObject * bases ;
134-
135- if (PyType_HasFeature (type , Py_TPFLAGS_VALID_VERSION_TAG ))
136- return 1 ;
137- if (!PyType_HasFeature (type , Py_TPFLAGS_HAVE_VERSION_TAG ))
138- return 0 ;
139- if (!PyType_HasFeature (type , Py_TPFLAGS_READY ))
140- return 0 ;
141-
142- type -> tp_version_tag = next_version_tag ++ ;
143- /* for stress-testing: next_version_tag &= 0xFF; */
144-
145- if (type -> tp_version_tag == 0 ) {
146- /* wrap-around or just starting Python - clear the whole
147- cache by filling names with references to Py_None.
148- Values are also set to NULL for added protection, as they
149- are borrowed reference */
150- for (i = 0 ; i < (1 << MCACHE_SIZE_EXP ); i ++ ) {
151- method_cache [i ].value = NULL ;
152- Py_XDECREF (method_cache [i ].name );
153- method_cache [i ].name = Py_None ;
154- Py_INCREF (Py_None );
155- }
156- /* mark all version tags as invalid */
157- type_modified (& PyBaseObject_Type );
158- return 1 ;
159- }
160- bases = type -> tp_bases ;
161- n = PyTuple_GET_SIZE (bases );
162- for (i = 0 ; i < n ; i ++ ) {
163- PyObject * b = PyTuple_GET_ITEM (bases , i );
164- assert (PyType_Check (b ));
165- if (!assign_version_tag ((PyTypeObject * )b ))
166- return 0 ;
167- }
168- type -> tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG ;
169- return 1 ;
170- }
171-
172-
1738static PyMemberDef type_members [] = {
1749 {"__basicsize__" , T_INT , offsetof(PyTypeObject ,tp_basicsize ),READONLY },
17510 {"__itemsize__" , T_INT , offsetof(PyTypeObject , tp_itemsize ), READONLY },
@@ -282,8 +117,6 @@ type_set_module(PyTypeObject *type, PyObject *value, void *context)
282117 return -1 ;
283118 }
284119
285- type_modified (type );
286-
287120 return PyDict_SetItemString (type -> tp_dict , "__module__" , value );
288121}
289122
@@ -1518,14 +1351,6 @@ mro_internal(PyTypeObject *type)
15181351 }
15191352 }
15201353 type -> tp_mro = tuple ;
1521-
1522- type_mro_modified (type , type -> tp_mro );
1523- /* corner case: the old-style super class might have been hidden
1524- from the custom MRO */
1525- type_mro_modified (type , type -> tp_bases );
1526-
1527- type_modified (type );
1528-
15291354 return 0 ;
15301355}
15311356
@@ -2318,16 +2143,6 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
23182143{
23192144 Py_ssize_t i , n ;
23202145 PyObject * mro , * res , * base , * dict ;
2321- unsigned int h ;
2322-
2323- if (MCACHE_CACHEABLE_NAME (name ) &&
2324- PyType_HasFeature (type ,Py_TPFLAGS_VALID_VERSION_TAG )) {
2325- /* fast path */
2326- h = MCACHE_HASH_METHOD (type , name );
2327- if (method_cache [h ].version == type -> tp_version_tag &&
2328- method_cache [h ].name == name )
2329- return method_cache [h ].value ;
2330- }
23312146
23322147 /* Look in tp_dict of types in MRO */
23332148 mro = type -> tp_mro ;
@@ -2338,7 +2153,6 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
23382153 if (mro == NULL )
23392154 return NULL ;
23402155
2341- res = NULL ;
23422156 assert (PyTuple_Check (mro ));
23432157 n = PyTuple_GET_SIZE (mro );
23442158 for (i = 0 ; i < n ; i ++ ) {
@@ -2352,18 +2166,9 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
23522166 assert (dict && PyDict_Check (dict ));
23532167 res = PyDict_GetItem (dict , name );
23542168 if (res != NULL )
2355- break ;
2356- }
2357-
2358- if (MCACHE_CACHEABLE_NAME (name ) && assign_version_tag (type )) {
2359- h = MCACHE_HASH_METHOD (type , name );
2360- method_cache [h ].version = type -> tp_version_tag ;
2361- method_cache [h ].value = res ; /* borrowed */
2362- Py_INCREF (name );
2363- Py_DECREF (method_cache [h ].name );
2364- method_cache [h ].name = name ;
2169+ return res ;
23652170 }
2366- return res ;
2171+ return NULL ;
23672172}
23682173
23692174/* This is similar to PyObject_GenericGetAttr(),
@@ -2453,6 +2258,10 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
24532258 type -> tp_name );
24542259 return -1 ;
24552260 }
2261+ /* XXX Example of how I expect this to be used...
2262+ if (update_subclasses(type, name, invalidate_cache, NULL) < 0)
2263+ return -1;
2264+ */
24562265 if (PyObject_GenericSetAttr ((PyObject * )type , name , value ) < 0 )
24572266 return -1 ;
24582267 return update_slot (type , name );
@@ -5875,13 +5684,6 @@ update_slot(PyTypeObject *type, PyObject *name)
58755684 slotdef * * pp ;
58765685 int offset ;
58775686
5878- /* Clear the VALID_VERSION flag of 'type' and all its
5879- subclasses. This could possibly be unified with the
5880- update_subclasses() recursion below, but carefully:
5881- they each have their own conditions on which to stop
5882- recursing into subclasses. */
5883- type_modified (type );
5884-
58855687 init_slotdefs ();
58865688 pp = ptrs ;
58875689 for (p = slotdefs ; p -> name ; p ++ ) {
0 commit comments