[Python-checkins] gh-81057: Move Global Variables Holding Objects to _PyRuntimeState. (gh-99487)

ericsnowcurrently webhook-mailer at python.org
Mon Nov 14 15:51:42 EST 2022


https://github.com/python/cpython/commit/a088290f9d53a6bd078de6ee67b2fa296fc1cc14
commit: a088290f9d53a6bd078de6ee67b2fa296fc1cc14
branch: main
author: Eric Snow <ericsnowcurrently at gmail.com>
committer: ericsnowcurrently <ericsnowcurrently at gmail.com>
date: 2022-11-14T13:50:56-07:00
summary:

gh-81057: Move Global Variables Holding Objects to _PyRuntimeState. (gh-99487)

This moves nearly all remaining object-holding globals in core code (other than static types).

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

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

diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h
index 3561f686a0de..5ad1f7d217f7 100644
--- a/Include/internal/pycore_global_objects.h
+++ b/Include/internal/pycore_global_objects.h
@@ -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) \
diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h
index a54906841edc..6bcb35b35610 100644
--- a/Include/internal/pycore_runtime.h
+++ b/Include/internal/pycore_runtime.h
@@ -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.
diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h
index 38c1747b016c..9a2aad24b569 100644
--- a/Include/internal/pycore_runtime_init.h
+++ b/Include/internal/pycore_runtime_init.h
@@ -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, \
diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h
index 5e7aca1b9f5a..71f3068900da 100644
--- a/Include/internal/pycore_typeobject.h
+++ b/Include/internal/pycore_typeobject.h
@@ -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 {
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 076f447a6acf..675d6d874de6 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -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;
 
diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py
index 972d89649af5..8bdd253fee5f 100755
--- a/Parser/asdl_c.py
+++ b/Parser/asdl_c.py
@@ -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
diff --git a/Python/Python-ast.c b/Python/Python-ast.c
index b57aca377b99..31c38e8a8057 100644
--- a/Python/Python-ast.c
+++ b/Python/Python-ast.c
@@ -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
diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c
index 6565b6b33ebd..79b2e2f15ba2 100644
--- a/Python/ast_unparse.c
+++ b/Python/ast_unparse.c
@@ -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 *
diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv
index ad4e0aebc6d1..aaae1e851480 100644
--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv
+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv
@@ -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	-
 
 
 ##################################
diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv
index e657fa77be01..414e68df60da 100644
--- a/Tools/c-analyzer/cpython/ignored.tsv
+++ b/Tools/c-analyzer/cpython/ignored.tsv
@@ -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	-



More information about the Python-checkins mailing list