@@ -620,42 +620,6 @@ _PyFrame_GetState(PyFrameObject *frame)
620
620
Py_UNREACHABLE ();
621
621
}
622
622
623
- static void
624
- add_load_fast_null_checks (PyCodeObject * co )
625
- {
626
- int changed = 0 ;
627
- _Py_CODEUNIT * instructions = _PyCode_CODE (co );
628
- for (Py_ssize_t i = 0 ; i < Py_SIZE (co ); i ++ ) {
629
- int opcode = _Py_OPCODE (instructions [i ]);
630
- switch (opcode ) {
631
- case LOAD_FAST :
632
- case LOAD_FAST__LOAD_FAST :
633
- case LOAD_FAST__LOAD_CONST :
634
- changed = 1 ;
635
- _Py_SET_OPCODE (instructions [i ], LOAD_FAST_CHECK );
636
- break ;
637
- case LOAD_CONST__LOAD_FAST :
638
- changed = 1 ;
639
- _Py_SET_OPCODE (instructions [i ], LOAD_CONST );
640
- break ;
641
- case STORE_FAST__LOAD_FAST :
642
- changed = 1 ;
643
- _Py_SET_OPCODE (instructions [i ], STORE_FAST );
644
- break ;
645
- }
646
- i += _PyOpcode_Caches [_PyOpcode_Deopt [opcode ]];
647
- }
648
- if (changed && co -> _co_cached != NULL ) {
649
- // invalidate cached co_code object
650
- Py_CLEAR (co -> _co_cached -> _co_code );
651
- Py_CLEAR (co -> _co_cached -> _co_cellvars );
652
- Py_CLEAR (co -> _co_cached -> _co_freevars );
653
- Py_CLEAR (co -> _co_cached -> _co_varnames );
654
- PyMem_Free (co -> _co_cached );
655
- co -> _co_cached = NULL ;
656
- }
657
- }
658
-
659
623
/* Setter for f_lineno - you can set f_lineno from within a trace function in
660
624
* order to jump to a given line of code, subject to some restrictions. Most
661
625
* lines are OK to jump to because they don't make any assumptions about the
@@ -745,8 +709,6 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
745
709
return -1 ;
746
710
}
747
711
748
- add_load_fast_null_checks (f -> f_frame -> f_code );
749
-
750
712
/* PyCode_NewWithPosOnlyArgs limits co_code to be under INT_MAX so this
751
713
* should never overflow. */
752
714
int len = (int )Py_SIZE (f -> f_frame -> f_code );
@@ -805,6 +767,31 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
805
767
PyErr_SetString (PyExc_ValueError , msg );
806
768
return -1 ;
807
769
}
770
+ // Populate any NULL locals that the compiler might have "proven" to exist
771
+ // in the new location. Rather than crashing or changing co_code, just bind
772
+ // None instead:
773
+ int unbound = 0 ;
774
+ for (int i = 0 ; i < f -> f_frame -> f_code -> co_nlocalsplus ; i ++ ) {
775
+ // Counting every unbound local is overly-cautious, but a full flow
776
+ // analysis (like we do in the compiler) is probably too expensive:
777
+ unbound += f -> f_frame -> localsplus [i ] == NULL ;
778
+ }
779
+ if (unbound ) {
780
+ const char * e = "assigning None to %d unbound local%s" ;
781
+ const char * s = (unbound == 1 ) ? "" : "s" ;
782
+ if (PyErr_WarnFormat (PyExc_RuntimeWarning , 0 , e , unbound , s )) {
783
+ return -1 ;
784
+ }
785
+ // Do this in a second pass to avoid writing a bunch of Nones when
786
+ // warnings are being treated as errors and the previous bit raises:
787
+ for (int i = 0 ; i < f -> f_frame -> f_code -> co_nlocalsplus ; i ++ ) {
788
+ if (f -> f_frame -> localsplus [i ] == NULL ) {
789
+ f -> f_frame -> localsplus [i ] = Py_NewRef (Py_None );
790
+ unbound -- ;
791
+ }
792
+ }
793
+ assert (unbound == 0 );
794
+ }
808
795
if (state == FRAME_SUSPENDED ) {
809
796
/* Account for value popped by yield */
810
797
start_stack = pop_value (start_stack );
@@ -1269,7 +1256,6 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
1269
1256
}
1270
1257
fast = _PyFrame_GetLocalsArray (frame );
1271
1258
co = frame -> f_code ;
1272
- bool added_null_checks = false;
1273
1259
1274
1260
PyErr_Fetch (& error_type , & error_value , & error_traceback );
1275
1261
for (int i = 0 ; i < co -> co_nlocalsplus ; i ++ ) {
@@ -1289,10 +1275,6 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
1289
1275
}
1290
1276
}
1291
1277
PyObject * oldvalue = fast [i ];
1292
- if (!added_null_checks && oldvalue != NULL && value == NULL ) {
1293
- add_load_fast_null_checks (co );
1294
- added_null_checks = true;
1295
- }
1296
1278
PyObject * cell = NULL ;
1297
1279
if (kind == CO_FAST_FREE ) {
1298
1280
// The cell was set when the frame was created from
@@ -1319,7 +1301,17 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
1319
1301
}
1320
1302
}
1321
1303
else if (value != oldvalue ) {
1322
- Py_XINCREF (value );
1304
+ if (value == NULL ) {
1305
+ // Probably can't delete this, since the compiler's flow
1306
+ // analysis may have already "proven" that it exists here:
1307
+ const char * e = "assigning None to unbound local %R" ;
1308
+ if (PyErr_WarnFormat (PyExc_RuntimeWarning , 0 , e , name )) {
1309
+ // It's okay if frame_obj is NULL, just try anyways:
1310
+ PyErr_WriteUnraisable ((PyObject * )frame -> frame_obj );
1311
+ }
1312
+ value = Py_NewRef (Py_None );
1313
+ }
1314
+ Py_INCREF (value );
1323
1315
Py_XSETREF (fast [i ], value );
1324
1316
}
1325
1317
Py_XDECREF (value );
0 commit comments