From a23306418309367b02a756eeed200db5ee8fef5c Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Fri, 26 Dec 2025 10:56:38 +0000 Subject: [PATCH 1/4] Rewind stop tracing to previous target --- Lib/test/test_capi/test_opt.py | 42 ++++++++++++++++++++++++++++++++++ Python/optimizer.c | 9 +++++--- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 9c9135411f9078..942e0c75d90af9 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -3194,6 +3194,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/Python/optimizer.c b/Python/optimizer.c index 5e97f20f869efd..3f11074c3272d2 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,10 @@ _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 mgiht be garbage as stop tracing usually indicates + // we are in something that we can't trace. + goto unsupported; } DPRINTF(2, "%p %d: %s(%d) %d %d\n", old_code, target, _PyOpcode_OpName[opcode], oparg, needs_guard_ip, old_stack_level); @@ -738,7 +741,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; } From 9c978c2fb8d6a6aed3c2e6a24ce2d836f2acbafd Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Fri, 26 Dec 2025 10:59:51 +0000 Subject: [PATCH 2/4] lint --- Lib/test/test_capi/test_opt.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 942e0c75d90af9..ead14ab755b49b 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -3203,15 +3203,15 @@ 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: @@ -3223,7 +3223,7 @@ async def async_for_driver(): ... except Exception: ... - + c = async_for_driver() while True: try: From 77f857c66740db5966eb64020bdc18ee4bafba1d Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 26 Dec 2025 11:00:49 +0000 Subject: [PATCH 3/4] =?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-12-26-11-00-44.gh-issue-143183.rhxzZr.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-26-11-00-44.gh-issue-143183.rhxzZr.rst 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. From eaa2a2e97021e8f0a704162c4b047f607ea28f36 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Fri, 26 Dec 2025 11:46:02 +0000 Subject: [PATCH 4/4] Update Python/optimizer.c Co-authored-by: Kumar Aditya --- Python/optimizer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/optimizer.c b/Python/optimizer.c index 3f11074c3272d2..e55dd7bab7ea04 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -693,7 +693,7 @@ _PyJit_translate_single_bytecode_to_trace( if (stop_tracing_opcode != 0) { // gh-143183: It's important we rewind to the last known proper target. - // The current target mgiht be garbage as stop tracing usually indicates + // The current target might be garbage as stop tracing usually indicates // we are in something that we can't trace. goto unsupported; }