]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-81057: Move Global Variables Holding Objects to _PyRuntimeState. (gh-99487)
authorEric Snow <ericsnowcurrently@gmail.com>
Mon, 14 Nov 2022 20:50:56 +0000 (13:50 -0700)
committerGitHub <noreply@github.com>
Mon, 14 Nov 2022 20:50:56 +0000 (13:50 -0700)
This moves nearly all remaining object-holding globals in core code (other than static types).

https://github.com/python/cpython/issues/81057

Include/internal/pycore_global_objects.h
Include/internal/pycore_runtime.h
Include/internal/pycore_runtime_init.h
Include/internal/pycore_typeobject.h
Objects/typeobject.c
Parser/asdl_c.py
Python/Python-ast.c
Python/ast_unparse.c
Tools/c-analyzer/cpython/globals-to-fix.tsv
Tools/c-analyzer/cpython/ignored.tsv

index 3561f686a0de5c1f2077d3cbc493196c90cdd3c1..5ad1f7d217f7db59495f84aeae6c86bb53cc8b1a 100644 (file)
@@ -10,6 +10,7 @@ extern "C" {
 
 #include "pycore_gc.h"              // PyGC_Head
 #include "pycore_global_strings.h"  // struct _Py_global_strings
+#include "pycore_typeobject.h"      // pytype_slotdef
 
 
 // These would be in pycore_long.h if it weren't for an include cycle.
@@ -20,6 +21,13 @@ extern "C" {
 // Only immutable objects should be considered runtime-global.
 // All others must be per-interpreter.
 
+#define _Py_CACHED_OBJECT(NAME) \
+    _PyRuntime.cached_objects.NAME
+
+struct _Py_cached_objects {
+    PyObject *str_replace_inf;
+};
+
 #define _Py_GLOBAL_OBJECT(NAME) \
     _PyRuntime.global_objects.NAME
 #define _Py_SINGLETON(NAME) \
@@ -54,6 +62,10 @@ struct _Py_global_objects {
 
 struct _Py_interp_cached_objects {
     int _not_set;
+    /* object.__reduce__ */
+    PyObject *objreduce;
+    PyObject *type_slots_pname;
+    pytype_slotdef *type_slots_ptrs[MAX_EQUIV];
 };
 
 #define _Py_INTERP_STATIC_OBJECT(interp, NAME) \
index a54906841edc865f19e26f340551b106218b095f..6bcb35b35610f0acb1c79e1acc66794d11c3ea65 100644 (file)
@@ -136,7 +136,15 @@ typedef struct pyruntimestate {
 
     struct _Py_unicode_runtime_ids unicode_ids;
 
+    struct {
+        /* Used to set PyTypeObject.tp_version_tag */
+        // bpo-42745: next_version_tag remains shared by all interpreters
+        // because of static types.
+        unsigned int next_version_tag;
+    } types;
+
     /* All the objects that are shared by the runtime's interpreters. */
+    struct _Py_cached_objects cached_objects;
     struct _Py_global_objects global_objects;
 
     /* The following fields are here to avoid allocation during init.
index 38c1747b016c50ad1b451db0d5108726f3a64fe0..9a2aad24b5697052204e0e5c3e899de3e27ece95 100644 (file)
@@ -36,6 +36,9 @@ extern "C" {
               until _PyInterpreterState_Enable() is called. */ \
             .next_id = -1, \
         }, \
+        .types = { \
+            .next_version_tag = 1, \
+        }, \
         .global_objects = { \
             .singletons = { \
                 .small_ints = _Py_small_ints_INIT, \
index 5e7aca1b9f5ae98c2f49c91fc394b6823f3e97cf..71f3068900da31c2ccd4bf9951fcb78e74599a55 100644 (file)
@@ -18,6 +18,15 @@ extern void _PyTypes_Fini(PyInterpreterState *);
 
 /* other API */
 
+/* Length of array of slotdef pointers used to store slots with the
+   same __name__.  There should be at most MAX_EQUIV-1 slotdef entries with
+   the same __name__, for any __name__. Since that's a static property, it is
+   appropriate to declare fixed-size arrays for this. */
+#define MAX_EQUIV 10
+
+typedef struct wrapperbase pytype_slotdef;
+
+
 // Type attribute lookup cache: speed up attribute and method lookups,
 // see _PyType_Lookup().
 struct type_cache_entry {
index 076f447a6acfc6722a0c1eef3f3f7b39e44f077b..675d6d874de6bd7479ef2ae2c5f9bf3ebd53c85a 100644 (file)
@@ -43,9 +43,7 @@ class object "PyObject *" "&PyBaseObject_Type"
         PyUnicode_IS_READY(name) &&                             \
         (PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE)
 
-// bpo-42745: next_version_tag remains shared by all interpreters because of static types
-// Used to set PyTypeObject.tp_version_tag
-static unsigned int next_version_tag = 1;
+#define next_version_tag (_PyRuntime.types.next_version_tag)
 
 typedef struct PySlot_Offset {
     short subslot_offset;
@@ -5828,7 +5826,8 @@ static PyObject *
 object___reduce_ex___impl(PyObject *self, int protocol)
 /*[clinic end generated code: output=2e157766f6b50094 input=f326b43fb8a4c5ff]*/
 {
-    static PyObject *objreduce;
+#define objreduce \
+    (_Py_INTERP_CACHED_OBJECT(_PyInterpreterState_Get(), objreduce))
     PyObject *reduce, *res;
 
     if (objreduce == NULL) {
@@ -5864,6 +5863,7 @@ object___reduce_ex___impl(PyObject *self, int protocol)
     }
 
     return _common_reduce(self, protocol);
+#undef objreduce
 }
 
 static PyObject *
@@ -8524,8 +8524,6 @@ __ne__ etc. all map to tp_richcompare) and one name may map to multiple slots
 an all-zero entry.
 */
 
-typedef struct wrapperbase slotdef;
-
 #undef TPSLOT
 #undef FLSLOT
 #undef AMSLOT
@@ -8574,7 +8572,7 @@ typedef struct wrapperbase slotdef;
     ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \
            #NAME "($self, value, /)\n--\n\n" DOC)
 
-static slotdef slotdefs[] = {
+static pytype_slotdef slotdefs[] = {
     TPSLOT(__getattribute__, tp_getattr, NULL, NULL, ""),
     TPSLOT(__getattr__, tp_getattr, NULL, NULL, ""),
     TPSLOT(__setattr__, tp_setattr, NULL, NULL, ""),
@@ -8799,12 +8797,6 @@ slotptr(PyTypeObject *type, int ioffset)
     return (void **)ptr;
 }
 
-/* Length of array of slotdef pointers used to store slots with the
-   same __name__.  There should be at most MAX_EQUIV-1 slotdef entries with
-   the same __name__, for any __name__. Since that's a static property, it is
-   appropriate to declare fixed-size arrays for this. */
-#define MAX_EQUIV 10
-
 /* Return a slot pointer for a given name, but ONLY if the attribute has
    exactly one slot function.  The name must be an interned string. */
 static void **
@@ -8813,9 +8805,10 @@ resolve_slotdups(PyTypeObject *type, PyObject *name)
     /* XXX Maybe this could be optimized more -- but is it worth it? */
 
     /* pname and ptrs act as a little cache */
-    static PyObject *pname;
-    static slotdef *ptrs[MAX_EQUIV];
-    slotdef *p, **pp;
+    PyInterpreterState *interp = _PyInterpreterState_Get();
+#define pname _Py_INTERP_CACHED_OBJECT(interp, type_slots_pname)
+#define ptrs _Py_INTERP_CACHED_OBJECT(interp, type_slots_ptrs)
+    pytype_slotdef *p, **pp;
     void **res, **ptr;
 
     if (pname != name) {
@@ -8842,6 +8835,8 @@ resolve_slotdups(PyTypeObject *type, PyObject *name)
         res = ptr;
     }
     return res;
+#undef pname
+#undef ptrs
 }
 
 
@@ -8899,8 +8894,8 @@ resolve_slotdups(PyTypeObject *type, PyObject *name)
  * When done, return a pointer to the next slotdef with a different offset,
  * because that's convenient for fixup_slot_dispatchers(). This function never
  * sets an exception: if an internal error happens (unlikely), it's ignored. */
-static slotdef *
-update_one_slot(PyTypeObject *type, slotdef *p)
+static pytype_slotdef *
+update_one_slot(PyTypeObject *type, pytype_slotdef *p)
 {
     PyObject *descr;
     PyWrapperDescrObject *d;
@@ -9015,7 +9010,7 @@ update_one_slot(PyTypeObject *type, slotdef *p)
 static int
 update_slots_callback(PyTypeObject *type, void *data)
 {
-    slotdef **pp = (slotdef **)data;
+    pytype_slotdef **pp = (pytype_slotdef **)data;
     for (; *pp; pp++) {
         update_one_slot(type, *pp);
     }
@@ -9026,9 +9021,9 @@ update_slots_callback(PyTypeObject *type, void *data)
 static int
 update_slot(PyTypeObject *type, PyObject *name)
 {
-    slotdef *ptrs[MAX_EQUIV];
-    slotdef *p;
-    slotdef **pp;
+    pytype_slotdef *ptrs[MAX_EQUIV];
+    pytype_slotdef *p;
+    pytype_slotdef **pp;
     int offset;
 
     assert(PyUnicode_CheckExact(name));
@@ -9065,7 +9060,7 @@ static void
 fixup_slot_dispatchers(PyTypeObject *type)
 {
     assert(!PyErr_Occurred());
-    for (slotdef *p = slotdefs; p->name; ) {
+    for (pytype_slotdef *p = slotdefs; p->name; ) {
         p = update_one_slot(type, p);
     }
 }
@@ -9073,7 +9068,7 @@ fixup_slot_dispatchers(PyTypeObject *type)
 static void
 update_all_slots(PyTypeObject* type)
 {
-    slotdef *p;
+    pytype_slotdef *p;
 
     /* Clear the VALID_VERSION flag of 'type' and all its subclasses. */
     PyType_Modified(type);
@@ -9244,7 +9239,7 @@ static int
 add_operators(PyTypeObject *type)
 {
     PyObject *dict = type->tp_dict;
-    slotdef *p;
+    pytype_slotdef *p;
     PyObject *descr;
     void **ptr;
 
index 972d89649af5fcecc5ba59e3561ed776e39dcddf..8bdd253fee5f8f00f153c1722669505b602236b4 100755 (executable)
@@ -1483,6 +1483,10 @@ def generate_ast_fini(module_state, f):
     for s in module_state:
         f.write("    Py_CLEAR(state->" + s + ');\n')
     f.write(textwrap.dedent("""
+                if (_PyInterpreterState_Get() == _PyInterpreterState_Main()) {
+                    Py_CLEAR(_Py_CACHED_OBJECT(str_replace_inf));
+                }
+
             #if !defined(NDEBUG)
                 state->initialized = -1;
             #else
index b57aca377b9914cec95375bc6940e84ccfb47fba..31c38e8a80576791b1bd84b4e50cc6f1161f99a7 100644 (file)
@@ -263,6 +263,10 @@ void _PyAST_Fini(PyInterpreterState *interp)
     Py_CLEAR(state->vararg);
     Py_CLEAR(state->withitem_type);
 
+    if (_PyInterpreterState_Get() == _PyInterpreterState_Main()) {
+        Py_CLEAR(_Py_CACHED_OBJECT(str_replace_inf));
+    }
+
 #if !defined(NDEBUG)
     state->initialized = -1;
 #else
index 6565b6b33ebd52edd92f7a3208797aec52d5068c..79b2e2f15ba243e46ad73145989fe79bded4e2ab 100644 (file)
@@ -13,7 +13,7 @@ _Py_DECLARE_STR(open_br, "{");
 _Py_DECLARE_STR(dbl_open_br, "{{");
 _Py_DECLARE_STR(close_br, "}");
 _Py_DECLARE_STR(dbl_close_br, "}}");
-static PyObject *_str_replace_inf;
+#define _str_replace_inf _Py_CACHED_OBJECT(str_replace_inf)
 
 /* Forward declarations for recursion via helper functions. */
 static PyObject *
index ad4e0aebc6d18cb7ce0ab07e920a5f40aafb4f35..aaae1e851480ebe72fca1e415c660bf83baa44f4 100644 (file)
@@ -298,15 +298,6 @@ Objects/setobject.c        -       _dummy_struct   -
 Objects/setobject.c    -       _PySet_Dummy    -
 Objects/sliceobject.c  -       _Py_EllipsisObject      -
 
-#-----------------------
-# cached - initialized once
-
-# manually cached PyUnicodeObject
-Python/ast_unparse.c   -       _str_replace_inf        -
-
-# other
-Objects/typeobject.c   object___reduce_ex___impl       objreduce       -
-
 #-----------------------
 # other
 
@@ -315,9 +306,6 @@ Python/context.c    -       _token_missing  -
 Python/hamt.c  -       _empty_bitmap_node      -
 Python/hamt.c  -       _empty_hamt     -
 
-# state
-Objects/typeobject.c   resolve_slotdups        pname   -
-
 
 ##################################
 # global non-objects to fix in core code
@@ -438,8 +426,6 @@ Python/perf_trampoline.c    -       perf_status     -
 Python/perf_trampoline.c       -       extra_code_index        -
 Python/perf_trampoline.c       -       code_arena      -
 Python/perf_trampoline.c       -       trampoline_api  -
-Objects/typeobject.c   -       next_version_tag        -
-Objects/typeobject.c   resolve_slotdups        ptrs    -
 Parser/pegen.c -       memo_statistics -
 Python/bootstrap_hash.c        -       urandom_cache   -
 Python/ceval_gil.c     make_pending_calls      busy    -
@@ -513,27 +499,12 @@ Modules/itertoolsmodule.c -       ziplongest_type -
 #-----------------------
 # other
 
-# statically initializd pointer to static type
-# XXX should be const?
-Modules/_io/winconsoleio.c     -       _PyWindowsConsoleIO_Type        -
-
-# initialized once
-Modules/_functoolsmodule.c     -       kwd_mark        -
-Modules/_io/_iomodule.c        -       _PyIO_empty_bytes       -
-Modules/_testcapi/heaptype.c   -       _testcapimodule -
-Modules/_testcapi/unicode.c    -       _testcapimodule -
-Modules/_tracemalloc.c -       tracemalloc_empty_traceback     -
-Modules/signalmodule.c -       DefaultHandler  -
-Modules/signalmodule.c -       IgnoreHandler   -
-Modules/signalmodule.c -       IntHandler      -
-
 # state
 Modules/faulthandler.c -       fatal_error     -
 Modules/faulthandler.c -       thread  -
 Modules/faulthandler.c -       user_signals    -
 Modules/faulthandler.c -       stack   -
 Modules/faulthandler.c -       old_stack       -
-Modules/signalmodule.c -       Handlers        -
 
 
 ##################################
@@ -554,6 +525,7 @@ Modules/timemodule.c        _PyTime_GetProcessTimeWithInfo  ticks_per_second        -
 
 Modules/_tracemalloc.c -       allocators      -
 Modules/_tracemalloc.c -       tables_lock     -
+Modules/_tracemalloc.c -       tracemalloc_empty_traceback     -
 Modules/_tracemalloc.c -       tracemalloc_traced_memory       -
 Modules/_tracemalloc.c -       tracemalloc_peak_traced_memory  -
 Modules/_tracemalloc.c -       tracemalloc_filenames   -
@@ -567,6 +539,7 @@ Modules/posixmodule.c       -       environ -
 Modules/signalmodule.c -       is_tripped      -
 Modules/signalmodule.c -       signal_global_state     -
 Modules/signalmodule.c -       wakeup  -
+Modules/signalmodule.c -       Handlers        -
 
 
 ##################################
index e657fa77be0145aa042351869cbdb97784b3cd3c..414e68df60dac9e1cc35ee8dc072b4939b3ff087 100644 (file)
@@ -181,6 +181,8 @@ Modules/_testbuffer.c       ndarray_memoryview_from_buffer  strides -
 Modules/_testbuffer.c  ndarray_memoryview_from_buffer  suboffsets      -
 Modules/_testbuffer.c  ndarray_push    kwlist  -
 Modules/_testbuffer.c  staticarray_init        kwlist  -
+Modules/_testcapi/heaptype.c   -       _testcapimodule -
+Modules/_testcapi/unicode.c    -       _testcapimodule -
 Modules/_testcapimodule.c      -       ContainerNoGC_members   -
 Modules/_testcapimodule.c      -       ContainerNoGC_type      -
 Modules/_testcapimodule.c      -       FmData  -
@@ -379,6 +381,7 @@ Modules/_decimal/_decimal.c -       ssize_constants -
 Modules/_elementtree.c -       ExpatMemoryHandler      -
 Modules/_io/_iomodule.c        -       static_types    -
 Modules/_io/textio.c   -       encodefuncs     -
+Modules/_io/winconsoleio.c     -       _PyWindowsConsoleIO_Type        -
 Modules/_localemodule.c        -       langinfo_constants      -
 Modules/_pickle.c      -       READ_WHOLE_LINE -
 Modules/_sqlite/module.c       -       error_codes     -