Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Merged
12 changes: 12 additions & 0 deletions Include/internal/pycore_global_objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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) \
Expand Down Expand Up @@ -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) \
Expand Down
8 changes: 8 additions & 0 deletions Include/internal/pycore_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions Include/internal/pycore_runtime_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, \
Expand Down
9 changes: 9 additions & 0 deletions Include/internal/pycore_typeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
45 changes: 20 additions & 25 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -5864,6 +5863,7 @@ object___reduce_ex___impl(PyObject *self, int protocol)
}

return _common_reduce(self, protocol);
#undef objreduce
}

static PyObject *
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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, ""),
Expand Down Expand Up @@ -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 **
Expand All @@ -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) {
Expand All @@ -8842,6 +8835,8 @@ resolve_slotdups(PyTypeObject *type, PyObject *name)
res = ptr;
}
return res;
#undef pname
#undef ptrs
}


Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand All @@ -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));
Expand Down Expand Up @@ -9065,15 +9060,15 @@ 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);
}
}

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);
Expand Down Expand Up @@ -9244,7 +9239,7 @@ static int
add_operators(PyTypeObject *type)
{
PyObject *dict = type->tp_dict;
slotdef *p;
pytype_slotdef *p;
PyObject *descr;
void **ptr;

Expand Down
4 changes: 4 additions & 0 deletions Parser/asdl_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions Python/Python-ast.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Python/ast_unparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down
31 changes: 2 additions & 29 deletions Tools/c-analyzer/cpython/globals-to-fix.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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 -
Expand Down Expand Up @@ -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 -


##################################
Expand All @@ -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 -
Expand All @@ -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 -


##################################
Expand Down
3 changes: 3 additions & 0 deletions Tools/c-analyzer/cpython/ignored.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -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 -
Expand Down Expand Up @@ -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 -
Expand Down