]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-94673: Add _PyStaticType_InitBuiltin() (#95152)
authorEric Snow <ericsnowcurrently@gmail.com>
Mon, 25 Jul 2022 18:47:31 +0000 (12:47 -0600)
committerGitHub <noreply@github.com>
Mon, 25 Jul 2022 18:47:31 +0000 (12:47 -0600)
This is the first of several precursors to storing tp_subclasses (and tp_weaklist) on the interpreter state for static builtin types.

We do the following:

* add `_PyStaticType_InitBuiltin()`
* add `_Py_TPFLAGS_STATIC_BUILTIN`
* set it on all static builtin types in `_PyStaticType_InitBuiltin()`
* shuffle some code around to be able to use _PyStaticType_InitBuiltin()
    * rename `_PyStructSequence_InitType()` to `_PyStructSequence_InitBuiltinWithFlags()`
    * add `_PyStructSequence_InitBuiltin()`.

13 files changed:
Include/internal/pycore_structseq.h
Include/internal/pycore_typeobject.h
Include/object.h
Objects/exceptions.c
Objects/floatobject.c
Objects/longobject.c
Objects/object.c
Objects/structseq.c
Objects/typeobject.c
Objects/unicodeobject.c
Python/errors.c
Python/sysmodule.c
Python/thread.c

index 0199c790e24cecfcfbceac226e15c3b353c9b731..d10a921c55ff8bc5393e723086cde3c077146ad9 100644 (file)
@@ -15,11 +15,18 @@ PyAPI_FUNC(PyTypeObject *) _PyStructSequence_NewType(
     PyStructSequence_Desc *desc,
     unsigned long tp_flags);
 
-PyAPI_FUNC(int) _PyStructSequence_InitType(
+PyAPI_FUNC(int) _PyStructSequence_InitBuiltinWithFlags(
     PyTypeObject *type,
     PyStructSequence_Desc *desc,
     unsigned long tp_flags);
 
+static inline int
+_PyStructSequence_InitBuiltin(PyTypeObject *type,
+                              PyStructSequence_Desc *desc)
+{
+    return _PyStructSequence_InitBuiltinWithFlags(type, desc, 0);
+}
+
 extern void _PyStructSequence_FiniType(PyTypeObject *type);
 
 #ifdef __cplusplus
index c480a3a57b436c958f7db7c2a0b1cb2acfa7cda7..46f3bf78b133eec183d813cf0a19f0baea4c9bc6 100644 (file)
@@ -41,6 +41,7 @@ struct type_cache {
 
 extern PyStatus _PyTypes_InitSlotDefs(void);
 
+extern int _PyStaticType_InitBuiltin(PyTypeObject *type);
 extern void _PyStaticType_Dealloc(PyTypeObject *type);
 
 
index a12b754c8ed8f32024d60e69a69709cd45cbee97..c00b9eb583420a1ce0c96726c98c752529c82485 100644 (file)
@@ -352,6 +352,9 @@ given type object has a specified feature.
 
 #ifndef Py_LIMITED_API
 
+/* Track types initialized using _PyStaticType_InitBuiltin(). */
+#define _Py_TPFLAGS_STATIC_BUILTIN (1 << 1)
+
 /* Placement of dict (and values) pointers are managed by the VM, not by the type.
  * The VM will automatically set tp_dictoffset. Should not be used for variable sized
  * classes, such as classes that extend tuple.
index 9aab683fd1ca7f8fa8f1e5997675b6423e9cd580..e06a8f4173cf8b73137bf0c270bf5095e3cfa154 100644 (file)
@@ -3556,8 +3556,7 @@ _PyExc_InitTypes(PyInterpreterState *interp)
 
     for (size_t i=0; i < Py_ARRAY_LENGTH(static_exceptions); i++) {
         PyTypeObject *exc = static_exceptions[i].exc;
-
-        if (PyType_Ready(exc) < 0) {
+        if (_PyStaticType_InitBuiltin(exc) < 0) {
             return -1;
         }
     }
index 47d308b8eb3702b03d760509a07d53452e96b2c7..4b1b24f2e702a471becec5a9621ac00ff3d68b28 100644 (file)
@@ -1992,7 +1992,8 @@ _PyFloat_InitTypes(PyInterpreterState *interp)
 
     /* Init float info */
     if (FloatInfoType.tp_name == NULL) {
-        if (PyStructSequence_InitType2(&FloatInfoType, &floatinfo_desc) < 0) {
+        if (_PyStructSequence_InitBuiltin(&FloatInfoType,
+                                          &floatinfo_desc) < 0) {
             return _PyStatus_ERR("can't init float info type");
         }
     }
index 4a1e5caf5a284392ee8c40c4dabd046d6193abbd..90ed02b8c27a19853c2ba6f9119eeee12a59377f 100644 (file)
@@ -6135,7 +6135,7 @@ _PyLong_InitTypes(PyInterpreterState *interp)
 
     /* initialize int_info */
     if (Int_InfoType.tp_name == NULL) {
-        if (PyStructSequence_InitType2(&Int_InfoType, &int_info_desc) < 0) {
+        if (_PyStructSequence_InitBuiltin(&Int_InfoType, &int_info_desc) < 0) {
             return _PyStatus_ERR("can't init int info type");
         }
     }
index 75aee909a3b4965414245badb44ae79ce92fa042..758b79eff5b3e30eac8579f1e4613bc5312a3701 100644 (file)
@@ -1975,8 +1975,8 @@ _PyTypes_InitTypes(PyInterpreterState *interp)
     // All other static types (unless initialized elsewhere)
     for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
         PyTypeObject *type = static_types[i];
-        if (PyType_Ready(type) < 0) {
-            return _PyStatus_ERR("Can't initialize types");
+        if (_PyStaticType_InitBuiltin(type) < 0) {
+            return _PyStatus_ERR("Can't initialize builtin type");
         }
         if (type == &PyType_Type) {
             // Sanitify checks of the two most important types
index 229e3d893ff6aa871c9a3569c8e4af0cd98bab1e..24cd0e705969b20c4a239ab926b3e6d8a716af32 100644 (file)
@@ -432,11 +432,21 @@ error:
     return -1;
 }
 
-static void
-initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members,
-                   Py_ssize_t n_members) {
-    Py_ssize_t i, k;
+static PyMemberDef *
+initialize_members(PyStructSequence_Desc *desc,
+                   Py_ssize_t *pn_members, Py_ssize_t *pn_unnamed_members)
+{
+    PyMemberDef *members;
+    Py_ssize_t n_members, n_unnamed_members;
+
+    n_members = count_members(desc, &n_unnamed_members);
+    members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
+    if (members == NULL) {
+        PyErr_NoMemory();
+        return NULL;
+    }
 
+    Py_ssize_t i, k;
     for (i = k = 0; i < n_members; ++i) {
         if (desc->fields[i].name == PyStructSequence_UnnamedField) {
             continue;
@@ -453,30 +463,17 @@ initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members,
         k++;
     }
     members[k].name = NULL;
+
+    *pn_members = n_members;
+    *pn_unnamed_members = n_unnamed_members;
+    return members;
 }
 
 
-int
-_PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc,
-                           unsigned long tp_flags)
+static void
+initialize_static_fields(PyTypeObject *type, PyStructSequence_Desc *desc,
+                         PyMemberDef *tp_members, unsigned long tp_flags)
 {
-    PyMemberDef *members;
-    Py_ssize_t n_members, n_unnamed_members;
-
-#ifdef Py_TRACE_REFS
-    /* if the type object was chained, unchain it first
-       before overwriting its storage */
-    if (type->ob_base.ob_base._ob_next) {
-        _Py_ForgetReference((PyObject *)type);
-    }
-#endif
-
-    /* PyTypeObject has already been initialized */
-    if (Py_REFCNT(type) != 0) {
-        PyErr_BadInternalCall();
-        return -1;
-    }
-
     type->tp_name = desc->name;
     type->tp_basicsize = sizeof(PyStructSequence) - sizeof(PyObject *);
     type->tp_itemsize = sizeof(PyObject *);
@@ -488,25 +485,20 @@ _PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc,
     type->tp_new = structseq_new;
     type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags;
     type->tp_traverse = (traverseproc) structseq_traverse;
+    type->tp_members = tp_members;
+}
 
-    n_members = count_members(desc, &n_unnamed_members);
-    members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
-    if (members == NULL) {
-        PyErr_NoMemory();
-        return -1;
-    }
-    initialize_members(desc, members, n_members);
-    type->tp_members = members;
-
+static int
+initialize_static_type(PyTypeObject *type, PyStructSequence_Desc *desc,
+                       Py_ssize_t n_members, Py_ssize_t n_unnamed_members) {
+    /* initialize_static_fields() should have been called already. */
     if (PyType_Ready(type) < 0) {
-        PyMem_Free(members);
         return -1;
     }
     Py_INCREF(type);
 
     if (initialize_structseq_dict(
             desc, type->tp_dict, n_members, n_unnamed_members) < 0) {
-        PyMem_Free(members);
         Py_DECREF(type);
         return -1;
     }
@@ -514,10 +506,63 @@ _PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc,
     return 0;
 }
 
+int
+_PyStructSequence_InitBuiltinWithFlags(PyTypeObject *type,
+                                       PyStructSequence_Desc *desc,
+                                       unsigned long tp_flags)
+{
+    PyMemberDef *members;
+    Py_ssize_t n_members, n_unnamed_members;
+
+    members = initialize_members(desc, &n_members, &n_unnamed_members);
+    if (members == NULL) {
+        return -1;
+    }
+    initialize_static_fields(type, desc, members, tp_flags);
+    if (_PyStaticType_InitBuiltin(type) < 0) {
+        PyMem_Free(members);
+        PyErr_Format(PyExc_RuntimeError,
+                     "Can't initialize builtin type %s",
+                     desc->name);
+        return -1;
+    }
+    if (initialize_static_type(type, desc, n_members, n_unnamed_members) < 0) {
+        PyMem_Free(members);
+        return -1;
+    }
+    return 0;
+}
+
 int
 PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
 {
-    return _PyStructSequence_InitType(type, desc, 0);
+    PyMemberDef *members;
+    Py_ssize_t n_members, n_unnamed_members;
+
+#ifdef Py_TRACE_REFS
+    /* if the type object was chained, unchain it first
+       before overwriting its storage */
+    if (type->ob_base.ob_base._ob_next) {
+        _Py_ForgetReference((PyObject *)type);
+    }
+#endif
+
+    /* PyTypeObject has already been initialized */
+    if (Py_REFCNT(type) != 0) {
+        PyErr_BadInternalCall();
+        return -1;
+    }
+
+    members = initialize_members(desc, &n_members, &n_unnamed_members);
+    if (members == NULL) {
+        return -1;
+    }
+    initialize_static_fields(type, desc, members, 0);
+    if (initialize_static_type(type, desc, n_members, n_unnamed_members) < 0) {
+        PyMem_Free(members);
+        return -1;
+    }
+    return 0;
 }
 
 void
@@ -569,13 +614,10 @@ _PyStructSequence_NewType(PyStructSequence_Desc *desc, unsigned long tp_flags)
     Py_ssize_t n_members, n_unnamed_members;
 
     /* Initialize MemberDefs */
-    n_members = count_members(desc, &n_unnamed_members);
-    members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
+    members = initialize_members(desc, &n_members, &n_unnamed_members);
     if (members == NULL) {
-        PyErr_NoMemory();
         return NULL;
     }
-    initialize_members(desc, members, n_members);
 
     /* Initialize Slots */
     slots[0] = (PyType_Slot){Py_tp_dealloc, (destructor)structseq_dealloc};
index 5ebff6084f4a9726fd460886f6bcc329dc1c48b6..8510196b6123b59a4931186217c0e3501b19423b 100644 (file)
@@ -6650,6 +6650,14 @@ PyType_Ready(PyTypeObject *type)
     return 0;
 }
 
+int
+_PyStaticType_InitBuiltin(PyTypeObject *self)
+{
+    self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN;
+
+    return PyType_Ready(self);
+}
+
 
 static int
 add_subclass(PyTypeObject *base, PyTypeObject *type)
index 669ffe70727468ce3c60c1f82d393c9a43cc816b..7e3caf1af14c5b252aebb6cb1219f2e3bb423b4e 100644 (file)
@@ -14604,13 +14604,13 @@ _PyUnicode_InitTypes(PyInterpreterState *interp)
         return _PyStatus_OK();
     }
 
-    if (PyType_Ready(&EncodingMapType) < 0) {
+    if (_PyStaticType_InitBuiltin(&EncodingMapType) < 0) {
         goto error;
     }
-    if (PyType_Ready(&PyFieldNameIter_Type) < 0) {
+    if (_PyStaticType_InitBuiltin(&PyFieldNameIter_Type) < 0) {
         goto error;
     }
-    if (PyType_Ready(&PyFormatterIter_Type) < 0) {
+    if (_PyStaticType_InitBuiltin(&PyFormatterIter_Type) < 0) {
         goto error;
     }
     return _PyStatus_OK();
index b6b5d9b046ce851fe1f9673e08a264b1a176cddb..2aa748c60c370478a40ddf60d9bdc943b5db8e58 100644 (file)
@@ -1229,8 +1229,8 @@ _PyErr_InitTypes(PyInterpreterState *interp)
     }
 
     if (UnraisableHookArgsType.tp_name == NULL) {
-        if (PyStructSequence_InitType2(&UnraisableHookArgsType,
-                                       &UnraisableHookArgs_desc) < 0) {
+        if (_PyStructSequence_InitBuiltin(&UnraisableHookArgsType,
+                                          &UnraisableHookArgs_desc) < 0) {
             return _PyStatus_ERR("failed to initialize UnraisableHookArgs type");
         }
     }
index a5fa551b95764ce9c239178a5cba1ab6687f7769..e861d9cbce415c45b24e84fd15ffae7135078c56 100644 (file)
@@ -28,7 +28,7 @@ Data members:
 #include "pycore_pymath.h"        // _PY_SHORT_FLOAT_REPR
 #include "pycore_pymem.h"         // _PyMem_SetDefaultAllocator()
 #include "pycore_pystate.h"       // _PyThreadState_GET()
-#include "pycore_structseq.h"     // _PyStructSequence_InitType()
+#include "pycore_structseq.h"     // _PyStructSequence_InitBuiltinWithFlags()
 #include "pycore_tuple.h"         // _PyTuple_FromArray()
 
 #include "frameobject.h"          // PyFrame_FastToLocalsWithError()
@@ -2921,7 +2921,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
     SET_SYS("int_info", PyLong_GetInfo());
     /* initialize hash_info */
     if (Hash_InfoType.tp_name == NULL) {
-        if (PyStructSequence_InitType2(&Hash_InfoType, &hash_info_desc) < 0) {
+        if (_PyStructSequence_InitBuiltin(&Hash_InfoType, &hash_info_desc) < 0) {
             goto type_init_failed;
         }
     }
@@ -2943,14 +2943,18 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
     SET_SYS_FROM_STRING("abiflags", ABIFLAGS);
 #endif
 
+#define ENSURE_INFO_TYPE(TYPE, DESC) \
+    do { \
+        if (TYPE.tp_name == NULL) { \
+            if (_PyStructSequence_InitBuiltinWithFlags( \
+                    &TYPE, &DESC, Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) { \
+                goto type_init_failed; \
+            } \
+        } \
+    } while (0)
+
     /* version_info */
-    if (VersionInfoType.tp_name == NULL) {
-        if (_PyStructSequence_InitType(&VersionInfoType,
-                                       &version_info_desc,
-                                       Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
-            goto type_init_failed;
-        }
-    }
+    ENSURE_INFO_TYPE(VersionInfoType, version_info_desc);
     version_info = make_version_info(tstate);
     SET_SYS("version_info", version_info);
 
@@ -2958,27 +2962,18 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
     SET_SYS("implementation", make_impl_info(version_info));
 
     // sys.flags: updated in-place later by _PySys_UpdateConfig()
-    if (FlagsType.tp_name == 0) {
-        if (_PyStructSequence_InitType(&FlagsType, &flags_desc,
-                                       Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
-            goto type_init_failed;
-        }
-    }
+    ENSURE_INFO_TYPE(FlagsType, flags_desc);
     SET_SYS("flags", make_flags(tstate->interp));
 
 #if defined(MS_WINDOWS)
     /* getwindowsversion */
-    if (WindowsVersionType.tp_name == 0) {
-        if (_PyStructSequence_InitType(&WindowsVersionType,
-                                       &windows_version_desc,
-                                       Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
-            goto type_init_failed;
-        }
-    }
+    ENSURE_INFO_TYPE(WindowsVersionType, windows_version_desc);
 
     SET_SYS_FROM_STRING("_vpath", VPATH);
 #endif
 
+#undef ENSURE_INFO_TYPE
+
     /* float repr style: 0.03 (short) vs 0.029999999999999999 (legacy) */
 #if _PY_SHORT_FLOAT_REPR == 1
     SET_SYS_FROM_STRING("float_repr_style", "short");
@@ -2990,7 +2985,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
 
     /* initialize asyncgen_hooks */
     if (AsyncGenHooksType.tp_name == NULL) {
-        if (PyStructSequence_InitType2(
+        if (_PyStructSequence_InitBuiltin(
                 &AsyncGenHooksType, &asyncgen_hooks_desc) < 0) {
             goto type_init_failed;
         }
index 846f02545271cf7e3e12bfa36a58af7d469ca214..d3211219dffe6ab895ec47325e2b3ade6ff06cb9 100644 (file)
@@ -155,7 +155,8 @@ PyThread_GetInfo(void)
 #endif
 
     if (ThreadInfoType.tp_name == 0) {
-        if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) < 0)
+        if (_PyStructSequence_InitBuiltin(&ThreadInfoType,
+                                          &threadinfo_desc) < 0)
             return NULL;
     }