]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-117398: Use Per-Interpreter State for the _datetime Static Types (gh-119929)
authorEric Snow <ericsnowcurrently@gmail.com>
Mon, 3 Jun 2024 23:09:18 +0000 (19:09 -0400)
committerGitHub <noreply@github.com>
Mon, 3 Jun 2024 23:09:18 +0000 (17:09 -0600)
We make use of the same mechanism that we use for the static builtin types.  This required a few tweaks.

The relevant code could use some cleanup but I opted to avoid the significant churn in this change.  I'll tackle that separately.

This change is the final piece needed to make _datetime support multiple interpreters.  I've updated the module slot accordingly.

13 files changed:
Include/internal/pycore_object.h
Include/internal/pycore_typeobject.h
Misc/NEWS.d/next/Library/2024-06-01-16-58-43.gh-issue-117398.kR0RW7.rst [new file with mode: 0644]
Modules/_datetimemodule.c
Objects/exceptions.c
Objects/object.c
Objects/structseq.c
Objects/typeobject.c
Objects/unicodeobject.c
Objects/weakrefobject.c
Python/crossinterp_exceptions.h
Tools/c-analyzer/cpython/globals-to-fix.tsv
Tools/c-analyzer/cpython/ignored.tsv

index f63e1da6fba025e0be92de80959a479d2e0f9221..6f133014ce06e29b43931f0b1b30cd8075d492f4 100644 (file)
@@ -589,7 +589,7 @@ _PyObject_GET_WEAKREFS_LISTPTR(PyObject *op)
     if (PyType_Check(op) &&
             ((PyTypeObject *)op)->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         PyInterpreterState *interp = _PyInterpreterState_GET();
-        static_builtin_state *state = _PyStaticType_GetState(
+        managed_static_type_state *state = _PyStaticType_GetState(
                                                 interp, (PyTypeObject *)op);
         return _PyStaticType_GET_WEAKREFS_LISTPTR(state);
     }
index 7e533bd138469baf4ce6485793b860881b5faa93..8664ae0e44533f6d2f355c5a04ca7658e10d120f 100644 (file)
@@ -44,10 +44,12 @@ struct type_cache {
 
 /* 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_STATIC_BUILTIN_TYPES 200
+#define _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES 200
+#define _Py_MAX_MANAGED_STATIC_EXT_TYPES 10
 
 typedef struct {
     PyTypeObject *type;
+    int isbuiltin;
     int readying;
     int ready;
     // XXX tp_dict can probably be statically allocated,
@@ -59,7 +61,7 @@ typedef struct {
        are also some diagnostic uses for the list of weakrefs,
        so we still keep it. */
     PyObject *tp_weaklist;
-} static_builtin_state;
+} managed_static_type_state;
 
 struct types_state {
     /* Used to set PyTypeObject.tp_version_tag.
@@ -105,8 +107,16 @@ struct types_state {
        num_builtins_initialized is incremented once for each static
        builtin type.  Once initialization is over for a subinterpreter,
        the value will be the same as for all other interpreters.  */
-    size_t num_builtins_initialized;
-    static_builtin_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES];
+    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;
+        size_t next_index;
+        managed_static_type_state initialized[_Py_MAX_MANAGED_STATIC_EXT_TYPES];
+    } for_extensions;
     PyMutex mutex;
 };
 
@@ -130,12 +140,35 @@ typedef struct wrapperbase pytype_slotdef;
 
 
 static inline PyObject **
-_PyStaticType_GET_WEAKREFS_LISTPTR(static_builtin_state *state)
+_PyStaticType_GET_WEAKREFS_LISTPTR(managed_static_type_state *state)
 {
     assert(state != NULL);
     return &state->tp_weaklist;
 }
 
+extern int _PyStaticType_InitBuiltin(
+    PyInterpreterState *interp,
+    PyTypeObject *type);
+extern void _PyStaticType_FiniBuiltin(
+    PyInterpreterState *interp,
+    PyTypeObject *type);
+extern void _PyStaticType_ClearWeakRefs(
+    PyInterpreterState *interp,
+    PyTypeObject *type);
+extern managed_static_type_state * _PyStaticType_GetState(
+    PyInterpreterState *interp,
+    PyTypeObject *type);
+
+// Export for '_datetime' shared extension.
+PyAPI_FUNC(int) _PyStaticType_InitForExtension(
+    PyInterpreterState *interp,
+     PyTypeObject *self);
+PyAPI_FUNC(void) _PyStaticType_FiniForExtension(
+    PyInterpreterState *interp,
+     PyTypeObject *self,
+     int final);
+
+
 /* Like PyType_GetModuleState, but skips verification
  * that type is a heap type with an associated module */
 static inline void *
@@ -151,11 +184,6 @@ _PyType_GetModuleState(PyTypeObject *type)
 }
 
 
-extern int _PyStaticType_InitBuiltin(PyInterpreterState *, PyTypeObject *type);
-extern static_builtin_state * _PyStaticType_GetState(PyInterpreterState *, PyTypeObject *);
-extern void _PyStaticType_ClearWeakRefs(PyInterpreterState *, PyTypeObject *type);
-extern void _PyStaticType_Dealloc(PyInterpreterState *, PyTypeObject *);
-
 // Export for 'math' shared extension, used via _PyType_IsReady() static inline
 // function
 PyAPI_FUNC(PyObject *) _PyType_GetDict(PyTypeObject *);
diff --git a/Misc/NEWS.d/next/Library/2024-06-01-16-58-43.gh-issue-117398.kR0RW7.rst b/Misc/NEWS.d/next/Library/2024-06-01-16-58-43.gh-issue-117398.kR0RW7.rst
new file mode 100644 (file)
index 0000000..b0fe066
--- /dev/null
@@ -0,0 +1,2 @@
+The ``_datetime`` module (C implementation for :mod:`datetime`) now supports
+being imported in multiple interpreters.
index 16bb4c6980aa08b742d3772e42f8c7700776e9f4..d6fa273c75e15ebbee96999ecfee99c97744e2ab 100644 (file)
@@ -111,26 +111,37 @@ get_module_state(PyObject *module)
 #define INTERP_KEY ((PyObject *)&_Py_ID(cached_datetime_module))
 
 static PyObject *
