From fbbac65b353ff12ae0224109fce2462655403961 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Fri, 9 Jan 2026 11:04:49 +0000 Subject: [PATCH 1/2] Lazily allocate tracer code and opt buffers --- Include/internal/pycore_tstate.h | 4 ++-- Python/optimizer.c | 7 +++++++ Python/optimizer_analysis.c | 10 +++++++++- Python/pystate.c | 14 ++++++++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h index 81cabb4dca47e4..262051c015ab5e 100644 --- a/Include/internal/pycore_tstate.h +++ b/Include/internal/pycore_tstate.h @@ -56,8 +56,8 @@ typedef struct _PyJitTracerState { _PyJitTracerInitialState initial_state; _PyJitTracerPreviousState prev_state; _PyJitTracerTranslatorState translator_state; - JitOptContext opt_context; - _PyUOpInstruction code_buffer[UOP_MAX_TRACE_LENGTH]; + JitOptContext *opt_context; + _PyUOpInstruction *code_buffer; } _PyJitTracerState; #endif diff --git a/Python/optimizer.c b/Python/optimizer.c index 73617f6ca26425..a0d72454aa3ea5 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1025,6 +1025,13 @@ _PyJit_TryInitializeTracing( if (oparg > 0xFFFF) { return 0; } + if (_tstate->jit_tracer_state.code_buffer == NULL) { + _tstate->jit_tracer_state.code_buffer = (_PyUOpInstruction *)_PyObject_VirtualAlloc(UOP_BUFFER_SIZE); + if (_tstate->jit_tracer_state.code_buffer == NULL) { + // Don't error, just go to next instruction. + return 0; + } + } PyObject *func = PyStackRef_AsPyObjectBorrow(frame->f_funcobj); if (func == NULL) { return 0; diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 56d4f9945d6908..d7b81f07d0b86f 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -345,7 +345,15 @@ optimize_uops( assert(!PyErr_Occurred()); PyFunctionObject *func = tstate->jit_tracer_state.initial_state.func; - JitOptContext *ctx = &tstate->jit_tracer_state.opt_context; + JitOptContext *ctx = tstate->jit_tracer_state.opt_context; + if (ctx == NULL) { + ctx = (JitOptContext *)_PyObject_VirtualAlloc(sizeof(JitOptContext)); + if (ctx == NULL) { + // Don't error, just bail. + return 0; + } + tstate->jit_tracer_state.opt_context = ctx; + } uint32_t opcode = UINT16_MAX; // Make sure that watchers are set up diff --git a/Python/pystate.c b/Python/pystate.c index 74507efa5b4cf3..a186ac58abadec 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1553,6 +1553,8 @@ init_threadstate(_PyThreadStateImpl *_tstate, init_policy(&_tstate->policy.jit.side_exit_initial_backoff, "PYTHON_JIT_SIDE_EXIT_INITIAL_BACKOFF", SIDE_EXIT_INITIAL_BACKOFF, 0, MAX_BACKOFF); + _tstate->jit_tracer_state.code_buffer = NULL; + _tstate->jit_tracer_state.opt_context = NULL; #endif tstate->delete_later = NULL; @@ -1867,6 +1869,18 @@ tstate_delete_common(PyThreadState *tstate, int release_gil) assert(tstate_impl->refcounts.values == NULL); #endif +#if _Py_TIER2 + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + if (_tstate->jit_tracer_state.code_buffer != NULL) { + _PyObject_VirtualFree(_tstate->jit_tracer_state.code_buffer, UOP_BUFFER_SIZE); + _tstate->jit_tracer_state.code_buffer = NULL; + } + if (_tstate->jit_tracer_state.opt_context != NULL) { + _PyObject_VirtualFree(_tstate->jit_tracer_state.opt_context, sizeof(JitOptContext)); + _tstate->jit_tracer_state.opt_context = NULL; + } +#endif + HEAD_UNLOCK(runtime); // XXX Unbind in PyThreadState_Clear(), or earlier From 2354e7884a17197f605eb185b0249a4b12f05200 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Fri, 9 Jan 2026 16:02:45 +0000 Subject: [PATCH 2/2] Cut down locals and stack size --- Include/internal/pycore_optimizer_types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h index de8e50921e3311..0a193268c4d618 100644 --- a/Include/internal/pycore_optimizer_types.h +++ b/Include/internal/pycore_optimizer_types.h @@ -10,8 +10,8 @@ extern "C" { #include "pycore_uop.h" // UOP_MAX_TRACE_LENGTH -// Holds locals, stack, locals, stack ... co_consts (in that order) -#define MAX_ABSTRACT_INTERP_SIZE 4096 +// Holds locals, stack, locals, stack ... (in that order) +#define MAX_ABSTRACT_INTERP_SIZE 512 #define TY_ARENA_SIZE (UOP_MAX_TRACE_LENGTH * 5)