for (b = blocks; b < end; b++) {
if (b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE)) {
uint32_t end;
- if (b->flags & ZEND_BB_UNREACHABLE_FREE) {
- /* Only keep the FREE for the loop var */
- ZEND_ASSERT(op_array->opcodes[b->start].opcode == ZEND_FREE
- || op_array->opcodes[b->start].opcode == ZEND_FE_FREE);
- b->len = 1;
- }
- end = b->start + b->len;
- i = b->start;
- b->start = target;
- while (i < end) {
- shiftlist[i] = i - target;
- if (EXPECTED(op_array->opcodes[i].opcode != ZEND_NOP) ||
- /* Keep NOP to support ZEND_VM_SMART_BRANCH. Using "target-1" instead of
- * "i-1" here to check the last non-NOP instruction. */
- (target > 0 &&
- i + 1 < op_array->last &&
- (op_array->opcodes[i+1].opcode == ZEND_JMPZ ||
- op_array->opcodes[i+1].opcode == ZEND_JMPNZ) &&
- zend_is_smart_branch(op_array->opcodes + target - 1))) {
- if (i != target) {
- op_array->opcodes[target] = op_array->opcodes[i];
- ssa->ops[target] = ssa->ops[i];
- }
- target++;
+ if (b->len) {
+ while (i < b->start) {
+ shiftlist[i] = i - target;
+ i++;
}
- i++;
- }
- if (target != end && b->len != 0) {
- zend_op *opline;
- zend_op *new_opline;
-
- b->len = target - b->start;
- opline = op_array->opcodes + end - 1;
- if (opline->opcode == ZEND_NOP) {
- continue;
+
+ if (b->flags & ZEND_BB_UNREACHABLE_FREE) {
+ /* Only keep the FREE for the loop var */
+ ZEND_ASSERT(op_array->opcodes[b->start].opcode == ZEND_FREE
+ || op_array->opcodes[b->start].opcode == ZEND_FE_FREE);
+ b->len = 1;
}
- new_opline = op_array->opcodes + target - 1;
- switch (new_opline->opcode) {
- case ZEND_JMP:
- case ZEND_FAST_CALL:
- ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op1, ZEND_OP1_JMP_ADDR(opline));
- break;
- case ZEND_JMPZNZ:
- new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
- /* break missing intentionally */
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- case ZEND_FE_RESET_R:
- case ZEND_FE_RESET_RW:
- case ZEND_JMP_SET:
- case ZEND_COALESCE:
- case ZEND_ASSERT_CHECK:
- ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op2, ZEND_OP2_JMP_ADDR(opline));
- break;
- case ZEND_CATCH:
- if (!opline->result.num) {
- new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
+ end = b->start + b->len;
+ b->start = target;
+ while (i < end) {
+ shiftlist[i] = i - target;
+ if (EXPECTED(op_array->opcodes[i].opcode != ZEND_NOP) ||
- /*keep NOP to support ZEND_VM_SMART_BRANCH */
- (i > 0 &&
++ /* Keep NOP to support ZEND_VM_SMART_BRANCH. Using "target-1" instead of
++ * "i-1" here to check the last non-NOP instruction. */
++ (target > 0 &&
+ i + 1 < op_array->last &&
+ (op_array->opcodes[i+1].opcode == ZEND_JMPZ ||
+ op_array->opcodes[i+1].opcode == ZEND_JMPNZ) &&
- zend_is_smart_branch(op_array->opcodes + i - 1))) {
++ zend_is_smart_branch(op_array->opcodes + target - 1))) {
+ if (i != target) {
+ op_array->opcodes[target] = op_array->opcodes[i];
+ ssa->ops[target] = ssa->ops[i];
+ ssa->cfg.map[target] = b - blocks;
}
- break;
- case ZEND_DECLARE_ANON_CLASS:
- case ZEND_DECLARE_ANON_INHERITED_CLASS:
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
- new_opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, new_opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
- break;
+ target++;
+ }
+ i++;
+ }
+ if (target != end) {
+ zend_op *opline;
+ zend_op *new_opline;
+
+ b->len = target - b->start;
+ opline = op_array->opcodes + end - 1;
+ if (opline->opcode == ZEND_NOP) {
+ continue;
+ }
+
+ new_opline = op_array->opcodes + target - 1;
+ zend_optimizer_migrate_jump(op_array, new_opline, opline);
}
+ } else {
+ b->start = target;
}
+ } else {
+ b->start = target;
+ b->len = 0;
}
}