-get_current_module(PyInterpreterState *interp)
+get_current_module(PyInterpreterState *interp, int *p_reloading)
 {
+    PyObject *mod = NULL;
+    int reloading = 0;
+
     PyObject *dict = PyInterpreterState_GetDict(interp);
     if (dict == NULL) {
-        return NULL;
+        goto error;
     }
     PyObject *ref = NULL;
     if (PyDict_GetItemRef(dict, INTERP_KEY, &ref) < 0) {
-        return NULL;
+        goto error;
     }
-    if (ref == NULL) {
-        return NULL;
+    if (ref != NULL) {
+        reloading = 1;
+        if (ref != Py_None) {
+            (void)PyWeakref_GetRef(ref, &mod);
+            if (mod == Py_None) {
+                Py_CLEAR(mod);
+            }
+            Py_DECREF(ref);
+        }
     }
-    PyObject *mod = NULL;
-    (void)PyWeakref_GetRef(ref, &mod);
-    if (mod == Py_None) {
-        Py_CLEAR(mod);
+    if (p_reloading != NULL) {
+        *p_reloading = reloading;
     }
-    Py_DECREF(ref);
     return mod;
+
+error:
+    assert(PyErr_Occurred());
+    return NULL;
 }
 
 static PyModuleDef datetimemodule;
@@ -139,7 +150,7 @@ static datetime_state *
 _get_current_state(PyObject **p_mod)
 {
     PyInterpreterState *interp = PyInterpreterState_Get();
-    PyObject *mod = get_current_module(interp);
+    PyObject *mod = get_current_module(interp, NULL);
     if (mod == NULL) {
         assert(!PyErr_Occurred());
         if (PyErr_Occurred()) {
@@ -184,8 +195,6 @@ clear_current_module(PyInterpreterState *interp, PyObject *expected)
 {
     PyObject *exc = PyErr_GetRaisedException();
 
-    PyObject *current = NULL;
-
     PyObject *dict = PyInterpreterState_GetDict(interp);
     if (dict == NULL) {
         goto error;
@@ -197,7 +206,10 @@ clear_current_module(PyInterpreterState *interp, PyObject *expected)
             goto error;
         }
         if (ref != NULL) {
+            PyObject *current = NULL;
             int rc = PyWeakref_GetRef(ref, &current);
+            /* We only need "current" for pointer comparison. */
+            Py_XDECREF(current);
             Py_DECREF(ref);
             if (rc < 0) {
                 goto error;
@@ -208,19 +220,17 @@ clear_current_module(PyInterpreterState *interp, PyObject *expected)
         }
     }
 
-    if (PyDict_DelItem(dict, INTERP_KEY) < 0) {
-        if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
-            goto error;
-        }
+    /* We use None to identify that the module was previously loaded. */
+    if (PyDict_SetItem(dict, INTERP_KEY, Py_None) < 0) {
+        goto error;
     }
 
     goto finally;
 
 error:
-    PyErr_Print();
+    PyErr_WriteUnraisable(NULL);
 
 finally:
-    Py_XDECREF(current);
     PyErr_SetRaisedException(exc);
 }
 
@@ -6947,14 +6957,19 @@ static PyTypeObject PyDateTime_DateTimeType = {
 };
 
 /* ---------------------------------------------------------------------------
- * Module methods and initialization.
+ * datetime C-API.
  */
 
-static PyMethodDef module_methods[] = {
-    {NULL, NULL}
+static PyTypeObject * const capi_types[] = {
+    &PyDateTime_DateType,
+    &PyDateTime_DateTimeType,
+    &PyDateTime_TimeType,
+    &PyDateTime_DeltaType,
+    &PyDateTime_TZInfoType,
+    /* Indirectly, via the utc object. */
+    &PyDateTime_TimeZoneType,
 };
 
-
 /* The C-API is process-global.  This violates interpreter isolation
  * due to the objects stored here.  Thus each of those objects must
  * be managed carefully. */
@@ -7004,6 +7019,11 @@ create_timezone_from_delta(int days, int sec, int ms, int normalize)
     return tz;
 }
 
+
+/* ---------------------------------------------------------------------------
+ * Module state lifecycle.
+ */
+
 static int
 init_state(datetime_state *st, PyObject *module, PyObject *old_module)
 {
@@ -7105,38 +7125,110 @@ clear_state(datetime_state *st)
     return 0;
 }
 
+
+/* ---------------------------------------------------------------------------
+ * Global module state.
+ */
+
+// If we make _PyStaticType_*ForExtension() public
+// then all this should be managed by the runtime.
+
+static struct {
+    PyMutex mutex;
+    int64_t interp_count;
+} _globals = {0};
+
+static void
+callback_for_interp_exit(void *Py_UNUSED(data))
+{
+    PyInterpreterState *interp = PyInterpreterState_Get();
+
+    assert(_globals.interp_count > 0);
+    PyMutex_Lock(&_globals.mutex);
+    _globals.interp_count -= 1;
+    int final = !_globals.interp_count;
+    PyMutex_Unlock(&_globals.mutex);
+
+    /* They must be done in reverse order so subclasses are finalized
+     * before base classes. */
+    for (size_t i = Py_ARRAY_LENGTH(capi_types); i > 0; i--) {
+        PyTypeObject *type = capi_types[i-1];
+        _PyStaticType_FiniForExtension(interp, type, final);
+    }
+}
+
+static int
+init_static_types(PyInterpreterState *interp, int reloading)
+{
+    if (reloading) {
+        return 0;
+    }
+
+    // `&...` is not a constant expression according to a strict reading
+    // of C standards. Fill tp_base at run-time rather than statically.
+    // See https://bugs.python.org/issue40777
+    PyDateTime_TimeZoneType.tp_base = &PyDateTime_TZInfoType;
+    PyDateTime_DateTimeType.tp_base = &PyDateTime_DateType;
+
+    /* Bases classes must be initialized before subclasses,
+     * so capi_types must have the types in the appropriate order. */
+    for (size_t i = 0; i < Py_ARRAY_LENGTH(capi_types); i++) {
+        PyTypeObject *type = capi_types[i];
+        if (_PyStaticType_InitForExtension(interp, type) < 0) {
+            return -1;
+        }
+    }
+
+    PyMutex_Lock(&_globals.mutex);
+    assert(_globals.interp_count >= 0);
+    _globals.interp_count += 1;
+    PyMutex_Unlock(&_globals.mutex);
+
+    /* It could make sense to add a separate callback
+     * for each of the types.  However, for now we can take the simpler
+     * approach of a single callback. */
+    if (PyUnstable_AtExit(interp, callback_for_interp_exit, NULL) < 0) {
+        callback_for_interp_exit(NULL);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/* ---------------------------------------------------------------------------
+ * Module methods and initialization.
+ */
+
+static PyMethodDef module_methods[] = {
+    {NULL, NULL}
+};
+
+
 static int
 _datetime_exec(PyObject *module)
 {
     int rc = -1;
     datetime_state *st = get_module_state(module);
+    int reloading = 0;
 
     PyInterpreterState *interp = PyInterpreterState_Get();
-    PyObject *old_module = get_current_module(interp);
+    PyObject *old_module = get_current_module(interp, &reloading);
     if (PyErr_Occurred()) {
         assert(old_module == NULL);
         goto error;
     }
     /* We actually set the "current" module right before a successful return. */
 
-    // `&...` is not a constant expression according to a strict reading
-    // of C standards. Fill tp_base at run-time rather than statically.
-    // See https://bugs.python.org/issue40777
-    PyDateTime_TimeZoneType.tp_base = &PyDateTime_TZInfoType;
-    PyDateTime_DateTimeType.tp_base = &PyDateTime_DateType;
-
-    PyTypeObject *capi_types[] = {
-        &PyDateTime_DateType,
-        &PyDateTime_DateTimeType,
-        &PyDateTime_TimeType,
-        &PyDateTime_DeltaType,
-        &PyDateTime_TZInfoType,
-        /* Indirectly, via the utc object. */
-        &PyDateTime_TimeZoneType,
-    };
+    if (init_static_types(interp, reloading) < 0) {
+        goto error;
+    }
 
     for (size_t i = 0; i < Py_ARRAY_LENGTH(capi_types); i++) {
-        if (PyModule_AddType(module, capi_types[i]) < 0) {
+        PyTypeObject *type = capi_types[i];
+        const char *name = _PyType_Name(type);
+        assert(name != NULL);
+        if (PyModule_AddObjectRef(module, name, (PyObject *)type) < 0) {
             goto error;
         }
     }
@@ -7145,11 +7237,8 @@ _datetime_exec(PyObject *module)
         goto error;
     }
 
-    /* For now we only set the objects on the static types once.
-     * We will relax that once each types __dict__ is per-interpreter. */
 #define DATETIME_ADD_MACRO(dict, c, value_expr)         \
     do {                                                \
-      if (PyDict_GetItemString(dict, c) == NULL) {      \
         assert(!PyErr_Occurred());                      \
         PyObject *value = (value_expr);                 \
         if (value == NULL) {                            \
@@ -7160,30 +7249,29 @@ _datetime_exec(PyObject *module)
             goto error;                                 \
         }                                               \
         Py_DECREF(value);                               \
-      }                                                 \
     } while(0)
 
     /* timedelta values */
-    PyObject *d = PyDateTime_DeltaType.tp_dict;
+    PyObject *d = _PyType_GetDict(&PyDateTime_DeltaType);
     DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
     DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0));
     DATETIME_ADD_MACRO(d, "max",
                        new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0));
 
     /* date values */
-    d = PyDateTime_DateType.tp_dict;
+    d = _PyType_GetDict(&PyDateTime_DateType);
     DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1));
     DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31));
     DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0));
 
     /* time values */
