From: Ken Jin Date: Fri, 19 Dec 2025 19:06:34 +0000 (+0800) Subject: gh-134584: JIT: Borrow references for immortal promoted globals (GH-142921) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6b4bc6e6a240966cfec488c25c83c40a101a94c8;p=thirdparty%2FPython%2Fcpython.git gh-134584: JIT: Borrow references for immortal promoted globals (GH-142921) JIT: Borrow references for immortal promoted globals --- diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 9a822834c14f..3ea93277dab2 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -3008,6 +3008,44 @@ class TestUopsOptimization(unittest.TestCase): for _ in range(TIER2_THRESHOLD+1): obj.attr = EvilAttr(obj.__dict__) + def test_promoted_global_refcount_eliminated(self): + result = script_helper.run_python_until_end('-c', textwrap.dedent(""" + import _testinternalcapi + import opcode + import _opcode + + def get_first_executor(func): + code = func.__code__ + co_code = code.co_code + for i in range(0, len(co_code), 2): + try: + return _opcode.get_executor(code, i) + except ValueError: + pass + return None + + def get_opnames(ex): + return {item[0] for item in ex} + + + def testfunc(n): + y = [] + for i in range(n): + x = tuple(y) + return x + + testfunc(_testinternalcapi.TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + assert ex is not None + uops = get_opnames(ex) + assert "_LOAD_GLOBAL_BUILTIN" not in uops + assert "_LOAD_CONST_INLINE_BORROW" in uops + assert "_POP_TOP_NOP" in uops + assert "_POP_TOP" not in uops + """), PYTHON_JIT="1") + self.assertEqual(result[0].rc, 0, result) + def test_constant_fold_tuple(self): def testfunc(n): for _ in range(n): diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index d2527fd85e3f..cd789db1fe89 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1376,7 +1376,12 @@ dummy_func(void) { res = sym_new_not_null(ctx); } else { - res = sym_new_const(ctx, cnst); + if (_Py_IsImmortal(cnst)) { + res = PyJitRef_Borrow(sym_new_const(ctx, cnst)); + } + else { + res = sym_new_const(ctx, cnst); + } } } @@ -1411,7 +1416,12 @@ dummy_func(void) { res = sym_new_not_null(ctx); } else { - res = sym_new_const(ctx, cnst); + if (_Py_IsImmortal(cnst)) { + res = PyJitRef_Borrow(sym_new_const(ctx, cnst)); + } + else { + res = sym_new_const(ctx, cnst); + } } } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 0389c6192e1c..85d3d0412151 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1330,7 +1330,12 @@ res = sym_new_not_null(ctx); } else { - res = sym_new_const(ctx, cnst); + if (_Py_IsImmortal(cnst)) { + res = PyJitRef_Borrow(sym_new_const(ctx, cnst)); + } + else { + res = sym_new_const(ctx, cnst); + } } CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; @@ -1367,7 +1372,12 @@ res = sym_new_not_null(ctx); } else { - res = sym_new_const(ctx, cnst); + if (_Py_IsImmortal(cnst)) { + res = PyJitRef_Borrow(sym_new_const(ctx, cnst)); + } + else { + res = sym_new_const(ctx, cnst); + } } CHECK_STACK_BOUNDS(1); stack_pointer[0] = res;