From 988cb277dd488f0099d9199504f264cc5c80ad9e Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 24 Aug 2025 20:45:53 +0800 Subject: [PATCH 1/2] Move stackref buffer to thread state to reduce interp stack usage --- Include/internal/pycore_tstate.h | 7 +++++++ Python/ceval_macros.h | 8 +++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h index bad968428c73a1..0f51cf1d2574dc 100644 --- a/Include/internal/pycore_tstate.h +++ b/Include/internal/pycore_tstate.h @@ -21,6 +21,10 @@ struct _gc_thread_state { }; #endif +/* How much scratch space to give stackref to PyObject* conversion. */ +#define MAX_STACKREF_SCRATCH 10 + + // Every PyThreadState is actually allocated as a _PyThreadStateImpl. The // PyThreadState fields are exposed as part of the C API, although most fields // are intended to be private. The _PyThreadStateImpl fields not exposed. @@ -47,6 +51,9 @@ typedef struct _PyThreadStateImpl { struct _qsbr_thread_state *qsbr; // only used by free-threaded build struct llist_node mem_free_queue; // delayed free queue + // Scratch space to convert _PyStackRef to PyObject * + // +1 to account for possible vectorcalls. + PyObject *stackref_scratch[MAX_STACKREF_SCRATCH + 1]; #ifdef Py_GIL_DISABLED // Stack references for the current thread that exist on the C stack struct _PyCStackRef *c_stack_refs; diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 64ca7716fdbdee..6e41e4146ad822 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -390,13 +390,11 @@ do { \ /* Stackref macros */ -/* How much scratch space to give stackref to PyObject* conversion. */ -#define MAX_STACKREF_SCRATCH 10 - #define STACKREFS_TO_PYOBJECTS(ARGS, ARG_COUNT, NAME) \ /* +1 because vectorcall might use -1 to write self */ \ - PyObject *NAME##_temp[MAX_STACKREF_SCRATCH+1]; \ - PyObject **NAME = _PyObjectArray_FromStackRefArray(ARGS, ARG_COUNT, NAME##_temp + 1); + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; \ + PyObject **NAME##_temp = _tstate->stackref_scratch; \ + PyObject **NAME = _PyObjectArray_FromStackRefArray(ARGS, ARG_COUNT, #define STACKREFS_TO_PYOBJECTS_CLEANUP(NAME) \ /* +1 because we +1 previously */ \ From e1702fd8e8af301ec326d790255b73f623ce93bc Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 24 Aug 2025 20:53:11 +0800 Subject: [PATCH 2/2] oopsie --- Python/ceval_macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 6e41e4146ad822..6efa1c58ec6e8d 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -394,7 +394,7 @@ do { \ /* +1 because vectorcall might use -1 to write self */ \ _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; \ PyObject **NAME##_temp = _tstate->stackref_scratch; \ - PyObject **NAME = _PyObjectArray_FromStackRefArray(ARGS, ARG_COUNT, + PyObject **NAME = _PyObjectArray_FromStackRefArray(ARGS, ARG_COUNT, NAME##_temp + 1); #define STACKREFS_TO_PYOBJECTS_CLEANUP(NAME) \ /* +1 because we +1 previously */ \