-    d = PyDateTime_TimeType.tp_dict;
+    d = _PyType_GetDict(&PyDateTime_TimeType);
     DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0));
     DATETIME_ADD_MACRO(d, "max", new_time(23, 59, 59, 999999, Py_None, 0));
     DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
 
     /* datetime values */
-    d = PyDateTime_DateTimeType.tp_dict;
+    d = _PyType_GetDict(&PyDateTime_DateTimeType);
     DATETIME_ADD_MACRO(d, "min",
                        new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0));
     DATETIME_ADD_MACRO(d, "max", new_datetime(MAXYEAR, 12, 31, 23, 59, 59,
@@ -7191,7 +7279,7 @@ _datetime_exec(PyObject *module)
     DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0));
 
     /* timezone values */
-    d = PyDateTime_TimeZoneType.tp_dict;
+    d = _PyType_GetDict(&PyDateTime_TimeZoneType);
     if (PyDict_SetItemString(d, "utc", (PyObject *)&utc_timezone) < 0) {
         goto error;
     }
@@ -7266,7 +7354,7 @@ finally:
 
 static PyModuleDef_Slot module_slots[] = {
     {Py_mod_exec, _datetime_exec},
-    {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
+    {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
     {Py_mod_gil, Py_MOD_GIL_NOT_USED},
     {0, NULL},
 };
@@ -7288,17 +7376,16 @@ module_clear(PyObject *mod)
     PyInterpreterState *interp = PyInterpreterState_Get();
     clear_current_module(interp, mod);
 
+    // We take care of the static types via an interpreter atexit hook.
+    // See callback_for_interp_exit() above.
+
     return 0;
 }
 
 static void
 module_free(void *mod)
 {
-    datetime_state *st = get_module_state((PyObject *)mod);
-    clear_state(st);
-
-    PyInterpreterState *interp = PyInterpreterState_Get();
-    clear_current_module(interp, (PyObject *)mod);
+    (void)module_clear((PyObject *)mod);
 }
 
 static PyModuleDef datetimemodule = {
index f9cd577c1c16be60cf8b727c479f12f09f548c89..3a72cce1dff0c7bf2dd3252460436e860d6dc148 100644 (file)
@@ -3725,7 +3725,7 @@ _PyExc_FiniTypes(PyInterpreterState *interp)
 {
     for (Py_ssize_t i=Py_ARRAY_LENGTH(static_exceptions) - 1; i >= 0; i--) {
         PyTypeObject *exc = static_exceptions[i].exc;
-        _PyStaticType_Dealloc(interp, exc);
+        _PyStaticType_FiniBuiltin(interp, exc);
     }
 }
 
index 5d53e9e5eaba4e09be12337d15294abd86b4d21a..2e9962f4651e1cfa24f4e66b09e1cafc6515d250 100644 (file)
@@ -2355,7 +2355,7 @@ _PyTypes_FiniTypes(PyInterpreterState *interp)
     // their base classes.
     for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types)-1; i>=0; i--) {
         PyTypeObject *type = static_types[i];
-        _PyStaticType_Dealloc(interp, type);
+        _PyStaticType_FiniBuiltin(interp, type);
     }
 }
 
