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 @@ -1790,6 +1790,37 @@ def testfunc(n):
17901790 # __init__ resolution allows promotion of range to constant
17911791 self .assertNotIn ("_LOAD_GLOBAL_BUILTINS" , uops )
17921792
1793+ # See https://github.com/python/cpython/issues/158072
1794+ def test_init_with_default_argument (self ):
1795+ script_helper .assert_python_ok ("-c" , textwrap .dedent (f"""\
1796+ sentinel = object()
1797+
1798+ class WithDefault:
1799+ def __init__(self, value=sentinel):
1800+ if value is not sentinel:
1801+ pass
1802+
1803+ for _ in range({ TIER2_THRESHOLD * 3 } ):
1804+ WithDefault()
1805+ """ ), PYTHON_JIT = "1" )
1806+
1807+ def test_init_with_changed_code_argcount (self ):
1808+ class C :
1809+ def __init__ (self , value ):
1810+ self .value = False
1811+
1812+ def varargs_init (self , * args ):
1813+ self .value = isinstance (args , tuple )
1814+
1815+ def testfunc (n ):
1816+ for _ in range (n ):
1817+ result = C (42 ).value
1818+ return result
1819+
1820+ self .assertFalse (testfunc (100 ))
1821+ C .__init__ .__code__ = C .varargs_init .__code__
1822+ self .assertTrue (testfunc (TIER2_THRESHOLD * 3 ))
1823+
17931824 def test_init_guards_removed (self ):
17941825 class MyPoint :
17951826 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