#define EX_VAR_TO_NUM(n) (ZEND_CALL_VAR(NULL, n) - ZEND_CALL_VAR_NUM(NULL, 0))
+#define ZEND_OPLINE_TO_OFFSET(opline, target) \
+ ((char*)(target) - (char*)(opline))
+
#define ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline_num) \
((char*)&(op_array)->opcodes[opline_num] - (char*)(opline))
# define OP_JMP_ADDR(opline, node) \
(node).jmp_addr
+# define ZEND_SET_OP_JMP_ADDR(opline, node, val) do { \
+ (node).jmp_addr = (val); \
+ } while (0)
+
/* convert jump target from compile-time to run-time */
# define ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, node) do { \
(node).jmp_addr = (op_array)->opcodes + (node).opline_num; \
# define OP_JMP_ADDR(opline, node) \
ZEND_OFFSET_TO_OPLINE(opline, (node).jmp_offset)
+# define ZEND_SET_OP_JMP_ADDR(opline, node, val) do { \
+ (node).jmp_offset = ZEND_OPLINE_TO_OFFSET(opline, val); \
+ } while (0)
+
/* convert jump target from compile-time to run-time */
# define ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, node) do { \
(node).jmp_offset = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, (node).opline_num); \
static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimizer_ctx *ctx)
{
zend_op *opline;
- zend_op *end = op_array->opcodes + op_array->last;
+ zend_op *opcodes = op_array->opcodes;
+ zend_op *end = opcodes + op_array->last;
zend_code_block *blocks, *cur_block;
uint32_t opno = 0;
memset(cfg, 0, sizeof(zend_cfg));
blocks = cfg->blocks = zend_arena_calloc(&ctx->arena, op_array->last + 2, sizeof(zend_code_block));
- opline = op_array->opcodes;
+ opline = opcodes;
blocks[0].start_opline = opline;
blocks[0].start_opline_no = 0;
while (opline < end) {
case ZEND_JMP:
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
- START_BLOCK_OP(ZEND_OP1(opline).opline_num);
+ START_BLOCK_OP(ZEND_OP1_JMP_ADDR(opline) - opcodes);
/* break missing intentionally */
case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
/* start new block from this+1 */
START_BLOCK_OP(opno + 1);
break;
- /* TODO: if conditional jmp depends on constant,
- don't start block that won't be executed */
- case ZEND_CATCH:
- START_BLOCK_OP(opline->extended_value);
- START_BLOCK_OP(opno + 1);
- break;
case ZEND_JMPZNZ:
- START_BLOCK_OP(opline->extended_value);
+ START_BLOCK_OP(ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - opcodes);
+ /* break missing intentionally */
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_ASSERT_CHECK:
- START_BLOCK_OP(ZEND_OP2(opline).opline_num);
+ START_BLOCK_OP(ZEND_OP2_JMP_ADDR(opline) - opcodes);
START_BLOCK_OP(opno + 1);
break;
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
- START_BLOCK_OP(opline->extended_value);
+ case ZEND_CATCH:
+ START_BLOCK_OP(ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - opcodes);
START_BLOCK_OP(opno + 1);
break;
}
cur_block->next = &blocks[opno];
/* what is the last OP of previous block? */
opline = blocks[opno].start_opline - 1;
- if (opline->opcode == ZEND_OP_DATA) {
- opline--;
- }
switch((unsigned)opline->opcode) {
case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
case ZEND_FAST_RET:
break;
case ZEND_JMP:
- cur_block->op1_to = &blocks[ZEND_OP1(opline).opline_num];
+ cur_block->op1_to = &blocks[ZEND_OP1_JMP_ADDR(opline) - opcodes];
break;
case ZEND_FAST_CALL:
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
- cur_block->op1_to = &blocks[ZEND_OP1(opline).opline_num];
+ cur_block->op1_to = &blocks[ZEND_OP1_JMP_ADDR(opline) - opcodes];
cur_block->follow_to = &blocks[opno];
break;
case ZEND_JMPZNZ:
- cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
- cur_block->ext_to = &blocks[opline->extended_value];
- break;
- case ZEND_CATCH:
- cur_block->ext_to = &blocks[opline->extended_value];
- cur_block->follow_to = &blocks[opno];
+ cur_block->op2_to = &blocks[ZEND_OP2_JMP_ADDR(opline) - opcodes];
+ cur_block->ext_to = &blocks[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - opcodes];
break;
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
- cur_block->ext_to = &blocks[opline->extended_value];
+ case ZEND_CATCH:
+ cur_block->ext_to = &blocks[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - opcodes];
cur_block->follow_to = &blocks[opno];
break;
case ZEND_JMPZ:
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_ASSERT_CHECK:
- cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
+ cur_block->op2_to = &blocks[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes];
/* break missing intentionally */
default:
/* next block follows this */
case ZEND_JMPZNZ:
{
/* T = BOOL_NOT(X) + JMPZNZ(T,L1,L2) -> NOP, JMPZNZ(X,L2,L1) */
- int op_t;
zend_code_block *op_b;
- op_t = opline->extended_value;
- opline->extended_value = ZEND_OP2(opline).opline_num;
- ZEND_OP2(opline).opline_num = op_t;
-
op_b = block->ext_to;
block->ext_to = block->op2_to;
block->op2_to = op_b;
static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array)
{
zend_code_block *blocks = cfg->blocks;
- zend_op *new_opcodes = emalloc(op_array->last * sizeof(zend_op));
- zend_op *opline = new_opcodes;
- zend_code_block *cur_block = blocks;
+ zend_op *new_opcodes;
+ zend_op *opline;
+ zend_code_block *cur_block;
+ int len = 0;
- /* Copy code of reachable blocks into a single buffer */
- while (cur_block) {
- if (cur_block->access) {
- memcpy(opline, cur_block->start_opline, cur_block->len * sizeof(zend_op));
- cur_block->start_opline = opline;
- opline += cur_block->len;
- if ((opline - 1)->opcode == ZEND_JMP) {
+ for (cur_block = blocks; cur_block; cur_block = cur_block->next) {
+ if (cur_block->access && cur_block->len) {
+ opline = cur_block->start_opline + cur_block->len - 1;
+ if (opline->opcode == ZEND_JMP) {
zend_code_block *next;
+
next = cur_block->next;
- while (next && !next->access) {
+ while (next && (!next->access || !next->len)) {
next = next->next;
}
if (next && next == cur_block->op1_to) {
/* JMP to the next block - strip it */
cur_block->follow_to = cur_block->op1_to;
cur_block->op1_to = NULL;
- MAKE_NOP((opline - 1));
- opline--;
+ MAKE_NOP(opline);
cur_block->len--;
}
}
- } else {
+ len += cur_block->len;
+ } else if (cur_block->start_opline && cur_block->len) {
/* this block will not be used, delete all constants there */
zend_op *_opl;
zend_op *end = cur_block->start_opline + cur_block->len;
- for (_opl = cur_block->start_opline; _opl && _opl < end; _opl++) {
+ for (_opl = cur_block->start_opline; _opl < end; _opl++) {
if (ZEND_OP1_TYPE(_opl) == IS_CONST) {
literal_dtor(&ZEND_OP1_LITERAL(_opl));
}
}
}
}
- cur_block = cur_block->next;
}
- op_array->last = opline-new_opcodes;
+ op_array->last = len;
+ new_opcodes = emalloc(op_array->last * sizeof(zend_op));
+ opline = new_opcodes;
+
+ /* Copy code of reachable blocks into a single buffer */
+ for (cur_block = blocks; cur_block; cur_block = cur_block->next) {
+ if (cur_block->access && cur_block->len) {
+ memcpy(opline, cur_block->start_opline, cur_block->len * sizeof(zend_op));
+ cur_block->start_opline = opline;
+ opline += cur_block->len;
+ }
+ }
/* adjust exception jump targets */
if (op_array->last_try_catch) {
}
/* adjust jump targets */
+ efree(op_array->opcodes);
+ op_array->opcodes = new_opcodes;
+
for (cur_block = blocks; cur_block; cur_block = cur_block->next) {
if (!cur_block->access) {
continue;
}
opline = cur_block->start_opline + cur_block->len - 1;
- if (opline->opcode == ZEND_OP_DATA) {
- opline--;
- }
if (cur_block->op1_to) {
- ZEND_OP1(opline).opline_num = cur_block->op1_to->start_opline - new_opcodes;
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, cur_block->op1_to->start_opline);
}
if (cur_block->op2_to) {
- ZEND_OP2(opline).opline_num = cur_block->op2_to->start_opline - new_opcodes;
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, cur_block->op2_to->start_opline);
}
if (cur_block->ext_to) {
- opline->extended_value = cur_block->ext_to->start_opline - new_opcodes;
+ opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, cur_block->ext_to->start_opline);
}
print_block(cur_block, new_opcodes, "Out ");
}
- efree(op_array->opcodes);
- op_array->opcodes = erealloc(new_opcodes, op_array->last * sizeof(zend_op));
/* adjust early binding list */
if (op_array->early_binding != (uint32_t)-1) {
for (opline = op_array->opcodes; opline < end; opline++) {
/* Kill JMP-over-NOP-s */
- if (opline->opcode == ZEND_JMP && ZEND_OP1(opline).opline_num > i) {
+ if (opline->opcode == ZEND_JMP && ZEND_OP1_JMP_ADDR(opline) > op_array->opcodes + i) {
/* check if there are only NOPs under the branch */
- zend_op *target = op_array->opcodes + ZEND_OP1(opline).opline_num - 1;
+ zend_op *target = ZEND_OP1_JMP_ADDR(opline) - 1;
while (target->opcode == ZEND_NOP) {
target--;
shift++;
} else {
if (shift) {
- op_array->opcodes[new_count] = *opline;
+ zend_op *new_opline = op_array->opcodes + new_count;
+
+ *new_opline = *opline;
+ switch (new_opline->opcode) {
+ case ZEND_JMP:
+ case ZEND_FAST_CALL:
+ case ZEND_DECLARE_ANON_CLASS:
+ case ZEND_DECLARE_ANON_INHERITED_CLASS:
+ 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_NEW:
+ 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_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ case ZEND_CATCH:
+ 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;
+ }
}
new_count++;
}
case ZEND_FAST_CALL:
case ZEND_DECLARE_ANON_CLASS:
case ZEND_DECLARE_ANON_INHERITED_CLASS:
- ZEND_OP1(opline).opline_num -= shiftlist[ZEND_OP1(opline).opline_num];
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, ZEND_OP1_JMP_ADDR(opline) - shiftlist[ZEND_OP1_JMP_ADDR(opline) - op_array->opcodes]);
break;
+ case ZEND_JMPZNZ:
+ opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value) - shiftlist[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_JMP_SET:
case ZEND_COALESCE:
case ZEND_ASSERT_CHECK:
- ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]);
break;
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
- opline->extended_value -= shiftlist[opline->extended_value];
- break;
- case ZEND_JMPZNZ:
- ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
- opline->extended_value -= shiftlist[opline->extended_value];
- break;
case ZEND_CATCH:
- opline->extended_value -= shiftlist[opline->extended_value];
+ opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value) - shiftlist[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]);
break;
}
}
if ((opline + 1)->opcode == ZEND_JMP) {
/* JMPZ(X, L1), JMP(L2) => JMPZNZ(X, L1, L2) */
/* JMPNZ(X, L1), JMP(L2) => JMPZNZ(X, L2, L1) */
- if (ZEND_OP2(opline).opline_num == ZEND_OP1(opline + 1).opline_num) {
+ if (ZEND_OP2_JMP_ADDR(opline) == ZEND_OP1_JMP_ADDR(opline + 1)) {
/* JMPZ(X, L1), JMP(L1) => NOP, JMP(L1) */
MAKE_NOP(opline);
} else {
if (opline->opcode == ZEND_JMPZ) {
- opline->extended_value = ZEND_OP1(opline + 1).opline_num;
+ opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, ZEND_OP1_JMP_ADDR(opline + 1));
} else {
- opline->extended_value = ZEND_OP2(opline).opline_num;
- COPY_NODE(opline->op2, (opline + 1)->op1);
+ opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, ZEND_OP2_JMP_ADDR(opline));
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(opline + 1));
}
opline->opcode = ZEND_JMPZNZ;
}
case ZEND_JMPZNZ:
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
- int opline_num;
+ zend_op *target_opline;
+
if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
- opline_num = opline->extended_value; /* JMPNZ */
+ target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); /* JMPNZ */
} else {
- opline_num = ZEND_OP2(opline).opline_num; /* JMPZ */
+ target_opline = ZEND_OP2_JMP_ADDR(opline); /* JMPZ */
}
literal_dtor(&ZEND_OP1_LITERAL(opline));
- ZEND_OP1(opline).opline_num = opline_num;
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
ZEND_OP1_TYPE(opline) = IS_UNUSED;
opline->opcode = ZEND_JMP;
}
/* we use "jmp_hitlist" to avoid infinity loops during jmp optimization */
#define CHECK_JMP(target, label) \
for (i=0; i<jmp_hitlist_count; i++) { \
- if (jmp_hitlist[i] == ZEND_OP1(&op_array->opcodes[target]).opline_num) { \
+ if (jmp_hitlist[i] == ZEND_OP1_JMP_ADDR(target)) { \
goto label; \
} \
} \
- jmp_hitlist[jmp_hitlist_count++] = ZEND_OP1(&op_array->opcodes[target]).opline_num;
+ jmp_hitlist[jmp_hitlist_count++] = ZEND_OP1_JMP_ADDR(target);
#define CHECK_JMP2(target, label) \
for (i=0; i<jmp_hitlist_count; i++) { \
- if (jmp_hitlist[i] == ZEND_OP2(&op_array->opcodes[target]).opline_num) { \
+ if (jmp_hitlist[i] == ZEND_OP2_JMP_ADDR(target)) { \
goto label; \
} \
} \
- jmp_hitlist[jmp_hitlist_count++] = ZEND_OP2(&op_array->opcodes[target]).opline_num;
+ jmp_hitlist[jmp_hitlist_count++] = ZEND_OP2_JMP_ADDR(target);
void zend_optimizer_pass3(zend_op_array *op_array)
{
zend_op *opline;
zend_op *end = op_array->opcodes + op_array->last;
- uint32_t *jmp_hitlist;
+ zend_op **jmp_hitlist;
int jmp_hitlist_count;
int i;
uint32_t opline_num = 0;
ALLOCA_FLAG(use_heap);
- jmp_hitlist = (uint32_t *)do_alloca(sizeof(uint32_t)*op_array->last, use_heap);
+ jmp_hitlist = (zend_op**)do_alloca(sizeof(zend_op*)*op_array->last, use_heap);
opline = op_array->opcodes;
while (opline < end) {
}
/* convert L: JMP L+1 to NOP */
- if (ZEND_OP1(opline).opline_num == opline_num + 1) {
+ if (ZEND_OP1_JMP_ADDR(opline) == opline + 1) {
MAKE_NOP(opline);
goto done_jmp_optimization;
}
/* convert JMP L1 ... L1: JMP L2 to JMP L2 .. L1: JMP L2 */
- while (ZEND_OP1(opline).opline_num < op_array->last
- && op_array->opcodes[ZEND_OP1(opline).opline_num].opcode == ZEND_JMP) {
- int target = ZEND_OP1(opline).opline_num;
+ while (ZEND_OP1_JMP_ADDR(opline) < end
+ && ZEND_OP1_JMP_ADDR(opline)->opcode == ZEND_JMP) {
+ zend_op *target = ZEND_OP1_JMP_ADDR(opline);
CHECK_JMP(target, done_jmp_optimization);
- ZEND_OP1(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num;
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, ZEND_OP1_JMP_ADDR(target));
}
break;
break;
}
- while (ZEND_OP2(opline).opline_num < op_array->last) {
- int target = ZEND_OP2(opline).opline_num;
- if (op_array->opcodes[target].opcode == ZEND_JMP) {
- ZEND_OP2(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num;
+ while (ZEND_OP2_JMP_ADDR(opline) < end) {
+ zend_op *target = ZEND_OP2_JMP_ADDR(opline);
+ if (target->opcode == ZEND_JMP) {
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(target));
} else {
break;
}
break;
}
- while (ZEND_OP2(opline).opline_num < op_array->last) {
- int target = ZEND_OP2(opline).opline_num;
+ while (ZEND_OP2_JMP_ADDR(opline) < end) {
+ zend_op *target = ZEND_OP2_JMP_ADDR(opline);
- if (op_array->opcodes[target].opcode == ZEND_JMP) {
+ if (target->opcode == ZEND_JMP) {
/* plain JMP */
/* JMPZ(X,L1), L1: JMP(L2) => JMPZ(X,L2), L1: JMP(L2) */
CHECK_JMP(target, done_jmp_optimization);
- ZEND_OP2(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num;
- } else if (op_array->opcodes[target].opcode == opline->opcode &&
- SAME_VAR(opline->op1, op_array->opcodes[target].op1)) {
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(target));
+ } else if (target->opcode == opline->opcode &&
+ SAME_VAR(opline->op1, target->op1)) {
/* same opcode and same var as this opcode */
/* JMPZ(X,L1), L1: JMPZ(X,L2) => JMPZ(X,L2), L1: JMPZ(X,L2) */
CHECK_JMP2(target, done_jmp_optimization);
- ZEND_OP2(opline).opline_num = ZEND_OP2(&op_array->opcodes[target]).opline_num;
- } else if (op_array->opcodes[target].opcode == opline->opcode + 3 &&
- SAME_VAR(opline->op1, op_array->opcodes[target].op1)) {
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(target));
+ } else if (target->opcode == opline->opcode + 3 &&
+ SAME_VAR(opline->op1, target->op1)) {
/* convert JMPZ(X,L1), L1: T JMPZ_EX(X,L2) to
T = JMPZ_EX(X, L2) */
- ZEND_OP2(opline).opline_num = ZEND_OP2(&op_array->opcodes[target]).opline_num;opline->opcode += 3;
- COPY_NODE(opline->result, op_array->opcodes[target].result);
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(target));
+ opline->opcode += 3;
+ COPY_NODE(opline->result, target->result);
break;
- } else if (op_array->opcodes[target].opcode == INV_COND(opline->opcode) &&
- SAME_VAR(opline->op1, op_array->opcodes[target].op1)) {
+ } else if (target->opcode == INV_COND(opline->opcode) &&
+ SAME_VAR(opline->op1, target->op1)) {
/* convert JMPZ(X,L1), L1: JMPNZ(X,L2) to
JMPZ(X,L1+1) */
- ZEND_OP2(opline).opline_num = target + 1;
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
break;
- } else if (op_array->opcodes[target].opcode == INV_COND_EX(opline->opcode) &&
- SAME_VAR(opline->op1, op_array->opcodes[target].op1)) {
+ } else if (target->opcode == INV_COND_EX(opline->opcode) &&
+ SAME_VAR(opline->op1, target->op1)) {
/* convert JMPZ(X,L1), L1: T = JMPNZ_EX(X,L2) to
T = JMPZ_EX(X,L1+1) */
- ZEND_OP2(opline).opline_num = target + 1;
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
opline->opcode += 3;
- COPY_NODE(opline->result, op_array->opcodes[target].result);
+ COPY_NODE(opline->result, target->result);
break;
} else {
break;
/* convert L: T = JMPZ_EX X,L+1 to T = BOOL(X) */
/* convert L: T = JMPZ_EX T,L+1 to NOP */
- if (ZEND_OP2(opline).opline_num == opline_num + 1) {
+ if (ZEND_OP2_JMP_ADDR(opline) == opline + 1) {
if (ZEND_OP1(opline).var == ZEND_RESULT(opline).var) {
MAKE_NOP(opline);
} else {
goto done_jmp_optimization;
}
- while (ZEND_OP2(opline).opline_num < op_array->last) {
- int target = ZEND_OP2(opline).opline_num;
- if (SAME_OPCODE_EX(opline->opcode, op_array->opcodes[target].opcode) &&
- SAME_VAR(op_array->opcodes[target].op1, T)) {
+ while (ZEND_OP2_JMP_ADDR(opline) < end) {
+ zend_op *target = ZEND_OP2_JMP_ADDR(opline);
+
+ if (SAME_OPCODE_EX(opline->opcode, target->opcode) &&
+ SAME_VAR(target->op1, T)) {
/* Check for JMPZ_EX to JMPZ[_EX] with the same condition, either with _EX or not */
- if (op_array->opcodes[target].opcode == opline->opcode) {
+ if (target->opcode == opline->opcode) {
/* change T only if we have _EX opcode there */
- COPY_NODE(T, op_array->opcodes[target].result);
+ COPY_NODE(T, target->result);
}
CHECK_JMP2(target, continue_jmp_ex_optimization);
- ZEND_OP2(opline).opline_num = ZEND_OP2(&op_array->opcodes[target]).opline_num;
- } else if (op_array->opcodes[target].opcode == ZEND_JMPZNZ &&
- SAME_VAR(op_array->opcodes[target].op1, T)) {
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(target));
+ } else if (target->opcode == ZEND_JMPZNZ &&
+ SAME_VAR(target->op1, T)) {
/* Check for JMPZNZ with same cond variable */
- int new_target;
+ zend_op *new_target;
+
CHECK_JMP2(target, continue_jmp_ex_optimization);
if (opline->opcode == ZEND_JMPZ_EX) {
- new_target = ZEND_OP2(&op_array->opcodes[target]).opline_num;
+ new_target = ZEND_OP2_JMP_ADDR(target);
} else {
/* JMPNZ_EX */
- new_target = op_array->opcodes[target].extended_value;
+ new_target = ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
}
- ZEND_OP2(opline).opline_num = new_target;
- } else if ((op_array->opcodes[target].opcode == INV_EX_COND_EX(opline->opcode) ||
- op_array->opcodes[target].opcode == INV_EX_COND(opline->opcode)) &&
- SAME_VAR(opline->op1, op_array->opcodes[target].op1)) {
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_target);
+ } else if ((target->opcode == INV_EX_COND_EX(opline->opcode) ||
+ target->opcode == INV_EX_COND(opline->opcode)) &&
+ SAME_VAR(opline->op1, target->op1)) {
/* convert JMPZ_EX(X,L1), L1: JMPNZ_EX(X,L2) to
JMPZ_EX(X,L1+1) */
- ZEND_OP2(opline).opline_num = target + 1;
- break;
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
+ break;
} else {
break;
}
}
/* JMPZNZ(X,L1,L2), L1: JMP(L3) => JMPZNZ(X,L3,L2), L1: JMP(L3) */
- while (ZEND_OP2(opline).opline_num < op_array->last
- && op_array->opcodes[ZEND_OP2(opline).opline_num].opcode == ZEND_JMP) {
- int target = ZEND_OP2(opline).opline_num;
+ while (ZEND_OP2_JMP_ADDR(opline) < end
+ && ZEND_OP2_JMP_ADDR(opline)->opcode == ZEND_JMP) {
+ zend_op *target = ZEND_OP2_JMP_ADDR(opline);
CHECK_JMP(target, continue_jmpznz_optimization);
- ZEND_OP2(opline).opline_num = ZEND_OP1(&op_array->opcodes[target]).opline_num;
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(target));
}
continue_jmpznz_optimization:
/* JMPZNZ(X,L1,L2), L2: JMP(L3) => JMPZNZ(X,L1,L3), L2: JMP(L3) */
- while (opline->extended_value < op_array->last
- && op_array->opcodes[opline->extended_value].opcode == ZEND_JMP) {
- int target = opline->extended_value;
+ while (ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) < end
+ && ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value)->opcode == ZEND_JMP) {
+ zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
CHECK_JMP(target, done_jmp_optimization);
- opline->extended_value = ZEND_OP1(&op_array->opcodes[target]).opline_num;
+ opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, ZEND_OP1_JMP_ADDR(target));
}
break;
if (opline->op2_type == IS_CONST) {
ZEND_PASS_TWO_UNDO_CONSTANT(op_array, opline->op2);
}
- switch (opline->opcode) {
- case ZEND_JMP:
- case ZEND_FAST_CALL:
- case ZEND_DECLARE_ANON_CLASS:
- case ZEND_DECLARE_ANON_INHERITED_CLASS:
- ZEND_PASS_TWO_UNDO_JMP_TARGET(op_array, opline, ZEND_OP1(opline));
- break;
- case ZEND_CATCH:
- /* relative offset into absolute index */
- opline->extended_value = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
- break;
- case ZEND_JMPZNZ:
- /* relative offset into absolute index */
- opline->extended_value = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
- /* break omitted intentionally */
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- case ZEND_JMP_SET:
- case ZEND_COALESCE:
- case ZEND_NEW:
- case ZEND_FE_RESET_R:
- case ZEND_FE_RESET_RW:
- case ZEND_ASSERT_CHECK:
- ZEND_PASS_TWO_UNDO_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
- break;
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
- opline->extended_value = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
- break;
- }
opline++;
}
if (opline->op2_type == IS_CONST) {
ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
}
- switch (opline->opcode) {
- case ZEND_JMP:
- case ZEND_FAST_CALL:
- case ZEND_DECLARE_ANON_CLASS:
- case ZEND_DECLARE_ANON_INHERITED_CLASS:
- ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, ZEND_OP1(opline));
- break;
- case ZEND_CATCH:
- /* absolute index to relative offset */
- opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
- break;
- case ZEND_JMPZNZ:
- /* absolute index to relative offset */
- opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
- /* break omitted intentionally */
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- case ZEND_JMP_SET:
- case ZEND_COALESCE:
- case ZEND_NEW:
- case ZEND_FE_RESET_R:
- case ZEND_FE_RESET_RW:
- case ZEND_ASSERT_CHECK:
- ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
- break;
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
- opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
- break;
- }
ZEND_VM_SET_OPCODE_HANDLER(opline);
opline++;
}
#define ZEND_OP1_TYPE(opline) (opline)->op1_type
#define ZEND_OP1(opline) (opline)->op1
#define ZEND_OP1_LITERAL(opline) (op_array)->literals[(opline)->op1.constant]
+#define ZEND_OP1_JMP_ADDR(opline) OP_JMP_ADDR(opline, (opline)->op1)
#define ZEND_OP2_TYPE(opline) (opline)->op2_type
#define ZEND_OP2(opline) (opline)->op2
#define ZEND_OP2_LITERAL(opline) (op_array)->literals[(opline)->op2.constant]
+#define ZEND_OP2_JMP_ADDR(opline) OP_JMP_ADDR(opline, (opline)->op2)
#define VAR_NUM(v) EX_VAR_TO_NUM(v)
#define NUM_VAR(v) ((uint32_t)(zend_uintptr_t)ZEND_CALL_VAR_NUM(0, v))