index ec5c5ab45ba81312d9bee9fad7491b17afaa8aaf..d8289f2638db0f9c1dc3ec4d9d58606318b893ea 100644 (file)
@@ -718,7 +718,7 @@ _PyStructSequence_FiniBuiltin(PyInterpreterState *interp, PyTypeObject *type)
         return;
     }
 
-    _PyStaticType_Dealloc(interp, type);
+    _PyStaticType_FiniBuiltin(interp, type);
 
     if (_Py_IsMainInterpreter(interp)) {
         // Undo _PyStructSequence_InitBuiltinWithFlags().
index 0095a79a2cafec4ad755b6130f27d632ef4b3715..880ac6b9c009fef9b5b796c7027feec5d819d3e6 100644 (file)
@@ -131,93 +131,159 @@ type_from_ref(PyObject *ref)
 
 #ifndef NDEBUG
 static inline int
-static_builtin_index_is_set(PyTypeObject *self)
+managed_static_type_index_is_set(PyTypeObject *self)
 {
     return self->tp_subclasses != NULL;
 }
 #endif
 
 static inline size_t
-static_builtin_index_get(PyTypeObject *self)
+managed_static_type_index_get(PyTypeObject *self)
 {
-    assert(static_builtin_index_is_set(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;
 }
 
 static inline void
-static_builtin_index_set(PyTypeObject *self, size_t index)
+managed_static_type_index_set(PyTypeObject *self, size_t index)
 {
-    assert(index < _Py_MAX_STATIC_BUILTIN_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);
 }
 
 static inline void
-static_builtin_index_clear(PyTypeObject *self)
+managed_static_type_index_clear(PyTypeObject *self)
 {
     self->tp_subclasses = NULL;
 }
 
-static inline static_builtin_state *
+static inline managed_static_type_state *
 static_builtin_state_get(PyInterpreterState *interp, PyTypeObject *self)
 {
-    return &(interp->types.builtins[static_builtin_index_get(self)]);
+    return &(interp->types.builtins.initialized[
+                        managed_static_type_index_get(self)]);
+}
+
+static inline managed_static_type_state *
+static_ext_type_state_get(PyInterpreterState *interp, PyTypeObject *self)
+{
+    return &(interp->types.for_extensions.initialized[
+                        managed_static_type_index_get(self)]);
+}
+
+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);
+    managed_static_type_state *state =
+            &(interp->types.builtins.initialized[index]);
+    if (state->type == self) {
+        return state;
+    }
+    if (index > _Py_MAX_MANAGED_STATIC_EXT_TYPES) {
+        return state;
+    }
+    return &(interp->types.for_extensions.initialized[index]);
 }
 
 /* For static types we store some state in an array on each interpreter. */
-static_builtin_state *
+managed_static_type_state *
 _PyStaticType_GetState(PyInterpreterState *interp, PyTypeObject *self)
 {
     assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN);
-    return static_builtin_state_get(interp, self);
+    return managed_static_type_state_get(interp, self);
 }
 
 /* Set the type's per-interpreter state. */
 static void
-static_builtin_state_init(PyInterpreterState *interp, PyTypeObject *self)
+managed_static_type_state_init(PyInterpreterState *interp, PyTypeObject *self,
+                               int isbuiltin, int initial)
 {
-    if (_Py_IsMainInterpreter(interp)) {
-        assert(!static_builtin_index_is_set(self));
-        static_builtin_index_set(self, interp->types.num_builtins_initialized);
+    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 {
-        assert(static_builtin_index_get(self) ==
-                interp->types.num_builtins_initialized);
+        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);
+        }
     }
-    static_builtin_state *state = static_builtin_state_get(interp, self);
 
-    /* It should only be called once for each builtin type. */
+    managed_static_type_state *state = isbuiltin
+        ? &(interp->types.builtins.initialized[index])
+        : &(interp->types.for_extensions.initialized[index]);
+
+    /* 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. */
 
-    interp->types.num_builtins_initialized++;
+    if (isbuiltin) {
+        interp->types.builtins.num_initialized++;
+    }
+    else {
+        interp->types.for_extensions.num_initialized++;
+    }
 }
 
 /* Reset the type's per-interpreter state.
-   This basically undoes what static_builtin_state_init() did. */
+   This basically undoes what managed_static_type_state_init() did. */
 static void
