@@ -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.
@@ -5929,9 +5951,16 @@ dump_basicblock(const basicblock *b)
5929
5951
}
5930
5952
#endif
5931
5953
5954
+
5955
+ static int
5956
+ normalize_basic_block (basicblock * bb ) ;
5957
+
5932
5958
static int
5933
5959
optimize_cfg (struct assembler * a , PyObject * consts );
5934
5960
5961
+ static int
5962
+ ensure_exits_have_lineno (struct compiler * c );
5963
+
5935
5964
static PyCodeObject *
5936
5965
assemble (struct compiler * c , int addNone )
5937
5966
{
@@ -5952,6 +5981,16 @@ assemble(struct compiler *c, int addNone)
5952
5981
ADDOP (c , RETURN_VALUE );
5953
5982
}
5954
5983
5984
+ for (b = c -> u -> u_blocks ; b != NULL ; b = b -> b_list ) {
5985
+ if (normalize_basic_block (b )) {
5986
+ goto error ;
5987
+ }
5988
+ }
5989
+
5990
+ if (ensure_exits_have_lineno (c )) {
5991
+ goto error ;
5992
+ }
5993
+
5955
5994
nblocks = 0 ;
5956
5995
entryblock = NULL ;
5957
5996
for (b = c -> u -> u_blocks ; b != NULL ; b = b -> b_list ) {
@@ -5966,6 +6005,7 @@ assemble(struct compiler *c, int addNone)
5966
6005
else
5967
6006
c -> u -> u_firstlineno = 1 ;
5968
6007
}
6008
+
5969
6009
if (!assemble_init (& a , nblocks , c -> u -> u_firstlineno ))
5970
6010
goto error ;
5971
6011
a .a_entry = entryblock ;
@@ -6338,7 +6378,6 @@ clean_basic_block(basicblock *bb) {
6338
6378
bb -> b_iused = dest ;
6339
6379
}
6340
6380
6341
-
6342
6381
static int
6343
6382
normalize_basic_block (basicblock * bb ) {
6344
6383
/* Mark blocks as exit and/or nofallthrough.
@@ -6367,7 +6406,6 @@ normalize_basic_block(basicblock *bb) {
6367
6406
return 0 ;
6368
6407
}
6369
6408
6370
-
6371
6409
static int
6372
6410
mark_reachable (struct assembler * a ) {
6373
6411
basicblock * * stack , * * sp ;
@@ -6398,8 +6436,27 @@ mark_reachable(struct assembler *a) {
6398
6436
return 0 ;
6399
6437
}
6400
6438
6439
+ /* If an instruction has no line number, but it's predecessor in the BB does,
6440
+ * then copy the line number. This reduces the size of the line number table,
6441
+ * but has no impact on the generated line number events.
6442
+ */
6443
+ static void
6444
+ minimize_lineno_table (struct assembler * a ) {
6445
+ for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
6446
+ int prev_lineno = -1 ;
6447
+ for (int i = 0 ; i < b -> b_iused ; i ++ ) {
6448
+ if (b -> b_instr [i ].i_lineno < 0 ) {
6449
+ b -> b_instr [i ].i_lineno = prev_lineno ;
6450
+ }
6451
+ else {
6452
+ prev_lineno = b -> b_instr [i ].i_lineno ;
6453
+ }
6454
+ }
6455
+
6456
+ }
6457
+ }
6401
6458
6402
- /* Perform basic peephole optimizations on a control flow graph.
6459
+ /* Perform optimizations on a control flow graph.
6403
6460
The consts object should still be in list form to allow new constants
6404
6461
to be appended.
6405
6462
@@ -6411,11 +6468,6 @@ mark_reachable(struct assembler *a) {
6411
6468
static int
6412
6469
optimize_cfg (struct assembler * a , PyObject * consts )
6413
6470
{
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
6471
for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
6420
6472
if (optimize_basic_block (b , consts )) {
6421
6473
return -1 ;
@@ -6432,9 +6484,71 @@ optimize_cfg(struct assembler *a, PyObject *consts)
6432
6484
b -> b_iused = 0 ;
6433
6485
}
6434
6486
}
6487
+ minimize_lineno_table (a );
6435
6488
return 0 ;
6436
6489
}
6437
6490
6491
+ static int
6492
+ is_exit_without_lineno (basicblock * b ) {
6493
+ if (!b -> b_exit ) {
6494
+ return 0 ;
6495
+ }
6496
+ for (int i = 0 ; i < b -> b_iused ; i ++ ) {
6497
+ if (b -> b_instr [i ].i_lineno >= 0 ) {
6498
+ return 0 ;
6499
+ }
6500
+ }
6501
+ return 1 ;
6502
+ }
6503
+
6504
+ /* PEP 626 mandates that the f_lineno of a frame is correct
6505
+ * after a frame terminates. It would be prohibitively expensive
6506
+ * to continuously update the f_lineno field at runtime,
6507
+ * so we make sure that all exiting instruction (raises and returns)
6508
+ * have a valid line number, allowing us to compute f_lineno lazily.
6509
+ * We can do this by duplicating the exit blocks without line number
6510
+ * so that none have more than one predecessor. We can then safely
6511
+ * copy the line number from the sole predecessor block.
6512
+ */
6513
+ static int
6514
+ ensure_exits_have_lineno (struct compiler * c )
6515
+ {
6516
+ /* Copy all exit blocks without line number that are targets of a jump.
6517
+ */
6518
+ for (basicblock * b = c -> u -> u_blocks ; b != NULL ; b = b -> b_list ) {
6519
+ if (b -> b_iused > 0 && is_jump (& b -> b_instr [b -> b_iused - 1 ])) {
6520
+ switch (b -> b_instr [b -> b_iused - 1 ].i_opcode ) {
6521
+ /* Note: Only actual jumps, not exception handlers */
6522
+ case SETUP_ASYNC_WITH :
6523
+ case SETUP_WITH :
6524
+ case SETUP_FINALLY :
6525
+ continue ;
6526
+ }
6527
+ basicblock * target = b -> b_instr [b -> b_iused - 1 ].i_target ;
6528
+ if (is_exit_without_lineno (target )) {
6529
+ basicblock * new_target = compiler_copy_block (c , target );
6530
+ if (new_target == NULL ) {
6531
+ return -1 ;
6532
+ }
6533
+ new_target -> b_instr [0 ].i_lineno = b -> b_instr [b -> b_iused - 1 ].i_lineno ;
6534
+ b -> b_instr [b -> b_iused - 1 ].i_target = new_target ;
6535
+ }
6536
+ }
6537
+ }
6538
+ /* Any remaining reachable exit blocks without line number can only be reached by
6539
+ * fall through, and thus can only have a single predecessor */
6540
+ for (basicblock * b = c -> u -> u_blocks ; b != NULL ; b = b -> b_list ) {
6541
+ if (!b -> b_nofallthrough && b -> b_next && b -> b_iused > 0 ) {
6542
+ if (is_exit_without_lineno (b -> b_next )) {
6543
+ assert (b -> b_next -> b_iused > 0 );
6544
+ b -> b_next -> b_instr [0 ].i_lineno = b -> b_instr [b -> b_iused - 1 ].i_lineno ;
6545
+ }
6546
+ }
6547
+ }
6548
+ return 0 ;
6549
+ }
6550
+
6551
+
6438
6552
/* Retained for API compatibility.
6439
6553
* Optimization is now done in optimize_cfg */
6440
6554
0 commit comments