https://github.com/python/cpython/commit/daa9aa4c0a8490f09b01339b6928434d7fe02843
commit: daa9aa4c0a8490f09b01339b6928434d7fe02843
branch: main
author: Ken Jin <[email protected]>
committer: Fidget-Spinner <[email protected]>
date: 2025-12-28T22:12:31Z
summary:

gh-143183: Rewind stop tracing to previous target (GH-143187)

Co-authored-by: Kumar Aditya <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2025-12-26-11-00-44.gh-issue-143183.rhxzZr.rst
M Lib/test/test_capi/test_opt.py
M Python/optimizer.c

diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index d090b22f3bb81d..ea1606fd5b5f05 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -3306,6 +3306,48 @@ class B: ...
         for i in range(TIER2_THRESHOLD * 10):
             f1()
 
+    def test_143183(self):
+        # https://github.com/python/cpython/issues/143183
+
+        result = script_helper.run_python_until_end('-c', textwrap.dedent(f"""
+        def f1():
+            class AsyncIter:
+                def __init__(self):
+                    self.limit = 0
+                    self.count = 0
+
+                def __aiter__(self):
+                    return self
+
+                async def __anext__(self):
+                    if self.count >= self.limit:
+                        ...
+                    self.count += 1j
+
+            class AsyncCtx:
+                async def async_for_driver():
+                    try:
+                        for _ in range({TIER2_THRESHOLD}):
+                            try:
+                                async for _ in AsyncIter():
+                                    ...
+                            except TypeError:
+                                ...
+                    except Exception:
+                        ...
+
+                c = async_for_driver()
+                while True:
+                    try:
+                        c.send(None)
+                    except StopIteration:
+                        break
+
+        for _ in range({TIER2_THRESHOLD // 40}):
+            f1()
+        """), PYTHON_JIT="1")
+        self.assertEqual(result[0].rc, 0, result)
+
 def global_identity(x):
     return x
 
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-26-11-00-44.gh-issue-143183.rhxzZr.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-26-11-00-44.gh-issue-143183.rhxzZr.rst
new file mode 100644
index 00000000000000..bee2eb672e8813
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-26-11-00-44.gh-issue-143183.rhxzZr.rst
@@ -0,0 +1 @@
+Fix a bug in the JIT when dealing with unsupported control-flow or operations.
diff --git a/Python/optimizer.c b/Python/optimizer.c
index 5e97f20f869efd..b497ac629960ac 100644
--- a/Python/optimizer.c
+++ b/Python/optimizer.c
@@ -625,6 +625,7 @@ _PyJit_translate_single_bytecode_to_trace(
     int trace_length = _tstate->jit_tracer_state.prev_state.code_curr_size;
     _PyUOpInstruction *trace = _tstate->jit_tracer_state.code_buffer;
     int max_length = _tstate->jit_tracer_state.prev_state.code_max_size;
+    int exit_op = stop_tracing_opcode == 0 ? _EXIT_TRACE : stop_tracing_opcode;
 
     _Py_CODEUNIT *this_instr =  _tstate->jit_tracer_state.prev_state.instr;
     _Py_CODEUNIT *target_instr = this_instr;
@@ -691,8 +692,11 @@ _PyJit_translate_single_bytecode_to_trace(
     }
 
     if (stop_tracing_opcode != 0) {
-        ADD_TO_TRACE(stop_tracing_opcode, 0, 0, target);
-        goto done;
+        // gh-143183: It's important we rewind to the last known proper target.
+        // The current target might be garbage as stop tracing usually 
indicates
+        // we are in something that we can't trace.
+        DPRINTF(2, "Told to stop tracing\n");
+        goto unsupported;
     }
 
     DPRINTF(2, "%p %d: %s(%d) %d %d\n", old_code, target, 
_PyOpcode_OpName[opcode], oparg, needs_guard_ip, old_stack_level);
@@ -703,10 +707,6 @@ _PyJit_translate_single_bytecode_to_trace(
     }
 #endif
 
-    if (opcode == ENTER_EXECUTOR) {
-        goto full;
-    }
-
     if (!_tstate->jit_tracer_state.prev_state.dependencies_still_valid) {
         goto full;
     }
@@ -720,11 +720,6 @@ _PyJit_translate_single_bytecode_to_trace(
 
     if (oparg > 0xFFFF) {
         DPRINTF(2, "Unsupported: oparg too large\n");
-        goto unsupported;
-    }
-
-    // TODO (gh-140277): The constituent use one extra stack slot. So we need 
to check for headroom.
-    if (opcode == BINARY_OP_SUBSCR_GETITEM && old_stack_level + 1 > 
old_code->co_stacksize) {
         unsupported:
         {
             // Rewind to previous instruction and replace with _EXIT_TRACE.
@@ -738,7 +733,7 @@ _PyJit_translate_single_bytecode_to_trace(
                 int32_t old_target = (int32_t)uop_get_target(curr);
                 curr++;
                 trace_length++;
-                curr->opcode = _EXIT_TRACE;
+                curr->opcode = exit_op;
                 curr->format = UOP_FORMAT_TARGET;
                 curr->target = old_target;
             }
@@ -746,6 +741,7 @@ _PyJit_translate_single_bytecode_to_trace(
         }
     }
 
+
     if (opcode == NOP) {
         return 1;
     }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to