File tree Expand file tree Collapse file tree
Misc/NEWS.d/next/Core_and_Builtins Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -1812,6 +1812,37 @@ def testfunc(n):
18121812 # __init__ resolution allows promotion of range to constant
18131813 self .assertNotIn ("_LOAD_GLOBAL_BUILTINS" , uops )
18141814
1815+ # See https://github.com/python/cpython/issues/158072
1816+ def test_init_with_default_argument (self ):
1817+ script_helper .assert_python_ok ("-c" , textwrap .dedent (f"""\
1818+ sentinel = object()
1819+
1820+ class WithDefault:
1821+ def __init__(self, value=sentinel):
1822+ if value is not sentinel:
1823+ pass
1824+
1825+ for _ in range({ TIER2_THRESHOLD * 3 } ):
1826+ WithDefault()
1827+ """ ), PYTHON_JIT = "1" )
1828+
1829+ def test_init_with_changed_code_argcount (self ):
1830+ class C :
1831+ def __init__ (self , value ):
1832+ self .value = False
1833+
1834+ def varargs_init (self , * args ):
1835+ self .value = isinstance (args , tuple )
1836+
1837+ def testfunc (n ):
1838+ for _ in range (n ):
1839+ result = C (42 ).value
1840+ return result
1841+
1842+ self .assertFalse (testfunc (100 ))
1843+ C .__init__ .__code__ = C .varargs_init .__code__
1844+ self .assertTrue (testfunc (TIER2_THRESHOLD * 3 ))
1845+
18151846 def test_init_guards_removed (self ):
18161847 class MyPoint :
18171848 def __init__ (self , x , y ):
Original file line number Diff line number Diff line change 1+ Fix a JIT crash when a class is instantiated with their default arguments
Original file line number Diff line number Diff line change @@ -1388,17 +1388,27 @@ _Py_uop_frame_new(
13881388 }
13891389
13901390 // Initialize with the initial state of all local variables
1391+ arg_len = Py_MIN (arg_len , co -> co_argcount );
13911392 for (int i = 0 ; i < arg_len ; i ++ ) {
13921393 frame -> locals [i ] = PyJitRef_RemoveUnique (args [i ]);
13931394 }
13941395
1395- // If the args are known, then it's safe to just initialize
1396- // every other non-set local to null symbol.
1397- bool default_null = args != NULL ;
1396+ // When args is available, missing parameters get defaults or *args/**kwargs.
1397+ // Other locals start as NULL. When args is NULL, treat all locals as unknown.
1398+ int parameter_count = co -> co_argcount + co -> co_kwonlyargcount ;
1399+ parameter_count += (co -> co_flags & CO_VARARGS ) != 0 ;
1400+ parameter_count += (co -> co_flags & CO_VARKEYWORDS ) != 0 ;
13981401
13991402 for (int i = arg_len ; i < co -> co_nlocalsplus ; i ++ ) {
1400- JitOptRef local = default_null ? _Py_uop_sym_new_null (ctx ) : _Py_uop_sym_new_unknown (ctx );
1401- frame -> locals [i ] = local ;
1403+ if (args == NULL ) {
1404+ frame -> locals [i ] = _Py_uop_sym_new_unknown (ctx );
1405+ }
1406+ else if (i < parameter_count ) {
1407+ frame -> locals [i ] = _Py_uop_sym_new_not_null (ctx );
1408+ }
1409+ else {
1410+ frame -> locals [i ] = _Py_uop_sym_new_null (ctx );
1411+ }
14021412 }
14031413
14041414 frame -> callable = _Py_uop_sym_new_not_null (ctx );
You can’t perform that action at this time.
0 commit comments