@@ -125,10 +125,37 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx,
125125 return SUCCESS ;
126126}
127127
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+
128155static void zend_ssa_remove_nops (zend_op_array * op_array , zend_ssa * ssa , zend_optimizer_ctx * ctx )
129156{
130157 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 ;
132159 zend_basic_block * b ;
133160 zend_func_info * func_info ;
134161 int j ;
@@ -152,7 +179,7 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
152179 }
153180 }
154181
155- for (b = blocks ; b < end ; b ++ ) {
182+ for (b = blocks ; b < blocks_end ; b ++ ) {
156183 if (b -> flags & (ZEND_BB_REACHABLE |ZEND_BB_UNREACHABLE_FREE )) {
157184 uint32_t end ;
158185
@@ -174,13 +201,7 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
174201 while (i < end ) {
175202 shiftlist [i ] = i - target ;
176203 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 )) {
184205 if (i != target ) {
185206 op_array -> opcodes [target ] = op_array -> opcodes [i ];
186207 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
240261 }
241262
242263 /* update branch targets */
243- for (b = blocks ; b < end ; b ++ ) {
264+ for (b = blocks ; b < blocks_end ; b ++ ) {
244265 if ((b -> flags & ZEND_BB_REACHABLE ) && b -> len != 0 ) {
245266 zend_op * opline = op_array -> opcodes + b -> start + b -> len - 1 ;
246267 zend_optimizer_shift_jump (op_array , opline , shiftlist );
0 commit comments