From 5f76e6fc7f92aa1acc00b7f60e33c74c627a4a20 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Wed, 26 Nov 2025 19:57:21 +0000 Subject: [PATCH 1/3] Protect against non-progressing specializations in tracing JIT --- Python/optimizer.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Python/optimizer.c b/Python/optimizer.c index 9db894f0bf054a..28d3946341dd55 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -610,6 +610,22 @@ _PyJit_translate_single_bytecode_to_trace( target--; } + if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]] > 0) { + uint16_t backoff = (this_instr + 1)->counter.value_and_backoff; + // adaptive_counter_cooldown is a fresh specialization. + // trigger_backoff_counter is what we set during tracing. + // All tracing backoffs should be freshly specialized or untouched. + // If not, that indicates a deopt during tracing, and + // thus the "actual" instruction executed is not the one that is + // in the instruction stream, but rather the deopt. + // It's important we check for this, as some specializations might make + // no progress (they can immediately deopt after specializing). + if (backoff != adaptive_counter_cooldown().value_and_backoff && + backoff != trigger_backoff_counter().value_and_backoff) { + opcode = _PyOpcode_Deopt[opcode]; + } + } + int old_stack_level = _tstate->jit_tracer_state.prev_state.instr_stacklevel; // Strange control-flow From 1446220253bd6bf0a4ca2470dc66ed61a90205bc Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 26 Nov 2025 20:01:15 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-11-26-20-01-07.gh-issue-141976.K8NDmR.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-11-26-20-01-07.gh-issue-141976.K8NDmR.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-11-26-20-01-07.gh-issue-141976.K8NDmR.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-26-20-01-07.gh-issue-141976.K8NDmR.rst new file mode 100644 index 00000000000000..098859cc141e0e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-26-20-01-07.gh-issue-141976.K8NDmR.rst @@ -0,0 +1 @@ +Protect against specialization failures in the tracing JIT compiler. From 0e949ad9f5576c278a132d11d71475dcc85c2f46 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Fri, 5 Dec 2025 17:00:59 +0000 Subject: [PATCH 3/3] address review --- Include/cpython/pystats.h | 1 + .../2025-11-26-20-01-07.gh-issue-141976.K8NDmR.rst | 2 +- Python/optimizer.c | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h index 1c94603c08b9b6..10ac98f2dfebe6 100644 --- a/Include/cpython/pystats.h +++ b/Include/cpython/pystats.h @@ -142,6 +142,7 @@ typedef struct _optimization_stats { uint64_t recursive_call; uint64_t low_confidence; uint64_t unknown_callee; + uint64_t trace_immediately_deopts; uint64_t executors_invalidated; UOpStats opcode[PYSTATS_MAX_UOP_ID + 1]; uint64_t unsupported_opcode[256]; diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-11-26-20-01-07.gh-issue-141976.K8NDmR.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-26-20-01-07.gh-issue-141976.K8NDmR.rst index 098859cc141e0e..654681515e43e5 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-11-26-20-01-07.gh-issue-141976.K8NDmR.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-26-20-01-07.gh-issue-141976.K8NDmR.rst @@ -1 +1 @@ -Protect against specialization failures in the tracing JIT compiler. +Protect against specialization failures in the tracing JIT compiler for performance reasons. diff --git a/Python/optimizer.c b/Python/optimizer.c index 28d3946341dd55..7fe914a7a426b9 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -620,8 +620,11 @@ _PyJit_translate_single_bytecode_to_trace( // in the instruction stream, but rather the deopt. // It's important we check for this, as some specializations might make // no progress (they can immediately deopt after specializing). + // We do this to improve performance, as otherwise a compiled trace + // will just deopt immediately. if (backoff != adaptive_counter_cooldown().value_and_backoff && backoff != trigger_backoff_counter().value_and_backoff) { + OPT_STAT_INC(trace_immediately_deopts); opcode = _PyOpcode_Deopt[opcode]; } }