@@ -29,6 +29,7 @@ typedef struct _PyCfgInstruction {
29
29
int i_opcode ;
30
30
int i_oparg ;
31
31
_PyCompilerSrcLocation i_loc ;
32
+ unsigned i_loc_propagated : 1 ; /* location was set by propagate_line_numbers */
32
33
struct _PyCfgBasicblock * i_target ; /* target block (if jump instruction) */
33
34
struct _PyCfgBasicblock * i_except ; /* target block when exception is raised */
34
35
} cfg_instr ;
@@ -504,6 +505,21 @@ no_redundant_jumps(cfg_builder *g) {
504
505
return true;
505
506
}
506
507
508
+ static bool
509
+ all_exits_have_lineno (basicblock * entryblock ) {
510
+ for (basicblock * b = entryblock ; b != NULL ; b = b -> b_next ) {
511
+ for (int i = 0 ; i < b -> b_iused ; i ++ ) {
512
+ cfg_instr * instr = & b -> b_instr [i ];
513
+ if (instr -> i_opcode == RETURN_VALUE ) {
514
+ if (instr -> i_loc .lineno < 0 ) {
515
+ assert (0 );
516
+ return false;
517
+ }
518
+ }
519
+ }
520
+ }
521
+ return true;
522
+ }
507
523
#endif
508
524
509
525
/***** CFG preprocessing (jump targets and exceptions) *****/
@@ -940,7 +956,10 @@ label_exception_targets(basicblock *entryblock) {
940
956
/***** CFG optimizations *****/
941
957
942
958
static int
943
- mark_reachable (basicblock * entryblock ) {
959
+ remove_unreachable (basicblock * entryblock ) {
960
+ for (basicblock * b = entryblock ; b != NULL ; b = b -> b_next ) {
961
+ b -> b_predecessors = 0 ;
962
+ }
944
963
basicblock * * stack = make_cfg_traversal_stack (entryblock );
945
964
if (stack == NULL ) {
946
965
return ERROR ;
@@ -972,6 +991,14 @@ mark_reachable(basicblock *entryblock) {
972
991
}
973
992
}
974
993
PyMem_Free (stack );
994
+
995
+ /* Delete unreachable instructions */
996
+ for (basicblock * b = entryblock ; b != NULL ; b = b -> b_next ) {
997
+ if (b -> b_predecessors == 0 ) {
998
+ b -> b_iused = 0 ;
999
+ b -> b_except_handler = 0 ;
1000
+ }
1001
+ }
975
1002
return SUCCESS ;
976
1003
}
977
1004
@@ -1149,13 +1176,15 @@ jump_thread(cfg_instr *inst, cfg_instr *target, int opcode)
1149
1176
assert (is_jump (target ));
1150
1177
// bpo-45773: If inst->i_target == target->i_target, then nothing actually
1151
1178
// changes (and we fall into an infinite loop):
1179
+ if (inst -> i_loc .lineno == -1 ) assert (inst -> i_loc_propagated );
1180
+ if (target -> i_loc .lineno == -1 ) assert (target -> i_loc_propagated );
1152
1181
if ((inst -> i_loc .lineno == target -> i_loc .lineno ||
1153
- inst -> i_loc . lineno == -1 || target -> i_loc . lineno == -1 ) &&
1182
+ inst -> i_loc_propagated || target -> i_loc_propagated ) &&
1154
1183
inst -> i_target != target -> i_target )
1155
1184
{
1156
1185
inst -> i_target = target -> i_target ;
1157
1186
inst -> i_opcode = opcode ;
1158
- if (inst -> i_loc . lineno == -1 ) {
1187
+ if (inst -> i_loc_propagated && ! target -> i_loc_propagated ) {
1159
1188
inst -> i_loc = target -> i_loc ;
1160
1189
}
1161
1190
return true;
@@ -1714,6 +1743,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
1714
1743
return ERROR ;
1715
1744
}
1716
1745
1746
+ static int resolve_line_numbers (cfg_builder * g , int firstlineno );
1717
1747
1718
1748
/* Perform optimizations on a control flow graph.
1719
1749
The consts object should still be in list form to allow new constants
@@ -1723,41 +1753,31 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
1723
1753
NOPs. Later those NOPs are removed.
1724
1754
*/
1725
1755
static int
1726
- optimize_cfg (cfg_builder * g , PyObject * consts , PyObject * const_cache )
1756
+ optimize_cfg (cfg_builder * g , PyObject * consts , PyObject * const_cache , int firstlineno )
1727
1757
{
1728
1758
assert (PyDict_CheckExact (const_cache ));
1729
1759
RETURN_IF_ERROR (check_cfg (g ));
1730
1760
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1731
1761
RETURN_IF_ERROR (inline_small_exit_blocks (b ));
1732
1762
}
1763
+ RETURN_IF_ERROR (remove_unreachable (g -> g_entryblock ));
1764
+ RETURN_IF_ERROR (resolve_line_numbers (g , firstlineno ));
1733
1765
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1734
1766
RETURN_IF_ERROR (optimize_basic_block (const_cache , b , consts ));
1735
- assert (b -> b_predecessors == 0 );
1736
1767
}
1737
1768
RETURN_IF_ERROR (remove_redundant_nops_and_pairs (g -> g_entryblock ));
1738
1769
for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1739
1770
RETURN_IF_ERROR (inline_small_exit_blocks (b ));
1740
1771
}
1741
- RETURN_IF_ERROR (mark_reachable (g -> g_entryblock ));
1742
-
1743
- /* Delete unreachable instructions */
1744
- for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1745
- if (b -> b_predecessors == 0 ) {
1746
- b -> b_iused = 0 ;
1747
- b -> b_except_handler = 0 ;
1748
- }
1749
- }
1750
- for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1751
- remove_redundant_nops (b );
1752
- }
1753
- RETURN_IF_ERROR (remove_redundant_jumps (g ));
1772
+ RETURN_IF_ERROR (remove_unreachable (g -> g_entryblock ));
1754
1773
1755
- for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1756
- remove_redundant_nops (b );
1774
+ for (int n = 0 ; n < 2 ; n ++ ) {
1775
+ for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
1776
+ remove_redundant_nops (b );
1777
+ }
1778
+ RETURN_IF_ERROR (remove_redundant_jumps (g ));
1757
1779
}
1758
1780
1759
- RETURN_IF_ERROR (remove_redundant_jumps (g ));
1760
-
1761
1781
assert (no_redundant_jumps (g ));
1762
1782
return SUCCESS ;
1763
1783
}
@@ -2174,7 +2194,13 @@ push_cold_blocks_to_end(cfg_builder *g) {
2174
2194
if (!IS_LABEL (b -> b_next -> b_label )) {
2175
2195
b -> b_next -> b_label .id = next_lbl ++ ;
2176
2196
}
2177
- basicblock_addop (explicit_jump , JUMP_NO_INTERRUPT , b -> b_next -> b_label .id , NO_LOCATION );
2197
+ cfg_instr * prev_instr = basicblock_last_instr (b );
2198
+ // b cannot be empty because at the end of an exception handler
2199
+ // there is always a POP_EXCEPT + RERAISE/RETURN
2200
+ assert (prev_instr );
2201
+
2202
+ basicblock_addop (explicit_jump , JUMP_NO_INTERRUPT , b -> b_next -> b_label .id ,
2203
+ prev_instr -> i_loc );
2178
2204
explicit_jump -> b_cold = 1 ;
2179
2205
explicit_jump -> b_next = b -> b_next ;
2180
2206
b -> b_next = explicit_jump ;
@@ -2345,6 +2371,7 @@ propagate_line_numbers(basicblock *entryblock) {
2345
2371
for (int i = 0 ; i < b -> b_iused ; i ++ ) {
2346
2372
if (b -> b_instr [i ].i_loc .lineno < 0 ) {
2347
2373
b -> b_instr [i ].i_loc = prev_location ;
2374
+ b -> b_instr [i ].i_loc_propagated = 1 ;
2348
2375
}
2349
2376
else {
2350
2377
prev_location = b -> b_instr [i ].i_loc ;
@@ -2354,6 +2381,7 @@ propagate_line_numbers(basicblock *entryblock) {
2354
2381
if (b -> b_next -> b_iused > 0 ) {
2355
2382
if (b -> b_next -> b_instr [0 ].i_loc .lineno < 0 ) {
2356
2383
b -> b_next -> b_instr [0 ].i_loc = prev_location ;
2384
+ b -> b_next -> b_instr [0 ].i_loc_propagated = 1 ;
2357
2385
}
2358
2386
}
2359
2387
}
@@ -2362,46 +2390,18 @@ propagate_line_numbers(basicblock *entryblock) {
2362
2390
if (target -> b_predecessors == 1 ) {
2363
2391
if (target -> b_instr [0 ].i_loc .lineno < 0 ) {
2364
2392
target -> b_instr [0 ].i_loc = prev_location ;
2393
+ target -> b_instr [0 ].i_loc_propagated = 1 ;
2365
2394
}
2366
2395
}
2367
2396
}
2368
2397
}
2369
2398
}
2370
2399
2371
- /* Make sure that all returns have a line number, even if early passes
2372
- * have failed to propagate a correct line number.
2373
- * The resulting line number may not be correct according to PEP 626,
2374
- * but should be "good enough", and no worse than in older versions. */
2375
- static void
2376
- guarantee_lineno_for_exits (basicblock * entryblock , int firstlineno ) {
2377
- int lineno = firstlineno ;
2378
- assert (lineno > 0 );
2379
- for (basicblock * b = entryblock ; b != NULL ; b = b -> b_next ) {
2380
- cfg_instr * last = basicblock_last_instr (b );
2381
- if (last == NULL ) {
2382
- continue ;
2383
- }
2384
- if (last -> i_loc .lineno < 0 ) {
2385
- if (last -> i_opcode == RETURN_VALUE ) {
2386
- for (int i = 0 ; i < b -> b_iused ; i ++ ) {
2387
- assert (b -> b_instr [i ].i_loc .lineno < 0 );
2388
-
2389
- b -> b_instr [i ].i_loc .lineno = lineno ;
2390
- }
2391
- }
2392
- }
2393
- else {
2394
- lineno = last -> i_loc .lineno ;
2395
- }
2396
- }
2397
- }
2398
-
2399
2400
static int
2400
2401
resolve_line_numbers (cfg_builder * g , int firstlineno )
2401
2402
{
2402
2403
RETURN_IF_ERROR (duplicate_exits_without_lineno (g ));
2403
2404
propagate_line_numbers (g -> g_entryblock );
2404
- guarantee_lineno_for_exits (g -> g_entryblock , firstlineno );
2405
2405
return SUCCESS ;
2406
2406
}
2407
2407
@@ -2417,14 +2417,15 @@ _PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache,
2417
2417
RETURN_IF_ERROR (label_exception_targets (g -> g_entryblock ));
2418
2418
2419
2419
/** Optimization **/
2420
- RETURN_IF_ERROR (optimize_cfg (g , consts , const_cache ));
2420
+ RETURN_IF_ERROR (optimize_cfg (g , consts , const_cache , firstlineno ));
2421
2421
RETURN_IF_ERROR (remove_unused_consts (g -> g_entryblock , consts ));
2422
2422
RETURN_IF_ERROR (
2423
2423
add_checks_for_loads_of_uninitialized_variables (
2424
2424
g -> g_entryblock , nlocals , nparams ));
2425
2425
insert_superinstructions (g );
2426
2426
2427
2427
RETURN_IF_ERROR (push_cold_blocks_to_end (g ));
2428
+ assert (all_exits_have_lineno (g -> g_entryblock ));
2428
2429
RETURN_IF_ERROR (resolve_line_numbers (g , firstlineno ));
2429
2430
return SUCCESS ;
2430
2431
}
0 commit comments