From e3057cec4880ee4600794628c2f4c4684761ee01 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 4 Jun 2024 12:46:11 -0600 Subject: [PATCH 1/8] Clean up managed_static_type_state_init() a little. --- Objects/typeobject.c | 77 ++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 958f42430c80a2..6664e9f9c9a81c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -145,12 +145,49 @@ managed_static_type_index_get(PyTypeObject *self) return (size_t)self->tp_subclasses - 1; } -static inline void -managed_static_type_index_set(PyTypeObject *self, size_t index) +static size_t +managed_static_type_index_init(PyInterpreterState *interp, + PyTypeObject *self, int isbuiltin) { + assert(!managed_static_type_index_is_set(self)); + + size_t index; + if (isbuiltin) { + assert(_Py_IsMainInterpreter(interp)); + index = interp->types.builtins.num_initialized; + assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); + interp->types.builtins.num_initialized++; + } + else { + PyMutex_Lock(&interp->types.mutex); + index = interp->types.for_extensions.next_index; + interp->types.for_extensions.next_index++; + interp->types.for_extensions.num_initialized++; + PyMutex_Unlock(&interp->types.mutex); + assert(index < _Py_MAX_MANAGED_STATIC_EXT_TYPES); + } + assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); /* We store a 1-based index so 0 can mean "not initialized". */ self->tp_subclasses = (PyObject *)(index + 1); + return index; +} + +static size_t +managed_static_type_index_sync(PyInterpreterState *interp, + PyTypeObject *self, int isbuiltin) +{ + size_t index = managed_static_type_index_get(self); + if (isbuiltin) { + assert(index == interp->types.builtins.num_initialized); + assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); + interp->types.builtins.num_initialized++; + } + else { + assert(index < _Py_MAX_MANAGED_STATIC_EXT_TYPES); + interp->types.for_extensions.num_initialized++; + } + return index; } static inline void @@ -214,32 +251,9 @@ managed_static_type_state_init(PyInterpreterState *interp, PyTypeObject *self, { assert(interp->runtime == &_PyRuntime); - size_t index; - if (initial) { - assert(!managed_static_type_index_is_set(self)); - if (isbuiltin) { - index = interp->types.builtins.num_initialized; - assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); - } - else { - PyMutex_Lock(&interp->types.mutex); - index = interp->types.for_extensions.next_index; - interp->types.for_extensions.next_index++; - PyMutex_Unlock(&interp->types.mutex); - assert(index < _Py_MAX_MANAGED_STATIC_EXT_TYPES); - } - managed_static_type_index_set(self, index); - } - else { - index = managed_static_type_index_get(self); - if (isbuiltin) { - assert(index == interp->types.builtins.num_initialized); - assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); - } - else { - assert(index < _Py_MAX_MANAGED_STATIC_EXT_TYPES); - } - } + size_t index = initial + ? managed_static_type_index_init(interp, self, isbuiltin) + : managed_static_type_index_sync(interp, self, isbuiltin); size_t full_index = isbuiltin ? index : index + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; @@ -269,13 +283,6 @@ managed_static_type_state_init(PyInterpreterState *interp, PyTypeObject *self, /* state->tp_subclasses is left NULL until init_subclasses() sets it. */ /* state->tp_weaklist is left NULL until insert_head() or insert_after() (in weakrefobject.c) sets it. */ - - if (isbuiltin) { - interp->types.builtins.num_initialized++; - } - else { - interp->types.for_extensions.num_initialized++; - } } /* Reset the type's per-interpreter state. From 049934be73ce0064875cce969b01ceb3636e94ac Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 4 Jun 2024 14:36:17 -0600 Subject: [PATCH 2/8] Track managed static types globally, with a shared index pool. --- Include/internal/pycore_typeobject.h | 7 +- Objects/typeobject.c | 202 ++++++++++++++++++--------- 2 files changed, 138 insertions(+), 71 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 32bd19d968b917..1ecab7fc5c8da0 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -31,8 +31,13 @@ struct _types_runtime_state { unsigned int next_version_tag; struct { + PyMutex mutex; + size_t num_builtins; + size_t num_types; + size_t next_index; struct { PyTypeObject *type; + int isbuiltin; int64_t interp_count; } types[_Py_MAX_MANAGED_STATIC_TYPES]; } managed_static; @@ -58,7 +63,6 @@ struct type_cache { typedef struct { PyTypeObject *type; - int isbuiltin; int readying; int ready; // XXX tp_dict can probably be statically allocated, @@ -125,7 +129,6 @@ struct types_state { /* We apply a similar strategy for managed extension modules. */ struct { size_t num_initialized; - size_t next_index; managed_static_type_state initialized[_Py_MAX_MANAGED_STATIC_EXT_TYPES]; } for_extensions; PyMutex mutex; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 6664e9f9c9a81c..bfe1b6e2970d01 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -149,25 +149,35 @@ static size_t managed_static_type_index_init(PyInterpreterState *interp, PyTypeObject *self, int isbuiltin) { + assert(interp->runtime == &_PyRuntime); assert(!managed_static_type_index_is_set(self)); size_t index; if (isbuiltin) { + index = _PyRuntime.types.managed_static.next_index; + _PyRuntime.types.managed_static.next_index += 1; assert(_Py_IsMainInterpreter(interp)); - index = interp->types.builtins.num_initialized; assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); - interp->types.builtins.num_initialized++; + assert(index == _PyRuntime.types.managed_static.num_builtins); + assert(index == interp->types.builtins.num_initialized); } else { + PyMutex_Lock(&_PyRuntime.types.managed_static.mutex); + index = _PyRuntime.types.managed_static.next_index; + _PyRuntime.types.managed_static.next_index += 1; + if (index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES) { + index = _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; + _PyRuntime.types.managed_static.next_index = index + 1; + } + PyMutex_Unlock(&_PyRuntime.types.managed_static.mutex); + assert(index < _Py_MAX_MANAGED_STATIC_TYPES); + PyMutex_Lock(&interp->types.mutex); - index = interp->types.for_extensions.next_index; - interp->types.for_extensions.next_index++; - interp->types.for_extensions.num_initialized++; + assert((index - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES) + == interp->types.for_extensions.num_initialized); PyMutex_Unlock(&interp->types.mutex); - assert(index < _Py_MAX_MANAGED_STATIC_EXT_TYPES); } - assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); /* We store a 1-based index so 0 can mean "not initialized". */ self->tp_subclasses = (PyObject *)(index + 1); return index; @@ -181,11 +191,14 @@ managed_static_type_index_sync(PyInterpreterState *interp, if (isbuiltin) { assert(index == interp->types.builtins.num_initialized); assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); - interp->types.builtins.num_initialized++; } else { - assert(index < _Py_MAX_MANAGED_STATIC_EXT_TYPES); - interp->types.for_extensions.num_initialized++; + // The following might not hold if there are more than one + // extension modules that have static types. + assert((index - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES) + == interp->types.for_extensions.num_initialized); + assert(index >= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); + assert(index < _Py_MAX_MANAGED_STATIC_TYPES); } return index; } @@ -201,21 +214,26 @@ static_ext_type_lookup(PyInterpreterState *interp, size_t index, int64_t *p_interp_count) { assert(interp->runtime == &_PyRuntime); - assert(index < _Py_MAX_MANAGED_STATIC_EXT_TYPES); + assert(index < _Py_MAX_MANAGED_STATIC_TYPES); + assert(index >= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); + assert(!_PyRuntime.types.managed_static.types[index].isbuiltin); +#ifndef NDEBUG + PyTypeObject *cached_type = + _PyRuntime.types.managed_static.types[index].type; +#endif - size_t full_index = index + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; int64_t interp_count = - _PyRuntime.types.managed_static.types[full_index].interp_count; + _PyRuntime.types.managed_static.types[index].interp_count; assert((interp_count == 0) == - (_PyRuntime.types.managed_static.types[full_index].type == NULL)); + (_PyRuntime.types.managed_static.types[index].type == NULL)); *p_interp_count = interp_count; + index -= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; PyTypeObject *type = interp->types.for_extensions.initialized[index].type; if (type == NULL) { return NULL; } - assert(!interp->types.for_extensions.initialized[index].isbuiltin); - assert(type == _PyRuntime.types.managed_static.types[full_index].type); + assert(type == cached_type); assert(managed_static_type_index_is_set(type)); return type; } @@ -225,15 +243,13 @@ managed_static_type_state_get(PyInterpreterState *interp, PyTypeObject *self) { // It's probably a builtin type. size_t index = managed_static_type_index_get(self); - managed_static_type_state *state = - &(interp->types.builtins.initialized[index]); - if (state->type == self) { - return state; + if (index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES) { + return &(interp->types.builtins.initialized[index]); } - if (index > _Py_MAX_MANAGED_STATIC_EXT_TYPES) { - return state; + else { + index -= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; + return &(interp->types.for_extensions.initialized[index]); } - return &(interp->types.for_extensions.initialized[index]); } /* For static types we store some state in an array on each interpreter. */ @@ -251,38 +267,53 @@ managed_static_type_state_init(PyInterpreterState *interp, PyTypeObject *self, { assert(interp->runtime == &_PyRuntime); - size_t index = initial - ? managed_static_type_index_init(interp, self, isbuiltin) - : managed_static_type_index_sync(interp, self, isbuiltin); - size_t full_index = isbuiltin - ? index - : index + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; - - assert((initial == 1) == - (_PyRuntime.types.managed_static.types[full_index].interp_count == 0)); - (void)_Py_atomic_add_int64( - &_PyRuntime.types.managed_static.types[full_index].interp_count, 1); - + size_t index; if (initial) { - assert(_PyRuntime.types.managed_static.types[full_index].type == NULL); - _PyRuntime.types.managed_static.types[full_index].type = self; + index = managed_static_type_index_init(interp, self, isbuiltin); + assert(_PyRuntime.types.managed_static.types[index].interp_count == 0); + + assert(_PyRuntime.types.managed_static.types[index].type == NULL); + _PyRuntime.types.managed_static.types[index].type = self; + _PyRuntime.types.managed_static.types[index].isbuiltin = isbuiltin; } else { - assert(_PyRuntime.types.managed_static.types[full_index].type == self); + index = managed_static_type_index_sync(interp, self, isbuiltin); + assert(_PyRuntime.types.managed_static.types[index].type == self); + assert(_PyRuntime.types.managed_static.types[index].interp_count > 0); } + (void)_Py_atomic_add_int64( + &_PyRuntime.types.managed_static.types[index].interp_count, 1); managed_static_type_state *state = isbuiltin ? &(interp->types.builtins.initialized[index]) - : &(interp->types.for_extensions.initialized[index]); + : &(interp->types.for_extensions.initialized[ + index - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES]); /* It should only be called once for each builtin type per interpreter. */ assert(state->type == NULL); state->type = self; - state->isbuiltin = isbuiltin; /* state->tp_subclasses is left NULL until init_subclasses() sets it. */ /* state->tp_weaklist is left NULL until insert_head() or insert_after() (in weakrefobject.c) sets it. */ + + if (isbuiltin) { + if (initial) { + _PyRuntime.types.managed_static.num_types += 1; + _PyRuntime.types.managed_static.num_builtins += 1; + } + interp->types.builtins.num_initialized += 1; + } + else { + if (initial) { + PyMutex_Lock(&_PyRuntime.types.managed_static.mutex); + _PyRuntime.types.managed_static.num_types += 1; + PyMutex_Unlock(&_PyRuntime.types.managed_static.mutex); + } + PyMutex_Lock(&interp->types.mutex); + interp->types.for_extensions.num_initialized += 1; + PyMutex_Unlock(&interp->types.mutex); + } } /* Reset the type's per-interpreter state. @@ -292,44 +323,75 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self, int isbuiltin, int final) { size_t index = managed_static_type_index_get(self); - size_t full_index = isbuiltin - ? index - : index + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; - - managed_static_type_state *state = isbuiltin - ? &(interp->types.builtins.initialized[index]) - : &(interp->types.for_extensions.initialized[index]); + managed_static_type_state *state; + if (isbuiltin) { + assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); + assert(!final + || _PyRuntime.types.managed_static.num_types == + _PyRuntime.types.managed_static.num_builtins); + assert(!final + || _PyRuntime.types.managed_static.next_index <= + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); + assert(_PyRuntime.types.managed_static.types[index].isbuiltin); + state = &(interp->types.builtins.initialized[index]); + } + else { + assert(index >= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); + assert(_PyRuntime.types.managed_static.num_types > + _PyRuntime.types.managed_static.num_builtins); + assert(_PyRuntime.types.managed_static.next_index > + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); + assert(!_PyRuntime.types.managed_static.types[index].isbuiltin); + state = &(interp->types.for_extensions.initialized[ + index - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES]); + } assert(state != NULL); - assert(_PyRuntime.types.managed_static.types[full_index].interp_count > 0); - assert(_PyRuntime.types.managed_static.types[full_index].type == state->type); - - assert(state->type != NULL); - state->type = NULL; - assert(state->tp_weaklist == NULL); // It was already cleared out. - + assert(_PyRuntime.types.managed_static.types[index].type == state->type); + assert(_PyRuntime.types.managed_static.types[index].interp_count > 0); (void)_Py_atomic_add_int64( - &_PyRuntime.types.managed_static.types[full_index].interp_count, -1); - if (final) { - assert(!_PyRuntime.types.managed_static.types[full_index].interp_count); - _PyRuntime.types.managed_static.types[full_index].type = NULL; - - managed_static_type_index_clear(self); - } + &_PyRuntime.types.managed_static.types[index].interp_count, -1); + /* Update the various counts. */ if (isbuiltin) { - assert(interp->types.builtins.num_initialized > 0); - interp->types.builtins.num_initialized--; + interp->types.builtins.num_initialized -= 1; } else { PyMutex_Lock(&interp->types.mutex); - assert(interp->types.for_extensions.num_initialized > 0); - interp->types.for_extensions.num_initialized--; - if (interp->types.for_extensions.num_initialized == 0) { - interp->types.for_extensions.next_index = 0; - } + interp->types.for_extensions.num_initialized -= 1; PyMutex_Unlock(&interp->types.mutex); } + if (final) { + if (isbuiltin) { + _PyRuntime.types.managed_static.num_types -= 1; + _PyRuntime.types.managed_static.next_index -= 1; + _PyRuntime.types.managed_static.num_builtins -= 1; + } + else { + PyMutex_Lock(&_PyRuntime.types.managed_static.mutex); + _PyRuntime.types.managed_static.num_types -= 1; + _PyRuntime.types.managed_static.next_index -= 1; + if (_PyRuntime.types.managed_static.next_index == + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES) + { + _PyRuntime.types.managed_static.next_index = + _PyRuntime.types.managed_static.num_builtins; + } + PyMutex_Unlock(&_PyRuntime.types.managed_static.mutex); + } + } + + /* Clear the state. */ + assert(_PyRuntime.types.managed_static.types[index].type == self); + assert(state->type == self); + state->type = NULL; + assert(state->tp_weaklist == NULL); // It was already cleared out. + if (final) { + assert(!_PyRuntime.types.managed_static.types[index].interp_count); + _PyRuntime.types.managed_static.types[index].type = NULL; + _PyRuntime.types.managed_static.types[index].isbuiltin = 0; + managed_static_type_index_clear(self); + } } // Also see _PyStaticType_InitBuiltin() and _PyStaticType_FiniBuiltin(). @@ -5889,7 +5951,9 @@ fini_static_type(PyInterpreterState *interp, PyTypeObject *type, void _PyTypes_FiniExtTypes(PyInterpreterState *interp) { - for (size_t i = _Py_MAX_MANAGED_STATIC_EXT_TYPES; i > 0; i--) { + for (size_t i = _Py_MAX_MANAGED_STATIC_TYPES; + i > _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; i--) + { if (interp->types.for_extensions.num_initialized == 0) { break; } From 1503e29dc87834403b78390e4f40c6755dfef879 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 4 Jun 2024 15:04:05 -0600 Subject: [PATCH 3/8] Unify the two per-interpreter structs. --- Include/internal/pycore_typeobject.h | 45 ++++++------ Objects/typeobject.c | 101 +++++++++++++-------------- 2 files changed, 70 insertions(+), 76 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 1ecab7fc5c8da0..67299d6849e21a 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -61,24 +61,14 @@ struct type_cache { struct type_cache_entry hashtable[1 << MCACHE_SIZE_EXP]; }; -typedef struct { - PyTypeObject *type; - int readying; - int ready; - // XXX tp_dict can probably be statically allocated, - // instead of dynamically and stored on the interpreter. - PyObject *tp_dict; - PyObject *tp_subclasses; - /* We never clean up weakrefs for static builtin types since - they will effectively never get triggered. However, there - are also some diagnostic uses for the list of weakrefs, - so we still keep it. */ - PyObject *tp_weaklist; -} managed_static_type_state; + +typedef struct managed_static_type_state managed_static_type_state; #define TYPE_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */ struct types_state { + PyMutex mutex; + /* Used to set PyTypeObject.tp_version_tag. It starts at _Py_MAX_GLOBAL_TYPE_VERSION_TAG + 1, where all those lower numbers are used for core static types. */ @@ -123,15 +113,24 @@ struct types_state { builtin type. Once initialization is over for a subinterpreter, the value will be the same as for all other interpreters. */ struct { - size_t num_initialized; - managed_static_type_state initialized[_Py_MAX_MANAGED_STATIC_BUILTIN_TYPES]; - } builtins; - /* We apply a similar strategy for managed extension modules. */ - struct { - size_t num_initialized; - managed_static_type_state initialized[_Py_MAX_MANAGED_STATIC_EXT_TYPES]; - } for_extensions; - PyMutex mutex; + size_t num_builtins; + size_t num_types; + struct managed_static_type_state { + //int initialized; + PyTypeObject *type; + int readying; + int ready; + // XXX tp_dict can probably be statically allocated, + // instead of dynamically and stored on the interpreter. + PyObject *tp_dict; + PyObject *tp_subclasses; + /* We never clean up weakrefs for static builtin types since + they will effectively never get triggered. However, there + are also some diagnostic uses for the list of weakrefs, + so we still keep it. */ + PyObject *tp_weaklist; + } types[_Py_MAX_MANAGED_STATIC_TYPES]; + } managed_static; // Borrowed references to type objects whose // tp_version_tag % TYPE_VERSION_CACHE_SIZE diff --git a/Objects/typeobject.c b/Objects/typeobject.c index bfe1b6e2970d01..6564c55c07616c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -159,7 +159,9 @@ managed_static_type_index_init(PyInterpreterState *interp, assert(_Py_IsMainInterpreter(interp)); assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); assert(index == _PyRuntime.types.managed_static.num_builtins); - assert(index == interp->types.builtins.num_initialized); + assert(index == interp->types.managed_static.num_builtins); + assert(index == _PyRuntime.types.managed_static.num_types); + assert(index == interp->types.managed_static.num_types); } else { PyMutex_Lock(&_PyRuntime.types.managed_static.mutex); @@ -170,13 +172,18 @@ managed_static_type_index_init(PyInterpreterState *interp, _PyRuntime.types.managed_static.next_index = index + 1; } PyMutex_Unlock(&_PyRuntime.types.managed_static.mutex); + assert(index >= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); assert(index < _Py_MAX_MANAGED_STATIC_TYPES); - - PyMutex_Lock(&interp->types.mutex); - assert((index - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES) - == interp->types.for_extensions.num_initialized); - PyMutex_Unlock(&interp->types.mutex); + assert(index >= _PyRuntime.types.managed_static.num_builtins); + assert(index >= interp->types.managed_static.num_builtins); + assert(index == (_PyRuntime.types.managed_static.num_types + + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES - + _PyRuntime.types.managed_static.num_builtins)); } + assert(_PyRuntime.types.managed_static.num_builtins == + interp->types.managed_static.num_builtins); + assert(_PyRuntime.types.managed_static.num_types == + interp->types.managed_static.num_types); /* We store a 1-based index so 0 can mean "not initialized". */ self->tp_subclasses = (PyObject *)(index + 1); @@ -188,17 +195,17 @@ managed_static_type_index_sync(PyInterpreterState *interp, PyTypeObject *self, int isbuiltin) { size_t index = managed_static_type_index_get(self); + assert(index >= interp->types.managed_static.num_types); + assert(index < _Py_MAX_MANAGED_STATIC_TYPES); if (isbuiltin) { - assert(index == interp->types.builtins.num_initialized); + assert(index == interp->types.managed_static.num_builtins); assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); } else { // The following might not hold if there are more than one // extension modules that have static types. - assert((index - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES) - == interp->types.for_extensions.num_initialized); + assert(index >= interp->types.managed_static.num_builtins); assert(index >= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); - assert(index < _Py_MAX_MANAGED_STATIC_TYPES); } return index; } @@ -217,39 +224,28 @@ static_ext_type_lookup(PyInterpreterState *interp, size_t index, assert(index < _Py_MAX_MANAGED_STATIC_TYPES); assert(index >= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); assert(!_PyRuntime.types.managed_static.types[index].isbuiltin); -#ifndef NDEBUG - PyTypeObject *cached_type = - _PyRuntime.types.managed_static.types[index].type; -#endif + PyTypeObject *type = _PyRuntime.types.managed_static.types[index].type; int64_t interp_count = _PyRuntime.types.managed_static.types[index].interp_count; - assert((interp_count == 0) == - (_PyRuntime.types.managed_static.types[index].type == NULL)); - *p_interp_count = interp_count; - - index -= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; - PyTypeObject *type = interp->types.for_extensions.initialized[index].type; if (type == NULL) { + assert(interp_count == 0); + *p_interp_count = interp_count; return NULL; } - assert(type == cached_type); + assert(interp_count > 0); + assert(interp->types.managed_static.types[index].type == type); assert(managed_static_type_index_is_set(type)); + + *p_interp_count = interp_count; return type; } static managed_static_type_state * managed_static_type_state_get(PyInterpreterState *interp, PyTypeObject *self) { - // It's probably a builtin type. size_t index = managed_static_type_index_get(self); - if (index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES) { - return &(interp->types.builtins.initialized[index]); - } - else { - index -= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; - return &(interp->types.for_extensions.initialized[index]); - } + return &(interp->types.managed_static.types[index]); } /* For static types we store some state in an array on each interpreter. */ @@ -271,7 +267,6 @@ managed_static_type_state_init(PyInterpreterState *interp, PyTypeObject *self, if (initial) { index = managed_static_type_index_init(interp, self, isbuiltin); assert(_PyRuntime.types.managed_static.types[index].interp_count == 0); - assert(_PyRuntime.types.managed_static.types[index].type == NULL); _PyRuntime.types.managed_static.types[index].type = self; _PyRuntime.types.managed_static.types[index].isbuiltin = isbuiltin; @@ -284,10 +279,8 @@ managed_static_type_state_init(PyInterpreterState *interp, PyTypeObject *self, (void)_Py_atomic_add_int64( &_PyRuntime.types.managed_static.types[index].interp_count, 1); - managed_static_type_state *state = isbuiltin - ? &(interp->types.builtins.initialized[index]) - : &(interp->types.for_extensions.initialized[ - index - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES]); + managed_static_type_state *state = + &(interp->types.managed_static.types[index]); /* It should only be called once for each builtin type per interpreter. */ assert(state->type == NULL); @@ -302,7 +295,8 @@ managed_static_type_state_init(PyInterpreterState *interp, PyTypeObject *self, _PyRuntime.types.managed_static.num_types += 1; _PyRuntime.types.managed_static.num_builtins += 1; } - interp->types.builtins.num_initialized += 1; + interp->types.managed_static.num_types += 1; + interp->types.managed_static.num_builtins += 1; } else { if (initial) { @@ -311,7 +305,7 @@ managed_static_type_state_init(PyInterpreterState *interp, PyTypeObject *self, PyMutex_Unlock(&_PyRuntime.types.managed_static.mutex); } PyMutex_Lock(&interp->types.mutex); - interp->types.for_extensions.num_initialized += 1; + interp->types.managed_static.num_types += 1; PyMutex_Unlock(&interp->types.mutex); } } @@ -323,7 +317,6 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self, int isbuiltin, int final) { size_t index = managed_static_type_index_get(self); - managed_static_type_state *state; if (isbuiltin) { assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); assert(!final @@ -333,7 +326,6 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self, || _PyRuntime.types.managed_static.next_index <= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); assert(_PyRuntime.types.managed_static.types[index].isbuiltin); - state = &(interp->types.builtins.initialized[index]); } else { assert(index >= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); @@ -342,9 +334,9 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self, assert(_PyRuntime.types.managed_static.next_index > _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); assert(!_PyRuntime.types.managed_static.types[index].isbuiltin); - state = &(interp->types.for_extensions.initialized[ - index - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES]); } + managed_static_type_state *state = + &(interp->types.managed_static.types[index]); assert(state != NULL); assert(_PyRuntime.types.managed_static.types[index].type == state->type); @@ -353,13 +345,9 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self, &_PyRuntime.types.managed_static.types[index].interp_count, -1); /* Update the various counts. */ + interp->types.managed_static.num_types -= 1; if (isbuiltin) { - interp->types.builtins.num_initialized -= 1; - } - else { - PyMutex_Lock(&interp->types.mutex); - interp->types.for_extensions.num_initialized -= 1; - PyMutex_Unlock(&interp->types.mutex); + interp->types.managed_static.num_builtins -= 1; } if (final) { if (isbuiltin) { @@ -951,14 +939,18 @@ _PyTypes_Fini(PyInterpreterState *interp) struct type_cache *cache = &interp->types.type_cache; type_cache_clear(cache, NULL); + assert(interp->types.managed_static.num_types == 0); // All the managed static types should have been finalized already. - assert(interp->types.for_extensions.num_initialized == 0); - for (size_t i = 0; i < _Py_MAX_MANAGED_STATIC_EXT_TYPES; i++) { - assert(interp->types.for_extensions.initialized[i].type == NULL); + for (size_t i = 0; i < _Py_MAX_MANAGED_STATIC_TYPES; i++) { + assert(interp->types.managed_static.types[i].type == NULL); } - assert(interp->types.builtins.num_initialized == 0); - for (size_t i = 0; i < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; i++) { - assert(interp->types.builtins.initialized[i].type == NULL); + if (_Py_IsMainInterpreter(interp)) { + assert(_PyRuntime.types.managed_static.num_types == 0); + // All the managed static types should have been finalized already. + for (size_t i = 0; i < _Py_MAX_MANAGED_STATIC_TYPES; i++) { + assert(_PyRuntime.types.managed_static.types[i].type == NULL); + assert(_PyRuntime.types.managed_static.types[i].interp_count == 0); + } } } @@ -5954,7 +5946,10 @@ _PyTypes_FiniExtTypes(PyInterpreterState *interp) for (size_t i = _Py_MAX_MANAGED_STATIC_TYPES; i > _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; i--) { - if (interp->types.for_extensions.num_initialized == 0) { + /* There may be gaps. */ + if (interp->types.managed_static.num_types == + interp->types.managed_static.num_builtins) + { break; } int64_t count = 0; From c820fdcd0df08efc238e77ce05b632e699e544ce Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 13 Jun 2024 13:31:47 -0600 Subject: [PATCH 4/8] Add some asserts. --- Objects/typeobject.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 6564c55c07616c..a891cccaa78a44 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5943,6 +5943,8 @@ fini_static_type(PyInterpreterState *interp, PyTypeObject *type, void _PyTypes_FiniExtTypes(PyInterpreterState *interp) { + /* Static extension types must be finalized before the builtins. */ + assert(interp->types.managed_static.num_builtins > 0); for (size_t i = _Py_MAX_MANAGED_STATIC_TYPES; i > _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; i--) { @@ -5954,6 +5956,8 @@ _PyTypes_FiniExtTypes(PyInterpreterState *interp) } int64_t count = 0; PyTypeObject *type = static_ext_type_lookup(interp, i-1, &count); + /* Currently there is no other way to finalize one of these types. */ + assert(type != NULL); if (type == NULL) { continue; } From de98b0f2ff4f18bf8041b4183f77bfe277a208bf Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 6 Jun 2024 11:03:46 -0600 Subject: [PATCH 5/8] wip - Do not reset a static type's index. --- Include/internal/pycore_typeobject.h | 15 +- Objects/typeobject.c | 219 ++++++++++++++------------- 2 files changed, 122 insertions(+), 112 deletions(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 67299d6849e21a..9f693141da10c6 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -18,11 +18,9 @@ extern "C" { #define _Py_MAX_GLOBAL_TYPE_VERSION_TAG (_Py_TYPE_BASE_VERSION_TAG - 1) /* For now we hard-code this to a value for which we are confident - all the static builtin types will fit (for all builds). */ -#define _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES 200 -#define _Py_MAX_MANAGED_STATIC_EXT_TYPES 10 -#define _Py_MAX_MANAGED_STATIC_TYPES \ - (_Py_MAX_MANAGED_STATIC_BUILTIN_TYPES + _Py_MAX_MANAGED_STATIC_EXT_TYPES) + all the managed static types will fit (for all builds). + That includes all static builtin types and managed extension types. */ +#define _Py_MAX_MANAGED_STATIC_TYPES 210 struct _types_runtime_state { /* Used to set PyTypeObject.tp_version_tag for core static types. */ @@ -30,6 +28,12 @@ struct _types_runtime_state { // because of static types. unsigned int next_version_tag; + /* We track every managed static type. Each one is assigned an + * index when it is first initialized using _PyStaticType_InitBuiltin() + * or _PyStaticType_InitForExtension(). It keeps that index for the + * duration of the process. The same index is used when accessing + * the global array of type state, as well as the per-interpreter + * array. */ struct { PyMutex mutex; size_t num_builtins; @@ -116,7 +120,6 @@ struct types_state { size_t num_builtins; size_t num_types; struct managed_static_type_state { - //int initialized; PyTypeObject *type; int readying; int ready; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a891cccaa78a44..996ce796edda20 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -142,48 +142,21 @@ managed_static_type_index_get(PyTypeObject *self) { assert(managed_static_type_index_is_set(self)); /* We store a 1-based index so 0 can mean "not initialized". */ - return (size_t)self->tp_subclasses - 1; + size_t index = (size_t)self->tp_subclasses - 1; + assert(index < _Py_MAX_MANAGED_STATIC_TYPES); + return index; } static size_t -managed_static_type_index_init(PyInterpreterState *interp, - PyTypeObject *self, int isbuiltin) +managed_static_type_index_init(PyTypeObject *self) { - assert(interp->runtime == &_PyRuntime); assert(!managed_static_type_index_is_set(self)); - size_t index; - if (isbuiltin) { - index = _PyRuntime.types.managed_static.next_index; - _PyRuntime.types.managed_static.next_index += 1; - assert(_Py_IsMainInterpreter(interp)); - assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); - assert(index == _PyRuntime.types.managed_static.num_builtins); - assert(index == interp->types.managed_static.num_builtins); - assert(index == _PyRuntime.types.managed_static.num_types); - assert(index == interp->types.managed_static.num_types); - } - else { - PyMutex_Lock(&_PyRuntime.types.managed_static.mutex); - index = _PyRuntime.types.managed_static.next_index; - _PyRuntime.types.managed_static.next_index += 1; - if (index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES) { - index = _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; - _PyRuntime.types.managed_static.next_index = index + 1; - } - PyMutex_Unlock(&_PyRuntime.types.managed_static.mutex); - assert(index >= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); - assert(index < _Py_MAX_MANAGED_STATIC_TYPES); - assert(index >= _PyRuntime.types.managed_static.num_builtins); - assert(index >= interp->types.managed_static.num_builtins); - assert(index == (_PyRuntime.types.managed_static.num_types + - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES - - _PyRuntime.types.managed_static.num_builtins)); - } - assert(_PyRuntime.types.managed_static.num_builtins == - interp->types.managed_static.num_builtins); - assert(_PyRuntime.types.managed_static.num_types == - interp->types.managed_static.num_types); + PyMutex_Lock(&_PyRuntime.types.managed_static.mutex); + size_t index = _PyRuntime.types.managed_static.next_index; + _PyRuntime.types.managed_static.next_index += 1; + PyMutex_Unlock(&_PyRuntime.types.managed_static.mutex); + assert(index < _Py_MAX_MANAGED_STATIC_TYPES); /* We store a 1-based index so 0 can mean "not initialized". */ self->tp_subclasses = (PyObject *)(index + 1); @@ -191,29 +164,23 @@ managed_static_type_index_init(PyInterpreterState *interp, } static size_t -managed_static_type_index_sync(PyInterpreterState *interp, - PyTypeObject *self, int isbuiltin) +managed_static_type_index_reinit(PyTypeObject *self) { size_t index = managed_static_type_index_get(self); - assert(index >= interp->types.managed_static.num_types); - assert(index < _Py_MAX_MANAGED_STATIC_TYPES); - if (isbuiltin) { - assert(index == interp->types.managed_static.num_builtins); - assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); - } - else { - // The following might not hold if there are more than one - // extension modules that have static types. - assert(index >= interp->types.managed_static.num_builtins); - assert(index >= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); + PyMutex_Lock(&_PyRuntime.types.managed_static.mutex); + if (index >= _PyRuntime.types.managed_static.next_index) { + _PyRuntime.types.managed_static.next_index = index + 1; } + PyMutex_Unlock(&_PyRuntime.types.managed_static.mutex); return index; } static inline void -managed_static_type_index_clear(PyTypeObject *self) +managed_static_type_index_clear(PyTypeObject *Py_UNUSED(self)) { - self->tp_subclasses = NULL; + /* We actually leave the index set on the type (in tp_subclasses). + That way it will occupy the same array entry if re-initialized, + rather than advancing next_index. */ } static PyTypeObject * @@ -222,22 +189,22 @@ static_ext_type_lookup(PyInterpreterState *interp, size_t index, { assert(interp->runtime == &_PyRuntime); assert(index < _Py_MAX_MANAGED_STATIC_TYPES); - assert(index >= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); + assert(index >= _PyRuntime.types.managed_static.num_builtins); assert(!_PyRuntime.types.managed_static.types[index].isbuiltin); PyTypeObject *type = _PyRuntime.types.managed_static.types[index].type; - int64_t interp_count = - _PyRuntime.types.managed_static.types[index].interp_count; + int64_t count = _PyRuntime.types.managed_static.types[index].interp_count; if (type == NULL) { - assert(interp_count == 0); - *p_interp_count = interp_count; + /* It was already cleared. */ + assert(count == 0); + *p_interp_count = count; return NULL; } - assert(interp_count > 0); + assert(count > 0); assert(interp->types.managed_static.types[index].type == type); assert(managed_static_type_index_is_set(type)); - *p_interp_count = interp_count; + *p_interp_count = count; return type; } @@ -262,52 +229,105 @@ managed_static_type_state_init(PyInterpreterState *interp, PyTypeObject *self, int isbuiltin, int initial) { assert(interp->runtime == &_PyRuntime); + assert(!isbuiltin || + ((initial == 0) == (_Py_IsMainInterpreter(interp) == 0))); + /* Initialize the index. */ size_t index; if (initial) { - index = managed_static_type_index_init(interp, self, isbuiltin); - assert(_PyRuntime.types.managed_static.types[index].interp_count == 0); + if (managed_static_type_index_is_set(self)) { + /* The runtime was re-initialized. */ + index = managed_static_type_index_reinit(self); + } + else { + index = managed_static_type_index_init(self); + } + } + else { + index = managed_static_type_index_get(self); + } + managed_static_type_state *state = + &(interp->types.managed_static.types[index]); + + /* Check the existing global state. */ + if (initial) { + if (isbuiltin) { + assert(_PyRuntime.types.managed_static.num_builtins == + _PyRuntime.types.managed_static.num_types); + assert(index == _PyRuntime.types.managed_static.num_builtins); + assert(index == _PyRuntime.types.managed_static.num_types); + /* All builtin static types are initialized during runtime init, + before any extension module static type is initialized, + and always in the same order. */ + assert(index == 0 || + _PyRuntime.types.managed_static.types[index-1].isbuiltin); + } + else { + assert(_PyRuntime.types.managed_static.num_builtins <= + _PyRuntime.types.managed_static.num_types); + assert(index >= _PyRuntime.types.managed_static.num_builtins); + /* There may be gaps for ext. module static types. */ + assert(index <= _PyRuntime.types.managed_static.num_types); + } assert(_PyRuntime.types.managed_static.types[index].type == NULL); - _PyRuntime.types.managed_static.types[index].type = self; - _PyRuntime.types.managed_static.types[index].isbuiltin = isbuiltin; + assert(_PyRuntime.types.managed_static.types[index].interp_count == 0); } else { - index = managed_static_type_index_sync(interp, self, isbuiltin); assert(_PyRuntime.types.managed_static.types[index].type == self); + assert(_PyRuntime.types.managed_static.types[index].isbuiltin == isbuiltin); assert(_PyRuntime.types.managed_static.types[index].interp_count > 0); } - (void)_Py_atomic_add_int64( - &_PyRuntime.types.managed_static.types[index].interp_count, 1); - - managed_static_type_state *state = - &(interp->types.managed_static.types[index]); - /* It should only be called once for each builtin type per interpreter. */ + /* Check the existing per-interpreter state. */ + if (initial) { + assert(_PyRuntime.types.managed_static.num_builtins == + interp->types.managed_static.num_builtins); + assert(_PyRuntime.types.managed_static.num_types == + interp->types.managed_static.num_types); + if (isbuiltin) { + assert(index == interp->types.managed_static.num_builtins); + assert(index == interp->types.managed_static.num_types); + } + else { + assert(index >= interp->types.managed_static.num_builtins); + /* There may be gaps for ext. module static types. */ + assert(index <= interp->types.managed_static.num_types); + } + } + else { + } assert(state->type == NULL); - state->type = self; - - /* state->tp_subclasses is left NULL until init_subclasses() sets it. */ - /* state->tp_weaklist is left NULL until insert_head() or insert_after() - (in weakrefobject.c) sets it. */ + assert(!state->readying && !state->ready); + assert(state->tp_dict == NULL); + assert(state->tp_subclasses == NULL); + assert(state->tp_weaklist == NULL); - if (isbuiltin) { - if (initial) { + /* Update the global state. */ + if (initial) { + if (isbuiltin) { _PyRuntime.types.managed_static.num_types += 1; _PyRuntime.types.managed_static.num_builtins += 1; } - interp->types.managed_static.num_types += 1; - interp->types.managed_static.num_builtins += 1; - } - else { - if (initial) { + else { PyMutex_Lock(&_PyRuntime.types.managed_static.mutex); _PyRuntime.types.managed_static.num_types += 1; PyMutex_Unlock(&_PyRuntime.types.managed_static.mutex); } - PyMutex_Lock(&interp->types.mutex); - interp->types.managed_static.num_types += 1; - PyMutex_Unlock(&interp->types.mutex); } + _PyRuntime.types.managed_static.types[index].type = self; + _PyRuntime.types.managed_static.types[index].isbuiltin = isbuiltin; + (void)_Py_atomic_add_int64( + &_PyRuntime.types.managed_static.types[index].interp_count, 1); + + /* Update the per-interpreter state. */ + interp->types.managed_static.num_types += 1; + if (isbuiltin) { + interp->types.managed_static.num_builtins += 1; + } + state->type = self; + /* state->tp_subclasses is left NULL until init_subclasses() sets it. */ + /* state->tp_weaklist is left NULL until insert_head() or insert_after() + (in weakrefobject.c) sets it. */ } /* Reset the type's per-interpreter state. @@ -316,23 +336,18 @@ static void managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self, int isbuiltin, int final) { + assert(interp->runtime == &_PyRuntime); + size_t index = managed_static_type_index_get(self); if (isbuiltin) { - assert(index < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); assert(!final || _PyRuntime.types.managed_static.num_types == _PyRuntime.types.managed_static.num_builtins); - assert(!final - || _PyRuntime.types.managed_static.next_index <= - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); assert(_PyRuntime.types.managed_static.types[index].isbuiltin); } else { - assert(index >= _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); assert(_PyRuntime.types.managed_static.num_types > _PyRuntime.types.managed_static.num_builtins); - assert(_PyRuntime.types.managed_static.next_index > - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES); assert(!_PyRuntime.types.managed_static.types[index].isbuiltin); } managed_static_type_state *state = @@ -352,19 +367,11 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self, if (final) { if (isbuiltin) { _PyRuntime.types.managed_static.num_types -= 1; - _PyRuntime.types.managed_static.next_index -= 1; _PyRuntime.types.managed_static.num_builtins -= 1; } else { PyMutex_Lock(&_PyRuntime.types.managed_static.mutex); _PyRuntime.types.managed_static.num_types -= 1; - _PyRuntime.types.managed_static.next_index -= 1; - if (_PyRuntime.types.managed_static.next_index == - _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES) - { - _PyRuntime.types.managed_static.next_index = - _PyRuntime.types.managed_static.num_builtins; - } PyMutex_Unlock(&_PyRuntime.types.managed_static.mutex); } } @@ -5945,8 +5952,8 @@ _PyTypes_FiniExtTypes(PyInterpreterState *interp) { /* Static extension types must be finalized before the builtins. */ assert(interp->types.managed_static.num_builtins > 0); - for (size_t i = _Py_MAX_MANAGED_STATIC_TYPES; - i > _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; i--) + int started = 0; + for (size_t i = _Py_MAX_MANAGED_STATIC_TYPES; i > 0; i--) { /* There may be gaps. */ if (interp->types.managed_static.num_types == @@ -5956,13 +5963,13 @@ _PyTypes_FiniExtTypes(PyInterpreterState *interp) } int64_t count = 0; PyTypeObject *type = static_ext_type_lookup(interp, i-1, &count); + assert(!started || type != NULL); /* Currently there is no other way to finalize one of these types. */ - assert(type != NULL); - if (type == NULL) { - continue; + if (type != NULL) { + started = 1; + int final = (count == 1); + fini_static_type(interp, type, 0, final); } - int final = (count == 1); - fini_static_type(interp, type, 0, final); } } From bbfafd8aaf05b1e2f7d61e06c151450edc6c5b7d Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 17 Jun 2024 16:16:42 -0600 Subject: [PATCH 6/8] Small cleanup. --- Objects/typeobject.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 996ce796edda20..ae775d0ee38655 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -127,7 +127,7 @@ type_from_ref(PyObject *ref) } -/* helpers for for static builtin types */ +/* helpers for for managed static types */ #ifndef NDEBUG static inline int @@ -389,6 +389,24 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self, } } +static void +managed_static_types_fini(PyInterpreterState *interp) +{ + assert(interp->types.managed_static.num_types == 0); + // All the managed static types should have been finalized already. + for (size_t i = 0; i < _Py_MAX_MANAGED_STATIC_TYPES; i++) { + assert(interp->types.managed_static.types[i].type == NULL); + } + if (_Py_IsMainInterpreter(interp)) { + assert(_PyRuntime.types.managed_static.num_types == 0); + // All the managed static types should have been finalized already. + for (size_t i = 0; i < _Py_MAX_MANAGED_STATIC_TYPES; i++) { + assert(_PyRuntime.types.managed_static.types[i].type == NULL); + assert(_PyRuntime.types.managed_static.types[i].interp_count == 0); + } + } +} + // Also see _PyStaticType_InitBuiltin() and _PyStaticType_FiniBuiltin(). /* end static builtin helpers */ @@ -946,19 +964,7 @@ _PyTypes_Fini(PyInterpreterState *interp) struct type_cache *cache = &interp->types.type_cache; type_cache_clear(cache, NULL); - assert(interp->types.managed_static.num_types == 0); - // All the managed static types should have been finalized already. - for (size_t i = 0; i < _Py_MAX_MANAGED_STATIC_TYPES; i++) { - assert(interp->types.managed_static.types[i].type == NULL); - } - if (_Py_IsMainInterpreter(interp)) { - assert(_PyRuntime.types.managed_static.num_types == 0); - // All the managed static types should have been finalized already. - for (size_t i = 0; i < _Py_MAX_MANAGED_STATIC_TYPES; i++) { - assert(_PyRuntime.types.managed_static.types[i].type == NULL); - assert(_PyRuntime.types.managed_static.types[i].interp_count == 0); - } - } + managed_static_types_fini(interp); } From 2a30616d633cefb7496034c52f8571e3c85d3baa Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 17 Jun 2024 16:46:18 -0600 Subject: [PATCH 7/8] Drop an ifdef. --- Objects/typeobject.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index ae775d0ee38655..26097c25e6b1c4 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -129,13 +129,11 @@ type_from_ref(PyObject *ref) /* helpers for for managed static types */ -#ifndef NDEBUG static inline int managed_static_type_index_is_set(PyTypeObject *self) { return self->tp_subclasses != NULL; } -#endif static inline size_t managed_static_type_index_get(PyTypeObject *self) From 6a20de307bd9cddaa0cab6b870c81274ac557655 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 18 Jun 2024 13:57:11 -0600 Subject: [PATCH 8/8] Silence some compiler warnings. --- Objects/typeobject.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 26097c25e6b1c4..82cc5d233fd88b 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5956,7 +5956,9 @@ _PyTypes_FiniExtTypes(PyInterpreterState *interp) { /* Static extension types must be finalized before the builtins. */ assert(interp->types.managed_static.num_builtins > 0); +#ifndef NDEBUG int started = 0; +#endif for (size_t i = _Py_MAX_MANAGED_STATIC_TYPES; i > 0; i--) { /* There may be gaps. */ @@ -5970,7 +5972,9 @@ _PyTypes_FiniExtTypes(PyInterpreterState *interp) assert(!started || type != NULL); /* Currently there is no other way to finalize one of these types. */ if (type != NULL) { +#ifndef NDEBUG started = 1; +#endif int final = (count == 1); fini_static_type(interp, type, 0, final); }