@@ -812,6 +812,28 @@ compiler_use_next_block(struct compiler *c, basicblock *block)
812
812
return block ;
813
813
}
814
814
815
+ static basicblock *
816
+ compiler_copy_block (struct compiler * c , basicblock * block )
817
+ {
818
+ /* Cannot copy a block if it has a fallthrough, since
819
+ * a block can only have one fallthrough predecessor.
820
+ */
821
+ assert (block -> b_nofallthrough );
822
+ basicblock * result = compiler_next_block (c );
823
+ if (result == NULL ) {
824
+ return NULL ;
825
+ }
826
+ for (int i = 0 ; i < block -> b_iused ; i ++ ) {
827
+ int n = compiler_next_instr (result );
828
+ if (n < 0 ) {
829
+ return NULL ;
830
+ }
831
+ result -> b_instr [n ] = block -> b_instr [i ];
832
+ }
833
+ result -> b_exit = block -> b_exit ;
834
+ return result ;
835
+ }
836
+
815
837
/* Returns the offset of the next instruction in the current block's
816
838
b_instr array. Resizes the b_instr as necessary.
817
839
Returns -1 on failure.
@@ -2732,12 +2754,13 @@ compiler_if(struct compiler *c, stmt_ty s)
2732
2754
static int
2733
2755
compiler_for (struct compiler * c , stmt_ty s )
2734
2756
{
2735
- basicblock * start , * cleanup , * end ;
2757
+ basicblock * start , * body , * cleanup , * end ;
2736
2758
2737
2759
start = compiler_new_block (c );
2760
+ body = compiler_new_block (c );
2738
2761
cleanup = compiler_new_block (c );
2739
2762
end = compiler_new_block (c );
2740
- if (start == NULL || end == NULL || cleanup == NULL ) {
2763
+ if (start == NULL || body == NULL || end == NULL || cleanup == NULL ) {
2741
2764
return 0 ;
2742
2765
}
2743
2766
if (!compiler_push_fblock (c , FOR_LOOP , start , end , NULL )) {
@@ -2747,6 +2770,7 @@ compiler_for(struct compiler *c, stmt_ty s)
2747
2770
ADDOP (c , GET_ITER );
2748
2771
compiler_use_next_block (c , start );
2749
2772
ADDOP_JUMP (c , FOR_ITER , cleanup );
2773
+ compiler_use_next_block (c , body );
2750
2774
VISIT (c , expr , s -> v .For .target );
2751
2775
VISIT_SEQ (c , stmt , s -> v .For .body );
2752
2776
ADDOP_JUMP (c , JUMP_ABSOLUTE , start );
@@ -5929,9 +5953,16 @@ dump_basicblock(const basicblock *b)
5929
5953
}
5930
5954
#endif
5931
5955
5956
+
5957
+ static int
5958
+ normalize_basic_block (basicblock * bb );
5959
+
5932
5960
static int
5933
5961
optimize_cfg (struct assembler * a , PyObject * consts );
5934
5962
5963
+ static int
5964
+ ensure_exits_have_lineno (struct compiler * c );
5965
+
5935
5966
static PyCodeObject *
5936
5967
assemble (struct compiler * c , int addNone )
5937
5968
{
@@ -5952,6 +5983,16 @@ assemble(struct compiler *c, int addNone)
5952
5983
ADDOP (c , RETURN_VALUE );
5953
5984
}
5954
5985
5986
+ for (basicblock * b = c -> u -> u_blocks ; b != NULL ; b = b -> b_list ) {
5987
+ if (normalize_basic_block (b )) {
5988
+ goto error ;
5989
+ }
5990
+ }
5991
+
5992
+ if (ensure_exits_have_lineno (c )) {
5993
+ goto error ;
5994
+ }
5995
+
5955
5996
nblocks = 0 ;
5956
5997
entryblock = NULL ;
5957
5998
for (b = c -> u -> u_blocks ; b != NULL ; b = b -> b_list ) {
@@ -5966,6 +6007,7 @@ assemble(struct compiler *c, int addNone)
5966
6007
else
5967
6008
c -> u -> u_firstlineno = 1 ;
5968
6009
}
6010
+
5969
6011
if (!assemble_init (& a , nblocks , c -> u -> u_firstlineno ))
5970
6012
goto error ;
5971
6013
a .a_entry = entryblock ;
@@ -6338,7 +6380,6 @@ clean_basic_block(basicblock *bb) {
6338
6380
bb -> b_iused = dest ;
6339
6381
}
6340
6382
6341
-
6342
6383
static int
6343
6384
normalize_basic_block (basicblock * bb ) {
6344
6385
/* Mark blocks as exit and/or nofallthrough.
@@ -6349,7 +6390,8 @@ normalize_basic_block(basicblock *bb) {
6349
6390
case RAISE_VARARGS :
6350
6391
case RERAISE :
6351
6392
bb -> b_exit = 1 ;
6352
- /* fall through */
6393
+ bb -> b_nofallthrough = 1 ;
6394
+ break ;
6353
6395
case JUMP_ABSOLUTE :
6354
6396
case JUMP_FORWARD :
6355
6397
bb -> b_nofallthrough = 1 ;
@@ -6358,16 +6400,21 @@ normalize_basic_block(basicblock *bb) {
6358
6400
case POP_JUMP_IF_TRUE :
6359
6401
case JUMP_IF_FALSE_OR_POP :
6360
6402
case JUMP_IF_TRUE_OR_POP :
6403
+ case FOR_ITER :
6361
6404
if (i != bb -> b_iused - 1 ) {
6362
6405
PyErr_SetString (PyExc_SystemError , "malformed control flow graph." );
6363
6406
return -1 ;
6364
6407
}
6408
+ /* Skip over empty basic blocks. */
6409
+ while (bb -> b_instr [i ].i_target -> b_iused == 0 ) {
6410
+ bb -> b_instr [i ].i_target = bb -> b_instr [i ].i_target -> b_next ;
6411
+ }
6412
+
6365
6413
}
6366
6414
}
6367
6415
return 0 ;
6368
6416
}
6369
6417
6370
-
6371
6418
static int
6372
6419
mark_reachable (struct assembler * a ) {
6373
6420
basicblock * * stack , * * sp ;
@@ -6398,8 +6445,27 @@ mark_reachable(struct assembler *a) {
6398
6445
return 0 ;
6399
6446
}
6400
6447
6448
+ /* If an instruction has no line number, but it's predecessor in the BB does,
6449
+ * then copy the line number. This reduces the size of the line number table,
6450
+ * but has no impact on the generated line number events.
6451
+ */
6452
+ static void
6453
+ minimize_lineno_table (struct assembler * a ) {
6454
+ for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
6455
+ int prev_lineno = -1 ;
6456
+ for (int i = 0 ; i < b -> b_iused ; i ++ ) {
6457
+ if (b -> b_instr [i ].i_lineno < 0 ) {
6458
+ b -> b_instr [i ].i_lineno = prev_lineno ;
6459
+ }
6460
+ else {
6461
+ prev_lineno = b -> b_instr [i ].i_lineno ;
6462
+ }
6463
+ }
6464
+
6465
+ }
6466
+ }
6401
6467
6402
- /* Perform basic peephole optimizations on a control flow graph.
6468
+ /* Perform optimizations on a control flow graph.
6403
6469
The consts object should still be in list form to allow new constants
6404
6470
to be appended.
6405
6471
@@ -6411,11 +6477,6 @@ mark_reachable(struct assembler *a) {
6411
6477
static int
6412
6478
optimize_cfg (struct assembler * a , PyObject * consts )
6413
6479
{
6414
- for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
6415
- if (normalize_basic_block (b )) {
6416
- return -1 ;
6417
- }
6418
- }
6419
6480
for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
6420
6481
if (optimize_basic_block (b , consts )) {
6421
6482
return -1 ;
@@ -6432,9 +6493,63 @@ optimize_cfg(struct assembler *a, PyObject *consts)
6432
6493
b -> b_iused = 0 ;
6433
6494
}
6434
6495
}
6496
+ minimize_lineno_table (a );
6497
+ return 0 ;
6498
+ }
6499
+
6500
+ static inline int
6501
+ is_exit_without_lineno (basicblock * b ) {
6502
+ return b -> b_exit && b -> b_instr [0 ].i_lineno < 0 ;
6503
+ }
6504
+
6505
+ /* PEP 626 mandates that the f_lineno of a frame is correct
6506
+ * after a frame terminates. It would be prohibitively expensive
6507
+ * to continuously update the f_lineno field at runtime,
6508
+ * so we make sure that all exiting instruction (raises and returns)
6509
+ * have a valid line number, allowing us to compute f_lineno lazily.
6510
+ * We can do this by duplicating the exit blocks without line number
6511
+ * so that none have more than one predecessor. We can then safely
6512
+ * copy the line number from the sole predecessor block.
6513
+ */
6514
+ static int
6515
+ ensure_exits_have_lineno (struct compiler * c )
6516
+ {
6517
+ /* Copy all exit blocks without line number that are targets of a jump.
6518
+ */
6519
+ for (basicblock * b = c -> u -> u_blocks ; b != NULL ; b = b -> b_list ) {
6520
+ if (b -> b_iused > 0 && is_jump (& b -> b_instr [b -> b_iused - 1 ])) {
6521
+ switch (b -> b_instr [b -> b_iused - 1 ].i_opcode ) {
6522
+ /* Note: Only actual jumps, not exception handlers */
6523
+ case SETUP_ASYNC_WITH :
6524
+ case SETUP_WITH :
6525
+ case SETUP_FINALLY :
6526
+ continue ;
6527
+ }
6528
+ basicblock * target = b -> b_instr [b -> b_iused - 1 ].i_target ;
6529
+ if (is_exit_without_lineno (target )) {
6530
+ basicblock * new_target = compiler_copy_block (c , target );
6531
+ if (new_target == NULL ) {
6532
+ return -1 ;
6533
+ }
6534
+ new_target -> b_instr [0 ].i_lineno = b -> b_instr [b -> b_iused - 1 ].i_lineno ;
6535
+ b -> b_instr [b -> b_iused - 1 ].i_target = new_target ;
6536
+ }
6537
+ }
6538
+ }
6539
+ /* Any remaining reachable exit blocks without line number can only be reached by
6540
+ * fall through, and thus can only have a single predecessor */
6541
+ for (basicblock * b = c -> u -> u_blocks ; b != NULL ; b = b -> b_list ) {
6542
+ if (!b -> b_nofallthrough && b -> b_next && b -> b_iused > 0 ) {
6543
+ if (is_exit_without_lineno (b -> b_next )) {
6544
+ assert (b -> b_next -> b_iused > 0 );
6545
+ b -> b_next -> b_instr [0 ].i_lineno = b -> b_instr [b -> b_iused - 1 ].i_lineno ;
6546
+ }
6547
+ }
6548
+ }
6435
6549
return 0 ;
6436
6550
}
6437
6551
6552
+
6438
6553
/* Retained for API compatibility.
6439
6554
* Optimization is now done in optimize_cfg */
6440
6555
0 commit comments