]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-141976: Protect against non-progressing specializations in tracing JIT (GH-141989)
authorKen Jin <kenjin@python.org>
Wed, 10 Dec 2025 19:39:11 +0000 (03:39 +0800)
committerGitHub <noreply@github.com>
Wed, 10 Dec 2025 19:39:11 +0000 (19:39 +0000)
Include/cpython/pystats.h
Misc/NEWS.d/next/Core_and_Builtins/2025-11-26-20-01-07.gh-issue-141976.K8NDmR.rst [new file with mode: 0644]
Python/optimizer.c

index 1c94603c08b9b60b23238b2cb207db2d16bb957a..10ac98f2dfebe6fdd811c694b5b05639a0f19d2c 100644 (file)
@@ -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
new file mode 100644 (file)
index 0000000..6546815
--- /dev/null
@@ -0,0 +1 @@
+Protect against specialization failures in the tracing JIT compiler for performance reasons.
index 9db894f0bf054a127c9b8d3477f76830f5ffef05..7fe914a7a426b9d40ba3196f72233e78db133ddc 100644 (file)
@@ -610,6 +610,25 @@ _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).
+        // 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];
+        }
+    }
+
     int old_stack_level = _tstate->jit_tracer_state.prev_state.instr_stacklevel;
 
     // Strange control-flow