From 42bf5cdc132811bb2f85032393ed6206475d826f Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 17 Mar 2025 10:50:51 +0000 Subject: [PATCH 1/5] More refactoring of core header files --- Include/internal/pycore_call.h | 1 + Include/internal/pycore_code.h | 62 --------------------- Include/internal/pycore_dict.h | 1 + Include/internal/pycore_frame.h | 1 + Include/internal/pycore_freelist.h | 2 +- Include/internal/pycore_gc.h | 81 ++++++++++++++++++++++++++++ Include/internal/pycore_interp.h | 20 ------- Include/internal/pycore_object.h | 81 +--------------------------- Include/internal/pycore_pystate.h | 3 +- Include/internal/pycore_typeobject.h | 3 +- Makefile.pre.in | 1 + Modules/_asynciomodule.c | 2 + Modules/_datetimemodule.c | 1 + Modules/_io/bufferedio.c | 1 + Modules/_io/iobase.c | 1 + Modules/_operator.c | 3 ++ Modules/_posixsubprocess.c | 1 + Modules/_sqlite/connection.c | 1 + Modules/_sre/sre.c | 1 + Modules/_threadmodule.c | 1 + Modules/_zoneinfo.c | 1 + Modules/faulthandler.c | 1 + Objects/enumobject.c | 1 + Objects/fileobject.c | 1 + Objects/floatobject.c | 1 + Objects/frameobject.c | 1 + Objects/funcobject.c | 1 + Objects/genobject.c | 2 - Objects/longobject.c | 1 + Objects/obmalloc.c | 1 + Objects/structseq.c | 1 + Objects/typeobject.c | 3 ++ Objects/typevarobject.c | 2 + Objects/unionobject.c | 1 + PCbuild/pythoncore.vcxproj | 5 +- PCbuild/pythoncore.vcxproj.filters | 9 ++++ Parser/action_helpers.c | 1 + Python/ast.c | 1 + Python/ast_opt.c | 1 + Python/bltinmodule.c | 1 + Python/codegen.c | 2 + Python/compile.c | 3 ++ Python/errors.c | 2 + Python/frame.c | 1 + Python/getargs.c | 1 + Python/import.c | 1 + Python/importdl.c | 1 + Python/marshal.c | 1 + Python/pythonrun.c | 1 + Python/specialize.c | 1 + Python/symtable.c | 1 + 51 files changed, 151 insertions(+), 168 deletions(-) diff --git a/Include/internal/pycore_call.h b/Include/internal/pycore_call.h index 49f5c3322de267..38d005c039f7a3 100644 --- a/Include/internal/pycore_call.h +++ b/Include/internal/pycore_call.h @@ -9,6 +9,7 @@ extern "C" { #endif #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_stats.h" /* Suggested size (number of positional arguments) for arrays of PyObject* allocated on a C stack to avoid allocating memory on the heap memory. Such diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 530eaf80e08c63..a1a04815d86536 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -318,68 +318,6 @@ extern void _Py_Specialize_Send(_PyStackRef receiver, _Py_CODEUNIT *instr); extern void _Py_Specialize_ToBool(_PyStackRef value, _Py_CODEUNIT *instr); extern void _Py_Specialize_ContainsOp(_PyStackRef value, _Py_CODEUNIT *instr); -#ifdef Py_STATS - -#include "pycore_bitutils.h" // _Py_bit_length - -#define STAT_INC(opname, name) do { if (_Py_stats) _Py_stats->opcode_stats[opname].specialization.name++; } while (0) -#define STAT_DEC(opname, name) do { if (_Py_stats) _Py_stats->opcode_stats[opname].specialization.name--; } while (0) -#define OPCODE_EXE_INC(opname) do { if (_Py_stats) _Py_stats->opcode_stats[opname].execution_count++; } while (0) -#define CALL_STAT_INC(name) do { if (_Py_stats) _Py_stats->call_stats.name++; } while (0) -#define OBJECT_STAT_INC(name) do { if (_Py_stats) _Py_stats->object_stats.name++; } while (0) -#define OBJECT_STAT_INC_COND(name, cond) \ - do { if (_Py_stats && cond) _Py_stats->object_stats.name++; } while (0) -#define EVAL_CALL_STAT_INC(name) do { if (_Py_stats) _Py_stats->call_stats.eval_calls[name]++; } while (0) -#define EVAL_CALL_STAT_INC_IF_FUNCTION(name, callable) \ - do { if (_Py_stats && PyFunction_Check(callable)) _Py_stats->call_stats.eval_calls[name]++; } while (0) -#define GC_STAT_ADD(gen, name, n) do { if (_Py_stats) _Py_stats->gc_stats[(gen)].name += (n); } while (0) -#define OPT_STAT_INC(name) do { if (_Py_stats) _Py_stats->optimization_stats.name++; } while (0) -#define OPT_STAT_ADD(name, n) do { if (_Py_stats) _Py_stats->optimization_stats.name += (n); } while (0) -#define UOP_STAT_INC(opname, name) do { if (_Py_stats) { assert(opname < 512); _Py_stats->optimization_stats.opcode[opname].name++; } } while (0) -#define UOP_PAIR_INC(uopcode, lastuop) \ - do { \ - if (lastuop && _Py_stats) { \ - _Py_stats->optimization_stats.opcode[lastuop].pair_count[uopcode]++; \ - } \ - lastuop = uopcode; \ - } while (0) -#define OPT_UNSUPPORTED_OPCODE(opname) do { if (_Py_stats) _Py_stats->optimization_stats.unsupported_opcode[opname]++; } while (0) -#define OPT_ERROR_IN_OPCODE(opname) do { if (_Py_stats) _Py_stats->optimization_stats.error_in_opcode[opname]++; } while (0) -#define OPT_HIST(length, name) \ - do { \ - if (_Py_stats) { \ - int bucket = _Py_bit_length(length >= 1 ? length - 1 : 0); \ - bucket = (bucket >= _Py_UOP_HIST_SIZE) ? _Py_UOP_HIST_SIZE - 1 : bucket; \ - _Py_stats->optimization_stats.name[bucket]++; \ - } \ - } while (0) -#define RARE_EVENT_STAT_INC(name) do { if (_Py_stats) _Py_stats->rare_event_stats.name++; } while (0) -#define OPCODE_DEFERRED_INC(opname) do { if (_Py_stats && opcode == opname) _Py_stats->opcode_stats[opname].specialization.deferred++; } while (0) - -// Export for '_opcode' shared extension -PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void); - -#else -#define STAT_INC(opname, name) ((void)0) -#define STAT_DEC(opname, name) ((void)0) -#define OPCODE_EXE_INC(opname) ((void)0) -#define CALL_STAT_INC(name) ((void)0) -#define OBJECT_STAT_INC(name) ((void)0) -#define OBJECT_STAT_INC_COND(name, cond) ((void)0) -#define EVAL_CALL_STAT_INC(name) ((void)0) -#define EVAL_CALL_STAT_INC_IF_FUNCTION(name, callable) ((void)0) -#define GC_STAT_ADD(gen, name, n) ((void)0) -#define OPT_STAT_INC(name) ((void)0) -#define OPT_STAT_ADD(name, n) ((void)0) -#define UOP_STAT_INC(opname, name) ((void)0) -#define UOP_PAIR_INC(uopcode, lastuop) ((void)0) -#define OPT_UNSUPPORTED_OPCODE(opname) ((void)0) -#define OPT_ERROR_IN_OPCODE(opname) ((void)0) -#define OPT_HIST(length, name) ((void)0) -#define RARE_EVENT_STAT_INC(name) ((void)0) -#define OPCODE_DEFERRED_INC(opname) ((void)0) -#endif // !Py_STATS - // Utility functions for reading/writing 32/64-bit values in the inline caches. // Great care should be taken to ensure that these functions remain correct and // performant! They should compile to just "move" instructions on all supported diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index f4c55ca6cf64d2..973772a262e9f2 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -11,6 +11,7 @@ extern "C" { #include "pycore_object.h" // PyManagedDictPointer #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_SSIZE_ACQUIRE #include "pycore_stackref.h" // _PyStackRef +#include "pycore_stats.h" // Unsafe flavor of PyDict_GetItemWithError(): no error checking extern PyObject* _PyDict_GetItemWithError(PyObject *dp, PyObject *key); diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index a3a5d034056dfd..fc395d8a4491fe 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -12,6 +12,7 @@ extern "C" { #include // offsetof() #include "pycore_code.h" // STATS #include "pycore_stackref.h" // _PyStackRef +#include "pycore_stats.h" /* See InternalDocs/frames.md for an explanation of the frame stack * including explanation of the PyFrameObject and _PyInterpreterFrame diff --git a/Include/internal/pycore_freelist.h b/Include/internal/pycore_freelist.h index 84a5ab30f3eeea..9c5a48835fabdf 100644 --- a/Include/internal/pycore_freelist.h +++ b/Include/internal/pycore_freelist.h @@ -11,7 +11,7 @@ extern "C" { #include "pycore_freelist_state.h" // struct _Py_freelists #include "pycore_object.h" // _PyObject_IS_GC #include "pycore_pystate.h" // _PyThreadState_GET -#include "pycore_code.h" // OBJECT_STAT_INC +#include "pycore_stats.h" // OBJECT_STAT_INC static inline struct _Py_freelists * _Py_freelists_GET(void) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 17125131183ed1..107a86178a4d7f 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -9,6 +9,7 @@ extern "C" { #endif #include "pycore_runtime_structs.h" +#include "pycore_pystate.h" /* Get an object's GC head */ @@ -203,6 +204,86 @@ static inline void _PyGC_CLEAR_FINALIZED(PyObject *op) { #endif } + +/* Tell the GC to track this object. + * + * The object must not be tracked by the GC. + * + * NB: While the object is tracked by the collector, it must be safe to call the + * ob_traverse method. + * + * Internal note: interp->gc.generation0->_gc_prev doesn't have any bit flags + * because it's not object header. So we don't use _PyGCHead_PREV() and + * _PyGCHead_SET_PREV() for it to avoid unnecessary bitwise operations. + * + * See also the public PyObject_GC_Track() function. + */ +static inline void _PyObject_GC_TRACK( +// The preprocessor removes _PyObject_ASSERT_FROM() calls if NDEBUG is defined +#ifndef NDEBUG + const char *filename, int lineno, +#endif + PyObject *op) +{ + _PyObject_ASSERT_FROM(op, !_PyObject_GC_IS_TRACKED(op), + "object already tracked by the garbage collector", + filename, lineno, __func__); +#ifdef Py_GIL_DISABLED + _PyObject_SET_GC_BITS(op, _PyGC_BITS_TRACKED); +#else + PyGC_Head *gc = _Py_AS_GC(op); + _PyObject_ASSERT_FROM(op, + (gc->_gc_prev & _PyGC_PREV_MASK_COLLECTING) == 0, + "object is in generation which is garbage collected", + filename, lineno, __func__); + + PyInterpreterState *interp = _PyInterpreterState_GET(); + PyGC_Head *generation0 = &interp->gc.young.head; + PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev); + _PyGCHead_SET_NEXT(last, gc); + _PyGCHead_SET_PREV(gc, last); + uintptr_t not_visited = 1 ^ interp->gc.visited_space; + gc->_gc_next = ((uintptr_t)generation0) | not_visited; + generation0->_gc_prev = (uintptr_t)gc; +#endif +} + +/* Tell the GC to stop tracking this object. + * + * Internal note: This may be called while GC. So _PyGC_PREV_MASK_COLLECTING + * must be cleared. But _PyGC_PREV_MASK_FINALIZED bit is kept. + * + * The object must be tracked by the GC. + * + * See also the public PyObject_GC_UnTrack() which accept an object which is + * not tracked. + */ +static inline void _PyObject_GC_UNTRACK( +// The preprocessor removes _PyObject_ASSERT_FROM() calls if NDEBUG is defined +#ifndef NDEBUG + const char *filename, int lineno, +#endif + PyObject *op) +{ + _PyObject_ASSERT_FROM(op, _PyObject_GC_IS_TRACKED(op), + "object not tracked by the garbage collector", + filename, lineno, __func__); + +#ifdef Py_GIL_DISABLED + _PyObject_CLEAR_GC_BITS(op, _PyGC_BITS_TRACKED); +#else + PyGC_Head *gc = _Py_AS_GC(op); + PyGC_Head *prev = _PyGCHead_PREV(gc); + PyGC_Head *next = _PyGCHead_NEXT(gc); + _PyGCHead_SET_NEXT(prev, next); + _PyGCHead_SET_PREV(next, prev); + gc->_gc_next = 0; + gc->_gc_prev &= _PyGC_PREV_MASK_FINALIZED; +#endif +} + + + /* NOTE: about untracking of mutable objects. diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 791038d45b3775..a5502629769e8e 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -100,9 +100,6 @@ extern void _PyInterpreterState_SetWhence( PyInterpreterState *interp, long whence); -extern const PyConfig* _PyInterpreterState_GetConfig(PyInterpreterState *interp); - - /* Runtime Feature Flags @@ -137,23 +134,6 @@ PyAPI_FUNC(PyStatus) _PyInterpreterState_New( PyThreadState *tstate, PyInterpreterState **pinterp); - -#define RARE_EVENT_INTERP_INC(interp, name) \ - do { \ - /* saturating add */ \ - int val = FT_ATOMIC_LOAD_UINT8_RELAXED(interp->rare_events.name); \ - if (val < UINT8_MAX) { \ - FT_ATOMIC_STORE_UINT8(interp->rare_events.name, val + 1); \ - } \ - RARE_EVENT_STAT_INC(name); \ - } while (0); \ - -#define RARE_EVENT_INC(name) \ - do { \ - PyInterpreterState *interp = PyInterpreterState_Get(); \ - RARE_EVENT_INTERP_INC(interp, name); \ - } while (0); \ - #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 0b686b416ec193..b0a7acd3ec9cc1 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -11,10 +11,9 @@ extern "C" { #include #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() #include "pycore_emscripten_trampoline.h" // _PyCFunction_TrampolineCall() -#include "pycore_interp.h" // PyInterpreterState.gc #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_PTR_RELAXED #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_stackref.h" +#include "pycore_typeobject.h" // _PyStaticType_GetState() #include "pycore_uniqueid.h" // _PyObject_ThreadIncrefSlow() // This value is added to `ob_ref_shared` for objects that use deferred @@ -455,84 +454,6 @@ _PyObject_InitVar(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size) Py_SET_SIZE(op, size); } - -/* Tell the GC to track this object. - * - * The object must not be tracked by the GC. - * - * NB: While the object is tracked by the collector, it must be safe to call the - * ob_traverse method. - * - * Internal note: interp->gc.generation0->_gc_prev doesn't have any bit flags - * because it's not object header. So we don't use _PyGCHead_PREV() and - * _PyGCHead_SET_PREV() for it to avoid unnecessary bitwise operations. - * - * See also the public PyObject_GC_Track() function. - */ -static inline void _PyObject_GC_TRACK( -// The preprocessor removes _PyObject_ASSERT_FROM() calls if NDEBUG is defined -#ifndef NDEBUG - const char *filename, int lineno, -#endif - PyObject *op) -{ - _PyObject_ASSERT_FROM(op, !_PyObject_GC_IS_TRACKED(op), - "object already tracked by the garbage collector", - filename, lineno, __func__); -#ifdef Py_GIL_DISABLED - _PyObject_SET_GC_BITS(op, _PyGC_BITS_TRACKED); -#else - PyGC_Head *gc = _Py_AS_GC(op); - _PyObject_ASSERT_FROM(op, - (gc->_gc_prev & _PyGC_PREV_MASK_COLLECTING) == 0, - "object is in generation which is garbage collected", - filename, lineno, __func__); - - PyInterpreterState *interp = _PyInterpreterState_GET(); - PyGC_Head *generation0 = &interp->gc.young.head; - PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev); - _PyGCHead_SET_NEXT(last, gc); - _PyGCHead_SET_PREV(gc, last); - uintptr_t not_visited = 1 ^ interp->gc.visited_space; - gc->_gc_next = ((uintptr_t)generation0) | not_visited; - generation0->_gc_prev = (uintptr_t)gc; -#endif -} - -/* Tell the GC to stop tracking this object. - * - * Internal note: This may be called while GC. So _PyGC_PREV_MASK_COLLECTING - * must be cleared. But _PyGC_PREV_MASK_FINALIZED bit is kept. - * - * The object must be tracked by the GC. - * - * See also the public PyObject_GC_UnTrack() which accept an object which is - * not tracked. - */ -static inline void _PyObject_GC_UNTRACK( -// The preprocessor removes _PyObject_ASSERT_FROM() calls if NDEBUG is defined -#ifndef NDEBUG - const char *filename, int lineno, -#endif - PyObject *op) -{ - _PyObject_ASSERT_FROM(op, _PyObject_GC_IS_TRACKED(op), - "object not tracked by the garbage collector", - filename, lineno, __func__); - -#ifdef Py_GIL_DISABLED - _PyObject_CLEAR_GC_BITS(op, _PyGC_BITS_TRACKED); -#else - PyGC_Head *gc = _Py_AS_GC(op); - PyGC_Head *prev = _PyGCHead_PREV(gc); - PyGC_Head *next = _PyGCHead_NEXT(gc); - _PyGCHead_SET_NEXT(prev, next); - _PyGCHead_SET_PREV(next, prev); - gc->_gc_next = 0; - gc->_gc_prev &= _PyGC_PREV_MASK_FINALIZED; -#endif -} - // Macros to accept any type for the parameter, and to automatically pass // the filename and the filename (if NDEBUG is not defined) where the macro // is called. diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index d4867a7b96bfeb..0a2ccd898dcd20 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -11,7 +11,8 @@ extern "C" { #include "pycore_runtime_structs.h" // _PyRuntime #include "pycore_runtime.h" // _PyRuntimeState_GetFinalizing #include "pycore_tstate.h" // _PyThreadStateImpl -#include "pycore_interp.h" // _PyInterpreterState_GetConfig + +extern const PyConfig* _PyInterpreterState_GetConfig(PyInterpreterState *interp); // 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_typeobject.h b/Include/internal/pycore_typeobject.h index b5e72b7c38ffff..a5bea7116ba807 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -8,9 +8,10 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_function.h" #include "pycore_moduleobject.h" // PyModuleObject -#include "pycore_lock.h" // PyMutex #include "pycore_runtime_structs.h" // type state +#include "pycore_stats.h" /* state */ diff --git a/Makefile.pre.in b/Makefile.pre.in index a65854ac125c60..05ff1b959bdbaa 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1303,6 +1303,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_setobject.h \ $(srcdir)/Include/internal/pycore_signal.h \ $(srcdir)/Include/internal/pycore_sliceobject.h \ + $(srcdir)/Include/internal/pycore_stats.h \ $(srcdir)/Include/internal/pycore_strhex.h \ $(srcdir)/Include/internal/pycore_structs.h \ $(srcdir)/Include/internal/pycore_structseq.h \ diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 4822afbfdcdc81..3c2622acdd1443 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -6,7 +6,9 @@ #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION_MUT() #include "pycore_dict.h" // _PyDict_GetItem_KnownHash() #include "pycore_freelist.h" // _Py_FREELIST_POP() +#include "pycore_genobject.h" #include "pycore_llist.h" // struct llist_node +#include "pycore_list.h" // _PyList_AppendTakeRef() #include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_object.h" // _PyObject_SetMaybeWeakref diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 83b92fe606984c..70b59d67f56bda 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -13,6 +13,7 @@ #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_object.h" // _PyObject_Init() #include "pycore_time.h" // _PyTime_ObjectToTime_t() +#include "pycore_unicodeobject.h" // _PyUnicode_Copy() #include "datetime.h" diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 57aa990941eb4b..7028c1ad9d1b94 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -9,6 +9,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() +#include "pycore_fileutils.h" // _PyFile_Flush #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_pyerrors.h" // _Py_FatalErrorFormat() #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 7e0822e3350eeb..cd4c7e7cead277 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -10,6 +10,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallMethod() +#include "pycore_fileutils.h" // _PyFile_Flush #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_object.h" // _PyType_HasFeature() #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() diff --git a/Modules/_operator.c b/Modules/_operator.c index c287ea2780c528..8f5c25ebb81a1b 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -3,6 +3,9 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_runtime.h" // _Py_ID() #include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_unicodeobject.h" // _PyUnicode_InternMortal() +#include "pycore_tuple.h" // _PyTuple_ITEMS() +#include "pycore_typeobject.h" // _PyType_GetModuleState() #include "clinic/_operator.c.h" diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index ad6d7ceda84e37..422bb32f103be7 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -5,6 +5,7 @@ #include "Python.h" #include "pycore_fileutils.h" +#include "pycore_interp.h" // _PyInterpreterState_GetFinalizing #include "pycore_pystate.h" #include "pycore_signal.h" // _Py_RestoreSignals() #if defined(HAVE_PIPE2) && !defined(_GNU_SOURCE) diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 13bc0b9199c4c4..2a184f787542ec 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -37,6 +37,7 @@ #include "pycore_modsupport.h" // _PyArg_NoKeywords() #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() +#include "pycore_unicodeobject.h" // _PyUnicode_AsUTF8NoNUL #include "pycore_weakref.h" #include diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 1c0e44c933a7bf..0e614d99ad35a4 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -43,6 +43,7 @@ static const char copyright[] = #include "pycore_dict.h" // _PyDict_Next() #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_unicodeobject.h" // _PyUnicode_Copy #include "sre.h" // SRE_CODE diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index ef045fce3df9aa..643f5dc47ab7a7 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -2,6 +2,7 @@ /* Interface to Sjoerd's portable C thread library */ #include "Python.h" +#include "pycore_fileutils.h" // _PyFile_Flush #include "pycore_interp.h" // _PyInterpreterState.threads.count #include "pycore_lock.h" #include "pycore_moduleobject.h" // _PyModule_GetState() diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index 8c882bef24867e..ff1cd96d21dbaa 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -6,6 +6,7 @@ #include "pycore_critical_section.h" // _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED() #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() +#include "pycore_typeobject.h" // _PyType_GetModuleState() #include "datetime.h" // PyDateTime_TZInfo diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index fac10190d314da..1cdd2952e397d5 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -2,6 +2,7 @@ #include "pycore_ceval.h" // _PyEval_IsGILEnabled #include "pycore_initconfig.h" // _PyStatus_ERR #include "pycore_pyerrors.h" // _Py_DumpExtensionModules +#include "pycore_fileutils.h" // _PyFile_Flush #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_signal.h" // Py_NSIG #include "pycore_sysmodule.h" // _PySys_GetRequiredAttr() diff --git a/Objects/enumobject.c b/Objects/enumobject.c index cbe91eec114230..f5d9d41262a157 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -5,6 +5,7 @@ #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _PyObject_GC_TRACK() +#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString #include "clinic/enumobject.c.h" diff --git a/Objects/fileobject.c b/Objects/fileobject.c index c9a20ccd75324a..bd96b43e62e9df 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_runtime.h" // _PyRuntime +#include "pycore_unicodeobject.h" // _PyUnicode_AsUTF8String #ifdef HAVE_UNISTD_H # include // isatty() diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 324abddcf2a46d..af43357439d309 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -14,6 +14,7 @@ #include "pycore_object.h" // _PyObject_Init(), _PyDebugAllocatorStats() #include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR #include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_stackref.h" // PyStackRef_AsPyObjectBorrow() #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() #include // DBL_MAX diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 001b58dc052416..152005a19a8565 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -5,6 +5,7 @@ #include "pycore_code.h" // CO_FAST_LOCAL, etc. #include "pycore_dict.h" // _PyDict_LoadBuiltinsFromGlobals() #include "pycore_function.h" // _PyFunction_FromConstructor() +#include "pycore_genobject.h" // _PyGen_GetGeneratorFromFrame() #include "pycore_moduleobject.h" // _PyModule_GetDict() #include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_object.h" // _PyObject_GC_UNTRACK() diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 169db2048c6a74..f5e519dad471e8 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -7,6 +7,7 @@ #include "pycore_modsupport.h" // _PyArg_NoKeywords() #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_pyerrors.h" // _PyErr_Occurred() +#include "pycore_stats.h" static const char * diff --git a/Objects/genobject.c b/Objects/genobject.c index 9decca5048f5cf..005f1a13c4b4c2 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -17,8 +17,6 @@ #include "pycore_pyerrors.h" // _PyErr_ClearExcState() #include "pycore_pystate.h" // _PyThreadState_GET() -#include "pystats.h" - // Forward declarations static PyObject* gen_close(PyObject *, PyObject *); static PyObject* async_gen_asend_new(PyAsyncGenObject *, PyObject *); diff --git a/Objects/longobject.c b/Objects/longobject.c index 51ecbd9e0ee0bd..9498c06c4208e7 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -11,6 +11,7 @@ #include "pycore_object.h" // _PyObject_Init() #include "pycore_runtime.h" // _PY_NSMALLPOSINTS #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() +#include "pycore_unicodeobject.h" // _PyUnicode_Equal() #include // DBL_MANT_DIG #include // offsetof diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index 33fca3abfb3509..189a673882dc78 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_code.h" // stats +#include "pycore_interp.h" // _PyInterpreterState_HasFeature #include "pycore_object.h" // _PyDebugAllocatorStats() definition #include "pycore_obmalloc.h" #include "pycore_pyerrors.h" // _Py_FatalErrorFormat() diff --git a/Objects/structseq.c b/Objects/structseq.c index b7741209df9264..a1b6dd624b3a37 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -13,6 +13,7 @@ #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_structseq.h" // PyStructSequence_InitType() #include "pycore_tuple.h" // _PyTuple_FromArray() +#include "pycore_typeobject.h" // _PyStaticType_FiniBuiltin() static const char visible_length_key[] = "n_sequence_fields"; static const char real_length_key[] = "n_fields"; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index bc840ed51ffe4c..6bfcb7622e9adf 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6,6 +6,7 @@ #include "pycore_code.h" // CO_FAST_FREE #include "pycore_dict.h" // _PyDict_KeysSize() #include "pycore_frame.h" // _PyInterpreterFrame +#include "pycore_function.h" // _PyFunction_GetVersionForCurrentState() #include "pycore_lock.h" // _PySeqLock_* #include "pycore_long.h" // _PyLong_IsNegative(), _PyLong_GetOne() #include "pycore_memoryobject.h" // _PyMemoryView_FromBufferProc() @@ -18,9 +19,11 @@ #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_symtable.h" // _Py_Mangle() #include "pycore_typeobject.h" // struct type_cache +#include "pycore_unicodeobject.h" // _PyUnicode_Copy #include "pycore_unionobject.h" // _Py_union_type_or #include "pycore_weakref.h" // _PyWeakref_GET_REF() #include "pycore_cell.h" // PyCell_GetRef() +#include "pycore_stats.h" #include "opcode.h" // MAKE_CELL #include // ptrdiff_t diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 258969c6fa4ba8..92d8a919ba51ce 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -1,8 +1,10 @@ // TypeVar, TypeVarTuple, ParamSpec, and TypeAlias #include "Python.h" +#include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK, PyAnnotateFormat #include "pycore_typevarobject.h" #include "pycore_unionobject.h" // _Py_union_type_or, _Py_union_from_tuple +#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString() #include "structmember.h" /*[clinic input] diff --git a/Objects/unionobject.c b/Objects/unionobject.c index 065b0b8539775c..08422662e8118a 100644 --- a/Objects/unionobject.c +++ b/Objects/unionobject.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK #include "pycore_typevarobject.h" // _PyTypeAlias_Type, _Py_typing_type_repr +#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString #include "pycore_unionobject.h" diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 4eda251ee0ce53..24d0afad0f6100 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -292,15 +292,18 @@ + + + + - diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 6c76a6ab592a84..14eebd978db73e 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -219,15 +219,24 @@ Include + + Include + Include Include + + Include + Include + + Include + Include diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 52d63401a6e6b5..2489183072888e 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -4,6 +4,7 @@ #include "string_parser.h" #include "pycore_runtime.h" // _PyRuntime #include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal() void * _PyPegen_dummy_name(Parser *p, ...) diff --git a/Python/ast.c b/Python/ast.c index 597df5b63b5f39..fb0acbc157b4ee 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -5,6 +5,7 @@ #include "Python.h" #include "pycore_ast.h" // asdl_stmt_seq #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString #include #include diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 2c6e16817f2aad..d3e044ca5a1517 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -5,6 +5,7 @@ #include "pycore_long.h" // _PyLong #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_setobject.h" // _PySet_NextEntry() +#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString() typedef struct { diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index c5455bef59a655..9f14d1745575d6 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -5,6 +5,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_Vector() #include "pycore_compile.h" // _PyAST_Compile() +#include "pycore_fileutils.h" // _PyFile_Flush #include "pycore_long.h" // _PyLong_CompactValue #include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _Py_AddToAllObjects() diff --git a/Python/codegen.c b/Python/codegen.c index a049417033046d..e1f647451f7002 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -19,6 +19,7 @@ #include "pycore_opcode_utils.h" #undef NEED_OPCODE_TABLES #include "pycore_c_array.h" // _Py_c_array_t +#include "pycore_code.h" // COMPARISON_LESS_THAN #include "pycore_compile.h" #include "pycore_instruction_sequence.h" // _PyInstructionSequence_NewLabel() #include "pycore_intrinsics.h" @@ -26,6 +27,7 @@ #include "pycore_object.h" // _Py_ANNOTATE_FORMAT_VALUE_WITH_FAKE_GLOBALS #include "pycore_pystate.h" // _Py_GetConfig() #include "pycore_symtable.h" // PySTEntryObject +#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString #define NEED_OPCODE_METADATA #include "pycore_opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed diff --git a/Python/compile.c b/Python/compile.c index cd68b897cf6188..dc55aef4f32f4d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -16,10 +16,13 @@ #include "Python.h" #include "pycore_ast.h" // PyAST_Check, _PyAST_GetDocString() +#include "pycore_code.h" #include "pycore_compile.h" #include "pycore_flowgraph.h" #include "pycore_pystate.h" // _Py_GetConfig() #include "pycore_setobject.h" // _PySet_NextEntry() +#include "pycore_stats.h" +#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString() #include "cpython/code.h" diff --git a/Python/errors.c b/Python/errors.c index bf48c107e253a3..1c632a79954cb4 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -4,12 +4,14 @@ #include "Python.h" #include "pycore_audit.h" // _PySys_Audit() #include "pycore_call.h" // _PyObject_CallNoArgs() +#include "pycore_fileutils.h" // _PyFile_Flush #include "pycore_initconfig.h" // _PyStatus_ERR() #include "pycore_pyerrors.h" // _PyErr_Format() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() #include "pycore_sysmodule.h" // _PySys_GetOptionalAttr() #include "pycore_traceback.h" // _PyTraceBack_FromFrame() +#include "pycore_unicodeobject.h" // _PyUnicode_Equal #ifdef MS_WINDOWS # include diff --git a/Python/frame.c b/Python/frame.c index afb3e768491540..166ce07882126a 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -5,6 +5,7 @@ #include "frameobject.h" #include "pycore_code.h" // stats #include "pycore_frame.h" +#include "pycore_genobject.h" #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "opcode.h" diff --git a/Python/getargs.c b/Python/getargs.c index 6485a714a4e3fe..022a4115038902 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -10,6 +10,7 @@ #include "pycore_pystate.h" // _Py_IsMainInterpreter() #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_pyerrors.h" // _Py_CalculateSuggestions() +#include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal /* Export Stable ABIs (abi only) */ PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...); diff --git a/Python/import.c b/Python/import.c index 78b380ca6e505c..690793edb807f4 100644 --- a/Python/import.c +++ b/Python/import.c @@ -8,6 +8,7 @@ #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_interp.h" // struct _import_runtime_state #include "pycore_magic_number.h" // PYC_MAGIC_NUMBER_TOKEN +#include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_namespace.h" // _PyNamespace_Type #include "pycore_object.h" // _Py_SetImmortal() #include "pycore_pyerrors.h" // _PyErr_SetString() diff --git a/Python/importdl.c b/Python/importdl.c index 996ca7ed2a3108..06cc95bef2e551 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -4,6 +4,7 @@ #include "Python.h" #include "pycore_call.h" #include "pycore_import.h" +#include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_pyerrors.h" // _PyErr_FormatFromCause() #include "pycore_pystate.h" #include "pycore_runtime.h" diff --git a/Python/marshal.c b/Python/marshal.c index cf7011652513ae..c1e9114bc03a64 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -15,6 +15,7 @@ #include "pycore_setobject.h" // _PySet_NextEntry() #include "marshal.h" // Py_MARSHAL_VERSION #include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_unicodeobject.h" // _PyUnicode_InternalImmortal() #ifdef __APPLE__ # include "TargetConditionals.h" diff --git a/Python/pythonrun.c b/Python/pythonrun.c index ebe222b736c50e..41f2174b2d6037 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -14,6 +14,7 @@ #include "pycore_audit.h" // _PySys_Audit() #include "pycore_ceval.h" // _Py_EnterRecursiveCall() #include "pycore_compile.h" // _PyAST_Compile() +#include "pycore_fileutils.h" // _PyFile_Flush #include "pycore_interp.h" // PyInterpreterState.importlib #include "pycore_object.h" // _PyDebug_PrintTotalRefs() #include "pycore_parser.h" // _PyParser_ASTFromString() diff --git a/Python/specialize.c b/Python/specialize.c index 0466b5bee90330..89791ed1d8409c 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -6,6 +6,7 @@ #include "pycore_critical_section.h" #include "pycore_descrobject.h" // _PyMethodWrapper_Type #include "pycore_dict.h" // DICT_KEYS_UNICODE +#include "pycore_frame.h" // FRAME_SPECIALS_SIZE #include "pycore_function.h" // _PyFunction_GetVersionForCurrentState() #include "pycore_long.h" // _PyLong_IsNonNegativeCompact() #include "pycore_moduleobject.h" diff --git a/Python/symtable.c b/Python/symtable.c index 4d6384f597f1f0..7dc8b6d6093c93 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -3,6 +3,7 @@ #include "pycore_parser.h" // _PyParser_ASTFromString() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_symtable.h" // PySTEntryObject +#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString // Set this to 1 to dump all symtables to stdout for debugging #define _PY_DUMP_SYMTABLE 0 From c24f24f07e63b5a849bbcdf6ea1f5a10dc6f8dce Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 17 Mar 2025 10:53:23 +0000 Subject: [PATCH 2/5] Add new file --- Include/internal/pycore_stats.h | 97 +++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 Include/internal/pycore_stats.h diff --git a/Include/internal/pycore_stats.h b/Include/internal/pycore_stats.h new file mode 100644 index 00000000000000..ab649574f33dbf --- /dev/null +++ b/Include/internal/pycore_stats.h @@ -0,0 +1,97 @@ +#ifndef Py_INTERNAL_STATS_H +#define Py_INTERNAL_STATS_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#include "pycore_structs.h" // + + +#ifdef Py_STATS + +#include "pycore_bitutils.h" // _Py_bit_length + +#define STAT_INC(opname, name) do { if (_Py_stats) _Py_stats->opcode_stats[opname].specialization.name++; } while (0) +#define STAT_DEC(opname, name) do { if (_Py_stats) _Py_stats->opcode_stats[opname].specialization.name--; } while (0) +#define OPCODE_EXE_INC(opname) do { if (_Py_stats) _Py_stats->opcode_stats[opname].execution_count++; } while (0) +#define CALL_STAT_INC(name) do { if (_Py_stats) _Py_stats->call_stats.name++; } while (0) +#define OBJECT_STAT_INC(name) do { if (_Py_stats) _Py_stats->object_stats.name++; } while (0) +#define OBJECT_STAT_INC_COND(name, cond) \ + do { if (_Py_stats && cond) _Py_stats->object_stats.name++; } while (0) +#define EVAL_CALL_STAT_INC(name) do { if (_Py_stats) _Py_stats->call_stats.eval_calls[name]++; } while (0) +#define EVAL_CALL_STAT_INC_IF_FUNCTION(name, callable) \ + do { if (_Py_stats && PyFunction_Check(callable)) _Py_stats->call_stats.eval_calls[name]++; } while (0) +#define GC_STAT_ADD(gen, name, n) do { if (_Py_stats) _Py_stats->gc_stats[(gen)].name += (n); } while (0) +#define OPT_STAT_INC(name) do { if (_Py_stats) _Py_stats->optimization_stats.name++; } while (0) +#define OPT_STAT_ADD(name, n) do { if (_Py_stats) _Py_stats->optimization_stats.name += (n); } while (0) +#define UOP_STAT_INC(opname, name) do { if (_Py_stats) { assert(opname < 512); _Py_stats->optimization_stats.opcode[opname].name++; } } while (0) +#define UOP_PAIR_INC(uopcode, lastuop) \ + do { \ + if (lastuop && _Py_stats) { \ + _Py_stats->optimization_stats.opcode[lastuop].pair_count[uopcode]++; \ + } \ + lastuop = uopcode; \ + } while (0) +#define OPT_UNSUPPORTED_OPCODE(opname) do { if (_Py_stats) _Py_stats->optimization_stats.unsupported_opcode[opname]++; } while (0) +#define OPT_ERROR_IN_OPCODE(opname) do { if (_Py_stats) _Py_stats->optimization_stats.error_in_opcode[opname]++; } while (0) +#define OPT_HIST(length, name) \ + do { \ + if (_Py_stats) { \ + int bucket = _Py_bit_length(length >= 1 ? length - 1 : 0); \ + bucket = (bucket >= _Py_UOP_HIST_SIZE) ? _Py_UOP_HIST_SIZE - 1 : bucket; \ + _Py_stats->optimization_stats.name[bucket]++; \ + } \ + } while (0) +#define RARE_EVENT_STAT_INC(name) do { if (_Py_stats) _Py_stats->rare_event_stats.name++; } while (0) +#define OPCODE_DEFERRED_INC(opname) do { if (_Py_stats && opcode == opname) _Py_stats->opcode_stats[opname].specialization.deferred++; } while (0) + +// Export for '_opcode' shared extension +PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void); + +#else +#define STAT_INC(opname, name) ((void)0) +#define STAT_DEC(opname, name) ((void)0) +#define OPCODE_EXE_INC(opname) ((void)0) +#define CALL_STAT_INC(name) ((void)0) +#define OBJECT_STAT_INC(name) ((void)0) +#define OBJECT_STAT_INC_COND(name, cond) ((void)0) +#define EVAL_CALL_STAT_INC(name) ((void)0) +#define EVAL_CALL_STAT_INC_IF_FUNCTION(name, callable) ((void)0) +#define GC_STAT_ADD(gen, name, n) ((void)0) +#define OPT_STAT_INC(name) ((void)0) +#define OPT_STAT_ADD(name, n) ((void)0) +#define UOP_STAT_INC(opname, name) ((void)0) +#define UOP_PAIR_INC(uopcode, lastuop) ((void)0) +#define OPT_UNSUPPORTED_OPCODE(opname) ((void)0) +#define OPT_ERROR_IN_OPCODE(opname) ((void)0) +#define OPT_HIST(length, name) ((void)0) +#define RARE_EVENT_STAT_INC(name) ((void)0) +#define OPCODE_DEFERRED_INC(opname) ((void)0) +#endif // !Py_STATS + + +#define RARE_EVENT_INTERP_INC(interp, name) \ + do { \ + /* saturating add */ \ + int val = FT_ATOMIC_LOAD_UINT8_RELAXED(interp->rare_events.name); \ + if (val < UINT8_MAX) { \ + FT_ATOMIC_STORE_UINT8(interp->rare_events.name, val + 1); \ + } \ + RARE_EVENT_STAT_INC(name); \ + } while (0); \ + +#define RARE_EVENT_INC(name) \ + do { \ + PyInterpreterState *interp = PyInterpreterState_Get(); \ + RARE_EVENT_INTERP_INC(interp, name); \ + } while (0); \ + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_STATS_H */ From 5eccfab54e7e962b2ae5421c5f0657b4e5bf7084 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 17 Mar 2025 11:26:08 +0000 Subject: [PATCH 3/5] More refactoring for free-threading --- Include/internal/pycore_object.h | 16 +--------------- Include/internal/pycore_stackref.h | 19 +++++++++++++++++++ Objects/listobject.c | 1 + Python/bytecodes.c | 1 + Python/specialize.c | 1 + 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index b0a7acd3ec9cc1..ce86f9b93fe7ab 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -9,8 +9,8 @@ extern "C" { #endif #include -#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() #include "pycore_emscripten_trampoline.h" // _PyCFunction_TrampolineCall() +#include "pycore_object_deferred.h" // _PyObject_HasDeferredRefcount #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_PTR_RELAXED #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_typeobject.h" // _PyStaticType_GetState() @@ -539,20 +539,6 @@ _Py_TryIncrefCompare(PyObject **src, PyObject *op) return 1; } -static inline int -_Py_TryIncrefCompareStackRef(PyObject **src, PyObject *op, _PyStackRef *out) -{ - if (_PyObject_HasDeferredRefcount(op)) { - *out = (_PyStackRef){ .bits = (intptr_t)op | Py_TAG_DEFERRED }; - return 1; - } - if (_Py_TryIncrefCompare(src, op)) { - *out = PyStackRef_FromPyObjectSteal(op); - return 1; - } - return 0; -} - /* Loads and increfs an object from ptr, which may contain a NULL value. Safe with concurrent (atomic) updates to ptr. NOTE: The writer must set maybe-weakref on the stored object! */ diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index 398a1bdaf1cf81..9a9ec4be5b6ebf 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -14,6 +14,7 @@ extern "C" { #endif #include "pycore_object_deferred.h" +#include "pycore_object.h" #include #include @@ -639,6 +640,24 @@ PyStackRef_FunctionCheck(_PyStackRef stackref) return PyFunction_Check(PyStackRef_AsPyObjectBorrow(stackref)); } +#ifdef Py_GIL_DISABLED + +static inline int +_Py_TryIncrefCompareStackRef(PyObject **src, PyObject *op, _PyStackRef *out) +{ + if (_PyObject_HasDeferredRefcount(op)) { + *out = (_PyStackRef){ .bits = (intptr_t)op | Py_TAG_DEFERRED }; + return 1; + } + if (_Py_TryIncrefCompare(src, op)) { + *out = PyStackRef_FromPyObjectSteal(op); + return 1; + } + return 0; +} + +#endif + #ifdef __cplusplus } #endif diff --git a/Objects/listobject.c b/Objects/listobject.c index 95656686e461ac..917bef1a66ddff 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -12,6 +12,7 @@ #include "pycore_long.h" // _PyLong_DigitCount #include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _PyObject_GC_TRACK(), _PyDebugAllocatorStats() +#include "pycore_stackref.h" // _Py_TryIncrefCompareStackRef() #include "pycore_tuple.h" // _PyTuple_FromArray() #include "pycore_typeobject.h" // _Py_TYPE_VERSION_LIST #include "pycore_setobject.h" // _PySet_NextEntry() diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 7af4d642edb919..66546080b1f5fe 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -29,6 +29,7 @@ #include "pycore_long.h" // _PyLong_ExactDealloc() #include "pycore_setobject.h" // _PySet_NextEntry() #include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs +#include "pycore_stackref.h" #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_typeobject.h" // _PySuper_Lookup() diff --git a/Python/specialize.c b/Python/specialize.c index 89791ed1d8409c..07c49140446c12 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -8,6 +8,7 @@ #include "pycore_dict.h" // DICT_KEYS_UNICODE #include "pycore_frame.h" // FRAME_SPECIALS_SIZE #include "pycore_function.h" // _PyFunction_GetVersionForCurrentState() +#include "pycore_list.h" // _PyListIterObject #include "pycore_long.h" // _PyLong_IsNonNegativeCompact() #include "pycore_moduleobject.h" #include "pycore_object.h" From 76915b8577ef81474a436f41bacd7d06e3913096 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 17 Mar 2025 11:31:17 +0000 Subject: [PATCH 4/5] Add missing include for JIT build --- Python/optimizer_symbols.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 5adc1c8a62ce8b..8445546ffdf716 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -6,6 +6,7 @@ #include "pycore_frame.h" #include "pycore_long.h" #include "pycore_optimizer.h" +#include "pycore_tuple.h" // _PyTuple_FromArray() #include #include From 82cb3d5a010b24b9706ebc3421b94f5f8d620eed Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 17 Mar 2025 11:38:06 +0000 Subject: [PATCH 5/5] Add missing include for Windows --- Modules/_winapi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 4391bfc09f9cb8..fd518212717c40 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -38,6 +38,7 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() #include "pycore_pystate.h" // _PyInterpreterState_GET +#include "pycore_unicodeobject.h" // _PyUnicode_WideCharString_Opt_Converter