mirror of
https://github.com/python/cpython
synced 2026-09-29 12:10:30 +03:00
gh-95795: Move types.next_version_tag to PyInterpreterState (gh-102343)
Core static types will continue to use the global value. All other types will use the per-interpreter value. They all share the same range, where the global types use values < 2^16 and each interpreter uses values higher than that.
This commit is contained in:
parent
0dc8b50d33
commit
209a0a7655
4 changed files with 94 additions and 43 deletions
|
|
@ -45,7 +45,9 @@ class object "PyObject *" "&PyBaseObject_Type"
|
|||
PyUnicode_IS_READY(name) && \
|
||||
(PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE)
|
||||
|
||||
#define next_version_tag (_PyRuntime.types.next_version_tag)
|
||||
#define NEXT_GLOBAL_VERSION_TAG _PyRuntime.types.next_version_tag
|
||||
#define NEXT_VERSION_TAG(interp) \
|
||||
(interp)->types.next_version_tag
|
||||
|
||||
typedef struct PySlot_Offset {
|
||||
short subslot_offset;
|
||||
|
|
@ -332,7 +334,7 @@ _PyType_ClearCache(PyInterpreterState *interp)
|
|||
// use Py_SETREF() rather than using slower Py_XSETREF().
|
||||
type_cache_clear(cache, Py_None);
|
||||
|
||||
return next_version_tag - 1;
|
||||
return NEXT_VERSION_TAG(interp) - 1;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -401,7 +403,7 @@ PyType_ClearWatcher(int watcher_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int assign_version_tag(PyTypeObject *type);
|
||||
static int assign_version_tag(PyInterpreterState *interp, PyTypeObject *type);
|
||||
|
||||
int
|
||||
PyType_Watch(int watcher_id, PyObject* obj)
|
||||
|
|
@ -416,7 +418,7 @@ PyType_Watch(int watcher_id, PyObject* obj)
|
|||
return -1;
|
||||
}
|
||||
// ensure we will get a callback on the next modification
|
||||
assign_version_tag(type);
|
||||
assign_version_tag(interp, type);
|
||||
type->tp_watched |= (1 << watcher_id);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -549,7 +551,9 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
|||
}
|
||||
}
|
||||
return;
|
||||
|
||||
clear:
|
||||
assert(!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
|
||||
type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
|
||||
type->tp_version_tag = 0; /* 0 is not a valid version tag */
|
||||
if (PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
|
||||
|
|
@ -560,7 +564,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
|||
}
|
||||
|
||||
static int
|
||||
assign_version_tag(PyTypeObject *type)
|
||||
assign_version_tag(PyInterpreterState *interp, PyTypeObject *type)
|
||||
{
|
||||
/* Ensure that the tp_version_tag is valid and set
|
||||
Py_TPFLAGS_VALID_VERSION_TAG. To respect the invariant, this
|
||||
|
|
@ -574,18 +578,30 @@ assign_version_tag(PyTypeObject *type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (next_version_tag == 0) {
|
||||
/* We have run out of version numbers */
|
||||
return 0;
|
||||
if (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) {
|
||||
/* static types */
|
||||
if (NEXT_GLOBAL_VERSION_TAG > _Py_MAX_GLOBAL_TYPE_VERSION_TAG) {
|
||||
/* We have run out of version numbers */
|
||||
return 0;
|
||||
}
|
||||
type->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++;
|
||||
assert (type->tp_version_tag <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG);
|
||||
}
|
||||
else {
|
||||
/* heap types */
|
||||
if (NEXT_VERSION_TAG(interp) == 0) {
|
||||
/* We have run out of version numbers */
|
||||
return 0;
|
||||
}
|
||||
type->tp_version_tag = NEXT_VERSION_TAG(interp)++;
|
||||
assert (type->tp_version_tag != 0);
|
||||
}
|
||||
type->tp_version_tag = next_version_tag++;
|
||||
assert (type->tp_version_tag != 0);
|
||||
|
||||
PyObject *bases = type->tp_bases;
|
||||
Py_ssize_t n = PyTuple_GET_SIZE(bases);
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
PyObject *b = PyTuple_GET_ITEM(bases, i);
|
||||
if (!assign_version_tag(_PyType_CAST(b)))
|
||||
if (!assign_version_tag(interp, _PyType_CAST(b)))
|
||||
return 0;
|
||||
}
|
||||
type->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG;
|
||||
|
|
@ -594,7 +610,8 @@ assign_version_tag(PyTypeObject *type)
|
|||
|
||||
int PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
|
||||
{
|
||||
return assign_version_tag(type);
|
||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||
return assign_version_tag(interp, type);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2346,7 +2363,15 @@ mro_internal(PyTypeObject *type, PyObject **p_old_mro)
|
|||
from the custom MRO */
|
||||
type_mro_modified(type, type->tp_bases);
|
||||
|
||||
PyType_Modified(type);
|
||||
// XXX Expand this to Py_TPFLAGS_IMMUTABLETYPE?
|
||||
if (!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)) {
|
||||
PyType_Modified(type);
|
||||
}
|
||||
else {
|
||||
/* For static builtin types, this is only called during init
|
||||
before the method cache has been populated. */
|
||||
assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG));
|
||||
}
|
||||
|
||||
if (p_old_mro != NULL)
|
||||
*p_old_mro = old_mro; /* transfer the ownership */
|
||||
|
|
@ -4181,6 +4206,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
|
|||
{
|
||||
PyObject *res;
|
||||
int error;
|
||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||
|
||||
unsigned int h = MCACHE_HASH_METHOD(type, name);
|
||||
struct type_cache *cache = get_type_cache();
|
||||
|
|
@ -4215,7 +4241,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(type)) {
|
||||
if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(interp, type)) {
|
||||
h = MCACHE_HASH_METHOD(type, name);
|
||||
struct type_cache_entry *entry = &cache->hashtable[h];
|
||||
entry->version = type->tp_version_tag;
|
||||
|
|
@ -6676,8 +6702,11 @@ type_ready_mro(PyTypeObject *type)
|
|||
assert(type->tp_mro != NULL);
|
||||
assert(PyTuple_Check(type->tp_mro));
|
||||
|
||||
/* All bases of statically allocated type should be statically allocated */
|
||||
/* All bases of statically allocated type should be statically allocated,
|
||||
and static builtin types must have static builtin bases. */
|
||||
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
|
||||
assert(type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE);
|
||||
int isbuiltin = type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN;
|
||||
PyObject *mro = type->tp_mro;
|
||||
Py_ssize_t n = PyTuple_GET_SIZE(mro);
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
|
|
@ -6689,6 +6718,7 @@ type_ready_mro(PyTypeObject *type)
|
|||
type->tp_name, base->tp_name);
|
||||
return -1;
|
||||
}
|
||||
assert(!isbuiltin || (base->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -7000,7 +7030,11 @@ PyType_Ready(PyTypeObject *type)
|
|||
int
|
||||
_PyStaticType_InitBuiltin(PyTypeObject *self)
|
||||
{
|
||||
self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN;
|
||||
self->tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN;
|
||||
|
||||
assert(NEXT_GLOBAL_VERSION_TAG <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG);
|
||||
self->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++;
|
||||
self->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG;
|
||||
|
||||
static_builtin_state_init(self);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue