// bpo-42745: next_version_tag remains shared by all interpreters because of static types
// Used to set PyTypeObject.tp_version_tag
-static unsigned int next_version_tag = 0;
+static unsigned int next_version_tag = 1;
typedef struct PySlot_Offset {
short subslot_offset;
static void
-type_cache_clear(struct type_cache *cache, int use_none)
+type_cache_clear(struct type_cache *cache, PyObject *value)
{
for (Py_ssize_t i = 0; i < (1 << MCACHE_SIZE_EXP); i++) {
struct type_cache_entry *entry = &cache->hashtable[i];
entry->version = 0;
- if (use_none) {
- // Set to None so _PyType_Lookup() can use Py_SETREF(),
- // rather than using slower Py_XSETREF().
- Py_XSETREF(entry->name, Py_NewRef(Py_None));
- }
- else {
- Py_CLEAR(entry->name);
- }
+ Py_XSETREF(entry->name, _Py_XNewRef(value));
entry->value = NULL;
}
-
- // Mark all version tags as invalid
- PyType_Modified(&PyBaseObject_Type);
}
sizeof(cache->hashtable) / 1024);
#endif
- unsigned int cur_version_tag = next_version_tag - 1;
- if (_Py_IsMainInterpreter(interp)) {
- next_version_tag = 0;
- }
+ // Set to None, rather than NULL, so _PyType_Lookup() can
+ // use Py_SETREF() rather than using slower Py_XSETREF().
+ type_cache_clear(cache, Py_None);
- type_cache_clear(cache, 0);
-
- return cur_version_tag;
+ return next_version_tag - 1;
}
void
_PyType_Fini(PyInterpreterState *interp)
{
- _PyType_ClearCache(interp);
+ struct type_cache *cache = &interp->type_cache;
+ type_cache_clear(cache, NULL);
if (_Py_IsMainInterpreter(interp)) {
clear_slotdefs();
}
if (!_PyType_HasFeature(type, Py_TPFLAGS_READY))
return 0;
- type->tp_version_tag = next_version_tag++;
- /* for stress-testing: next_version_tag &= 0xFF; */
-
- if (type->tp_version_tag == 0) {
- // Wrap-around or just starting Python - clear the whole cache
- type_cache_clear(cache, 1);
+ if (next_version_tag == 0) {
+ /* We have run out of version numbers */
return 0;
}
+ type->tp_version_tag = next_version_tag++;
+ assert (type->tp_version_tag != 0);
bases = type->tp_bases;
n = PyTuple_GET_SIZE(bases);