@@ -125,10 +125,37 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx,
125
125
return SUCCESS ;
126
126
}
127
127
128
+ static zend_bool is_smart_branch_inhibiting_nop (
129
+ zend_op_array * op_array , uint32_t target , uint32_t current ,
130
+ zend_basic_block * b , zend_basic_block * blocks_end )
131
+ {
132
+ uint32_t next ;
133
+ /* Target points one past the last non-nop instruction. Make sure there is one. */
134
+ if (target == 0 ) {
135
+ return 0 ;
136
+ }
137
+
138
+ /* Find the next instruction, skipping unreachable or empty blocks. */
139
+ next = current + 1 ;
140
+ if (next >= b -> start + b -> len ) {
141
+ do {
142
+ b ++ ;
143
+ if (b == blocks_end ) {
144
+ return 0 ;
145
+ }
146
+ } while (!(b -> flags & ZEND_BB_REACHABLE ) || b -> len == 0 );
147
+ next = b -> start ;
148
+ }
149
+
150
+ return (op_array -> opcodes [next ].opcode == ZEND_JMPZ ||
151
+ op_array -> opcodes [next ].opcode == ZEND_JMPNZ ) &&
152
+ zend_is_smart_branch (op_array -> opcodes + target - 1 );
153
+ }
154
+
128
155
static void zend_ssa_remove_nops (zend_op_array * op_array , zend_ssa * ssa , zend_optimizer_ctx * ctx )
129
156
{
130
157
zend_basic_block * blocks = ssa -> cfg .blocks ;
131
- zend_basic_block * end = blocks + ssa -> cfg .blocks_count ;
158
+ zend_basic_block * blocks_end = blocks + ssa -> cfg .blocks_count ;
132
159
zend_basic_block * b ;
133
160
zend_func_info * func_info ;
134
161
int j ;
@@ -152,7 +179,7 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
152
179
}
153
180
}
154
181
155
- for (b = blocks ; b < end ; b ++ ) {
182
+ for (b = blocks ; b < blocks_end ; b ++ ) {
156
183
if (b -> flags & (ZEND_BB_REACHABLE |ZEND_BB_UNREACHABLE_FREE )) {
157
184
uint32_t end ;
158
185
@@ -174,13 +201,7 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
174
201
while (i < end ) {
175
202
shiftlist [i ] = i - target ;
176
203
if (EXPECTED (op_array -> opcodes [i ].opcode != ZEND_NOP ) ||
177
- /* Keep NOP to support ZEND_VM_SMART_BRANCH. Using "target-1" instead of
178
- * "i-1" here to check the last non-NOP instruction. */
179
- (target > 0 &&
180
- i + 1 < op_array -> last &&
181
- (op_array -> opcodes [i + 1 ].opcode == ZEND_JMPZ ||
182
- op_array -> opcodes [i + 1 ].opcode == ZEND_JMPNZ ) &&
183
- zend_is_smart_branch (op_array -> opcodes + target - 1 ))) {
204
+ is_smart_branch_inhibiting_nop (op_array , target , i , b , blocks_end )) {
184
205
if (i != target ) {
185
206
op_array -> opcodes [target ] = op_array -> opcodes [i ];
186
207
ssa -> ops [target ] = ssa -> ops [i ];
@@ -240,7 +261,7 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
240
261
}
241
262
242
263
/* update branch targets */
243
- for (b = blocks ; b < end ; b ++ ) {
264
+ for (b = blocks ; b < blocks_end ; b ++ ) {
244
265
if ((b -> flags & ZEND_BB_REACHABLE ) && b -> len != 0 ) {
245
266
zend_op * opline = op_array -> opcodes + b -> start + b -> len - 1 ;
246
267
zend_optimizer_shift_jump (op_array , opline , shiftlist );
0 commit comments