@@ -29,6 +29,7 @@ typedef struct _PyCfgInstruction {
2929 int i_opcode ;
3030 int i_oparg ;
3131 _PyCompilerSrcLocation i_loc ;
32+ unsigned i_loc_propagated : 1 ; /* location was set by propagate_line_numbers */
3233 struct _PyCfgBasicblock * i_target ; /* target block (if jump instruction) */
3334 struct _PyCfgBasicblock * i_except ; /* target block when exception is raised */
3435} cfg_instr ;
@@ -504,6 +505,21 @@ no_redundant_jumps(cfg_builder *g) {
504505 return true;
505506}
506507
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+ }
507523#endif
508524
509525/***** CFG preprocessing (jump targets and exceptions) *****/
@@ -940,7 +956,10 @@ label_exception_targets(basicblock *entryblock) {
940956/***** CFG optimizations *****/
941957
942958static 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+ }
944963 basicblock * * stack = make_cfg_traversal_stack (entryblock );
945964 if (stack == NULL ) {
946965 return ERROR ;
@@ -972,6 +991,14 @@ mark_reachable(basicblock *entryblock) {
972991 }
973992 }
974993 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+ }
9751002 return SUCCESS ;
9761003}
9771004
@@ -1149,13 +1176,15 @@ jump_thread(cfg_instr *inst, cfg_instr *target, int opcode)
11491176 assert (is_jump (target ));
11501177 // bpo-45773: If inst->i_target == target->i_target, then nothing actually
11511178 // 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 );
11521181 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 ) &&
11541183 inst -> i_target != target -> i_target )
11551184 {
11561185 inst -> i_target = target -> i_target ;
11571186 inst -> i_opcode = opcode ;
1158- if (inst -> i_loc . lineno == -1 ) {
1187+ if (inst -> i_loc_propagated && ! target -> i_loc_propagated ) {
11591188 inst -> i_loc = target -> i_loc ;
11601189 }
11611190 return true;
@@ -1714,6 +1743,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
17141743 return ERROR ;
17151744}
17161745
1746+ static int resolve_line_numbers (cfg_builder * g , int firstlineno );
17171747
17181748/* Perform optimizations on a control flow graph.
17191749 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)
17231753 NOPs. Later those NOPs are removed.
17241754*/
17251755static 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 )
17271757{
17281758 assert (PyDict_CheckExact (const_cache ));
17291759 RETURN_IF_ERROR (check_cfg (g ));
17301760 for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
17311761 RETURN_IF_ERROR (inline_small_exit_blocks (b ));
17321762 }
1763+ RETURN_IF_ERROR (remove_unreachable (g -> g_entryblock ));
1764+ RETURN_IF_ERROR (resolve_line_numbers (g , firstlineno ));
17331765 for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
17341766 RETURN_IF_ERROR (optimize_basic_block (const_cache , b , consts ));
1735- assert (b -> b_predecessors == 0 );
17361767 }
17371768 RETURN_IF_ERROR (remove_redundant_nops_and_pairs (g -> g_entryblock ));
17381769 for (basicblock * b = g -> g_entryblock ; b != NULL ; b = b -> b_next ) {
17391770 RETURN_IF_ERROR (inline_small_exit_blocks (b ));
17401771 }
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 ));
17541773
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 ));
17571779 }
17581780
1759- RETURN_IF_ERROR (remove_redundant_jumps (g ));
1760-
17611781 assert (no_redundant_jumps (g ));
17621782 return SUCCESS ;
17631783}
@@ -2174,7 +2194,13 @@ push_cold_blocks_to_end(cfg_builder *g) {
21742194 if (!IS_LABEL (b -> b_next -> b_label )) {
21752195 b -> b_next -> b_label .id = next_lbl ++ ;
21762196 }
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 );
21782204 explicit_jump -> b_cold = 1 ;
21792205 explicit_jump -> b_next = b -> b_next ;
21802206 b -> b_next = explicit_jump ;
@@ -2345,6 +2371,7 @@ propagate_line_numbers(basicblock *entryblock) {
23452371 for (int i = 0 ; i < b -> b_iused ; i ++ ) {
23462372 if (b -> b_instr [i ].i_loc .lineno < 0 ) {
23472373 b -> b_instr [i ].i_loc = prev_location ;
2374+ b -> b_instr [i ].i_loc_propagated = 1 ;
23482375 }
23492376 else {
23502377 prev_location = b -> b_instr [i ].i_loc ;
@@ -2354,6 +2381,7 @@ propagate_line_numbers(basicblock *entryblock) {
23542381 if (b -> b_next -> b_iused > 0 ) {
23552382 if (b -> b_next -> b_instr [0 ].i_loc .lineno < 0 ) {
23562383 b -> b_next -> b_instr [0 ].i_loc = prev_location ;
2384+ b -> b_next -> b_instr [0 ].i_loc_propagated = 1 ;
23572385 }
23582386 }
23592387 }
@@ -2362,46 +2390,18 @@ propagate_line_numbers(basicblock *entryblock) {
23622390 if (target -> b_predecessors == 1 ) {
23632391 if (target -> b_instr [0 ].i_loc .lineno < 0 ) {
23642392 target -> b_instr [0 ].i_loc = prev_location ;
2393+ target -> b_instr [0 ].i_loc_propagated = 1 ;
23652394 }
23662395 }
23672396 }
23682397 }
23692398}
23702399
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-
23992400static int
24002401resolve_line_numbers (cfg_builder * g , int firstlineno )
24012402{
24022403 RETURN_IF_ERROR (duplicate_exits_without_lineno (g ));
24032404 propagate_line_numbers (g -> g_entryblock );
2404- guarantee_lineno_for_exits (g -> g_entryblock , firstlineno );
24052405 return SUCCESS ;
24062406}
24072407
@@ -2417,14 +2417,15 @@ _PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache,
24172417 RETURN_IF_ERROR (label_exception_targets (g -> g_entryblock ));
24182418
24192419 /** Optimization **/
2420- RETURN_IF_ERROR (optimize_cfg (g , consts , const_cache ));
2420+ RETURN_IF_ERROR (optimize_cfg (g , consts , const_cache , firstlineno ));
24212421 RETURN_IF_ERROR (remove_unused_consts (g -> g_entryblock , consts ));
24222422 RETURN_IF_ERROR (
24232423 add_checks_for_loads_of_uninitialized_variables (
24242424 g -> g_entryblock , nlocals , nparams ));
24252425 insert_superinstructions (g );
24262426
24272427 RETURN_IF_ERROR (push_cold_blocks_to_end (g ));
2428+ assert (all_exits_have_lineno (g -> g_entryblock ));
24282429 RETURN_IF_ERROR (resolve_line_numbers (g , firstlineno ));
24292430 return SUCCESS ;
24302431}
0 commit comments