-static_builtin_state_clear(PyInterpreterState *interp, PyTypeObject *self)
+managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self,
+                                int isbuiltin, int final)
 {
-    static_builtin_state *state = static_builtin_state_get(interp, self);
+    managed_static_type_state *state = isbuiltin
+        ? static_builtin_state_get(interp, self)
+        : static_ext_type_state_get(interp, self);
 
     assert(state->type != NULL);
     state->type = NULL;
     assert(state->tp_weaklist == NULL);  // It was already cleared out.
 
-    if (_Py_IsMainInterpreter(interp)) {
-        static_builtin_index_clear(self);
+    if (final) {
+        managed_static_type_index_clear(self);
     }
 
-    assert(interp->types.num_builtins_initialized > 0);
-    interp->types.num_builtins_initialized--;
+    if (isbuiltin) {
+        assert(interp->types.builtins.num_initialized > 0);
+        interp->types.builtins.num_initialized--;
+    }
+    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;
+        }
+        PyMutex_Unlock(&interp->types.mutex);
+    }
 }
 
-// Also see _PyStaticType_InitBuiltin() and _PyStaticType_Dealloc().
+// Also see _PyStaticType_InitBuiltin() and _PyStaticType_FiniBuiltin().
 
 /* end static builtin helpers */
 
