@@ -68,8 +68,12 @@ typedef struct basicblock_ {
68
68
unsigned b_seen : 1 ;
69
69
/* b_return is true if a RETURN_VALUE opcode is inserted. */
70
70
unsigned b_return : 1 ;
71
+ /* b_finally is true if block is entry to a `finally` section */
72
+ unsigned b_finally : 1 ;
71
73
/* depth of stack upon entry of block, computed by stackdepth() */
72
74
int b_startdepth ;
75
+ /* max relative stack depth for this `finally` subgraph */
76
+ int b_finallydepth ;
73
77
/* instruction offset for block, computed by assemble_jump_offsets() */
74
78
int b_offset ;
75
79
} basicblock ;
@@ -792,6 +796,13 @@ compiler_use_next_block(struct compiler *c, basicblock *block)
792
796
return block ;
793
797
}
794
798
799
+ static void
800
+ compiler_starts_finally (basicblock * block )
801
+ {
802
+ assert (block != NULL );
803
+ block -> b_finally = 1 ;
804
+ }
805
+
795
806
/* Returns the offset of the next instruction in the current block's
796
807
b_instr array. Resizes the b_instr as necessary.
797
808
Returns -1 on failure.
@@ -863,8 +874,8 @@ compiler_set_lineno(struct compiler *c, int off)
863
874
b -> b_instr [off ].i_lineno = c -> u -> u_lineno ;
864
875
}
865
876
866
- int
867
- PyCompile_OpcodeStackEffect (int opcode , int oparg )
877
+ static int
878
+ inline_delta (int opcode , int oparg )
868
879
{
869
880
switch (opcode ) {
870
881
case POP_TOP :
@@ -937,7 +948,7 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
937
948
case INPLACE_OR :
938
949
return -1 ;
939
950
case WITH_EXCEPT_START :
940
- return 2 ;
951
+ return 1 ;
941
952
case RETURN_VALUE :
942
953
return -1 ;
943
954
case IMPORT_STAR :
@@ -951,7 +962,7 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
951
962
case POP_BLOCK :
952
963
return 0 ;
953
964
case POP_EXCEPT :
954
- return 0 ; /* -3 except if bad bytecode */
965
+ return -3 ;
955
966
case RERAISE :
956
967
return -3 ;
957
968
@@ -964,7 +975,7 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
964
975
case UNPACK_EX :
965
976
return (oparg & 0xFF ) + (oparg >>8 );
966
977
case FOR_ITER :
967
- return 1 ; /* or -1, at end of iterator */
978
+ return 1 ;
968
979
969
980
case STORE_ATTR :
970
981
return -2 ;
@@ -1003,14 +1014,17 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
1003
1014
case IMPORT_FROM :
1004
1015
return 1 ;
1005
1016
1006
- case JUMP_FORWARD :
1007
- case JUMP_IF_TRUE_OR_POP : /* -1 if jump not taken */
1008
- case JUMP_IF_FALSE_OR_POP : /* "" */
1017
+ case JUMP_FORWARD : /* These always branch, so this value is meaningless. */
1009
1018
case JUMP_ABSOLUTE :
1010
1019
case END_ITER :
1020
+ return 0 ;
1011
1021
case JUMP_FINALLY :
1012
1022
return 0 ;
1013
1023
1024
+ case JUMP_IF_TRUE_OR_POP : /* 0 if jump taken */
1025
+ case JUMP_IF_FALSE_OR_POP : /* "" */
1026
+ return -1 ;
1027
+
1014
1028
case LOAD_ADDR :
1015
1029
return 1 ;
1016
1030
@@ -1022,12 +1036,8 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
1022
1036
return 1 ;
1023
1037
1024
1038
case SETUP_EXCEPT :
1025
- return 6 ; /* can push 3 values for the new exception
1026
- + 3 others for the previous exception state */
1027
1039
case SETUP_WITH :
1028
- return 5 ; /* can push 3 values for the new exception
1029
- + 3 others for the previous exception state
1030
- -1 for the context manager. */
1040
+ return 0 ;
1031
1041
1032
1042
case BEFORE_WITH :
1033
1043
return 1 ;
@@ -1093,6 +1103,56 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
1093
1103
return PY_INVALID_STACK_EFFECT ; /* not reachable */
1094
1104
}
1095
1105
1106
+ static int
1107
+ branch_delta (int opcode ) {
1108
+ switch (opcode ) {
1109
+ case POP_JUMP_IF_FALSE :
1110
+ case POP_JUMP_IF_TRUE :
1111
+ return -1 ;
1112
+ case FOR_ITER :
1113
+ return -1 ;
1114
+ case JUMP_FORWARD :
1115
+ case END_ITER :
1116
+ case JUMP_ABSOLUTE :
1117
+ case LOAD_ADDR :
1118
+ case JUMP_IF_TRUE_OR_POP : /* -1 if jump not taken */
1119
+ case JUMP_IF_FALSE_OR_POP : /* "" */
1120
+ return 0 ;
1121
+ case JUMP_FINALLY :
1122
+ return 1 ;
1123
+ case SETUP_EXCEPT :
1124
+ return 6 ; /* can push 3 values for the new exception
1125
+ + 3 others for the previous exception state */
1126
+ case SETUP_WITH :
1127
+ return 5 ; /* can push 3 values for the new exception
1128
+ + 3 others for the previous exception state
1129
+ -1 for the context manager. */
1130
+ default :
1131
+ return PY_INVALID_STACK_EFFECT ;
1132
+ }
1133
+ }
1134
+
1135
+ static int
1136
+ is_terminator (int opcode ) {
1137
+ switch (opcode ) {
1138
+ case RETURN_VALUE :
1139
+ case RAISE_VARARGS :
1140
+ case RERAISE :
1141
+ case JUMP_ABSOLUTE :
1142
+ case JUMP_FORWARD :
1143
+ case END_FINALLY :
1144
+ return 1 ;
1145
+ default :
1146
+ return 0 ;
1147
+ }
1148
+ }
1149
+
1150
+ int
1151
+ PyCompile_OpcodeStackEffect (int opcode , int oparg )
1152
+ {
1153
+ return inline_delta (opcode , oparg );
1154
+ }
1155
+
1096
1156
/* Add an opcode with no argument.
1097
1157
Returns 0 on failure, 1 on success.
1098
1158
*/
@@ -2753,6 +2813,7 @@ compiler_try_finally(struct compiler *c, stmt_ty s)
2753
2813
if (!compiler_push_finally_end (c , finalbody ))
2754
2814
return 0 ;
2755
2815
compiler_use_next_block (c , finalbody );
2816
+ compiler_starts_finally (finalbody );
2756
2817
VISIT_SEQ (c , stmt , s -> v .Try .finalbody );
2757
2818
ADDOP (c , END_FINALLY );
2758
2819
compiler_pop_fblock (c , FINALLY_END , finalbody );
@@ -5173,54 +5234,69 @@ dfs(struct compiler *c, basicblock *b, struct assembler *a)
5173
5234
}
5174
5235
5175
5236
static int
5176
- stackdepth_walk (struct compiler * c , basicblock * b , int depth , int maxdepth )
5237
+ stackdepth_walk (struct compiler * c , basicblock * b , int start_depth , int input_maxdepth )
5177
5238
{
5178
- int i , target_depth , effect ;
5239
+ int i , depth , effect , maxdepth ;
5179
5240
struct instr * instr ;
5180
- if (b -> b_seen || b -> b_startdepth >= depth )
5241
+ depth = start_depth ;
5242
+ maxdepth = input_maxdepth ;
5243
+ if (b -> b_finally ) {
5244
+ /* Finally blocks are special. We treat them as a separate CFG, computing their
5245
+ * max-depth from 0. Then we add that to the stack depth for each jump to
5246
+ * the finally block. */
5247
+ if (b -> b_seen ) {
5248
+ int total = start_depth + b -> b_finallydepth ;
5249
+ return total > input_maxdepth ? total : input_maxdepth ;
5250
+ }
5251
+ b -> b_finallydepth = 0 ;
5252
+ depth = 0 ;
5253
+ maxdepth = 0 ;
5254
+ }
5255
+ else if (b -> b_seen || b -> b_startdepth >= depth ) {
5181
5256
return maxdepth ;
5257
+ }
5182
5258
b -> b_seen = 1 ;
5183
5259
b -> b_startdepth = depth ;
5260
+ if (depth > maxdepth )
5261
+ maxdepth = depth ;
5184
5262
for (i = 0 ; i < b -> b_iused ; i ++ ) {
5185
5263
instr = & b -> b_instr [i ];
5186
- effect = PyCompile_OpcodeStackEffect (instr -> i_opcode , instr -> i_oparg );
5264
+ effect = inline_delta (instr -> i_opcode , instr -> i_oparg );
5187
5265
if (effect == PY_INVALID_STACK_EFFECT ) {
5188
5266
fprintf (stderr , "opcode = %d\n" , instr -> i_opcode );
5189
5267
Py_FatalError ("PyCompile_OpcodeStackEffect()" );
5190
5268
}
5269
+ if (instr -> i_jrel || instr -> i_jabs ) {
5270
+ int branch_effect = branch_delta (instr -> i_opcode );
5271
+ if (branch_effect == PY_INVALID_STACK_EFFECT ) {
5272
+ fprintf (stderr , "opcode = %d\n" , instr -> i_opcode );
5273
+ Py_FatalError ("branch_delta()" );
5274
+ }
5275
+ b -> b_finallydepth = maxdepth ;
5276
+ maxdepth = stackdepth_walk (c , instr -> i_target ,
5277
+ depth + branch_effect , maxdepth );
5278
+ }
5191
5279
depth += effect ;
5192
-
5193
5280
if (depth > maxdepth )
5194
5281
maxdepth = depth ;
5195
5282
assert (depth >= 0 ); /* invalid code or bug in stackdepth() */
5196
- if (instr -> i_jrel || instr -> i_jabs ) {
5197
- target_depth = depth ;
5198
- if (instr -> i_opcode == FOR_ITER ) {
5199
- target_depth = depth - 2 ;
5200
- }
5201
- else if (instr -> i_opcode == SETUP_EXCEPT ||
5202
- instr -> i_opcode == SETUP_WITH ) {
5203
- target_depth = depth + 3 ;
5204
- if (target_depth > maxdepth )
5205
- maxdepth = target_depth ;
5206
- }
5207
- else if (instr -> i_opcode == JUMP_IF_TRUE_OR_POP ||
5208
- instr -> i_opcode == JUMP_IF_FALSE_OR_POP )
5209
- depth = depth - 1 ;
5210
- maxdepth = stackdepth_walk (c , instr -> i_target ,
5211
- target_depth , maxdepth );
5212
- if (instr -> i_opcode == JUMP_ABSOLUTE ||
5213
- instr -> i_opcode == JUMP_FORWARD ||
5214
- instr -> i_opcode == END_ITER ) {
5215
- goto out ; /* remaining code is dead */
5216
- }
5283
+ if (is_terminator (instr -> i_opcode )) {
5284
+ goto out ; /* remaining code is dead */
5217
5285
}
5218
5286
}
5219
- if (b -> b_next )
5287
+ if (b -> b_next ) {
5288
+ b -> b_finallydepth = maxdepth ;
5220
5289
maxdepth = stackdepth_walk (c , b -> b_next , depth , maxdepth );
5290
+ }
5221
5291
out :
5222
- b -> b_seen = 0 ;
5223
- return maxdepth ;
5292
+ if (b -> b_finally ) {
5293
+ b -> b_finallydepth = maxdepth ;
5294
+ int total = start_depth + maxdepth ;
5295
+ return total > input_maxdepth ? total : input_maxdepth ;
5296
+ } else {
5297
+ b -> b_seen = 0 ;
5298
+ return maxdepth ;
5299
+ }
5224
5300
}
5225
5301
5226
5302
/* Find the flow path that needs the largest stack. We assume that
0 commit comments