summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2022-11-14 20:50:56 (GMT)
committerGitHub <noreply@github.com>2022-11-14 20:50:56 (GMT)
commita088290f9d53a6bd078de6ee67b2fa296fc1cc14 (patch)
treecd464c7ed31b1fd4ea145eaa8cb073a7fac70985
parent619cadcda6a8ba4a038c1807b6566a90e25db934 (diff)
downloadcpython-a088290f9d53a6bd078de6ee67b2fa296fc1cc14.zip
cpython-a088290f9d53a6bd078de6ee67b2fa296fc1cc14.tar.gz
cpython-a088290f9d53a6bd078de6ee67b2fa296fc1cc14.tar.bz2
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
-rw-r--r--Include/internal/pycore_global_objects.h12
-rw-r--r--Include/internal/pycore_runtime.h8
-rw-r--r--Include/internal/pycore_runtime_init.h3
-rw-r--r--Include/internal/pycore_typeobject.h9
-rw-r--r--Objects/typeobject.c45
-rwxr-xr-xParser/asdl_c.py4
-rw-r--r--Python/Python-ast.c4
-rw-r--r--Python/ast_unparse.c2
-rw-r--r--Tools/c-analyzer/cpython/globals-to-fix.tsv31
-rw-r--r--Tools/c-analyzer/cpython/ignored.tsv3
10 files changed, 66 insertions, 55 deletions
diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h
index 3561f68..5ad1f7d 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 a549068..6bcb35b 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 38c1747..9a2aad2 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 5e7aca1..71f3068 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 076f447..675d6d8 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 972d896..8bdd253 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 b57aca3..31c38e8 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 6565b6b..79b2e2f 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 ad4e0ae..aaae1e8 100644
--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv
+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv
@@ -299,15 +299,6 @@ 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
# initialized once
@@ -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 e657fa7..414e68d 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 -