https://github.com/python/cpython/commit/2402f84665df41732c94db2ccd6f90dd13479fa8
commit: 2402f84665df41732c94db2ccd6f90dd13479fa8
branch: main
author: Ken Jin <[email protected]>
committer: Fidget-Spinner <[email protected]>
date: 2025-09-04T02:05:06+08:00
summary:

gh-138431: JIT Optimizer --- Fix round-tripping references for str and tuple 
(GH-138458)

Co-authored-by: Mark Shannon <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2025-09-03-15-35-34.gh-issue-138431.EUsrtA.rst
M Include/internal/pycore_optimizer.h
M Lib/test/test_capi/test_opt.py
M Python/optimizer_bytecodes.c
M Python/optimizer_cases.c.h

diff --git a/Include/internal/pycore_optimizer.h 
b/Include/internal/pycore_optimizer.h
index 3a5ae0a054ed3c..01c98c36f052a9 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 c796b0dd4b5b7e..ffd65dbb1464f8 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -2501,6 +2501,22 @@ def testfunc(n):
         # 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 00000000000000..11fc3c05d5aa7a
--- /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 781296dc7f48fc..eccbddf0546ab3 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 14e985b42ea0ce..8617355e25f418 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);

_______________________________________________
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