mirror of https://github.com/python/cpython
bpo-44914: Maintain invariants of type version tags. (GH-27773)
* Do not invalidate type versions unnecessarily.
This commit is contained in:
parent
62bc716fde
commit
1a511dc92d
|
@ -0,0 +1,5 @@
|
|||
Class version tags are no longer recycled.
|
||||
|
||||
This means that a version tag serves as a unique identifier for the state of
|
||||
a class. We rely on this for effective specialization of the LOAD_ATTR and
|
||||
other instructions.
|
|
@ -45,7 +45,7 @@ class object "PyObject *" "&PyBaseObject_Type"
|
|||
|
||||
// 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;
|
||||
|
@ -233,24 +233,14 @@ get_type_cache(void)
|
|||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -287,14 +277,11 @@ _PyType_ClearCache(PyInterpreterState *interp)
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -309,7 +296,8 @@ PyType_ClearCache(void)
|
|||
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();
|
||||
}
|
||||
|
@ -426,14 +414,12 @@ assign_version_tag(struct type_cache *cache, PyTypeObject *type)
|
|||
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);
|
||||
|
|
Loading…
Reference in New Issue