https://github.com/python/cpython/commit/a1aeec61c4321ba9a6966109343bd88dcf9cb26a commit: a1aeec61c4321ba9a6966109343bd88dcf9cb26a branch: main author: Mark Shannon <m...@hotpy.org> committer: markshannon <m...@hotpy.org> date: 2025-03-17T09:19:04Z summary:
GH-131238: Core header refactor (GH-131250) * Moves most structs in pycore_ header files into pycore_structs.h and pycore_runtime_structs.h * Removes many cross-header dependencies files: A Include/internal/pycore_interp_structs.h A Include/internal/pycore_runtime_structs.h A Include/internal/pycore_structs.h M Include/cpython/code.h M Include/cpython/object.h M Include/internal/pycore_atexit.h M Include/internal/pycore_backoff.h M Include/internal/pycore_ceval_state.h M Include/internal/pycore_code.h M Include/internal/pycore_codecs.h M Include/internal/pycore_context.h M Include/internal/pycore_dtoa.h M Include/internal/pycore_fileutils.h M Include/internal/pycore_floatobject.h M Include/internal/pycore_function.h M Include/internal/pycore_gc.h M Include/internal/pycore_global_objects.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_hamt.h M Include/internal/pycore_import.h M Include/internal/pycore_index_pool.h M Include/internal/pycore_instruments.h M Include/internal/pycore_interp.h M Include/internal/pycore_long.h M Include/internal/pycore_parser.h M Include/internal/pycore_pyhash.h M Include/internal/pycore_pymem.h M Include/internal/pycore_pystate.h M Include/internal/pycore_pythread.h M Include/internal/pycore_runtime.h M Include/internal/pycore_runtime_init.h M Include/internal/pycore_stackref.h M Include/internal/pycore_time.h M Include/internal/pycore_typeobject.h M Include/internal/pycore_unicodeobject.h M Include/internal/pycore_uniqueid.h M Include/internal/pycore_warnings.h M Makefile.pre.in M Modules/_codecsmodule.c M Modules/_cursesmodule.c M Modules/_tkinter.c M Objects/genobject.c M Objects/listobject.c M Objects/object.c M Objects/unicodeobject.c M Parser/pegen.c M Python/bootstrap_hash.c M Python/dtoa.c M Python/formatter_unicode.c M Python/initconfig.c M Python/instrumentation.c M Python/interpconfig.c M Python/intrinsics.c M Python/pylifecycle.c M Python/pystate.c M Python/suggestions.c M Tools/build/generate_global_objects.py diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 2bd3e08631f0ad..3f0dce03455526 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -8,25 +8,6 @@ extern "C" { #endif -/* Total tool ids available */ -#define _PY_MONITORING_TOOL_IDS 8 -/* Count of all local monitoring events */ -#define _PY_MONITORING_LOCAL_EVENTS 11 -/* Count of all "real" monitoring events (not derived from other events) */ -#define _PY_MONITORING_UNGROUPED_EVENTS 16 -/* Count of all monitoring events */ -#define _PY_MONITORING_EVENTS 19 - -/* Tables of which tools are active for each monitored event. */ -typedef struct _Py_LocalMonitors { - uint8_t tools[_PY_MONITORING_LOCAL_EVENTS]; -} _Py_LocalMonitors; - -typedef struct _Py_GlobalMonitors { - uint8_t tools[_PY_MONITORING_UNGROUPED_EVENTS]; -} _Py_GlobalMonitors; - - typedef struct { PyObject *_co_code; PyObject *_co_varnames; @@ -34,44 +15,12 @@ typedef struct { PyObject *_co_freevars; } _PyCoCached; -/* Ancillary data structure used for instrumentation. - Line instrumentation creates this with sufficient - space for one entry per code unit. The total size - of the data will be `bytes_per_entry * Py_SIZE(code)` */ -typedef struct { - uint8_t bytes_per_entry; - uint8_t data[1]; -} _PyCoLineInstrumentationData; - - typedef struct { int size; int capacity; struct _PyExecutorObject *executors[1]; } _PyExecutorArray; -/* Main data structure used for instrumentation. - * This is allocated when needed for instrumentation - */ -typedef struct { - /* Monitoring specific to this code object */ - _Py_LocalMonitors local_monitors; - /* Monitoring that is active on this code object */ - _Py_LocalMonitors active_monitors; - /* The tools that are to be notified for events for the matching code unit */ - uint8_t *tools; - /* The version of tools when they instrument the code */ - uintptr_t tool_versions[_PY_MONITORING_TOOL_IDS]; - /* Information to support line events */ - _PyCoLineInstrumentationData *lines; - /* The tools that are to be notified for line events for the matching code unit */ - uint8_t *line_tools; - /* Information to support instruction events */ - /* The underlying instructions, which can themselves be instrumented */ - uint8_t *per_instruction_opcodes; - /* The tools that are to be notified for instruction events for the matching code unit */ - uint8_t *per_instruction_tools; -} _PyCoMonitoringData; #ifdef Py_GIL_DISABLED @@ -151,7 +100,7 @@ typedef struct { _PyExecutorArray *co_executors; /* executors from optimizer */ \ _PyCoCached *_co_cached; /* cached co_* attributes */ \ uintptr_t _co_instrumentation_version; /* current instrumentation version */ \ - _PyCoMonitoringData *_co_monitoring; /* Monitoring data */ \ + struct _PyCoMonitoringData *_co_monitoring; /* Monitoring data */ \ Py_ssize_t _co_unique_id; /* ID used for per-thread refcounting */ \ int _co_firsttraceable; /* index of first traceable instruction */ \ /* Scratch space for extra data relating to the code object. \ diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 184aa63b3a5ed1..e2300aee7a207a 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -512,7 +512,6 @@ PyAPI_FUNC(int) PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void * PyAPI_FUNC(int) _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict); PyAPI_FUNC(void) PyObject_ClearManagedDict(PyObject *obj); -#define TYPE_MAX_WATCHERS 8 typedef int(*PyType_WatchCallback)(PyTypeObject *); PyAPI_FUNC(int) PyType_AddWatcher(PyType_WatchCallback callback); diff --git a/Include/internal/pycore_atexit.h b/Include/internal/pycore_atexit.h index db1e5568e09413..4d4c455cc4b24f 100644 --- a/Include/internal/pycore_atexit.h +++ b/Include/internal/pycore_atexit.h @@ -12,44 +12,6 @@ extern "C" { #endif -//############### -// runtime atexit - -typedef void (*atexit_callbackfunc)(void); - -struct _atexit_runtime_state { - PyMutex mutex; -#define NEXITFUNCS 32 - atexit_callbackfunc callbacks[NEXITFUNCS]; - int ncallbacks; -}; - - -//################### -// interpreter atexit - -typedef void (*atexit_datacallbackfunc)(void *); - -typedef struct atexit_callback { - atexit_datacallbackfunc func; - void *data; - struct atexit_callback *next; -} atexit_callback; - -struct atexit_state { -#ifdef Py_GIL_DISABLED - PyMutex ll_callbacks_lock; -#endif - atexit_callback *ll_callbacks; - - // XXX The rest of the state could be moved to the atexit module state - // and a low-level callback added for it during module exec. - // For the moment we leave it here. - - // List containing tuples with callback information. - // e.g. [(func, args, kwargs), ...] - PyObject *callbacks; -}; #ifdef Py_GIL_DISABLED # define _PyAtExit_LockCallbacks(state) PyMutex_Lock(&state->ll_callbacks_lock); diff --git a/Include/internal/pycore_backoff.h b/Include/internal/pycore_backoff.h index b5e33fa8b7abc0..6291afe9e7b4f8 100644 --- a/Include/internal/pycore_backoff.h +++ b/Include/internal/pycore_backoff.h @@ -10,14 +10,7 @@ extern "C" { #endif #include <assert.h> -#include <stdbool.h> -#include <stdint.h> - - -typedef struct { - uint16_t value_and_backoff; -} _Py_BackoffCounter; - +#include "pycore_structs.h" // _Py_BackoffCounter /* 16-bit countdown counters using exponential backoff. diff --git a/Include/internal/pycore_ceval_state.h b/Include/internal/pycore_ceval_state.h index 009a1ea41eb985..8077c8c68819e3 100644 --- a/Include/internal/pycore_ceval_state.h +++ b/Include/internal/pycore_ceval_state.h @@ -12,16 +12,6 @@ extern "C" { #include "pycore_gil.h" // struct _gil_runtime_state -typedef int (*_Py_pending_call_func)(void *); - -struct _pending_call { - _Py_pending_call_func func; - void *arg; - int flags; -}; - -#define PENDINGCALLSARRAYSIZE 300 - #define MAXPENDINGCALLS PENDINGCALLSARRAYSIZE /* For interpreter-level pending calls, we want to avoid spending too much time on pending calls in any one thread, so we apply a limit. */ @@ -40,69 +30,6 @@ struct _pending_call { pending calls for the main thread. */ #define MAXPENDINGCALLSLOOP_MAIN 0 -struct _pending_calls { - PyThreadState *handling_thread; - PyMutex mutex; - /* Request for running pending calls. */ - int32_t npending; - /* The maximum allowed number of pending calls. - If the queue fills up to this point then _PyEval_AddPendingCall() - will return _Py_ADD_PENDING_FULL. */ - int32_t max; - /* We don't want a flood of pending calls to interrupt any one thread - for too long, so we keep a limit on the number handled per pass. - A value of 0 means there is no limit (other than the maximum - size of the list of pending calls). */ - int32_t maxloop; - struct _pending_call calls[PENDINGCALLSARRAYSIZE]; - int first; - int next; -}; - - -typedef enum { - PERF_STATUS_FAILED = -1, // Perf trampoline is in an invalid state - PERF_STATUS_NO_INIT = 0, // Perf trampoline is not initialized - PERF_STATUS_OK = 1, // Perf trampoline is ready to be executed -} perf_status_t; - -#ifdef PY_HAVE_PERF_TRAMPOLINE -struct code_arena_st; - -struct trampoline_api_st { - void* (*init_state)(void); - void (*write_state)(void* state, const void *code_addr, - unsigned int code_size, PyCodeObject* code); - int (*free_state)(void* state); - void *state; - Py_ssize_t code_padding; -}; -#endif - - -struct _ceval_runtime_state { - struct { -#ifdef PY_HAVE_PERF_TRAMPOLINE - perf_status_t status; - int perf_trampoline_type; - Py_ssize_t extra_code_index; - struct code_arena_st *code_arena; - struct trampoline_api_st trampoline_api; - FILE *map_file; - Py_ssize_t persist_after_fork; -#else - int _not_used; -#endif - } perf; - /* Pending calls to be made only on the main thread. */ - // The signal machinery falls back on this - // so it must be especially stable and efficient. - // For example, we use a preallocated array - // for the list of pending calls. - struct _pending_calls pending_mainthread; - PyMutex sys_trace_profile_mutex; -}; - #ifdef PY_HAVE_PERF_TRAMPOLINE # define _PyEval_RUNTIME_PERF_INIT \ @@ -116,18 +43,6 @@ struct _ceval_runtime_state { #endif -struct _ceval_state { - /* This variable holds the global instrumentation version. When a thread is - running, this value is overlaid onto PyThreadState.eval_breaker so that - changes in the instrumentation version will trigger the eval breaker. */ - uintptr_t instrumentation_version; - int recursion_limit; - struct _gil_runtime_state *gil; - int own_gil; - struct _pending_calls pending; -}; - - #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index c3edbb3dffe79b..530eaf80e08c63 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -8,30 +8,13 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_structs.h" // _Py_CODEUNIT #include "pycore_stackref.h" // _PyStackRef #include "pycore_lock.h" // PyMutex #include "pycore_backoff.h" // _Py_BackoffCounter #include "pycore_tstate.h" // _PyThreadStateImpl -/* Each instruction in a code object is a fixed-width value, - * currently 2 bytes: 1-byte opcode + 1-byte oparg. The EXTENDED_ARG - * opcode allows for larger values but the current limit is 3 uses - * of EXTENDED_ARG (see Python/compile.c), for a maximum - * 32-bit value. This aligns with the note in Python/compile.c - * (compiler_addop_i_line) indicating that the max oparg value is - * 2**32 - 1, rather than INT_MAX. - */ - -typedef union { - uint16_t cache; - struct { - uint8_t code; - uint8_t arg; - } op; - _Py_BackoffCounter counter; // First cache entry of specializable op -} _Py_CODEUNIT; - #define _PyCode_CODE(CO) _Py_RVALUE((_Py_CODEUNIT *)(CO)->co_code_adaptive) #define _PyCode_NBYTES(CO) (Py_SIZE(CO) * (Py_ssize_t)sizeof(_Py_CODEUNIT)) @@ -67,16 +50,10 @@ _py_set_opcode(_Py_CODEUNIT *word, uint8_t opcode) #define _PyCode_HAS_INSTRUMENTATION(CODE) \ (CODE->_co_instrumentation_version > 0) -struct _py_code_state { - PyMutex mutex; - // Interned constants from code objects. Used by the free-threaded build. - struct _Py_hashtable_t *constants; -}; extern PyStatus _PyCode_Init(PyInterpreterState *interp); extern void _PyCode_Fini(PyInterpreterState *interp); -#define CODE_MAX_WATCHERS 8 /* PEP 659 * Specialization and quickening structs and helper functions @@ -185,14 +162,6 @@ typedef struct { #define INLINE_CACHE_ENTRIES_CONTAINS_OP CACHE_ENTRIES(_PyContainsOpCache) -// Borrowed references to common callables: -struct callable_cache { - PyObject *isinstance; - PyObject *len; - PyObject *list_append; - PyObject *object__getattribute__; -}; - /* "Locals plus" for a code object is the set of locals + cell vars + * free vars. This relates to variable names as well as offsets into * the "fast locals" storage array of execution frames. The compiler diff --git a/Include/internal/pycore_codecs.h b/Include/internal/pycore_codecs.h index 4400be8b33dee7..7c44a449270202 100644 --- a/Include/internal/pycore_codecs.h +++ b/Include/internal/pycore_codecs.h @@ -9,6 +9,7 @@ extern "C" { #endif #include "pycore_lock.h" // PyMutex +#include "pycore_runtime_structs.h" // struct codecs_state /* Initialize codecs-related state for the given interpreter, including registering the first codec search function. Must be called before any other @@ -70,27 +71,6 @@ extern PyObject* _PyCodecInfo_GetIncrementalEncoder( PyObject *codec_info, const char *errors); -// Per-interpreter state used by codecs.c. -struct codecs_state { - // A list of callable objects used to search for codecs. - PyObject *search_path; - - // A dict mapping codec names to codecs returned from a callable in - // search_path. - PyObject *search_cache; - - // A dict mapping error handling strategies to functions to implement them. - PyObject *error_registry; - -#ifdef Py_GIL_DISABLED - // Used to safely delete a specific item from search_path. - PyMutex search_path_mutex; -#endif - - // Whether or not the rest of the state is initialized. - int initialized; -}; - #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_context.h b/Include/internal/pycore_context.h index c2b98d15da68fa..c77ef7910c09aa 100644 --- a/Include/internal/pycore_context.h +++ b/Include/internal/pycore_context.h @@ -5,9 +5,7 @@ # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_hamt.h" // PyHamtObject - -#define CONTEXT_MAX_WATCHERS 8 +#include "pycore_structs.h" extern PyTypeObject _PyContextTokenMissing_Type; diff --git a/Include/internal/pycore_dtoa.h b/Include/internal/pycore_dtoa.h index e4222c5267d6be..2e2e990a7e2d38 100644 --- a/Include/internal/pycore_dtoa.h +++ b/Include/internal/pycore_dtoa.h @@ -11,53 +11,18 @@ extern "C" { #include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR -typedef uint32_t ULong; - -struct -Bigint { - struct Bigint *next; - int k, maxwds, sign, wds; - ULong x[1]; -}; - #if defined(Py_USING_MEMORY_DEBUGGER) || _PY_SHORT_FLOAT_REPR == 0 -struct _dtoa_state { - int _not_used; -}; #define _dtoa_state_INIT(INTERP) \ {0} -#else // !Py_USING_MEMORY_DEBUGGER && _PY_SHORT_FLOAT_REPR != 0 - -/* The size of the Bigint freelist */ -#define Bigint_Kmax 7 +#else -/* The size of the cached powers of 5 array */ -#define Bigint_Pow5size 8 - -#ifndef PRIVATE_MEM -#define PRIVATE_MEM 2304 -#endif -#define Bigint_PREALLOC_SIZE \ - ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) - -struct _dtoa_state { - // p5s is an array of powers of 5 of the form: - // 5**(2**(i+2)) for 0 <= i < Bigint_Pow5size - struct Bigint *p5s[Bigint_Pow5size]; - // XXX This should be freed during runtime fini. - struct Bigint *freelist[Bigint_Kmax+1]; - double preallocated[Bigint_PREALLOC_SIZE]; - double *preallocated_next; -}; #define _dtoa_state_INIT(INTERP) \ { \ .preallocated_next = (INTERP)->dtoa.preallocated, \ } - -#endif // !Py_USING_MEMORY_DEBUGGER - +#endif extern double _Py_dg_strtod(const char *str, char **ptr); extern char* _Py_dg_dtoa(double d, int mode, int ndigits, diff --git a/Include/internal/pycore_fileutils.h b/Include/internal/pycore_fileutils.h index 13f86b01bbfe8f..1ef23588d85527 100644 --- a/Include/internal/pycore_fileutils.h +++ b/Include/internal/pycore_fileutils.h @@ -9,6 +9,7 @@ extern "C" { #endif #include <locale.h> // struct lconv +#include "pycore_runtime_structs.h" // _Py_error_handler /* A routine to check if a file descriptor can be select()-ed. */ @@ -19,22 +20,6 @@ extern "C" { #define _PyIsSelectable_fd(FD) ((unsigned int)(FD) < (unsigned int)FD_SETSIZE) #endif -struct _fileutils_state { - int force_ascii; -}; - -typedef enum { - _Py_ERROR_UNKNOWN=0, - _Py_ERROR_STRICT, - _Py_ERROR_SURROGATEESCAPE, - _Py_ERROR_REPLACE, - _Py_ERROR_IGNORE, - _Py_ERROR_BACKSLASHREPLACE, - _Py_ERROR_SURROGATEPASS, - _Py_ERROR_XMLCHARREFREPLACE, - _Py_ERROR_OTHER -} _Py_error_handler; - // Export for '_testinternalcapi' shared extension PyAPI_FUNC(_Py_error_handler) _Py_GetErrorHandler(const char *errors); diff --git a/Include/internal/pycore_floatobject.h b/Include/internal/pycore_floatobject.h index f44b081b06cea5..317f984188bad8 100644 --- a/Include/internal/pycore_floatobject.h +++ b/Include/internal/pycore_floatobject.h @@ -17,20 +17,6 @@ extern PyStatus _PyFloat_InitTypes(PyInterpreterState *); extern void _PyFloat_FiniType(PyInterpreterState *); -/* other API */ - -enum _py_float_format_type { - _py_float_format_unknown, - _py_float_format_ieee_big_endian, - _py_float_format_ieee_little_endian, -}; - -struct _Py_float_runtime_state { - enum _py_float_format_type float_format; - enum _py_float_format_type double_format; -}; - - PyAPI_FUNC(void) _PyFloat_ExactDealloc(PyObject *op); diff --git a/Include/internal/pycore_function.h b/Include/internal/pycore_function.h index c45d281125febb..8fa040fec3bf03 100644 --- a/Include/internal/pycore_function.h +++ b/Include/internal/pycore_function.h @@ -16,33 +16,11 @@ extern PyObject* _PyFunction_Vectorcall( size_t nargsf, PyObject *kwnames); -#define FUNC_MAX_WATCHERS 8 #define FUNC_VERSION_UNSET 0 #define FUNC_VERSION_CLEARED 1 #define FUNC_VERSION_FIRST_VALID 2 -#define FUNC_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */ - -struct _func_version_cache_item { - PyFunctionObject *func; - PyObject *code; -}; - -struct _py_func_state { -#ifdef Py_GIL_DISABLED - // Protects next_version - PyMutex mutex; -#endif - - uint32_t next_version; - // Borrowed references to function and code objects whose - // func_version % FUNC_VERSION_CACHE_SIZE - // once was equal to the index in the table. - // They are cleared when the function or code object is deallocated. - struct _func_version_cache_item func_version_cache[FUNC_VERSION_CACHE_SIZE]; -}; - extern PyFunctionObject* _PyFunction_FromConstructor(PyFrameConstructor *constr); static inline int diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index b1806df2706097..17125131183ed1 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -8,18 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -/* GC information is stored BEFORE the object structure. */ -typedef struct { - // Tagged pointer to next object in the list. - // 0 means the object is not tracked - uintptr_t _gc_next; - - // Tagged pointer to previous object in the list. - // Lowest two bits are used for flags documented later. - uintptr_t _gc_prev; -} PyGC_Head; - -#define _PyGC_Head_UNUSED PyGC_Head +#include "pycore_runtime_structs.h" /* Get an object's GC head */ @@ -214,12 +203,6 @@ static inline void _PyGC_CLEAR_FINALIZED(PyObject *op) { #endif } - -/* GC runtime state */ - -/* If we change this, we need to change the default value in the - signature of gc.collect. */ -#define NUM_GENERATIONS 3 /* NOTE: about untracking of mutable objects. @@ -261,90 +244,6 @@ static inline void _PyGC_CLEAR_FINALIZED(PyObject *op) { the algorithm was refined in response to issue #14775. */ -struct gc_generation { - PyGC_Head head; - int threshold; /* collection threshold */ - int count; /* count of allocations or collections of younger - generations */ -}; - -struct gc_collection_stats { - /* number of collected objects */ - Py_ssize_t collected; - /* total number of uncollectable objects (put into gc.garbage) */ - Py_ssize_t uncollectable; -}; - -/* Running stats per generation */ -struct gc_generation_stats { - /* total number of collections */ - Py_ssize_t collections; - /* total number of collected objects */ - Py_ssize_t collected; - /* total number of uncollectable objects (put into gc.garbage) */ - Py_ssize_t uncollectable; -}; - -enum _GCPhase { - GC_PHASE_MARK = 0, - GC_PHASE_COLLECT = 1 -}; - -struct _gc_runtime_state { - /* List of objects that still need to be cleaned up, singly linked - * via their gc headers' gc_prev pointers. */ - PyObject *trash_delete_later; - /* Current call-stack depth of tp_dealloc calls. */ - int trash_delete_nesting; - - /* Is automatic collection enabled? */ - int enabled; - int debug; - /* linked lists of container objects */ - struct gc_generation young; - struct gc_generation old[2]; - /* a permanent generation which won't be collected */ - struct gc_generation permanent_generation; - struct gc_generation_stats generation_stats[NUM_GENERATIONS]; - /* true if we are currently running the collector */ - int collecting; - /* list of uncollectable objects */ - PyObject *garbage; - /* a list of callbacks to be invoked when collection is performed */ - PyObject *callbacks; - - Py_ssize_t heap_size; - Py_ssize_t work_to_do; - /* Which of the old spaces is the visited space */ - int visited_space; - int phase; - -#ifdef Py_GIL_DISABLED - /* This is the number of objects that survived the last full - collection. It approximates the number of long lived objects - tracked by the GC. - - (by "full collection", we mean a collection of the oldest - generation). */ - Py_ssize_t long_lived_total; - /* This is the number of objects that survived all "non-full" - collections, and are awaiting to undergo a full collection for - the first time. */ - Py_ssize_t long_lived_pending; - - /* True if gc.freeze() has been used. */ - int freeze_active; -#endif -}; - -#ifdef Py_GIL_DISABLED -struct _gc_thread_state { - /* Thread-local allocation count. */ - Py_ssize_t alloc_count; -}; -#endif - - extern void _PyGC_InitState(struct _gc_runtime_state *); extern Py_ssize_t _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason); diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h index 611f01d1c32710..13251d4676be7d 100644 --- a/Include/internal/pycore_global_objects.h +++ b/Include/internal/pycore_global_objects.h @@ -8,18 +8,6 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_context.h" // _PyContextTokenMissing -#include "pycore_gc.h" // _PyGC_Head_UNUSED -#include "pycore_global_strings.h" // struct _Py_global_strings -#include "pycore_hamt.h" // PyHamtNode_Bitmap -#include "pycore_hashtable.h" // _Py_hashtable_t -#include "pycore_typeobject.h" // pytype_slotdef - - -// These would be in pycore_long.h if it weren't for an include cycle. -#define _PY_NSMALLPOSINTS 257 -#define _PY_NSMALLNEGINTS 5 - // Only immutable objects should be considered runtime-global. // All others must be per-interpreter. @@ -29,76 +17,16 @@ extern "C" { #define _Py_SINGLETON(NAME) \ _Py_GLOBAL_OBJECT(singletons.NAME) -struct _Py_cached_objects { - // XXX We could statically allocate the hashtable. - _Py_hashtable_t *interned_strings; -}; - -struct _Py_static_objects { - struct { - /* Small integers are preallocated in this array so that they - * can be shared. - * The integers that are preallocated are those in the range - * -_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (exclusive). - */ - PyLongObject small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS]; - - PyBytesObject bytes_empty; - struct { - PyBytesObject ob; - char eos; - } bytes_characters[256]; - - struct _Py_global_strings strings; - - _PyGC_Head_UNUSED _tuple_empty_gc_not_used; - PyTupleObject tuple_empty; - - _PyGC_Head_UNUSED _hamt_bitmap_node_empty_gc_not_used; - PyHamtNode_Bitmap hamt_bitmap_node_empty; - _PyContextTokenMissing context_token_missing; - } singletons; -}; #define _Py_INTERP_CACHED_OBJECT(interp, NAME) \ (interp)->cached_objects.NAME -struct _Py_interp_cached_objects { -#ifdef Py_GIL_DISABLED - PyMutex interned_mutex; -#endif - PyObject *interned_strings; - - /* object.__reduce__ */ - PyObject *objreduce; - PyObject *type_slots_pname; - pytype_slotdef *type_slots_ptrs[MAX_EQUIV]; - - /* TypeVar and related types */ - PyTypeObject *generic_type; - PyTypeObject *typevar_type; - PyTypeObject *typevartuple_type; - PyTypeObject *paramspec_type; - PyTypeObject *paramspecargs_type; - PyTypeObject *paramspeckwargs_type; - PyTypeObject *constevaluator_type; -}; #define _Py_INTERP_STATIC_OBJECT(interp, NAME) \ (interp)->static_objects.NAME #define _Py_INTERP_SINGLETON(interp, NAME) \ _Py_INTERP_STATIC_OBJECT(interp, singletons.NAME) -struct _Py_interp_static_objects { - struct { - int _not_used; - // hamt_empty is here instead of global because of its weakreflist. - _PyGC_Head_UNUSED _hamt_empty_gc_not_used; - PyHamtObject hamt_empty; - PyBaseExceptionObject last_resort_memory_error; - } singletons; -}; - #ifdef __cplusplus } diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 97a75d0c46c867..5056128dc97ca0 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -8,6 +8,8 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_global_objects.h" // struct _Py_SINGLETON + // The data structure & init here are inspired by Tools/build/deepfreeze.py. // All field names generated by ASCII_STR() have a common prefix, diff --git a/Include/internal/pycore_hamt.h b/Include/internal/pycore_hamt.h index d8742c7cb63578..f973ce6dcb20e0 100644 --- a/Include/internal/pycore_hamt.h +++ b/Include/internal/pycore_hamt.h @@ -5,6 +5,7 @@ # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_structs.h" // PyHamtNode /* HAMT tree is shaped by hashes of keys. Every group of 5 bits of a hash denotes @@ -34,28 +35,6 @@ extern PyTypeObject _PyHamtItems_Type; #define PyHamt_Check(o) Py_IS_TYPE((o), &_PyHamt_Type) -/* Abstract tree node. */ -typedef struct { - PyObject_HEAD -} PyHamtNode; - - -/* An HAMT immutable mapping collection. */ -typedef struct { - PyObject_HEAD - PyHamtNode *h_root; - PyObject *h_weakreflist; - Py_ssize_t h_count; -} PyHamtObject; - - -typedef struct { - PyObject_VAR_HEAD - uint32_t b_bitmap; - PyObject *b_array[1]; -} PyHamtNode_Bitmap; - - /* A struct to hold the state of depth-first traverse of the tree. HAMT is an immutable collection. Iterators will hold a strong reference diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index 5fe60df0a92fbc..2b68228f8c6470 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -10,6 +10,7 @@ extern "C" { #endif #include "pycore_lock.h" // PyMutex +#include "pycore_runtime_structs.h" // _import_state #include "pycore_hashtable.h" // _Py_hashtable_t extern int _PyImport_IsInitialized(PyInterpreterState *); @@ -31,73 +32,6 @@ extern int _PyImport_FixupBuiltin( PyObject *modules ); - -struct _import_runtime_state { - /* The builtin modules (defined in config.c). */ - struct _inittab *inittab; - /* The most recent value assigned to a PyModuleDef.m_base.m_index. - This is incremented each time PyModuleDef_Init() is called, - which is just about every time an extension module is imported. - See PyInterpreterState.modules_by_index for more info. */ - Py_ssize_t last_module_index; - struct { - /* A lock to guard the cache. */ - PyMutex mutex; - /* The actual cache of (filename, name, PyModuleDef) for modules. - Only legacy (single-phase init) extension modules are added - and only if they support multiple initialization (m_size >= 0) - or are imported in the main interpreter. - This is initialized lazily in fix_up_extension() in import.c. - Modules are added there and looked up in _imp.find_extension(). */ - _Py_hashtable_t *hashtable; - } extensions; - /* Package context -- the full module name for package imports */ - const char * pkgcontext; -}; - -struct _import_state { - /* cached sys.modules dictionary */ - PyObject *modules; - /* This is the list of module objects for all legacy (single-phase init) - extension modules ever loaded in this process (i.e. imported - in this interpreter or in any other). Py_None stands in for - modules that haven't actually been imported in this interpreter. - - A module's index (PyModuleDef.m_base.m_index) is used to look up - the corresponding module object for this interpreter, if any. - (See PyState_FindModule().) When any extension module - is initialized during import, its moduledef gets initialized by - PyModuleDef_Init(), and the first time that happens for each - PyModuleDef, its index gets set to the current value of - a global counter (see _PyRuntimeState.imports.last_module_index). - The entry for that index in this interpreter remains unset until - the module is actually imported here. (Py_None is used as - a placeholder.) Note that multi-phase init modules always get - an index for which there will never be a module set. - - This is initialized lazily in PyState_AddModule(), which is also - where modules get added. */ - PyObject *modules_by_index; - /* importlib module._bootstrap */ - PyObject *importlib; - /* override for config->use_frozen_modules (for tests) - (-1: "off", 1: "on", 0: no override) */ - int override_frozen_modules; - int override_multi_interp_extensions_check; -#ifdef HAVE_DLOPEN - int dlopenflags; -#endif - PyObject *import_func; - /* The global import lock. */ - _PyRecursiveMutex lock; - /* diagnostic info in PyImport_ImportModuleLevelObject() */ - struct { - int import_level; - PyTime_t accumulated; - int header; - } find_and_load; -}; - #ifdef HAVE_DLOPEN # include <dlfcn.h> // RTLD_NOW, RTLD_LAZY # if HAVE_DECL_RTLD_NOW diff --git a/Include/internal/pycore_index_pool.h b/Include/internal/pycore_index_pool.h index e81bfd4d6ed03d..2ce06be48c5379 100644 --- a/Include/internal/pycore_index_pool.h +++ b/Include/internal/pycore_index_pool.h @@ -13,32 +13,12 @@ extern "C" { #ifdef Py_GIL_DISABLED +#include "pycore_interp_structs.h" + // This contains code for allocating unique indices in an array. It is used by // the free-threaded build to assign each thread a globally unique index into // each code object's thread-local bytecode array. -// A min-heap of indices -typedef struct _PyIndexHeap { - int32_t *values; - - // Number of items stored in values - Py_ssize_t size; - - // Maximum number of items that can be stored in values - Py_ssize_t capacity; -} _PyIndexHeap; - -// An unbounded pool of indices. Indices are allocated starting from 0. They -// may be released back to the pool once they are no longer in use. -typedef struct _PyIndexPool { - PyMutex mutex; - - // Min heap of indices available for allocation - _PyIndexHeap free_indices; - - // Next index to allocate if no free indices are available - int32_t next_index; -} _PyIndexPool; // Allocate the smallest available index. Returns -1 on error. extern int32_t _PyIndexPool_AllocIndex(_PyIndexPool *indices); diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h index 92d8f056f402fc..0e85f97073dd67 100644 --- a/Include/internal/pycore_instruments.h +++ b/Include/internal/pycore_instruments.h @@ -5,14 +5,12 @@ # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_frame.h" // _PyInterpreterFrame +#include "pycore_structs.h" // _Py_CODEUNIT #ifdef __cplusplus extern "C" { #endif -#define PY_MONITORING_TOOL_IDS 8 - typedef uint32_t _PyMonitoringEventSet; /* Tool IDs */ @@ -36,32 +34,32 @@ int _PyMonitoring_GetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringE extern int _Py_call_instrumentation(PyThreadState *tstate, int event, - _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); + struct _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); extern int -_Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, +_Py_call_instrumentation_line(PyThreadState *tstate, struct _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev); extern int _Py_call_instrumentation_instruction( - PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr); + PyThreadState *tstate, struct _PyInterpreterFrame* frame, _Py_CODEUNIT *instr); _Py_CODEUNIT * _Py_call_instrumentation_jump( _Py_CODEUNIT *instr, PyThreadState *tstate, int event, - _PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest); + struct _PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest); extern int _Py_call_instrumentation_arg(PyThreadState *tstate, int event, - _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg); + struct _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg); extern int _Py_call_instrumentation_2args(PyThreadState *tstate, int event, - _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1); + struct _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1); extern void _Py_call_instrumentation_exc2(PyThreadState *tstate, int event, - _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1); + struct _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1); extern int _Py_Instrumentation_GetLine(PyCodeObject *code, int index); @@ -69,6 +67,59 @@ _Py_Instrumentation_GetLine(PyCodeObject *code, int index); extern PyObject _PyInstrumentation_MISSING; extern PyObject _PyInstrumentation_DISABLE; + +/* Total tool ids available */ +#define PY_MONITORING_TOOL_IDS 8 +/* Count of all local monitoring events */ +#define _PY_MONITORING_LOCAL_EVENTS 11 +/* Count of all "real" monitoring events (not derived from other events) */ +#define _PY_MONITORING_UNGROUPED_EVENTS 16 +/* Count of all monitoring events */ +#define _PY_MONITORING_EVENTS 19 + +/* Tables of which tools are active for each monitored event. */ +typedef struct _Py_LocalMonitors { + uint8_t tools[_PY_MONITORING_LOCAL_EVENTS]; +} _Py_LocalMonitors; + +typedef struct _Py_GlobalMonitors { + uint8_t tools[_PY_MONITORING_UNGROUPED_EVENTS]; +} _Py_GlobalMonitors; + +/* Ancillary data structure used for instrumentation. + Line instrumentation creates this with sufficient + space for one entry per code unit. The total size + of the data will be `bytes_per_entry * Py_SIZE(code)` */ +typedef struct { + uint8_t bytes_per_entry; + uint8_t data[1]; +} _PyCoLineInstrumentationData; + + +/* Main data structure used for instrumentation. + * This is allocated when needed for instrumentation + */ +typedef struct _PyCoMonitoringData { + /* Monitoring specific to this code object */ + _Py_LocalMonitors local_monitors; + /* Monitoring that is active on this code object */ + _Py_LocalMonitors active_monitors; + /* The tools that are to be notified for events for the matching code unit */ + uint8_t *tools; + /* The version of tools when they instrument the code */ + uintptr_t tool_versions[PY_MONITORING_TOOL_IDS]; + /* Information to support line events */ + _PyCoLineInstrumentationData *lines; + /* The tools that are to be notified for line events for the matching code unit */ + uint8_t *line_tools; + /* Information to support instruction events */ + /* The underlying instructions, which can themselves be instrumented */ + uint8_t *per_instruction_opcodes; + /* The tools that are to be notified for instruction events for the matching code unit */ + uint8_t *per_instruction_tools; +} _PyCoMonitoringData; + + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index c247c7270d1caa..791038d45b3775 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -10,8 +10,7 @@ extern "C" { #include <stdbool.h> // bool -#include "pycore_ast_state.h" // struct ast_state -#include "pycore_atexit.h" // struct atexit_state +#include "pycore_runtime_structs.h" #include "pycore_ceval_state.h" // struct _ceval_state #include "pycore_code.h" // struct callable_cache #include "pycore_codecs.h" // struct codecs_state @@ -43,70 +42,9 @@ extern "C" { #include "pycore_warnings.h" // struct _warnings_runtime_state -struct _Py_long_state { - int max_str_digits; -}; - -// Support for stop-the-world events. This exists in both the PyRuntime struct -// for global pauses and in each PyInterpreterState for per-interpreter pauses. -struct _stoptheworld_state { - PyMutex mutex; // Serializes stop-the-world attempts. - - // NOTE: The below fields are protected by HEAD_LOCK(runtime), not by the - // above mutex. - bool requested; // Set when a pause is requested. - bool world_stopped; // Set when the world is stopped. - bool is_global; // Set when contained in PyRuntime struct. - - PyEvent stop_event; // Set when thread_countdown reaches zero. - Py_ssize_t thread_countdown; // Number of threads that must pause. - - PyThreadState *requester; // Thread that requested the pause (may be NULL). -}; - -#ifdef Py_GIL_DISABLED -// This should be prime but otherwise the choice is arbitrary. A larger value -// increases concurrency at the expense of memory. -# define NUM_WEAKREF_LIST_LOCKS 127 -#endif - -/* cross-interpreter data registry */ - -/* Tracks some rare events per-interpreter, used by the optimizer to turn on/off - specific optimizations. */ -typedef struct _rare_events { - /* Setting an object's class, obj.__class__ = ... */ - uint8_t set_class; - /* Setting the bases of a class, cls.__bases__ = ... */ - uint8_t set_bases; - /* Setting the PEP 523 frame eval function, _PyInterpreterState_SetFrameEvalFunc() */ - uint8_t set_eval_frame_func; - /* Modifying the builtins, __builtins__.__dict__[var] = ... */ - uint8_t builtin_dict; - /* Modifying a function, e.g. func.__defaults__ = ..., etc. */ - uint8_t func_modification; -} _rare_events; /* interpreter state */ -/* PyInterpreterState holds the global state for one of the runtime's - interpreters. Typically the initial (main) interpreter is the only one. - - The PyInterpreterState typedef is in Include/pytypedefs.h. - */ -struct _is { - - /* This struct contains the eval_breaker, - * which is by far the hottest field in this struct - * and should be placed at the beginning. */ - struct _ceval_state ceval; - - PyInterpreterState *next; - - int64_t id; - Py_ssize_t id_refcount; - int requires_idref; - #define _PyInterpreterState_WHENCE_NOTSET -1 #define _PyInterpreterState_WHENCE_UNKNOWN 0 #define _PyInterpreterState_WHENCE_RUNTIME 1 @@ -115,193 +53,6 @@ struct _is { #define _PyInterpreterState_WHENCE_XI 4 #define _PyInterpreterState_WHENCE_STDLIB 5 #define _PyInterpreterState_WHENCE_MAX 5 - long _whence; - - /* Has been initialized to a safe state. - - In order to be effective, this must be set to 0 during or right - after allocation. */ - int _initialized; - /* Has been fully initialized via pylifecycle.c. */ - int _ready; - int finalizing; - - uintptr_t last_restart_version; - struct pythreads { - uint64_t next_unique_id; - /* The linked list of threads, newest first. */ - PyThreadState *head; - _PyThreadStateImpl *preallocated; - /* The thread currently executing in the __main__ module, if any. */ - PyThreadState *main; - /* Used in Modules/_threadmodule.c. */ - Py_ssize_t count; - /* Support for runtime thread stack size tuning. - A value of 0 means using the platform's default stack size - or the size specified by the THREAD_STACK_SIZE macro. */ - /* Used in Python/thread.c. */ - size_t stacksize; - } threads; - - /* Reference to the _PyRuntime global variable. This field exists - to not have to pass runtime in addition to tstate to a function. - Get runtime from tstate: tstate->interp->runtime. */ - struct pyruntimestate *runtime; - - /* Set by Py_EndInterpreter(). - - Use _PyInterpreterState_GetFinalizing() - and _PyInterpreterState_SetFinalizing() - to access it, don't access it directly. */ - PyThreadState* _finalizing; - /* The ID of the OS thread in which we are finalizing. */ - unsigned long _finalizing_id; - - struct _gc_runtime_state gc; - - /* The following fields are here to avoid allocation during init. - The data is exposed through PyInterpreterState pointer fields. - These fields should not be accessed directly outside of init. - - All other PyInterpreterState pointer fields are populated when - needed and default to NULL. - - For now there are some exceptions to that rule, which require - allocation during init. These will be addressed on a case-by-case - basis. Also see _PyRuntimeState regarding the various mutex fields. - */ - - // Dictionary of the sys module - PyObject *sysdict; - - // Dictionary of the builtins module - PyObject *builtins; - - struct _import_state imports; - - /* The per-interpreter GIL, which might not be used. */ - struct _gil_runtime_state _gil; - - /* ---------- IMPORTANT --------------------------- - The fields above this line are declared as early as - possible to facilitate out-of-process observability - tools. */ - - struct codecs_state codecs; - - PyConfig config; - unsigned long feature_flags; - - PyObject *dict; /* Stores per-interpreter state */ - - PyObject *sysdict_copy; - PyObject *builtins_copy; - // Initialized to _PyEval_EvalFrameDefault(). - _PyFrameEvalFunction eval_frame; - - PyFunction_WatchCallback func_watchers[FUNC_MAX_WATCHERS]; - // One bit is set for each non-NULL entry in func_watchers - uint8_t active_func_watchers; - - Py_ssize_t co_extra_user_count; - freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS]; - - /* cross-interpreter data and utils */ - _PyXI_state_t xi; - -#ifdef HAVE_FORK - PyObject *before_forkers; - PyObject *after_forkers_parent; - PyObject *after_forkers_child; -#endif - - struct _warnings_runtime_state warnings; - struct atexit_state atexit; - struct _stoptheworld_state stoptheworld; - struct _qsbr_shared qsbr; - -#if defined(Py_GIL_DISABLED) - struct _mimalloc_interp_state mimalloc; - struct _brc_state brc; // biased reference counting state - struct _Py_unique_id_pool unique_ids; // object ids for per-thread refcounts - PyMutex weakref_locks[NUM_WEAKREF_LIST_LOCKS]; - _PyIndexPool tlbc_indices; -#endif - // Per-interpreter list of tasks, any lingering tasks from thread - // states gets added here and removed from the corresponding - // thread state's list. - struct llist_node asyncio_tasks_head; - // `asyncio_tasks_lock` is used when tasks are moved - // from thread's list to interpreter's list. - PyMutex asyncio_tasks_lock; - - // Per-interpreter state for the obmalloc allocator. For the main - // interpreter and for all interpreters that don't have their - // own obmalloc state, this points to the static structure in - // obmalloc.c obmalloc_state_main. For other interpreters, it is - // heap allocated by _PyMem_init_obmalloc() and freed when the - // interpreter structure is freed. In the case of a heap allocated - // obmalloc state, it is not safe to hold on to or use memory after - // the interpreter is freed. The obmalloc state corresponding to - // that allocated memory is gone. See free_obmalloc_arenas() for - // more comments. - struct _obmalloc_state *obmalloc; - - PyObject *audit_hooks; - PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS]; - PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS]; - PyContext_WatchCallback context_watchers[CONTEXT_MAX_WATCHERS]; - // One bit is set for each non-NULL entry in code_watchers - uint8_t active_code_watchers; - uint8_t active_context_watchers; - - struct _py_object_state object_state; - struct _Py_unicode_state unicode; - struct _Py_long_state long_state; - struct _dtoa_state dtoa; - struct _py_func_state func_state; - struct _py_code_state code_state; - - struct _Py_dict_state dict_state; - struct _Py_exc_state exc_state; - struct _Py_mem_interp_free_queue mem_free_queue; - - struct ast_state ast; - struct types_state types; - struct callable_cache callable_cache; - bool jit; - _PyExecutorObject *executor_list_head; - size_t trace_run_counter; - _rare_events rare_events; - PyDict_WatchCallback builtins_dict_watcher; - - _Py_GlobalMonitors monitors; - bool sys_profile_initialized; - bool sys_trace_initialized; - Py_ssize_t sys_profiling_threads; /* Count of threads with c_profilefunc set */ - Py_ssize_t sys_tracing_threads; /* Count of threads with c_tracefunc set */ - PyObject *monitoring_callables[PY_MONITORING_TOOL_IDS][_PY_MONITORING_EVENTS]; - PyObject *monitoring_tool_names[PY_MONITORING_TOOL_IDS]; - uintptr_t monitoring_tool_versions[PY_MONITORING_TOOL_IDS]; - - struct _Py_interp_cached_objects cached_objects; - struct _Py_interp_static_objects static_objects; - - Py_ssize_t _interactive_src_count; - - /* the initial PyInterpreterState.threads.head */ - _PyThreadStateImpl _initial_thread; - // _initial_thread should be the last field of PyInterpreterState. - // See https://github.com/python/cpython/issues/127117. - -#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) - uint64_t next_stackref; - _Py_hashtable_t *open_stackrefs_table; -# ifdef Py_STACKREF_CLOSE_DEBUG - _Py_hashtable_t *closed_stackrefs_table; -# endif -#endif -}; /* other API */ diff --git a/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h new file mode 100644 index 00000000000000..ec788de316fcef --- /dev/null +++ b/Include/internal/pycore_interp_structs.h @@ -0,0 +1,967 @@ +#ifndef Py_INTERNAL_INTERP_STRUCTS_H +#define Py_INTERNAL_INTERP_STRUCTS_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "pycore_structs.h" +#include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR +#include "pycore_llist.h" +#include "pycore_ast_state.h" // struct ast_state + + +/* This file contains the struct definitions for interpreter state + * and other necessary structs */ + +#define CODE_MAX_WATCHERS 8 +#define CONTEXT_MAX_WATCHERS 8 +#define FUNC_MAX_WATCHERS 8 +#define TYPE_MAX_WATCHERS 8 + + +#ifdef Py_GIL_DISABLED +// This should be prime but otherwise the choice is arbitrary. A larger value +// increases concurrency at the expense of memory. +# define NUM_WEAKREF_LIST_LOCKS 127 +#endif + +typedef int (*_Py_pending_call_func)(void *); + +struct _pending_call { + _Py_pending_call_func func; + void *arg; + int flags; +}; + +#define PENDINGCALLSARRAYSIZE 300 + +struct _pending_calls { + PyThreadState *handling_thread; + PyMutex mutex; + /* Request for running pending calls. */ + int32_t npending; + /* The maximum allowed number of pending calls. + If the queue fills up to this point then _PyEval_AddPendingCall() + will return _Py_ADD_PENDING_FULL. */ + int32_t max; + /* We don't want a flood of pending calls to interrupt any one thread + for too long, so we keep a limit on the number handled per pass. + A value of 0 means there is no limit (other than the maximum + size of the list of pending calls). */ + int32_t maxloop; + struct _pending_call calls[PENDINGCALLSARRAYSIZE]; + int first; + int next; +}; + +typedef enum { + PERF_STATUS_FAILED = -1, // Perf trampoline is in an invalid state + PERF_STATUS_NO_INIT = 0, // Perf trampoline is not initialized + PERF_STATUS_OK = 1, // Perf trampoline is ready to be executed +} perf_status_t; + +#ifdef PY_HAVE_PERF_TRAMPOLINE +struct code_arena_st; + +struct trampoline_api_st { + void* (*init_state)(void); + void (*write_state)(void* state, const void *code_addr, + unsigned int code_size, PyCodeObject* code); + int (*free_state)(void* state); + void *state; + Py_ssize_t code_padding; +}; +#endif + + +struct _ceval_runtime_state { + struct { +#ifdef PY_HAVE_PERF_TRAMPOLINE + perf_status_t status; + int perf_trampoline_type; + Py_ssize_t extra_code_index; + struct code_arena_st *code_arena; + struct trampoline_api_st trampoline_api; + FILE *map_file; + Py_ssize_t persist_after_fork; +#else + int _not_used; +#endif + } perf; + /* Pending calls to be made only on the main thread. */ + // The signal machinery falls back on this + // so it must be especially stable and efficient. + // For example, we use a preallocated array + // for the list of pending calls. + struct _pending_calls pending_mainthread; + PyMutex sys_trace_profile_mutex; +}; + + +struct _ceval_state { + /* This variable holds the global instrumentation version. When a thread is + running, this value is overlaid onto PyThreadState.eval_breaker so that + changes in the instrumentation version will trigger the eval breaker. */ + uintptr_t instrumentation_version; + int recursion_limit; + struct _gil_runtime_state *gil; + int own_gil; + struct _pending_calls pending; +}; + + +//############### +// runtime atexit + +typedef void (*atexit_callbackfunc)(void); + +struct _atexit_runtime_state { + PyMutex mutex; +#define NEXITFUNCS 32 + atexit_callbackfunc callbacks[NEXITFUNCS]; + int ncallbacks; +}; + + +//################### +// interpreter atexit + +typedef void (*atexit_datacallbackfunc)(void *); + +typedef struct atexit_callback { + atexit_datacallbackfunc func; + void *data; + struct atexit_callback *next; +} atexit_callback; + +struct atexit_state { +#ifdef Py_GIL_DISABLED + PyMutex ll_callbacks_lock; +#endif + atexit_callback *ll_callbacks; + + // XXX The rest of the state could be moved to the atexit module state + // and a low-level callback added for it during module exec. + // For the moment we leave it here. + + // List containing tuples with callback information. + // e.g. [(func, args, kwargs), ...] + PyObject *callbacks; +}; + + +/****** Garbage collector **********/ + +/* GC information is stored BEFORE the object structure. */ +typedef struct { + // Tagged pointer to next object in the list. + // 0 means the object is not tracked + uintptr_t _gc_next; + + // Tagged pointer to previous object in the list. + // Lowest two bits are used for flags documented later. + uintptr_t _gc_prev; +} PyGC_Head; + +#define _PyGC_Head_UNUSED PyGC_Head + +struct gc_generation { + PyGC_Head head; + int threshold; /* collection threshold */ + int count; /* count of allocations or collections of younger + generations */ +}; + +struct gc_collection_stats { + /* number of collected objects */ + Py_ssize_t collected; + /* total number of uncollectable objects (put into gc.garbage) */ + Py_ssize_t uncollectable; +}; + +/* Running stats per generation */ +struct gc_generation_stats { + /* total number of collections */ + Py_ssize_t collections; + /* total number of collected objects */ + Py_ssize_t collected; + /* total number of uncollectable objects (put into gc.garbage) */ + Py_ssize_t uncollectable; +}; + +enum _GCPhase { + GC_PHASE_MARK = 0, + GC_PHASE_COLLECT = 1 +}; + +/* If we change this, we need to change the default value in the + signature of gc.collect. */ +#define NUM_GENERATIONS 3 + +struct _gc_runtime_state { + /* List of objects that still need to be cleaned up, singly linked + * via their gc headers' gc_prev pointers. */ + PyObject *trash_delete_later; + /* Current call-stack depth of tp_dealloc calls. */ + int trash_delete_nesting; + + /* Is automatic collection enabled? */ + int enabled; + int debug; + /* linked lists of container objects */ + struct gc_generation young; + struct gc_generation old[2]; + /* a permanent generation which won't be collected */ + struct gc_generation permanent_generation; + struct gc_generation_stats generation_stats[NUM_GENERATIONS]; + /* true if we are currently running the collector */ + int collecting; + /* list of uncollectable objects */ + PyObject *garbage; + /* a list of callbacks to be invoked when collection is performed */ + PyObject *callbacks; + + Py_ssize_t heap_size; + Py_ssize_t work_to_do; + /* Which of the old spaces is the visited space */ + int visited_space; + int phase; + +#ifdef Py_GIL_DISABLED + /* This is the number of objects that survived the last full + collection. It approximates the number of long lived objects + tracked by the GC. + + (by "full collection", we mean a collection of the oldest + generation). */ + Py_ssize_t long_lived_total; + /* This is the number of objects that survived all "non-full" + collections, and are awaiting to undergo a full collection for + the first time. */ + Py_ssize_t long_lived_pending; + + /* True if gc.freeze() has been used. */ + int freeze_active; +#endif +}; + +#ifdef Py_GIL_DISABLED +struct _gc_thread_state { + /* Thread-local allocation count. */ + Py_ssize_t alloc_count; +}; +#endif + +#include "pycore_gil.h" + +/****** Thread state **************/ +#include "pytypedefs.h" +#include "pystate.h" +#include "pycore_tstate.h" + + +/**** Import ********/ + +struct _import_runtime_state { + /* The builtin modules (defined in config.c). */ + struct _inittab *inittab; + /* The most recent value assigned to a PyModuleDef.m_base.m_index. + This is incremented each time PyModuleDef_Init() is called, + which is just about every time an extension module is imported. + See PyInterpreterState.modules_by_index for more info. */ + Py_ssize_t last_module_index; + struct { + /* A lock to guard the cache. */ + PyMutex mutex; + /* The actual cache of (filename, name, PyModuleDef) for modules. + Only legacy (single-phase init) extension modules are added + and only if they support multiple initialization (m_size >= 0) + or are imported in the main interpreter. + This is initialized lazily in fix_up_extension() in import.c. + Modules are added there and looked up in _imp.find_extension(). */ + struct _Py_hashtable_t *hashtable; + } extensions; + /* Package context -- the full module name for package imports */ + const char * pkgcontext; +}; + +struct _import_state { + /* cached sys.modules dictionary */ + PyObject *modules; + /* This is the list of module objects for all legacy (single-phase init) + extension modules ever loaded in this process (i.e. imported + in this interpreter or in any other). Py_None stands in for + modules that haven't actually been imported in this interpreter. + + A module's index (PyModuleDef.m_base.m_index) is used to look up + the corresponding module object for this interpreter, if any. + (See PyState_FindModule().) When any extension module + is initialized during import, its moduledef gets initialized by + PyModuleDef_Init(), and the first time that happens for each + PyModuleDef, its index gets set to the current value of + a global counter (see _PyRuntimeState.imports.last_module_index). + The entry for that index in this interpreter remains unset until + the module is actually imported here. (Py_None is used as + a placeholder.) Note that multi-phase init modules always get + an index for which there will never be a module set. + + This is initialized lazily in PyState_AddModule(), which is also + where modules get added. */ + PyObject *modules_by_index; + /* importlib module._bootstrap */ + PyObject *importlib; + /* override for config->use_frozen_modules (for tests) + (-1: "off", 1: "on", 0: no override) */ + int override_frozen_modules; + int override_multi_interp_extensions_check; +#ifdef HAVE_DLOPEN + int dlopenflags; +#endif + PyObject *import_func; + /* The global import lock. */ + _PyRecursiveMutex lock; + /* diagnostic info in PyImport_ImportModuleLevelObject() */ + struct { + int import_level; + PyTime_t accumulated; + int header; + } find_and_load; +}; + + + +/********** Interpreter state **************/ + +#include "pycore_object_state.h" +#include "pycore_crossinterp.h" + + +struct _Py_long_state { + int max_str_digits; +}; + +struct codecs_state { + // A list of callable objects used to search for codecs. + PyObject *search_path; + + // A dict mapping codec names to codecs returned from a callable in + // search_path. + PyObject *search_cache; + + // A dict mapping error handling strategies to functions to implement them. + PyObject *error_registry; + +#ifdef Py_GIL_DISABLED + // Used to safely delete a specific item from search_path. + PyMutex search_path_mutex; +#endif + + // Whether or not the rest of the state is initialized. + int initialized; +}; + +// Support for stop-the-world events. This exists in both the PyRuntime struct +// for global pauses and in each PyInterpreterState for per-interpreter pauses. +struct _stoptheworld_state { + PyMutex mutex; // Serializes stop-the-world attempts. + + // NOTE: The below fields are protected by HEAD_LOCK(runtime), not by the + // above mutex. + bool requested; // Set when a pause is requested. + bool world_stopped; // Set when the world is stopped. + bool is_global; // Set when contained in PyRuntime struct. + + PyEvent stop_event; // Set when thread_countdown reaches zero. + Py_ssize_t thread_countdown; // Number of threads that must pause. + + PyThreadState *requester; // Thread that requested the pause (may be NULL). +}; + +/* Tracks some rare events per-interpreter, used by the optimizer to turn on/off + specific optimizations. */ +typedef struct _rare_events { + /* Setting an object's class, obj.__class__ = ... */ + uint8_t set_class; + /* Setting the bases of a class, cls.__bases__ = ... */ + uint8_t set_bases; + /* Setting the PEP 523 frame eval function, _PyInterpreterState_SetFrameEvalFunc() */ + uint8_t set_eval_frame_func; + /* Modifying the builtins, __builtins__.__dict__[var] = ... */ + uint8_t builtin_dict; + /* Modifying a function, e.g. func.__defaults__ = ..., etc. */ + uint8_t func_modification; +} _rare_events; + +struct +Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + uint32_t x[1]; +}; + +#if defined(Py_USING_MEMORY_DEBUGGER) || _PY_SHORT_FLOAT_REPR == 0 + +struct _dtoa_state { + int _not_used; +}; + +#else // !Py_USING_MEMORY_DEBUGGER && _PY_SHORT_FLOAT_REPR != 0 + +/* The size of the Bigint freelist */ +#define Bigint_Kmax 7 + +/* The size of the cached powers of 5 array */ +#define Bigint_Pow5size 8 + +#ifndef PRIVATE_MEM +#define PRIVATE_MEM 2304 +#endif +#define Bigint_PREALLOC_SIZE \ + ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) + +struct _dtoa_state { + // p5s is an array of powers of 5 of the form: + // 5**(2**(i+2)) for 0 <= i < Bigint_Pow5size + struct Bigint *p5s[Bigint_Pow5size]; + // XXX This should be freed during runtime fini. + struct Bigint *freelist[Bigint_Kmax+1]; + double preallocated[Bigint_PREALLOC_SIZE]; + double *preallocated_next; +}; + +#endif // !Py_USING_MEMORY_DEBUGGER + +struct _py_code_state { + PyMutex mutex; + // Interned constants from code objects. Used by the free-threaded build. + struct _Py_hashtable_t *constants; +}; + +#define FUNC_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */ + +struct _func_version_cache_item { + PyFunctionObject *func; + PyObject *code; +}; + +struct _py_func_state { +#ifdef Py_GIL_DISABLED + // Protects next_version + PyMutex mutex; +#endif + + uint32_t next_version; + // Borrowed references to function and code objects whose + // func_version % FUNC_VERSION_CACHE_SIZE + // once was equal to the index in the table. + // They are cleared when the function or code object is deallocated. + struct _func_version_cache_item func_version_cache[FUNC_VERSION_CACHE_SIZE]; +}; + +#include "pycore_dict_state.h" +#include "pycore_exceptions.h" + + +/****** type state *********/ + +/* For now we hard-code this to a value for which we are confident + all the static builtin types will fit (for all builds). */ +#define _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES 200 +#define _Py_MAX_MANAGED_STATIC_EXT_TYPES 10 +#define _Py_MAX_MANAGED_STATIC_TYPES \ + (_Py_MAX_MANAGED_STATIC_BUILTIN_TYPES + _Py_MAX_MANAGED_STATIC_EXT_TYPES) + +struct _types_runtime_state { + /* Used to set PyTypeObject.tp_version_tag for core static types. */ + // bpo-42745: next_version_tag remains shared by all interpreters + // because of static types. + unsigned int next_version_tag; + + struct { + struct { + PyTypeObject *type; + int64_t interp_count; + } types[_Py_MAX_MANAGED_STATIC_TYPES]; + } managed_static; +}; + + +// Type attribute lookup cache: speed up attribute and method lookups, +// see _PyType_Lookup(). +struct type_cache_entry { + unsigned int version; // initialized from type->tp_version_tag +#ifdef Py_GIL_DISABLED + _PySeqLock sequence; +#endif + PyObject *name; // reference to exactly a str or None + PyObject *value; // borrowed reference or NULL +}; + +#define MCACHE_SIZE_EXP 12 + +struct type_cache { + struct type_cache_entry hashtable[1 << MCACHE_SIZE_EXP]; +}; + +typedef struct { + PyTypeObject *type; + int isbuiltin; + int readying; + int ready; + // XXX tp_dict can probably be statically allocated, + // instead of dynamically and stored on the interpreter. + PyObject *tp_dict; + PyObject *tp_subclasses; + /* We never clean up weakrefs for static builtin types since + they will effectively never get triggered. However, there + are also some diagnostic uses for the list of weakrefs, + so we still keep it. */ + PyObject *tp_weaklist; +} managed_static_type_state; + +#define TYPE_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */ + +struct types_state { + /* Used to set PyTypeObject.tp_version_tag. + It starts at _Py_MAX_GLOBAL_TYPE_VERSION_TAG + 1, + where all those lower numbers are used for core static types. */ + unsigned int next_version_tag; + + struct type_cache type_cache; + + /* Every static builtin type is initialized for each interpreter + during its own initialization, including for the main interpreter + during global runtime initialization. This is done by calling + _PyStaticType_InitBuiltin(). + + The first time a static builtin type is initialized, all the + normal PyType_Ready() stuff happens. The only difference from + normal is that there are three PyTypeObject fields holding + objects which are stored here (on PyInterpreterState) rather + than in the corresponding PyTypeObject fields. Those are: + tp_dict (cls.__dict__), tp_subclasses (cls.__subclasses__), + and tp_weaklist. + + When a subinterpreter is initialized, each static builtin type + is still initialized, but only the interpreter-specific portion, + namely those three objects. + + Those objects are stored in the PyInterpreterState.types.builtins + array, at the index corresponding to each specific static builtin + type. That index (a size_t value) is stored in the tp_subclasses + field. For static builtin types, we re-purposed the now-unused + tp_subclasses to avoid adding another field to PyTypeObject. + In all other cases tp_subclasses holds a dict like before. + (The field was previously defined as PyObject*, but is now void* + to reflect its dual use.) + + The index for each static builtin type isn't statically assigned. + Instead it is calculated the first time a type is initialized + (by the main interpreter). The index matches the order in which + the type was initialized relative to the others. The actual + value comes from the current value of num_builtins_initialized, + as each type is initialized for the main interpreter. + + num_builtins_initialized is incremented once for each static + builtin type. Once initialization is over for a subinterpreter, + the value will be the same as for all other interpreters. */ + struct { + size_t num_initialized; + managed_static_type_state initialized[_Py_MAX_MANAGED_STATIC_BUILTIN_TYPES]; + } builtins; + /* We apply a similar strategy for managed extension modules. */ + struct { + size_t num_initialized; + size_t next_index; + managed_static_type_state initialized[_Py_MAX_MANAGED_STATIC_EXT_TYPES]; + } for_extensions; + PyMutex mutex; + + // Borrowed references to type objects whose + // tp_version_tag % TYPE_VERSION_CACHE_SIZE + // once was equal to the index in the table. + // They are cleared when the type object is deallocated. + PyTypeObject *type_version_cache[TYPE_VERSION_CACHE_SIZE]; +}; + +struct _warnings_runtime_state { + /* Both 'filters' and 'onceregistry' can be set in warnings.py; + get_warnings_attr() will reset these variables accordingly. */ + PyObject *filters; /* List */ + PyObject *once_registry; /* Dict */ + PyObject *default_action; /* String */ + _PyRecursiveMutex lock; + long filters_version; +}; + +struct _Py_mem_interp_free_queue { + int has_work; // true if the queue is not empty + PyMutex mutex; // protects the queue + struct llist_node head; // queue of _mem_work_chunk items +}; + + +/****** Unicode state *********/ + +typedef enum { + _Py_ERROR_UNKNOWN=0, + _Py_ERROR_STRICT, + _Py_ERROR_SURROGATEESCAPE, + _Py_ERROR_REPLACE, + _Py_ERROR_IGNORE, + _Py_ERROR_BACKSLASHREPLACE, + _Py_ERROR_SURROGATEPASS, + _Py_ERROR_XMLCHARREFREPLACE, + _Py_ERROR_OTHER +} _Py_error_handler; + +struct _Py_unicode_runtime_ids { + PyMutex mutex; + // next_index value must be preserved when Py_Initialize()/Py_Finalize() + // is called multiple times: see _PyUnicode_FromId() implementation. + Py_ssize_t next_index; +}; + +struct _Py_unicode_runtime_state { + struct _Py_unicode_runtime_ids ids; +}; + +/* fs_codec.encoding is initialized to NULL. + Later, it is set to a non-NULL string by _PyUnicode_InitEncodings(). */ +struct _Py_unicode_fs_codec { + char *encoding; // Filesystem encoding (encoded to UTF-8) + int utf8; // encoding=="utf-8"? + char *errors; // Filesystem errors (encoded to UTF-8) + _Py_error_handler error_handler; +}; + +struct _Py_unicode_ids { + Py_ssize_t size; + PyObject **array; +}; + +#include "pycore_ucnhash.h" + +struct _Py_unicode_state { + struct _Py_unicode_fs_codec fs_codec; + + _PyUnicode_Name_CAPI *ucnhash_capi; + + // Unicode identifiers (_Py_Identifier): see _PyUnicode_FromId() + struct _Py_unicode_ids ids; +}; + +// Borrowed references to common callables: +struct callable_cache { + PyObject *isinstance; + PyObject *len; + PyObject *list_append; + PyObject *object__getattribute__; +}; + +#include "pycore_obmalloc.h" + +/* 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; + + +struct _Py_interp_cached_objects { +#ifdef Py_GIL_DISABLED + PyMutex interned_mutex; +#endif + PyObject *interned_strings; + + /* object.__reduce__ */ + PyObject *objreduce; + PyObject *type_slots_pname; + pytype_slotdef *type_slots_ptrs[MAX_EQUIV]; + + /* TypeVar and related types */ + PyTypeObject *generic_type; + PyTypeObject *typevar_type; + PyTypeObject *typevartuple_type; + PyTypeObject *paramspec_type; + PyTypeObject *paramspecargs_type; + PyTypeObject *paramspeckwargs_type; + PyTypeObject *constevaluator_type; +}; + +struct _Py_interp_static_objects { + struct { + int _not_used; + // hamt_empty is here instead of global because of its weakreflist. + _PyGC_Head_UNUSED _hamt_empty_gc_not_used; + PyHamtObject hamt_empty; + PyBaseExceptionObject last_resort_memory_error; + } singletons; +}; + +#include "pycore_instruments.h" + + +#ifdef Py_GIL_DISABLED + +// A min-heap of indices +typedef struct _PyIndexHeap { + int32_t *values; + + // Number of items stored in values + Py_ssize_t size; + + // Maximum number of items that can be stored in values + Py_ssize_t capacity; +} _PyIndexHeap; + +// An unbounded pool of indices. Indices are allocated starting from 0. They +// may be released back to the pool once they are no longer in use. +typedef struct _PyIndexPool { + PyMutex mutex; + + // Min heap of indices available for allocation + _PyIndexHeap free_indices; + + // Next index to allocate if no free indices are available + int32_t next_index; +} _PyIndexPool; + +typedef union _Py_unique_id_entry { + // Points to the next free type id, when part of the freelist + union _Py_unique_id_entry *next; + + // Stores the object when the id is assigned + PyObject *obj; +} _Py_unique_id_entry; + +struct _Py_unique_id_pool { + PyMutex mutex; + + // combined table of object with allocated unique ids and unallocated ids. + _Py_unique_id_entry *table; + + // Next entry to allocate inside 'table' or NULL + _Py_unique_id_entry *freelist; + + // size of 'table' + Py_ssize_t size; +}; + +#endif + + +/* PyInterpreterState holds the global state for one of the runtime's + interpreters. Typically the initial (main) interpreter is the only one. + + The PyInterpreterState typedef is in Include/pytypedefs.h. + */ +struct _is { + + /* This struct contains the eval_breaker, + * which is by far the hottest field in this struct + * and should be placed at the beginning. */ + struct _ceval_state ceval; + + PyInterpreterState *next; + + int64_t id; + Py_ssize_t id_refcount; + int requires_idref; + + long _whence; + + /* Has been initialized to a safe state. + + In order to be effective, this must be set to 0 during or right + after allocation. */ + int _initialized; + /* Has been fully initialized via pylifecycle.c. */ + int _ready; + int finalizing; + + uintptr_t last_restart_version; + struct pythreads { + uint64_t next_unique_id; + /* The linked list of threads, newest first. */ + PyThreadState *head; + _PyThreadStateImpl *preallocated; + /* The thread currently executing in the __main__ module, if any. */ + PyThreadState *main; + /* Used in Modules/_threadmodule.c. */ + Py_ssize_t count; + /* Support for runtime thread stack size tuning. + A value of 0 means using the platform's default stack size + or the size specified by the THREAD_STACK_SIZE macro. */ + /* Used in Python/thread.c. */ + size_t stacksize; + } threads; + + /* Reference to the _PyRuntime global variable. This field exists + to not have to pass runtime in addition to tstate to a function. + Get runtime from tstate: tstate->interp->runtime. */ + struct pyruntimestate *runtime; + + /* Set by Py_EndInterpreter(). + + Use _PyInterpreterState_GetFinalizing() + and _PyInterpreterState_SetFinalizing() + to access it, don't access it directly. */ + PyThreadState* _finalizing; + /* The ID of the OS thread in which we are finalizing. */ + unsigned long _finalizing_id; + + struct _gc_runtime_state gc; + + /* The following fields are here to avoid allocation during init. + The data is exposed through PyInterpreterState pointer fields. + These fields should not be accessed directly outside of init. + + All other PyInterpreterState pointer fields are populated when + needed and default to NULL. + + For now there are some exceptions to that rule, which require + allocation during init. These will be addressed on a case-by-case + basis. Also see _PyRuntimeState regarding the various mutex fields. + */ + + // Dictionary of the sys module + PyObject *sysdict; + + // Dictionary of the builtins module + PyObject *builtins; + + struct _import_state imports; + + /* The per-interpreter GIL, which might not be used. */ + struct _gil_runtime_state _gil; + + /* ---------- IMPORTANT --------------------------- + The fields above this line are declared as early as + possible to facilitate out-of-process observability + tools. */ + + struct codecs_state codecs; + + PyConfig config; + unsigned long feature_flags; + + PyObject *dict; /* Stores per-interpreter state */ + + PyObject *sysdict_copy; + PyObject *builtins_copy; + // Initialized to _PyEval_EvalFrameDefault(). + _PyFrameEvalFunction eval_frame; + + PyFunction_WatchCallback func_watchers[FUNC_MAX_WATCHERS]; + // One bit is set for each non-NULL entry in func_watchers + uint8_t active_func_watchers; + + Py_ssize_t co_extra_user_count; + freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS]; + + /* cross-interpreter data and utils */ + _PyXI_state_t xi; + +#ifdef HAVE_FORK + PyObject *before_forkers; + PyObject *after_forkers_parent; + PyObject *after_forkers_child; +#endif + + struct _warnings_runtime_state warnings; + struct atexit_state atexit; + struct _stoptheworld_state stoptheworld; + struct _qsbr_shared qsbr; + +#if defined(Py_GIL_DISABLED) + struct _mimalloc_interp_state mimalloc; + struct _brc_state brc; // biased reference counting state + struct _Py_unique_id_pool unique_ids; // object ids for per-thread refcounts + PyMutex weakref_locks[NUM_WEAKREF_LIST_LOCKS]; + _PyIndexPool tlbc_indices; +#endif + // Per-interpreter list of tasks, any lingering tasks from thread + // states gets added here and removed from the corresponding + // thread state's list. + struct llist_node asyncio_tasks_head; + // `asyncio_tasks_lock` is used when tasks are moved + // from thread's list to interpreter's list. + PyMutex asyncio_tasks_lock; + + // Per-interpreter state for the obmalloc allocator. For the main + // interpreter and for all interpreters that don't have their + // own obmalloc state, this points to the static structure in + // obmalloc.c obmalloc_state_main. For other interpreters, it is + // heap allocated by _PyMem_init_obmalloc() and freed when the + // interpreter structure is freed. In the case of a heap allocated + // obmalloc state, it is not safe to hold on to or use memory after + // the interpreter is freed. The obmalloc state corresponding to + // that allocated memory is gone. See free_obmalloc_arenas() for + // more comments. + struct _obmalloc_state *obmalloc; + + PyObject *audit_hooks; + PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS]; + PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS]; + PyContext_WatchCallback context_watchers[CONTEXT_MAX_WATCHERS]; + // One bit is set for each non-NULL entry in code_watchers + uint8_t active_code_watchers; + uint8_t active_context_watchers; + + struct _py_object_state object_state; + struct _Py_unicode_state unicode; + struct _Py_long_state long_state; + struct _dtoa_state dtoa; + struct _py_func_state func_state; + struct _py_code_state code_state; + + struct _Py_dict_state dict_state; + struct _Py_exc_state exc_state; + struct _Py_mem_interp_free_queue mem_free_queue; + + struct ast_state ast; + struct types_state types; + struct callable_cache callable_cache; + bool jit; + struct _PyExecutorObject *executor_list_head; + size_t trace_run_counter; + _rare_events rare_events; + PyDict_WatchCallback builtins_dict_watcher; + + _Py_GlobalMonitors monitors; + bool sys_profile_initialized; + bool sys_trace_initialized; + Py_ssize_t sys_profiling_threads; /* Count of threads with c_profilefunc set */ + Py_ssize_t sys_tracing_threads; /* Count of threads with c_tracefunc set */ + PyObject *monitoring_callables[PY_MONITORING_TOOL_IDS][_PY_MONITORING_EVENTS]; + PyObject *monitoring_tool_names[PY_MONITORING_TOOL_IDS]; + uintptr_t monitoring_tool_versions[PY_MONITORING_TOOL_IDS]; + + struct _Py_interp_cached_objects cached_objects; + struct _Py_interp_static_objects static_objects; + + Py_ssize_t _interactive_src_count; + + /* the initial PyInterpreterState.threads.head */ + _PyThreadStateImpl _initial_thread; + // _initial_thread should be the last field of PyInterpreterState. + // See https://github.com/python/cpython/issues/127117. + +#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) + uint64_t next_stackref; + _Py_hashtable_t *open_stackrefs_table; +# ifdef Py_STACKREF_CLOSE_DEBUG + _Py_hashtable_t *closed_stackrefs_table; +# endif +#endif +}; + + + +#ifdef __cplusplus +} +#endif +#endif /* Py_INTERNAL_INTERP_STRUCTS_H */ diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index df0656a7cb8f0c..7b7f4e79ec653d 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -9,7 +9,8 @@ extern "C" { #endif #include "pycore_bytesobject.h" // _PyBytesWriter -#include "pycore_global_objects.h"// _PY_NSMALLNEGINTS +#include "pycore_runtime_structs.h"// _PY_NSMALLNEGINTS +#include "pycore_global_objects.h"// _PY_SINGLETON #include "pycore_runtime.h" // _PyRuntime /* diff --git a/Include/internal/pycore_parser.h b/Include/internal/pycore_parser.h index b16084aaa15515..2885dee63dcf94 100644 --- a/Include/internal/pycore_parser.h +++ b/Include/internal/pycore_parser.h @@ -13,23 +13,6 @@ extern "C" { #include "pycore_global_strings.h" // _Py_DECLARE_STR() #include "pycore_pyarena.h" // PyArena - -#ifdef Py_DEBUG -#define _PYPEGEN_NSTATISTICS 2000 -#endif - -struct _parser_runtime_state { -#ifdef Py_DEBUG - long memo_statistics[_PYPEGEN_NSTATISTICS]; -#ifdef Py_GIL_DISABLED - PyMutex mutex; -#endif -#else - int _not_used; -#endif - struct _expr dummy_name; -}; - _Py_DECLARE_STR(empty, "") #if defined(Py_DEBUG) && defined(Py_GIL_DISABLED) #define _parser_runtime_state_INIT \ diff --git a/Include/internal/pycore_pyhash.h b/Include/internal/pycore_pyhash.h index 9414e7761171d2..84cb72fa6fd1b2 100644 --- a/Include/internal/pycore_pyhash.h +++ b/Include/internal/pycore_pyhash.h @@ -71,19 +71,6 @@ extern int _Py_HashSecret_Initialized; #endif -struct pyhash_runtime_state { - struct { -#ifndef MS_WINDOWS - int fd; - dev_t st_dev; - ino_t st_ino; -#else - // This is a placeholder so the struct isn't empty on Windows. - int _not_used; -#endif - } urandom_cache; -}; - #ifndef MS_WINDOWS # define _py_urandom_cache_INIT \ { \ diff --git a/Include/internal/pycore_pymem.h b/Include/internal/pycore_pymem.h index 5386d4c5f83031..aa20190e252a2d 100644 --- a/Include/internal/pycore_pymem.h +++ b/Include/internal/pycore_pymem.h @@ -27,34 +27,6 @@ PyAPI_FUNC(char*) _PyMem_Strdup(const char *str); // wcsdup() using PyMem_RawMalloc() extern wchar_t* _PyMem_RawWcsdup(const wchar_t *str); -typedef struct { - /* We tag each block with an API ID in order to tag API violations */ - char api_id; - PyMemAllocatorEx alloc; -} debug_alloc_api_t; - -struct _pymem_allocators { - PyMutex mutex; - struct { - PyMemAllocatorEx raw; - PyMemAllocatorEx mem; - PyMemAllocatorEx obj; - } standard; - struct { - debug_alloc_api_t raw; - debug_alloc_api_t mem; - debug_alloc_api_t obj; - } debug; - int is_debug_enabled; - PyObjectArenaAllocator obj_arena; -}; - -struct _Py_mem_interp_free_queue { - int has_work; // true if the queue is not empty - PyMutex mutex; // protects the queue - struct llist_node head; // queue of _mem_work_chunk items -}; - /* Special bytes broadcast into debug memory blocks at appropriate times. Strings of these are unlikely to be valid addresses, floats, ints or 7-bit ASCII. diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index f3667a8aa71c27..d4867a7b96bfeb 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -8,8 +8,10 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_runtime.h" // _PyRuntime -#include "pycore_tstate.h" // _PyThreadStateImpl +#include "pycore_runtime_structs.h" // _PyRuntime +#include "pycore_runtime.h" // _PyRuntimeState_GetFinalizing +#include "pycore_tstate.h" // _PyThreadStateImpl +#include "pycore_interp.h" // _PyInterpreterState_GetConfig // Values for PyThreadState.state. A thread must be in the "attached" state // before calling most Python APIs. If the GIL is enabled, then "attached" diff --git a/Include/internal/pycore_pythread.h b/Include/internal/pycore_pythread.h index a1e084cf67d58d..8457b07340f8dd 100644 --- a/Include/internal/pycore_pythread.h +++ b/Include/internal/pycore_pythread.h @@ -8,8 +8,8 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "dynamic_annotations.h" // _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX -#include "pycore_llist.h" // struct llist_node +#include "dynamic_annotations.h" // _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX +#include "pycore_llist.h" // struct llist_node // Get _POSIX_THREADS and _POSIX_SEMAPHORES macros if available #if (defined(HAVE_UNISTD_H) && !defined(_POSIX_THREADS) \ diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 9324ce9eb89d2c..bda8a30dd1d0ad 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -8,201 +8,9 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_atexit.h" // struct _atexit_runtime_state -#include "pycore_audit.h" // _Py_AuditHookEntry -#include "pycore_ceval_state.h" // struct _ceval_runtime_state -#include "pycore_crossinterp.h" // _PyXI_global_state_t -#include "pycore_debug_offsets.h" // _Py_DebugOffsets -#include "pycore_faulthandler.h" // struct _faulthandler_runtime_state -#include "pycore_floatobject.h" // struct _Py_float_runtime_state -#include "pycore_import.h" // struct _import_runtime_state -#include "pycore_interp.h" // PyInterpreterState -#include "pycore_object_state.h" // struct _py_object_runtime_state -#include "pycore_parser.h" // struct _parser_runtime_state -#include "pycore_pyhash.h" // struct pyhash_runtime_state -#include "pycore_pymem.h" // struct _pymem_allocators -#include "pycore_pythread.h" // struct _pythread_runtime_state -#include "pycore_signal.h" // struct _signals_runtime_state -#include "pycore_time.h" // struct _PyTime_runtime_state -#include "pycore_tracemalloc.h" // struct _tracemalloc_runtime_state -#include "pycore_typeobject.h" // struct _types_runtime_state -#include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_state +#include "pycore_runtime_structs.h" - -/* Full Python runtime state */ - -/* _PyRuntimeState holds the global state for the CPython runtime. - That data is exported by the internal API as a global variable - (_PyRuntime, defined near the top of pylifecycle.c). - */ -typedef struct pyruntimestate { - /* This field must be first to facilitate locating it by out of process - * debuggers. Out of process debuggers will use the offsets contained in this - * field to be able to locate other fields in several interpreter structures - * in a way that doesn't require them to know the exact layout of those - * structures. - * - * IMPORTANT: - * This struct is **NOT** backwards compatible between minor version of the - * interpreter and the members, order of members and size can change between - * minor versions. This struct is only guaranteed to be stable between patch - * versions for a given minor version of the interpreter. - */ - _Py_DebugOffsets debug_offsets; - - /* Has been initialized to a safe state. - - In order to be effective, this must be set to 0 during or right - after allocation. */ - int _initialized; - - /* Is running Py_PreInitialize()? */ - int preinitializing; - - /* Is Python preinitialized? Set to 1 by Py_PreInitialize() */ - int preinitialized; - - /* Is Python core initialized? Set to 1 by _Py_InitializeCore() */ - int core_initialized; - - /* Is Python fully initialized? Set to 1 by Py_Initialize() */ - int initialized; - - /* Set by Py_FinalizeEx(). Only reset to NULL if Py_Initialize() - is called again. - - Use _PyRuntimeState_GetFinalizing() and _PyRuntimeState_SetFinalizing() - to access it, don't access it directly. */ - PyThreadState *_finalizing; - /* The ID of the OS thread in which we are finalizing. */ - unsigned long _finalizing_id; - - struct pyinterpreters { - PyMutex mutex; - /* The linked list of interpreters, newest first. */ - PyInterpreterState *head; - /* The runtime's initial interpreter, which has a special role - in the operation of the runtime. It is also often the only - interpreter. */ - PyInterpreterState *main; - /* next_id is an auto-numbered sequence of small - integers. It gets initialized in _PyInterpreterState_Enable(), - which is called in Py_Initialize(), and used in - PyInterpreterState_New(). A negative interpreter ID - indicates an error occurred. The main interpreter will - always have an ID of 0. Overflow results in a RuntimeError. - If that becomes a problem later then we can adjust, e.g. by - using a Python int. */ - int64_t next_id; - } interpreters; - - /* Platform-specific identifier and PyThreadState, respectively, for the - main thread in the main interpreter. */ - unsigned long main_thread; - PyThreadState *main_tstate; - - /* ---------- IMPORTANT --------------------------- - The fields above this line are declared as early as - possible to facilitate out-of-process observability - tools. */ - - /* cross-interpreter data and utils */ - _PyXI_global_state_t xi; - - struct _pymem_allocators allocators; - struct _obmalloc_global_state obmalloc; - struct pyhash_runtime_state pyhash_state; - struct _pythread_runtime_state threads; - struct _signals_runtime_state signals; - - /* Used for the thread state bound to the current thread. */ - Py_tss_t autoTSSkey; - - /* Used instead of PyThreadState.trash when there is not current tstate. */ - Py_tss_t trashTSSkey; - - PyWideStringList orig_argv; - - struct _parser_runtime_state parser; - - struct _atexit_runtime_state atexit; - - struct _import_runtime_state imports; - struct _ceval_runtime_state ceval; - struct _gilstate_runtime_state { - /* bpo-26558: Flag to disable PyGILState_Check(). - If set to non-zero, PyGILState_Check() always return 1. */ - int check_enabled; - /* The single PyInterpreterState used by this process' - GILState implementation - */ - /* TODO: Given interp_main, it may be possible to kill this ref */ - PyInterpreterState *autoInterpreterState; - } gilstate; - struct _getargs_runtime_state { - struct _PyArg_Parser *static_parsers; - } getargs; - struct _fileutils_state fileutils; - struct _faulthandler_runtime_state faulthandler; - struct _tracemalloc_runtime_state tracemalloc; - struct _reftracer_runtime_state ref_tracer; - - // The rwmutex is used to prevent overlapping global and per-interpreter - // stop-the-world events. Global stop-the-world events lock the mutex - // exclusively (as a "writer"), while per-interpreter stop-the-world events - // lock it non-exclusively (as "readers"). - _PyRWMutex stoptheworld_mutex; - struct _stoptheworld_state stoptheworld; - - PyPreConfig preconfig; - - // Audit values must be preserved when Py_Initialize()/Py_Finalize() - // is called multiple times. - Py_OpenCodeHookFunction open_code_hook; - void *open_code_userdata; - struct { - PyMutex mutex; - _Py_AuditHookEntry *head; - } audit_hooks; - - struct _py_object_runtime_state object_state; - struct _Py_float_runtime_state float_state; - struct _Py_unicode_runtime_state unicode_state; - struct _types_runtime_state types; - struct _Py_time_runtime_state time; - -#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) - // Used in "Python/emscripten_trampoline.c" to choose between type - // reflection trampoline and EM_JS trampoline. - int (*emscripten_count_args_function)(PyCFunctionWithKeywords func); -#endif - - /* All the objects that are shared by the runtime's interpreters. */ - struct _Py_cached_objects cached_objects; - struct _Py_static_objects static_objects; - - /* The following fields are here to avoid allocation during init. - The data is exposed through _PyRuntimeState pointer fields. - These fields should not be accessed directly outside of init. - - All other _PyRuntimeState pointer fields are populated when - needed and default to NULL. - - For now there are some exceptions to that rule, which require - allocation during init. These will be addressed on a case-by-case - basis. Most notably, we don't pre-allocated the several mutex - (PyThread_type_lock) fields, because on Windows we only ever get - a pointer type. - */ - - /* _PyRuntimeState.interpreters.main */ - PyInterpreterState _main_interpreter; - // _main_interpreter should be the last field of _PyRuntimeState. - // See https://github.com/python/cpython/issues/127117. -} _PyRuntimeState; - - -/* other API */ +/* API */ // Export _PyRuntime for shared extensions which use it in static inline // functions for best performance, like _Py_IsMainThread() or _Py_ID(). diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 2ec32b64adde0b..5ea9b296feba75 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -8,11 +8,13 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_structs.h" #include "pycore_ceval_state.h" // _PyEval_RUNTIME_PERF_INIT #include "pycore_debug_offsets.h" // _Py_DebugOffsets_INIT() #include "pycore_faulthandler.h" // _faulthandler_runtime_state_INIT #include "pycore_floatobject.h" // _py_float_format_unknown #include "pycore_function.h" +#include "pycore_hamt.h" // _PyHamt_BitmapNode_Type #include "pycore_object.h" // _PyObject_HEAD_INIT #include "pycore_obmalloc_init.h" // _obmalloc_global_state_INIT #include "pycore_parser.h" // _parser_runtime_state_INIT diff --git a/Include/internal/pycore_runtime_structs.h b/Include/internal/pycore_runtime_structs.h new file mode 100644 index 00000000000000..2ea1d795f24789 --- /dev/null +++ b/Include/internal/pycore_runtime_structs.h @@ -0,0 +1,317 @@ +#ifndef Py_INTERNAL_RUNTIME_STRUCTS_H +#define Py_INTERNAL_RUNTIME_STRUCTS_H +#ifdef __cplusplus +extern "C" { +#endif + +/* This file contains the struct definitions for the runtime, interpreter + * and thread states, plus all smaller structs contained therein */ + +#include "pycore_structs.h" +#include "pycore_interp_structs.h" + +/************ Runtime state ************/ + +typedef struct { + /* We tag each block with an API ID in order to tag API violations */ + char api_id; + PyMemAllocatorEx alloc; +} debug_alloc_api_t; + +struct _pymem_allocators { + PyMutex mutex; + struct { + PyMemAllocatorEx raw; + PyMemAllocatorEx mem; + PyMemAllocatorEx obj; + } standard; + struct { + debug_alloc_api_t raw; + debug_alloc_api_t mem; + debug_alloc_api_t obj; + } debug; + int is_debug_enabled; + PyObjectArenaAllocator obj_arena; +}; + +enum _py_float_format_type { + _py_float_format_unknown, + _py_float_format_ieee_big_endian, + _py_float_format_ieee_little_endian, +}; + +struct _Py_float_runtime_state { + enum _py_float_format_type float_format; + enum _py_float_format_type double_format; +}; + +struct pyhash_runtime_state { + struct { +#ifndef MS_WINDOWS + int fd; + dev_t st_dev; + ino_t st_ino; +#else + // This is a placeholder so the struct isn't empty on Windows. + int _not_used; +#endif + } urandom_cache; +}; + +#include "pycore_tracemalloc.h" + +struct _fileutils_state { + int force_ascii; +}; + +#include "pycore_debug_offsets.h" +#include "pycore_signal.h" +#include "pycore_faulthandler.h" +#include "pycore_pythread.h" +#include "pycore_ast.h" + +#ifdef Py_DEBUG +#define _PYPEGEN_NSTATISTICS 2000 +#endif + +struct _parser_runtime_state { +#ifdef Py_DEBUG + long memo_statistics[_PYPEGEN_NSTATISTICS]; +#ifdef Py_GIL_DISABLED + PyMutex mutex; +#endif +#else + int _not_used; +#endif + struct _expr dummy_name; +}; + +typedef struct { + PyTime_t numer; + PyTime_t denom; +} _PyTimeFraction; + +struct _Py_time_runtime_state { +#if defined(MS_WINDOWS) || defined(__APPLE__) + _PyTimeFraction base; +#else + char _unused; +#endif +}; + + +struct _Py_cached_objects { + // XXX We could statically allocate the hashtable. + _Py_hashtable_t *interned_strings; +}; + +// These would be in pycore_long.h if it weren't for an include cycle. +#define _PY_NSMALLPOSINTS 257 +#define _PY_NSMALLNEGINTS 5 + +#include "pycore_global_strings.h" + +struct _Py_static_objects { + struct { + /* Small integers are preallocated in this array so that they + * can be shared. + * The integers that are preallocated are those in the range + * -_PY_NSMALLNEGINTS (inclusive) to _PY_NSMALLPOSINTS (exclusive). + */ + PyLongObject small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS]; + + PyBytesObject bytes_empty; + struct { + PyBytesObject ob; + char eos; + } bytes_characters[256]; + + struct _Py_global_strings strings; + + _PyGC_Head_UNUSED _tuple_empty_gc_not_used; + PyTupleObject tuple_empty; + + _PyGC_Head_UNUSED _hamt_bitmap_node_empty_gc_not_used; + PyHamtNode_Bitmap hamt_bitmap_node_empty; + _PyContextTokenMissing context_token_missing; + } singletons; +}; + +/* Full Python runtime state */ + +/* _PyRuntimeState holds the global state for the CPython runtime. + That data is exported by the internal API as a global variable + (_PyRuntime, defined near the top of pylifecycle.c). + */ +typedef struct pyruntimestate { + /* This field must be first to facilitate locating it by out of process + * debuggers. Out of process debuggers will use the offsets contained in this + * field to be able to locate other fields in several interpreter structures + * in a way that doesn't require them to know the exact layout of those + * structures. + * + * IMPORTANT: + * This struct is **NOT** backwards compatible between minor version of the + * interpreter and the members, order of members and size can change between + * minor versions. This struct is only guaranteed to be stable between patch + * versions for a given minor version of the interpreter. + */ + _Py_DebugOffsets debug_offsets; + + /* Has been initialized to a safe state. + + In order to be effective, this must be set to 0 during or right + after allocation. */ + int _initialized; + + /* Is running Py_PreInitialize()? */ + int preinitializing; + + /* Is Python preinitialized? Set to 1 by Py_PreInitialize() */ + int preinitialized; + + /* Is Python core initialized? Set to 1 by _Py_InitializeCore() */ + int core_initialized; + + /* Is Python fully initialized? Set to 1 by Py_Initialize() */ + int initialized; + + /* Set by Py_FinalizeEx(). Only reset to NULL if Py_Initialize() + is called again. + + Use _PyRuntimeState_GetFinalizing() and _PyRuntimeState_SetFinalizing() + to access it, don't access it directly. */ + PyThreadState *_finalizing; + /* The ID of the OS thread in which we are finalizing. */ + unsigned long _finalizing_id; + + struct pyinterpreters { + PyMutex mutex; + /* The linked list of interpreters, newest first. */ + PyInterpreterState *head; + /* The runtime's initial interpreter, which has a special role + in the operation of the runtime. It is also often the only + interpreter. */ + PyInterpreterState *main; + /* next_id is an auto-numbered sequence of small + integers. It gets initialized in _PyInterpreterState_Enable(), + which is called in Py_Initialize(), and used in + PyInterpreterState_New(). A negative interpreter ID + indicates an error occurred. The main interpreter will + always have an ID of 0. Overflow results in a RuntimeError. + If that becomes a problem later then we can adjust, e.g. by + using a Python int. */ + int64_t next_id; + } interpreters; + + /* Platform-specific identifier and PyThreadState, respectively, for the + main thread in the main interpreter. */ + unsigned long main_thread; + PyThreadState *main_tstate; + + /* ---------- IMPORTANT --------------------------- + The fields above this line are declared as early as + possible to facilitate out-of-process observability + tools. */ + + /* cross-interpreter data and utils */ + _PyXI_global_state_t xi; + + struct _pymem_allocators allocators; + struct _obmalloc_global_state obmalloc; + struct pyhash_runtime_state pyhash_state; + struct _pythread_runtime_state threads; + struct _signals_runtime_state signals; + + /* Used for the thread state bound to the current thread. */ + Py_tss_t autoTSSkey; + + /* Used instead of PyThreadState.trash when there is not current tstate. */ + Py_tss_t trashTSSkey; + + PyWideStringList orig_argv; + + struct _parser_runtime_state parser; + + struct _atexit_runtime_state atexit; + + struct _import_runtime_state imports; + struct _ceval_runtime_state ceval; + struct _gilstate_runtime_state { + /* bpo-26558: Flag to disable PyGILState_Check(). + If set to non-zero, PyGILState_Check() always return 1. */ + int check_enabled; + /* The single PyInterpreterState used by this process' + GILState implementation + */ + /* TODO: Given interp_main, it may be possible to kill this ref */ + PyInterpreterState *autoInterpreterState; + } gilstate; + struct _getargs_runtime_state { + struct _PyArg_Parser *static_parsers; + } getargs; + struct _fileutils_state fileutils; + struct _faulthandler_runtime_state faulthandler; + struct _tracemalloc_runtime_state tracemalloc; + struct _reftracer_runtime_state ref_tracer; + + // The rwmutex is used to prevent overlapping global and per-interpreter + // stop-the-world events. Global stop-the-world events lock the mutex + // exclusively (as a "writer"), while per-interpreter stop-the-world events + // lock it non-exclusively (as "readers"). + _PyRWMutex stoptheworld_mutex; + struct _stoptheworld_state stoptheworld; + + PyPreConfig preconfig; + + // Audit values must be preserved when Py_Initialize()/Py_Finalize() + // is called multiple times. + Py_OpenCodeHookFunction open_code_hook; + void *open_code_userdata; + struct { + PyMutex mutex; + struct _Py_AuditHookEntry *head; + } audit_hooks; + + struct _py_object_runtime_state object_state; + struct _Py_float_runtime_state float_state; + struct _Py_unicode_runtime_state unicode_state; + struct _types_runtime_state types; + struct _Py_time_runtime_state time; + +#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) + // Used in "Python/emscripten_trampoline.c" to choose between type + // reflection trampoline and EM_JS trampoline. + int (*emscripten_count_args_function)(PyCFunctionWithKeywords func); +#endif + + /* All the objects that are shared by the runtime's interpreters. */ + struct _Py_cached_objects cached_objects; + struct _Py_static_objects static_objects; + + /* The following fields are here to avoid allocation during init. + The data is exposed through _PyRuntimeState pointer fields. + These fields should not be accessed directly outside of init. + + All other _PyRuntimeState pointer fields are populated when + needed and default to NULL. + + For now there are some exceptions to that rule, which require + allocation during init. These will be addressed on a case-by-case + basis. Most notably, we don't pre-allocated the several mutex + (PyThread_type_lock) fields, because on Windows we only ever get + a pointer type. + */ + + /* _PyRuntimeState.interpreters.main */ + PyInterpreterState _main_interpreter; + // _main_interpreter should be the last field of _PyRuntimeState. + // See https://github.com/python/cpython/issues/127117. +} _PyRuntimeState; + + + +#ifdef __cplusplus +} +#endif +#endif /* Py_INTERNAL_RUNTIME_STRUCTS_H */ diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index 98ebf66946d726..398a1bdaf1cf81 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -4,9 +4,6 @@ extern "C" { #endif -// Define this to get precise tracking of stackrefs. -// #define Py_STACKREF_DEBUG 1 - // Define this to get precise tracking of closed stackrefs. // This will use unbounded memory, as it can only grow. // Use this to track double closes in short-lived programs @@ -60,10 +57,6 @@ extern "C" { #if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) -typedef union _PyStackRef { - uint64_t index; -} _PyStackRef; - #define Py_TAG_BITS 0 PyAPI_FUNC(PyObject *) _Py_stackref_get_object(_PyStackRef ref); @@ -203,10 +196,6 @@ PyStackRef_IsHeapSafe(_PyStackRef ref) #else -typedef union _PyStackRef { - uintptr_t bits; -} _PyStackRef; - #ifdef Py_GIL_DISABLED diff --git a/Include/internal/pycore_structs.h b/Include/internal/pycore_structs.h new file mode 100644 index 00000000000000..ed0e987c23e851 --- /dev/null +++ b/Include/internal/pycore_structs.h @@ -0,0 +1,74 @@ +#ifndef Py_INTERNAL_STRUCTS_H +#define Py_INTERNAL_STRUCTS_H +#ifdef __cplusplus +extern "C" { +#endif + +/* This files contains various key structs that are widely used + * and do not depend on other headers. */ + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + + +typedef struct { + uint16_t value_and_backoff; +} _Py_BackoffCounter; + +/* Each instruction in a code object is a fixed-width value, + * currently 2 bytes: 1-byte opcode + 1-byte oparg. The EXTENDED_ARG + * opcode allows for larger values but the current limit is 3 uses + * of EXTENDED_ARG (see Python/compile.c), for a maximum + * 32-bit value. This aligns with the note in Python/compile.c + * (compiler_addop_i_line) indicating that the max oparg value is + * 2**32 - 1, rather than INT_MAX. + */ +typedef union { + uint16_t cache; + struct { + uint8_t code; + uint8_t arg; + } op; + _Py_BackoffCounter counter; // First cache entry of specializable op +} _Py_CODEUNIT; + + +/* Abstract tree node. */ +typedef struct { + PyObject_HEAD +} PyHamtNode; + + +/* An HAMT immutable mapping collection. */ +typedef struct { + PyObject_HEAD + PyHamtNode *h_root; + PyObject *h_weakreflist; + Py_ssize_t h_count; +} PyHamtObject; + +typedef struct { + PyObject_VAR_HEAD + uint32_t b_bitmap; + PyObject *b_array[1]; +} PyHamtNode_Bitmap; + +#include "pycore_context.h" + +// Define this to get precise tracking of stackrefs. +// #define Py_STACKREF_DEBUG 1 + +typedef union _PyStackRef { +#if !defined(Py_GIL_DISABLED) && defined(Py_STACKREF_DEBUG) + uint64_t index; +#else + uintptr_t bits; +#endif +} _PyStackRef; + + +#ifdef __cplusplus +} +#endif +#endif /* Py_INTERNAL_STRUCTS_H */ diff --git a/Include/internal/pycore_time.h b/Include/internal/pycore_time.h index 833987fd639344..f50c43d8e552b5 100644 --- a/Include/internal/pycore_time.h +++ b/Include/internal/pycore_time.h @@ -57,6 +57,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_runtime_structs.h" #ifdef __clang__ struct timeval; @@ -307,11 +308,6 @@ PyAPI_FUNC(PyTime_t) _PyDeadline_Get(PyTime_t deadline); // --- _PyTimeFraction ------------------------------------------------------- -typedef struct { - PyTime_t numer; - PyTime_t denom; -} _PyTimeFraction; - // Set a fraction. // Return 0 on success. // Return -1 if the fraction is invalid. @@ -330,17 +326,6 @@ extern PyTime_t _PyTimeFraction_Mul( extern double _PyTimeFraction_Resolution( const _PyTimeFraction *frac); - -// --- _Py_time_runtime_state ------------------------------------------------ - -struct _Py_time_runtime_state { -#if defined(MS_WINDOWS) || defined(__APPLE__) - _PyTimeFraction base; -#else - char _unused; -#endif -}; - extern PyStatus _PyTime_Init(struct _Py_time_runtime_state *state); #ifdef __cplusplus diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 581153344a8e05..b5e72b7c38ffff 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -10,6 +10,7 @@ extern "C" { #include "pycore_moduleobject.h" // PyModuleObject #include "pycore_lock.h" // PyMutex +#include "pycore_runtime_structs.h" // type state /* state */ @@ -32,126 +33,6 @@ extern "C" { #define _Py_TYPE_BASE_VERSION_TAG (2<<16) #define _Py_MAX_GLOBAL_TYPE_VERSION_TAG (_Py_TYPE_BASE_VERSION_TAG - 1) -/* For now we hard-code this to a value for which we are confident - all the static builtin types will fit (for all builds). */ -#define _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES 200 -#define _Py_MAX_MANAGED_STATIC_EXT_TYPES 10 -#define _Py_MAX_MANAGED_STATIC_TYPES \ - (_Py_MAX_MANAGED_STATIC_BUILTIN_TYPES + _Py_MAX_MANAGED_STATIC_EXT_TYPES) - -struct _types_runtime_state { - /* Used to set PyTypeObject.tp_version_tag for core static types. */ - // bpo-42745: next_version_tag remains shared by all interpreters - // because of static types. - unsigned int next_version_tag; - - struct { - struct { - PyTypeObject *type; - int64_t interp_count; - } types[_Py_MAX_MANAGED_STATIC_TYPES]; - } managed_static; -}; - - -// Type attribute lookup cache: speed up attribute and method lookups, -// see _PyType_Lookup(). -struct type_cache_entry { - unsigned int version; // initialized from type->tp_version_tag -#ifdef Py_GIL_DISABLED - _PySeqLock sequence; -#endif - PyObject *name; // reference to exactly a str or None - PyObject *value; // borrowed reference or NULL -}; - -#define MCACHE_SIZE_EXP 12 - -struct type_cache { - struct type_cache_entry hashtable[1 << MCACHE_SIZE_EXP]; -}; - -typedef struct { - PyTypeObject *type; - int isbuiltin; - int readying; - int ready; - // XXX tp_dict can probably be statically allocated, - // instead of dynamically and stored on the interpreter. - PyObject *tp_dict; - PyObject *tp_subclasses; - /* We never clean up weakrefs for static builtin types since - they will effectively never get triggered. However, there - are also some diagnostic uses for the list of weakrefs, - so we still keep it. */ - PyObject *tp_weaklist; -} managed_static_type_state; - -#define TYPE_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */ - -struct types_state { - /* Used to set PyTypeObject.tp_version_tag. - It starts at _Py_MAX_GLOBAL_TYPE_VERSION_TAG + 1, - where all those lower numbers are used for core static types. */ - unsigned int next_version_tag; - - struct type_cache type_cache; - - /* Every static builtin type is initialized for each interpreter - during its own initialization, including for the main interpreter - during global runtime initialization. This is done by calling - _PyStaticType_InitBuiltin(). - - The first time a static builtin type is initialized, all the - normal PyType_Ready() stuff happens. The only difference from - normal is that there are three PyTypeObject fields holding - objects which are stored here (on PyInterpreterState) rather - than in the corresponding PyTypeObject fields. Those are: - tp_dict (cls.__dict__), tp_subclasses (cls.__subclasses__), - and tp_weaklist. - - When a subinterpreter is initialized, each static builtin type - is still initialized, but only the interpreter-specific portion, - namely those three objects. - - Those objects are stored in the PyInterpreterState.types.builtins - array, at the index corresponding to each specific static builtin - type. That index (a size_t value) is stored in the tp_subclasses - field. For static builtin types, we re-purposed the now-unused - tp_subclasses to avoid adding another field to PyTypeObject. - In all other cases tp_subclasses holds a dict like before. - (The field was previously defined as PyObject*, but is now void* - to reflect its dual use.) - - The index for each static builtin type isn't statically assigned. - Instead it is calculated the first time a type is initialized - (by the main interpreter). The index matches the order in which - the type was initialized relative to the others. The actual - value comes from the current value of num_builtins_initialized, - as each type is initialized for the main interpreter. - - num_builtins_initialized is incremented once for each static - builtin type. Once initialization is over for a subinterpreter, - the value will be the same as for all other interpreters. */ - struct { - size_t num_initialized; - managed_static_type_state initialized[_Py_MAX_MANAGED_STATIC_BUILTIN_TYPES]; - } builtins; - /* We apply a similar strategy for managed extension modules. */ - struct { - size_t num_initialized; - size_t next_index; - managed_static_type_state initialized[_Py_MAX_MANAGED_STATIC_EXT_TYPES]; - } for_extensions; - PyMutex mutex; - - // Borrowed references to type objects whose - // tp_version_tag % TYPE_VERSION_CACHE_SIZE - // once was equal to the index in the table. - // They are cleared when the type object is deallocated. - PyTypeObject *type_version_cache[TYPE_VERSION_CACHE_SIZE]; -}; - /* runtime lifecycle */ @@ -161,17 +42,6 @@ extern void _PyTypes_FiniExtTypes(PyInterpreterState *interp); extern void _PyTypes_Fini(PyInterpreterState *); extern void _PyTypes_AfterFork(void); -/* 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; - - static inline PyObject ** _PyStaticType_GET_WEAKREFS_LISTPTR(managed_static_type_state *state) { diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index 13c3213132568b..c22be338df48a3 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -287,40 +287,6 @@ extern void _PyUnicode_InternStatic(PyInterpreterState *interp, PyObject **); /* --- Other API ---------------------------------------------------------- */ -struct _Py_unicode_runtime_ids { - PyMutex mutex; - // next_index value must be preserved when Py_Initialize()/Py_Finalize() - // is called multiple times: see _PyUnicode_FromId() implementation. - Py_ssize_t next_index; -}; - -struct _Py_unicode_runtime_state { - struct _Py_unicode_runtime_ids ids; -}; - -/* fs_codec.encoding is initialized to NULL. - Later, it is set to a non-NULL string by _PyUnicode_InitEncodings(). */ -struct _Py_unicode_fs_codec { - char *encoding; // Filesystem encoding (encoded to UTF-8) - int utf8; // encoding=="utf-8"? - char *errors; // Filesystem errors (encoded to UTF-8) - _Py_error_handler error_handler; -}; - -struct _Py_unicode_ids { - Py_ssize_t size; - PyObject **array; -}; - -struct _Py_unicode_state { - struct _Py_unicode_fs_codec fs_codec; - - _PyUnicode_Name_CAPI *ucnhash_capi; - - // Unicode identifiers (_Py_Identifier): see _PyUnicode_FromId() - struct _Py_unicode_ids ids; -}; - extern void _PyUnicode_ClearInterned(PyInterpreterState *interp); // Like PyUnicode_AsUTF8(), but check for embedded null characters. diff --git a/Include/internal/pycore_uniqueid.h b/Include/internal/pycore_uniqueid.h index 9d3c866a704894..c80924d50e677a 100644 --- a/Include/internal/pycore_uniqueid.h +++ b/Include/internal/pycore_uniqueid.h @@ -24,26 +24,6 @@ extern "C" { // Each entry implicitly represents a unique id based on its offset in the // table. Non-allocated entries form a free-list via the 'next' pointer. // Allocated entries store the corresponding PyObject. -typedef union _Py_unique_id_entry { - // Points to the next free type id, when part of the freelist - union _Py_unique_id_entry *next; - - // Stores the object when the id is assigned - PyObject *obj; -} _Py_unique_id_entry; - -struct _Py_unique_id_pool { - PyMutex mutex; - - // combined table of object with allocated unique ids and unallocated ids. - _Py_unique_id_entry *table; - - // Next entry to allocate inside 'table' or NULL - _Py_unique_id_entry *freelist; - - // size of 'table' - Py_ssize_t size; -}; #define _Py_INVALID_UNIQUE_ID 0 diff --git a/Include/internal/pycore_warnings.h b/Include/internal/pycore_warnings.h index 672228cd6fbd19..e1348d529a2246 100644 --- a/Include/internal/pycore_warnings.h +++ b/Include/internal/pycore_warnings.h @@ -8,16 +8,6 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -struct _warnings_runtime_state { - /* Both 'filters' and 'onceregistry' can be set in warnings.py; - get_warnings_attr() will reset these variables accordingly. */ - PyObject *filters; /* List */ - PyObject *once_registry; /* Dict */ - PyObject *default_action; /* String */ - _PyRecursiveMutex lock; - long filters_version; -}; - extern int _PyWarnings_InitState(PyInterpreterState *interp); extern PyObject* _PyWarnings_Init(void); diff --git a/Makefile.pre.in b/Makefile.pre.in index 646096054a7b66..a65854ac125c60 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1255,6 +1255,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_instruments.h \ $(srcdir)/Include/internal/pycore_instruction_sequence.h \ $(srcdir)/Include/internal/pycore_interp.h \ + $(srcdir)/Include/internal/pycore_interp_structs.h \ $(srcdir)/Include/internal/pycore_intrinsics.h \ $(srcdir)/Include/internal/pycore_jit.h \ $(srcdir)/Include/internal/pycore_list.h \ @@ -1297,11 +1298,13 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_runtime.h \ $(srcdir)/Include/internal/pycore_runtime_init.h \ $(srcdir)/Include/internal/pycore_runtime_init_generated.h \ + $(srcdir)/Include/internal/pycore_runtime_structs.h \ $(srcdir)/Include/internal/pycore_semaphore.h \ $(srcdir)/Include/internal/pycore_setobject.h \ $(srcdir)/Include/internal/pycore_signal.h \ $(srcdir)/Include/internal/pycore_sliceobject.h \ $(srcdir)/Include/internal/pycore_strhex.h \ + $(srcdir)/Include/internal/pycore_structs.h \ $(srcdir)/Include/internal/pycore_structseq.h \ $(srcdir)/Include/internal/pycore_symtable.h \ $(srcdir)/Include/internal/pycore_sysmodule.h \ diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c index 471b42badc8e8c..7cf3f152eeecc6 100644 --- a/Modules/_codecsmodule.c +++ b/Modules/_codecsmodule.c @@ -32,6 +32,7 @@ Copyright (c) Corporation for National Research Initiatives. #include "Python.h" #include "pycore_codecs.h" // _PyCodec_Lookup() +#include "pycore_unicodeobject.h" // _PyUnicode_EncodeCharmap #ifdef MS_WINDOWS #include <windows.h> diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 2c88bd3cdf2347..2025724953969b 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -109,6 +109,7 @@ static const char PyCursesVersion[] = "2.2"; #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_structseq.h" // _PyStructSequence_NewType() #include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString() +#include "pycore_fileutils.h" // _Py_set_inheritable #ifdef __hpux #define STRICT_SYSV_CURSES diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index c7cc3a8071dc1c..77695401919cb7 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -32,6 +32,7 @@ Copyright (C) 1994 Steen Lumholt. #include "pycore_long.h" // _PyLong_IsNegative() #include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString() +#include "pycore_unicodeobject.h" // _PyUnicode_AsUTF8String #ifdef MS_WINDOWS # include <windows.h> diff --git a/Objects/genobject.c b/Objects/genobject.c index 2f70df79a3d3b0..9decca5048f5cf 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -3,6 +3,8 @@ #define _PY_INTERPRETER #include "Python.h" +#include "pycore_genobject.h" + #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_EvalFrame() #include "pycore_frame.h" // _PyInterpreterFrame diff --git a/Objects/listobject.c b/Objects/listobject.c index 85eb5e56853b8f..95656686e461ac 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -13,6 +13,7 @@ #include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _PyObject_GC_TRACK(), _PyDebugAllocatorStats() #include "pycore_tuple.h" // _PyTuple_FromArray() +#include "pycore_typeobject.h" // _Py_TYPE_VERSION_LIST #include "pycore_setobject.h" // _PySet_NextEntry() #include <stddef.h> diff --git a/Objects/object.c b/Objects/object.c index 58aec5f2b5b3e1..c8f3831d6f3b82 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -14,6 +14,7 @@ #include "pycore_initconfig.h" // _PyStatus_EXCEPTION() #include "pycore_instruction_sequence.h" // _PyInstructionSequence_Type #include "pycore_hashtable.h" // _Py_hashtable_new() +#include "pycore_hamt.h" // _PyHamtItems_Type #include "pycore_memoryobject.h" // _PyManagedBuffer_Type #include "pycore_namespace.h" // _PyNamespace_Type #include "pycore_object.h" // PyAPI_DATA() _Py_SwappedOp definition diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 085944cd6bd989..7a8ac322197b0e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -53,6 +53,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "pycore_object.h" // _PyObject_GC_TRACK(), _Py_FatalRefcountError() #include "pycore_pathconfig.h" // _Py_DumpPathConfig() #include "pycore_pyerrors.h" // _PyUnicodeTranslateError_Create() +#include "pycore_pyhash.h" // _Py_HashSecret_t #include "pycore_pylifecycle.h" // _Py_SetFileSystemEncoding() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI diff --git a/Parser/pegen.c b/Parser/pegen.c index be1768d0f2cff7..87a9ba02274d9f 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -1,7 +1,10 @@ #include <Python.h> #include "pycore_ast.h" // _PyAST_Validate(), #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_parser.h" // _PYPEGEN_NSTATISTICS #include "pycore_pyerrors.h" // PyExc_IncompleteInputError +#include "pycore_runtime.h" // _PyRuntime +#include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal #include <errcode.h> #include "lexer/lexer.h" diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c index 1dc5bffe1b0003..f0fb87c4a5d15e 100644 --- a/Python/bootstrap_hash.c +++ b/Python/bootstrap_hash.c @@ -1,6 +1,7 @@ #include "Python.h" #include "pycore_fileutils.h" // _Py_fstat_noraise() #include "pycore_initconfig.h" +#include "pycore_pyhash.h" // _Py_HashSecret_t #include "pycore_pylifecycle.h" // _PyOS_URandomNonblock() #include "pycore_runtime.h" // _PyRuntime diff --git a/Python/dtoa.c b/Python/dtoa.c index d0c89b2b468f75..61d776d9a20687 100644 --- a/Python/dtoa.c +++ b/Python/dtoa.c @@ -122,6 +122,7 @@ #include "pycore_pystate.h" // _PyInterpreterState_GET() #include <stdlib.h> // exit() + /* if _PY_SHORT_FLOAT_REPR == 0, then don't even try to compile the following code */ #if _PY_SHORT_FLOAT_REPR == 1 @@ -157,7 +158,7 @@ #endif -// ULong is defined in pycore_dtoa.h. +typedef uint32_t ULong; typedef int32_t Long; typedef uint64_t ULLong; diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c index dcfff2f5bc7d07..30807f428c7d71 100644 --- a/Python/formatter_unicode.c +++ b/Python/formatter_unicode.c @@ -5,6 +5,7 @@ #include "Python.h" #include "pycore_fileutils.h" // _Py_GetLocaleconvNumeric() #include "pycore_long.h" // _PyLong_FormatWriter() +#include "pycore_unicodeobject.h" // PyUnicode_MAX_CHAR_VALUE() #include <locale.h> /* Raises an exception about an unknown presentation type for this diff --git a/Python/initconfig.c b/Python/initconfig.c index 1fe92a021312fa..f73fbe76a96507 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -8,6 +8,7 @@ #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pylifecycle.h" // _Py_PreInitializeFromConfig() #include "pycore_pymem.h" // _PyMem_DefaultRawMalloc() +#include "pycore_pyhash.h" // _Py_HashSecret #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pystats.h" // _Py_StatsOn() #include "pycore_sysmodule.h" // _PySys_SetIntMaxStrDigits() diff --git a/Python/instrumentation.c b/Python/instrumentation.c index c180f4c55c9e1a..299066d9c206b6 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -18,6 +18,7 @@ #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_UINTPTR_RELEASE #include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_runtime_structs.h" // _PyCoMonitoringData /* Uncomment this to dump debugging output when assertions fail */ // #define INSTRUMENT_DEBUG 1 diff --git a/Python/interpconfig.c b/Python/interpconfig.c index 54e5dca284c215..1add8a81425b9a 100644 --- a/Python/interpconfig.c +++ b/Python/interpconfig.c @@ -1,6 +1,7 @@ /* PyInterpreterConfig API */ #include "Python.h" +#include "pycore_interp.h" // Py_RTFLAGS #include "pycore_pylifecycle.h" #include <stdbool.h> diff --git a/Python/intrinsics.c b/Python/intrinsics.c index 275e28f032e3b3..f6dfee3e9ab951 100644 --- a/Python/intrinsics.c +++ b/Python/intrinsics.c @@ -5,12 +5,15 @@ #include "pycore_frame.h" #include "pycore_function.h" #include "pycore_global_objects.h" +#include "pycore_genobject.h" // _PyAsyncGenValueWrapperNew #include "pycore_compile.h" // _PyCompile_GetUnaryIntrinsicName, etc #include "pycore_intrinsics.h" // INTRINSIC_PRINT #include "pycore_pyerrors.h" // _PyErr_SetString() #include "pycore_runtime.h" // _Py_ID() #include "pycore_sysmodule.h" // _PySys_GetRequiredAttr() +#include "pycore_tuple.h" // _PyTuple_FromArray() #include "pycore_typevarobject.h" // _Py_make_typevar() +#include "pycore_unicodeobject.h" // _PyUnicode_FromASCII /******** Unary functions ********/ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 4007e43c98d640..0513d614c6e1ef 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1,7 +1,8 @@ /* Python interpreter top-level routines, including init/exit */ #include "Python.h" - +#include "pycore_runtime_structs.h" +#include "pycore_unicodeobject.h" #include "pycore_audit.h" // _PySys_ClearAuditHooks() #include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_ceval.h" // _PyEval_FiniGIL() @@ -13,6 +14,7 @@ #include "pycore_freelist.h" // _PyObject_ClearFreeLists() #include "pycore_floatobject.h" // _PyFloat_InitTypes() #include "pycore_global_objects_fini_generated.h" // "_PyStaticObjects_CheckRefcnt() +#include "pycore_hamt.h" // _PyHamt_Type #include "pycore_import.h" // _PyImport_BootstrapImp() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_list.h" // _PyList_Fini() diff --git a/Python/pystate.c b/Python/pystate.c index fcd12d1b933360..99f8774d446986 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2,6 +2,8 @@ /* Thread and interpreter state structures and their interfaces */ #include "Python.h" +#include "pycore_runtime_structs.h" + #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_audit.h" // _Py_AuditHookEntry #include "pycore_ceval.h" @@ -18,6 +20,7 @@ #include "pycore_pylifecycle.h" // _PyAST_Fini() #include "pycore_pymem.h" // _PyMem_DebugEnabled() #include "pycore_pystate.h" +#include "pycore_runtime.h" // _PyRuntime #include "pycore_runtime_init.h" // _PyRuntimeState_INIT #include "pycore_stackref.h" // Py_STACKREF_DEBUG #include "pycore_time.h" // _PyTime_Init() diff --git a/Python/suggestions.c b/Python/suggestions.c index 2ce0bcfd54e23f..154a8ade1b0153 100644 --- a/Python/suggestions.c +++ b/Python/suggestions.c @@ -3,6 +3,7 @@ #include "pycore_frame.h" #include "pycore_pyerrors.h" // export _Py_UTF8_Edit_Cost() #include "pycore_runtime.h" // _Py_ID() +#include "pycore_unicodeobject.h" // _PyUnicode_Equal() #define MAX_CANDIDATE_ITEMS 750 #define MAX_STRING_SIZE 40 diff --git a/Tools/build/generate_global_objects.py b/Tools/build/generate_global_objects.py index b5b6de0e7dc2dc..219fea771d53a6 100644 --- a/Tools/build/generate_global_objects.py +++ b/Tools/build/generate_global_objects.py @@ -277,7 +277,7 @@ def generate_runtime_init(identifiers, strings): # First get some info from the declarations. nsmallposints = None nsmallnegints = None - with open(os.path.join(INTERNAL, 'pycore_global_objects.h')) as infile: + with open(os.path.join(INTERNAL, 'pycore_runtime_structs.h')) as infile: for line in infile: if line.startswith('#define _PY_NSMALLPOSINTS'): nsmallposints = int(line.split()[-1]) _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com