@@ -227,7 +293,7 @@ start_readying(PyTypeObject *type)
 {
     if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         PyInterpreterState *interp = _PyInterpreterState_GET();
-        static_builtin_state *state = static_builtin_state_get(interp, type);
+        managed_static_type_state *state = managed_static_type_state_get(interp, type);
         assert(state != NULL);
         assert(!state->readying);
         state->readying = 1;
@@ -242,7 +308,7 @@ stop_readying(PyTypeObject *type)
 {
     if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         PyInterpreterState *interp = _PyInterpreterState_GET();
-        static_builtin_state *state = static_builtin_state_get(interp, type);
+        managed_static_type_state *state = managed_static_type_state_get(interp, type);
         assert(state != NULL);
         assert(state->readying);
         state->readying = 0;
@@ -257,7 +323,7 @@ is_readying(PyTypeObject *type)
 {
     if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         PyInterpreterState *interp = _PyInterpreterState_GET();
-        static_builtin_state *state = static_builtin_state_get(interp, type);
+        managed_static_type_state *state = managed_static_type_state_get(interp, type);
         assert(state != NULL);
         return state->readying;
     }
@@ -272,7 +338,7 @@ lookup_tp_dict(PyTypeObject *self)
 {
     if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         PyInterpreterState *interp = _PyInterpreterState_GET();
-        static_builtin_state *state = _PyStaticType_GetState(interp, self);
+        managed_static_type_state *state = _PyStaticType_GetState(interp, self);
         assert(state != NULL);
         return state->tp_dict;
     }
@@ -298,7 +364,7 @@ set_tp_dict(PyTypeObject *self, PyObject *dict)
 {
     if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         PyInterpreterState *interp = _PyInterpreterState_GET();
-        static_builtin_state *state = _PyStaticType_GetState(interp, self);
+        managed_static_type_state *state = _PyStaticType_GetState(interp, self);
         assert(state != NULL);
         state->tp_dict = dict;
         return;
@@ -311,7 +377,7 @@ clear_tp_dict(PyTypeObject *self)
 {
     if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         PyInterpreterState *interp = _PyInterpreterState_GET();
-        static_builtin_state *state = _PyStaticType_GetState(interp, self);
+        managed_static_type_state *state = _PyStaticType_GetState(interp, self);
         assert(state != NULL);
         Py_CLEAR(state->tp_dict);
         return;
@@ -340,13 +406,13 @@ _PyType_GetBases(PyTypeObject *self)
 }
 
 static inline void
-set_tp_bases(PyTypeObject *self, PyObject *bases)
+set_tp_bases(PyTypeObject *self, PyObject *bases, int initial)
 {
     assert(PyTuple_CheckExact(bases));
     if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         // XXX tp_bases can probably be statically allocated for each
         // static builtin type.
-        assert(_Py_IsMainInterpreter(_PyInterpreterState_GET()));
+        assert(initial);
         assert(self->tp_bases == NULL);
         if (PyTuple_GET_SIZE(bases) == 0) {
             assert(self->tp_base == NULL);
@@ -363,10 +429,10 @@ set_tp_bases(PyTypeObject *self, PyObject *bases)
 }
 
 static inline void
-clear_tp_bases(PyTypeObject *self)
+clear_tp_bases(PyTypeObject *self, int final)
 {
     if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
-        if (_Py_IsMainInterpreter(_PyInterpreterState_GET())) {
+        if (final) {
             if (self->tp_bases != NULL) {
                 if (PyTuple_GET_SIZE(self->tp_bases) == 0) {
                     Py_CLEAR(self->tp_bases);
@@ -413,13 +479,13 @@ _PyType_GetMRO(PyTypeObject *self)
 }
 
 static inline void
-set_tp_mro(PyTypeObject *self, PyObject *mro)
+set_tp_mro(PyTypeObject *self, PyObject *mro, int initial)
 {
     assert(PyTuple_CheckExact(mro));
     if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         // XXX tp_mro can probably be statically allocated for each
         // static builtin type.
-        assert(_Py_IsMainInterpreter(_PyInterpreterState_GET()));
+        assert(initial);
         assert(self->tp_mro == NULL);
         /* Other checks are done via set_tp_bases. */
         _Py_SetImmortal(mro);
@@ -428,10 +494,10 @@ set_tp_mro(PyTypeObject *self, PyObject *mro)
 }
 
 static inline void
-clear_tp_mro(PyTypeObject *self)
+clear_tp_mro(PyTypeObject *self, int final)
 {
     if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
-        if (_Py_IsMainInterpreter(_PyInterpreterState_GET())) {
+        if (final) {
             if (self->tp_mro != NULL) {
                 if (PyTuple_GET_SIZE(self->tp_mro) == 0) {
                     Py_CLEAR(self->tp_mro);
@@ -457,7 +523,7 @@ init_tp_subclasses(PyTypeObject *self)
     }
     if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         PyInterpreterState *interp = _PyInterpreterState_GET();
-        static_builtin_state *state = _PyStaticType_GetState(interp, self);
+        managed_static_type_state *state = _PyStaticType_GetState(interp, self);
         state->tp_subclasses = subclasses;
         return subclasses;
     }
@@ -473,7 +539,7 @@ clear_tp_subclasses(PyTypeObject *self)
        has no subclass. */
     if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         PyInterpreterState *interp = _PyInterpreterState_GET();
-        static_builtin_state *state = _PyStaticType_GetState(interp, self);
+        managed_static_type_state *state = _PyStaticType_GetState(interp, self);
         Py_CLEAR(state->tp_subclasses);
         return;
     }
@@ -485,7 +551,7 @@ lookup_tp_subclasses(PyTypeObject *self)
 {
     if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
         PyInterpreterState *interp = _PyInterpreterState_GET();
-        static_builtin_state *state = _PyStaticType_GetState(interp, self);
+        managed_static_type_state *state = _PyStaticType_GetState(interp, self);
         assert(state != NULL);
         return state->tp_subclasses;
     }
@@ -774,10 +840,10 @@ _PyTypes_Fini(PyInterpreterState *interp)
     struct type_cache *cache = &interp->types.type_cache;
     type_cache_clear(cache, NULL);
 
-    assert(interp->types.num_builtins_initialized == 0);
+    assert(interp->types.builtins.num_initialized == 0);
     // All the static builtin types should have been finalized already.
-    for (size_t i = 0; i < _Py_MAX_STATIC_BUILTIN_TYPES; i++) {
-        assert(interp->types.builtins[i].type == NULL);
+    for (size_t i = 0; i < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES; i++) {
+        assert(interp->types.builtins.initialized[i].type == NULL);
     }
 }
 
@@ -1444,7 +1510,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
     Py_XDECREF(tuple);
 
     if (res < 0) {
-        set_tp_mro(type, old_mro);
+        set_tp_mro(type, old_mro, 0);
         Py_DECREF(new_mro);
         return -1;
     }
@@ -1545,7 +1611,7 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, void *context)
     assert(old_bases != NULL);
     PyTypeObject *old_base = type->tp_base;
 
-    set_tp_bases(type, Py_NewRef(new_bases));
+    set_tp_bases(type, Py_NewRef(new_bases), 0);
     type->tp_base = (PyTypeObject *)Py_NewRef(new_base);
 
     PyObject *temp = PyList_New(0);
@@ -1593,7 +1659,7 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, void *context)
                           "", 2, 3, &cls, &new_mro, &old_mro);
         /* Do not rollback if cls has a newer version of MRO.  */
         if (lookup_tp_mro(cls) == new_mro) {
-            set_tp_mro(cls, Py_XNewRef(old_mro));
+            set_tp_mro(cls, Py_XNewRef(old_mro), 0);
             Py_DECREF(new_mro);
         }
     }
@@ -1603,7 +1669,7 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, void *context)
     if (lookup_tp_bases(type) == new_bases) {
         assert(type->tp_base == new_base);
 
-        set_tp_bases(type, old_bases);
+        set_tp_bases(type, old_bases, 0);
         type->tp_base = old_base;
 
         Py_DECREF(new_bases);
@@ -3084,7 +3150,7 @@ mro_invoke(PyTypeObject *type)
      - Returns -1 in case of an error.
 */
 static int
-mro_internal_unlocked(PyTypeObject *type, PyObject **p_old_mro)
+mro_internal_unlocked(PyTypeObject *type, int initial, PyObject **p_old_mro)
 {
     ASSERT_TYPE_LOCK_HELD();
 
@@ -3107,7 +3173,7 @@ mro_internal_unlocked(PyTypeObject *type, PyObject **p_old_mro)
         return 0;
     }
 
-    set_tp_mro(type, new_mro);
+    set_tp_mro(type, new_mro, initial);
 
     type_mro_modified(type, new_mro);
     /* corner case: the super class might have been hidden
@@ -3137,7 +3203,7 @@ mro_internal(PyTypeObject *type, PyObject **p_old_mro)
 {
     int res;
     BEGIN_TYPE_LOCK()
-    res = mro_internal_unlocked(type, p_old_mro);
+    res = mro_internal_unlocked(type, 0, p_old_mro);
     END_TYPE_LOCK()
     return res;
 }
@@ -3732,7 +3798,7 @@ type_new_alloc(type_new_ctx *ctx)
     type->tp_as_mapping = &et->as_mapping;
     type->tp_as_buffer = &et->as_buffer;
 
-    set_tp_bases(type, Py_NewRef(ctx->bases));
+    set_tp_bases(type, Py_NewRef(ctx->bases), 1);
     type->tp_base = (PyTypeObject *)Py_NewRef(ctx->base);
 
     type->tp_dealloc = subtype_dealloc;
@@ -4722,7 +4788,7 @@ _PyType_FromMetaclass_impl(
     /* Set slots we have prepared */
 
     type->tp_base = (PyTypeObject *)Py_NewRef(base);
-    set_tp_bases(type, bases);
+    set_tp_bases(type, bases, 1);
     bases = NULL;  // We give our reference to bases to the type
 
     type->tp_doc = tp_doc;
@@ -5627,7 +5693,7 @@ type_dealloc_common(PyTypeObject *type)
 
 
 static void
-clear_static_tp_subclasses(PyTypeObject *type)
+clear_static_tp_subclasses(PyTypeObject *type, int isbuiltin)
 {
     PyObject *subclasses = lookup_tp_subclasses(type);
     if (subclasses == NULL) {
@@ -5664,47 +5730,64 @@ clear_static_tp_subclasses(PyTypeObject *type)
             continue;
         }
         // All static builtin subtypes should have been finalized already.
-        assert(!(subclass->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
+        assert(!isbuiltin || !(subclass->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
         Py_DECREF(subclass);
     }
+#else
+    (void)isbuiltin;
 #endif
 
     clear_tp_subclasses(type);
 }
 
 static void
-clear_static_type_objects(PyInterpreterState *interp, PyTypeObject *type)
+clear_static_type_objects(PyInterpreterState *interp, PyTypeObject *type,
+                          int isbuiltin, int final)
 {
-    if (_Py_IsMainInterpreter(interp)) {
+    if (final) {
         Py_CLEAR(type->tp_cache);
     }
     clear_tp_dict(type);
-    clear_tp_bases(type);
-    clear_tp_mro(type);
-    clear_static_tp_subclasses(type);
+    clear_tp_bases(type, final);
+    clear_tp_mro(type, final);
+    clear_static_tp_subclasses(type, isbuiltin);
 }
 
-void
-_PyStaticType_Dealloc(PyInterpreterState *interp, PyTypeObject *type)
+
+static void
+fini_static_type(PyInterpreterState *interp, PyTypeObject *type,
+                 int isbuiltin, int final)
 {
     assert(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN);
     assert(_Py_IsImmortal((PyObject *)type));
 
     type_dealloc_common(type);
 
-    clear_static_type_objects(interp, type);
+    clear_static_type_objects(interp, type, isbuiltin, final);
 
-    if (_Py_IsMainInterpreter(interp)) {
+    if (final) {
         type->tp_flags &= ~Py_TPFLAGS_READY;
         type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
         type->tp_version_tag = 0;
     }
 
     _PyStaticType_ClearWeakRefs(interp, type);
-    static_builtin_state_clear(interp, type);
+    managed_static_type_state_clear(interp, type, isbuiltin, final);
     /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */
 }
 
+void
+_PyStaticType_FiniForExtension(PyInterpreterState *interp, PyTypeObject *type, int final)
+{
+    fini_static_type(interp, type, 0, final);
+}
+
+void
+_PyStaticType_FiniBuiltin(PyInterpreterState *interp, PyTypeObject *type)
+{
+    fini_static_type(interp, type, 1, _Py_IsMainInterpreter(interp));
+}
+
 
 static void
 type_dealloc(PyObject *self)
@@ -7758,10 +7841,10 @@ type_ready_set_type(PyTypeObject *type)
 }
 
 static int
-type_ready_set_bases(PyTypeObject *type)
+type_ready_set_bases(PyTypeObject *type, int initial)
 {
     if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
-        if (!_Py_IsMainInterpreter(_PyInterpreterState_GET())) {
+        if (!initial) {
             assert(lookup_tp_bases(type) != NULL);
             return 0;
         }
@@ -7780,7 +7863,7 @@ type_ready_set_bases(PyTypeObject *type)
         if (bases == NULL) {
             return -1;
         }
-        set_tp_bases(type, bases);
+        set_tp_bases(type, bases, 1);
     }
     return 0;
 }
@@ -7890,12 +7973,12 @@ type_ready_preheader(PyTypeObject *type)
 }
 
 static int
-type_ready_mro(PyTypeObject *type)
+type_ready_mro(PyTypeObject *type, int initial)
 {
     ASSERT_TYPE_LOCK_HELD();
 
     if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) {
-        if (!_Py_IsMainInterpreter(_PyInterpreterState_GET())) {
+        if (!initial) {
             assert(lookup_tp_mro(type) != NULL);
             return 0;
         }
@@ -7903,7 +7986,7 @@ type_ready_mro(PyTypeObject *type)
     }
 
     /* Calculate method resolution order */
-    if (mro_internal_unlocked(type, NULL) < 0) {
+    if (mro_internal_unlocked(type, initial, NULL) < 0) {
         return -1;
     }
     PyObject *mro = lookup_tp_mro(type);
@@ -8058,7 +8141,7 @@ type_ready_add_subclasses(PyTypeObject *type)
 // Set tp_new and the "__new__" key in the type dictionary.
 // Use the Py_TPFLAGS_DISALLOW_INSTANTIATION flag.
 static int
-type_ready_set_new(PyTypeObject *type, int rerunbuiltin)
+type_ready_set_new(PyTypeObject *type, int initial)
 {
     PyTypeObject *base = type->tp_base;
     /* The condition below could use some explanation.
@@ -8080,7 +8163,7 @@ type_ready_set_new(PyTypeObject *type, int rerunbuiltin)
 
     if (!(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)) {
         if (type->tp_new != NULL) {
-            if (!rerunbuiltin || base == NULL || type->tp_new != base->tp_new) {
+            if (initial || base == NULL || type->tp_new != base->tp_new) {
                 // If "__new__" key does not exists in the type dictionary,
                 // set it to tp_new_wrapper().
                 if (add_tp_new_wrapper(type) < 0) {
@@ -8162,7 +8245,7 @@ type_ready_post_checks(PyTypeObject *type)
 
 
 static int
-type_ready(PyTypeObject *type, int rerunbuiltin)
+type_ready(PyTypeObject *type, int initial)
 {
     ASSERT_TYPE_LOCK_HELD();
 
@@ -8192,19 +8275,19 @@ type_ready(PyTypeObject *type, int rerunbuiltin)
     if (type_ready_set_type(type) < 0) {
         goto error;
     }
-    if (type_ready_set_bases(type) < 0) {
+    if (type_ready_set_bases(type, initial) < 0) {
         goto error;
     }
-    if (type_ready_mro(type) < 0) {
+    if (type_ready_mro(type, initial) < 0) {
         goto error;
     }
-    if (type_ready_set_new(type, rerunbuiltin) < 0) {
+    if (type_ready_set_new(type, initial) < 0) {
         goto error;
     }
     if (type_ready_fill_dict(type) < 0) {
         goto error;
     }
-    if (!rerunbuiltin) {
+    if (initial) {
         if (type_ready_inherit(type) < 0) {
             goto error;
         }
@@ -8218,7 +8301,7 @@ type_ready(PyTypeObject *type, int rerunbuiltin)
     if (type_ready_add_subclasses(type) < 0) {
         goto error;
     }
-    if (!rerunbuiltin) {
+    if (initial) {
         if (type_ready_managed_dict(type) < 0) {
             goto error;
         }
@@ -8258,7 +8341,7 @@ PyType_Ready(PyTypeObject *type)
     int res;
     BEGIN_TYPE_LOCK()
     if (!(type->tp_flags & Py_TPFLAGS_READY)) {
-        res = type_ready(type, 0);
+        res = type_ready(type, 1);
     } else {
         res = 0;
         assert(_PyType_CheckConsistency(type));
@@ -8267,17 +8350,18 @@ PyType_Ready(PyTypeObject *type)
     return res;
 }
 
-int
-_PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self)
+
+static int
+init_static_type(PyInterpreterState *interp, PyTypeObject *self,
+                 int isbuiltin, int initial)
 {
     assert(_Py_IsImmortal((PyObject *)self));
     assert(!(self->tp_flags & Py_TPFLAGS_HEAPTYPE));
     assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_DICT));
     assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF));
 
-    int ismain = _Py_IsMainInterpreter(interp);
     if ((self->tp_flags & Py_TPFLAGS_READY) == 0) {
-        assert(ismain);
+        assert(initial);
 
         self->tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN;
         self->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE;
@@ -8287,24 +8371,36 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self)
         self->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG;
     }
     else {
-        assert(!ismain);
+        assert(!initial);
         assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN);
         assert(self->tp_flags & Py_TPFLAGS_VALID_VERSION_TAG);
     }
 
-    static_builtin_state_init(interp, self);
+    managed_static_type_state_init(interp, self, isbuiltin, initial);
 
     int res;
     BEGIN_TYPE_LOCK();
-    res = type_ready(self, !ismain);
+    res = type_ready(self, initial);
     END_TYPE_LOCK()
     if (res < 0) {
         _PyStaticType_ClearWeakRefs(interp, self);
-        static_builtin_state_clear(interp, self);
+        managed_static_type_state_clear(interp, self, isbuiltin, initial);
     }
     return res;
 }
 
+int
+_PyStaticType_InitForExtension(PyInterpreterState *interp, PyTypeObject *self)
+{
+    return init_static_type(interp, self, 0, ((self->tp_flags & Py_TPFLAGS_READY) == 0));
+}
+
+int
+_PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self)
+{
+    return init_static_type(interp, self, 1, _Py_IsMainInterpreter(interp));
+}
+
 
 static int
 add_subclass(PyTypeObject *base, PyTypeObject *type)
index 53160f1799f2cc46a4d031b5767f8495e28b52a1..3b0b4173408724616540eab48981892100de1fd0 100644 (file)
@@ -15522,9 +15522,9 @@ unicode_is_finalizing(void)
 void
 _PyUnicode_FiniTypes(PyInterpreterState *interp)
 {
-    _PyStaticType_Dealloc(interp, &EncodingMapType);
-    _PyStaticType_Dealloc(interp, &PyFieldNameIter_Type);
-    _PyStaticType_Dealloc(interp, &PyFormatterIter_Type);
+    _PyStaticType_FiniBuiltin(interp, &EncodingMapType);
+    _PyStaticType_FiniBuiltin(interp, &PyFieldNameIter_Type);
+    _PyStaticType_FiniBuiltin(interp, &PyFormatterIter_Type);
 }
 
 
index 88afaec86827ed4bd2c0d5448963c60bd63db5c9..3b027e1b518ba6cc2c922af1f0da1595692e6f18 100644 (file)
@@ -1066,7 +1066,7 @@ PyObject_ClearWeakRefs(PyObject *object)
 void
 _PyStaticType_ClearWeakRefs(PyInterpreterState *interp, PyTypeObject *type)
 {
-    static_builtin_state *state = _PyStaticType_GetState(interp, type);
+    managed_static_type_state *state = _PyStaticType_GetState(interp, type);
     PyObject **list = _PyStaticType_GET_WEAKREFS_LISTPTR(state);
     // This is safe to do without holding the lock in free-threaded builds;
     // there is only one thread running and no new threads can be created.
index 6ecc10c7955fd85fcc031bb8093a9cc8f6a5dd68..278511da615c75d6ad2f1e64c55b1cda57f030b1 100644 (file)
@@ -90,6 +90,6 @@ static void
 fini_exceptions(PyInterpreterState *interp)
 {
     // Likewise with _fini_not_shareable_error_type().
-    _PyStaticType_Dealloc(interp, &_PyExc_InterpreterNotFoundError);
-    _PyStaticType_Dealloc(interp, &_PyExc_InterpreterError);
+    _PyStaticType_FiniBuiltin(interp, &_PyExc_InterpreterNotFoundError);
+    _PyStaticType_FiniBuiltin(interp, &_PyExc_InterpreterError);
 }
index 711ae343a8d876ab8c68acac38edfad89fb5fa82..4586a59f6ac2efebeebc6fdd8fcf7eb35905bcad 100644 (file)
@@ -307,6 +307,7 @@ Python/crossinterp_exceptions.h     -       PyExc_InterpreterNotFoundError  -
 Modules/_datetimemodule.c      -       zero_delta      -
 Modules/_datetimemodule.c      -       utc_timezone    -
 Modules/_datetimemodule.c      -       capi    -
+Modules/_datetimemodule.c      -       _globals        -
 Objects/boolobject.c   -       _Py_FalseStruct -
 Objects/boolobject.c   -       _Py_TrueStruct  -
 Objects/dictobject.c   -       empty_keys_struct       -
index a3bdf0396fd3e1bbca31a6c68e5ff257e3079c66..466f25daa14dc6f8ba77d12e4e1386b5c12bf79c 100644 (file)
@@ -217,6 +217,7 @@ Modules/_datetimemodule.c   -       max_fold_seconds        -
 Modules/_datetimemodule.c      datetime_isoformat      specs   -
 Modules/_datetimemodule.c      parse_hh_mm_ss_ff       correction      -
 Modules/_datetimemodule.c      time_isoformat  specs   -
+Modules/_datetimemodule.c      -       capi_types      -
 Modules/_decimal/_decimal.c    -       cond_map_template       -
 Modules/_decimal/_decimal.c    -       dec_signal_string       -
 Modules/_decimal/_decimal.c    -       dflt_ctx        -