From: Ken Jin Date: Wed, 3 Sep 2025 18:05:06 +0000 (+0800) Subject: gh-138431: JIT Optimizer --- Fix round-tripping references for str and tuple (GH... X-Git-Tag: v3.15.0a1~500 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2402f84665df41732c94db2ccd6f90dd13479fa8;p=thirdparty%2FPython%2Fcpython.git gh-138431: JIT Optimizer --- Fix round-tripping references for str and tuple (GH-138458) Co-authored-by: Mark Shannon <9448417+markshannon@users.noreply.github.com> --- diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 3a5ae0a054ed..01c98c36f052 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -251,6 +251,12 @@ PyJitRef_Wrap(JitOptSymbol *sym) return (JitOptRef){.bits=(uintptr_t)sym}; } +static inline JitOptRef +PyJitRef_StripReferenceInfo(JitOptRef ref) +{ + return PyJitRef_Wrap(PyJitRef_Unwrap(ref)); +} + static inline JitOptRef PyJitRef_Borrow(JitOptRef ref) { diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index c796b0dd4b5b..ffd65dbb1464 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2501,6 +2501,22 @@ class TestUopsOptimization(unittest.TestCase): # For now... until we constant propagate it away. self.assertIn("_BINARY_OP", uops) + def test_reference_tracking_across_call_doesnt_crash(self): + + def f1(): + for _ in range(TIER2_THRESHOLD + 1): + # Choose a value that won't occur elsewhere to avoid sharing + str("value that won't occur elsewhere to avoid sharing") + + f1() + + def f2(): + for _ in range(TIER2_THRESHOLD + 1): + # Choose a value that won't occur elsewhere to avoid sharing + tuple((31, -17, 25, "won't occur elsewhere")) + + f2() + def global_identity(x): return x diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-09-03-15-35-34.gh-issue-138431.EUsrtA.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-03-15-35-34.gh-issue-138431.EUsrtA.rst new file mode 100644 index 000000000000..11fc3c05d5aa --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-03-15-35-34.gh-issue-138431.EUsrtA.rst @@ -0,0 +1 @@ +Fix a bug in the JIT optimizer when round-tripping strings and tuples. diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 781296dc7f48..eccbddf0546a 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -762,9 +762,8 @@ dummy_func(void) { } op(_RETURN_VALUE, (retval -- res)) { - // We wrap and unwrap the value to mimic PyStackRef_MakeHeapSafe - // in bytecodes.c - JitOptRef temp = PyJitRef_Wrap(PyJitRef_Unwrap(retval)); + // Mimics PyStackRef_MakeHeapSafe in the interpreter. + JitOptRef temp = PyJitRef_StripReferenceInfo(retval); DEAD(retval); SAVE_STACK(); ctx->frame->stack_pointer = stack_pointer; @@ -925,7 +924,9 @@ dummy_func(void) { op(_CALL_STR_1, (unused, unused, arg -- res)) { if (sym_matches_type(arg, &PyUnicode_Type)) { // e.g. str('foo') or str(foo) where foo is known to be a string - res = arg; + // Note: we must strip the reference information because it goes + // through str() which strips the reference information from it. + res = PyJitRef_StripReferenceInfo(arg); } else { res = sym_new_type(ctx, &PyUnicode_Type); @@ -1065,7 +1066,9 @@ dummy_func(void) { op(_CALL_TUPLE_1, (callable, null, arg -- res)) { if (sym_matches_type(arg, &PyTuple_Type)) { // e.g. tuple((1, 2)) or tuple(foo) where foo is known to be a tuple - res = arg; + // Note: we must strip the reference information because it goes + // through tuple() which strips the reference information from it. + res = PyJitRef_StripReferenceInfo(arg); } else { res = sym_new_type(ctx, &PyTuple_Type); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 14e985b42ea0..8617355e25f4 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1060,7 +1060,7 @@ JitOptRef retval; JitOptRef res; retval = stack_pointer[-1]; - JitOptRef temp = PyJitRef_Wrap(PyJitRef_Unwrap(retval)); + JitOptRef temp = PyJitRef_StripReferenceInfo(retval); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); ctx->frame->stack_pointer = stack_pointer; @@ -2496,7 +2496,7 @@ JitOptRef res; arg = stack_pointer[-1]; if (sym_matches_type(arg, &PyUnicode_Type)) { - res = arg; + res = PyJitRef_StripReferenceInfo(arg); } else { res = sym_new_type(ctx, &PyUnicode_Type); @@ -2522,7 +2522,7 @@ JitOptRef res; arg = stack_pointer[-1]; if (sym_matches_type(arg, &PyTuple_Type)) { - res = arg; + res = PyJitRef_StripReferenceInfo(arg); } else { res = sym_new_type(ctx, &PyTuple_Type);