Skip to content

Commit 2402f84

Browse files
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>
1 parent 0d1f4e1 commit 2402f84

File tree

5 files changed

+34
-8
lines changed

5 files changed

+34
-8
lines changed

Include/internal/pycore_optimizer.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@ PyJitRef_Wrap(JitOptSymbol *sym)
251251
return (JitOptRef){.bits=(uintptr_t)sym};
252252
}
253253

254+
static inline JitOptRef
255+
PyJitRef_StripReferenceInfo(JitOptRef ref)
256+
{
257+
return PyJitRef_Wrap(PyJitRef_Unwrap(ref));
258+
}
259+
254260
static inline JitOptRef
255261
PyJitRef_Borrow(JitOptRef ref)
256262
{

Lib/test/test_capi/test_opt.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,6 +2501,22 @@ def testfunc(n):
25012501
# For now... until we constant propagate it away.
25022502
self.assertIn("_BINARY_OP", uops)
25032503

2504+
def test_reference_tracking_across_call_doesnt_crash(self):
2505+
2506+
def f1():
2507+
for _ in range(TIER2_THRESHOLD + 1):
2508+
# Choose a value that won't occur elsewhere to avoid sharing
2509+
str("value that won't occur elsewhere to avoid sharing")
2510+
2511+
f1()
2512+
2513+
def f2():
2514+
for _ in range(TIER2_THRESHOLD + 1):
2515+
# Choose a value that won't occur elsewhere to avoid sharing
2516+
tuple((31, -17, 25, "won't occur elsewhere"))
2517+
2518+
f2()
2519+
25042520

25052521
def global_identity(x):
25062522
return x
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a bug in the JIT optimizer when round-tripping strings and tuples.

Python/optimizer_bytecodes.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -762,9 +762,8 @@ dummy_func(void) {
762762
}
763763

764764
op(_RETURN_VALUE, (retval -- res)) {
765-
// We wrap and unwrap the value to mimic PyStackRef_MakeHeapSafe
766-
// in bytecodes.c
767-
JitOptRef temp = PyJitRef_Wrap(PyJitRef_Unwrap(retval));
765+
// Mimics PyStackRef_MakeHeapSafe in the interpreter.
766+
JitOptRef temp = PyJitRef_StripReferenceInfo(retval);
768767
DEAD(retval);
769768
SAVE_STACK();
770769
ctx->frame->stack_pointer = stack_pointer;
@@ -925,7 +924,9 @@ dummy_func(void) {
925924
op(_CALL_STR_1, (unused, unused, arg -- res)) {
926925
if (sym_matches_type(arg, &PyUnicode_Type)) {
927926
// e.g. str('foo') or str(foo) where foo is known to be a string
928-
res = arg;
927+
// Note: we must strip the reference information because it goes
928+
// through str() which strips the reference information from it.
929+
res = PyJitRef_StripReferenceInfo(arg);
929930
}
930931
else {
931932
res = sym_new_type(ctx, &PyUnicode_Type);
@@ -1065,7 +1066,9 @@ dummy_func(void) {
10651066
op(_CALL_TUPLE_1, (callable, null, arg -- res)) {
10661067
if (sym_matches_type(arg, &PyTuple_Type)) {
10671068
// e.g. tuple((1, 2)) or tuple(foo) where foo is known to be a tuple
1068-
res = arg;
1069+
// Note: we must strip the reference information because it goes
1070+
// through tuple() which strips the reference information from it.
1071+
res = PyJitRef_StripReferenceInfo(arg);
10691072
}
10701073
else {
10711074
res = sym_new_type(ctx, &PyTuple_Type);

Python/optimizer_cases.c.h

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)