diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 36efab51878141..3732482ea1d9e1 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1812,6 +1812,20 @@ def testfunc(n): # __init__ resolution allows promotion of range to constant self.assertNotIn("_LOAD_GLOBAL_BUILTINS", uops) + # See https://github.com/python/cpython/issues/158072 + def test_init_with_default_argument(self): + script_helper.assert_python_ok("-c", textwrap.dedent(f"""\ + sentinel = object() + + class WithDefault: + def __init__(self, value=sentinel): + if value is not sentinel: + pass + + for _ in range({TIER2_THRESHOLD * 3}): + WithDefault() + """), PYTHON_JIT="1") + def test_init_guards_removed(self): class MyPoint: def __init__(self, x, y): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-24-18-44-40.gh-issue-158072.mHveWw.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-24-18-44-40.gh-issue-158072.mHveWw.rst new file mode 100644 index 00000000000000..faff8fff4aec5c --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-24-18-44-40.gh-issue-158072.mHveWw.rst @@ -0,0 +1 @@ +Fix a JIT crash when a class is instantiated with their default arguments diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 79f81482d247e3..90a9d4332c5a35 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -1392,13 +1392,22 @@ _Py_uop_frame_new( frame->locals[i] = PyJitRef_RemoveUnique(args[i]); } - // If the args are known, then it's safe to just initialize - // every other non-set local to null symbol. - bool default_null = args != NULL; + // When args is available, missing parameters get defaults or *args/**kwargs. + // Other locals start as NULL. When args is NULL, treat all locals as unknown. + int parameter_count = co->co_argcount + co->co_kwonlyargcount; + parameter_count += (co->co_flags & CO_VARARGS) != 0; + parameter_count += (co->co_flags & CO_VARKEYWORDS) != 0; for (int i = arg_len; i < co->co_nlocalsplus; i++) { - JitOptRef local = default_null ? _Py_uop_sym_new_null(ctx) : _Py_uop_sym_new_unknown(ctx); - frame->locals[i] = local; + if (args == NULL) { + frame->locals[i] = _Py_uop_sym_new_unknown(ctx); + } + else if (i < parameter_count) { + frame->locals[i] = _Py_uop_sym_new_not_null(ctx); + } + else { + frame->locals[i] = _Py_uop_sym_new_null(ctx); + } } frame->callable = _Py_uop_sym_new_not_null(ctx);