From 843c1657358e7dab48fb8fa66574b48eb870989b Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 17 Nov 2015 07:15:35 +0300 Subject: [PATCH] Don't undo/redo "pass two" for jump targets in opcache optimizer. --- Zend/zend_compile.h | 11 ++ ext/opcache/Optimizer/block_pass.c | 103 +++++++-------- ext/opcache/Optimizer/nop_removal.c | 51 ++++++-- ext/opcache/Optimizer/pass2.c | 17 +-- ext/opcache/Optimizer/pass3.c | 123 +++++++++--------- ext/opcache/Optimizer/zend_optimizer.c | 64 --------- .../Optimizer/zend_optimizer_internal.h | 2 + 7 files changed, 172 insertions(+), 199 deletions(-) diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index ff74ec26e5..ce7dc3aefc 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -530,6 +530,9 @@ struct _zend_execute_data { #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)) @@ -545,6 +548,10 @@ struct _zend_execute_data { # 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; \ @@ -561,6 +568,10 @@ struct _zend_execute_data { # 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); \ diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 61f86f5ebb..9a818cfe44 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -113,13 +113,14 @@ static inline void print_block(zend_code_block *block, zend_op *opcodes, char *t 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) { @@ -128,7 +129,7 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz 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: @@ -139,14 +140,9 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz /* 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: @@ -157,12 +153,13 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz 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; } @@ -210,9 +207,6 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz 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: @@ -222,25 +216,22 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz 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: @@ -253,7 +244,7 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz 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 */ @@ -774,13 +765,8 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, 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; @@ -1087,36 +1073,35 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, 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)); } @@ -1125,10 +1110,20 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) } } } - 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) { @@ -1153,27 +1148,25 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) } /* 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) { diff --git a/ext/opcache/Optimizer/nop_removal.c b/ext/opcache/Optimizer/nop_removal.c index 75e84c7644..52967d16fd 100644 --- a/ext/opcache/Optimizer/nop_removal.c +++ b/ext/opcache/Optimizer/nop_removal.c @@ -45,9 +45,9 @@ void zend_optimizer_nop_removal(zend_op_array *op_array) 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--; @@ -63,7 +63,37 @@ void zend_optimizer_nop_removal(zend_op_array *op_array) 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++; } @@ -80,8 +110,11 @@ void zend_optimizer_nop_removal(zend_op_array *op_array) 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: @@ -92,18 +125,12 @@ void zend_optimizer_nop_removal(zend_op_array *op_array) 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; } } diff --git a/ext/opcache/Optimizer/pass2.c b/ext/opcache/Optimizer/pass2.c index 143167f816..3573c1038c 100644 --- a/ext/opcache/Optimizer/pass2.c +++ b/ext/opcache/Optimizer/pass2.c @@ -154,15 +154,15 @@ void zend_optimizer_pass2(zend_op_array *op_array) 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; } @@ -171,14 +171,15 @@ void zend_optimizer_pass2(zend_op_array *op_array) 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; } diff --git a/ext/opcache/Optimizer/pass3.c b/ext/opcache/Optimizer/pass3.c index 2a74717f10..fb3a01e26d 100644 --- a/ext/opcache/Optimizer/pass3.c +++ b/ext/opcache/Optimizer/pass3.c @@ -39,31 +39,31 @@ /* we use "jmp_hitlist" to avoid infinity loops during jmp optimization */ #define CHECK_JMP(target, label) \ for (i=0; iopcodes[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; iopcodes[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) { @@ -167,17 +167,17 @@ void zend_optimizer_pass3(zend_op_array *op_array) } /* 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; @@ -187,10 +187,10 @@ void zend_optimizer_pass3(zend_op_array *op_array) 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; } @@ -202,40 +202,41 @@ void zend_optimizer_pass3(zend_op_array *op_array) 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; @@ -254,7 +255,7 @@ void zend_optimizer_pass3(zend_op_array *op_array) /* 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 { @@ -264,36 +265,38 @@ void zend_optimizer_pass3(zend_op_array *op_array) 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; } @@ -385,19 +388,19 @@ continue_jmp_ex_optimization: } /* 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; diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 9fb7493054..a1cfda5e3f 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -608,38 +608,6 @@ static void zend_optimize_op_array(zend_op_array *op_array, 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++; } @@ -656,38 +624,6 @@ static void zend_optimize_op_array(zend_op_array *op_array, 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++; } diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 7f8962e3ab..414bc0a515 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -27,9 +27,11 @@ #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)) -- 2.50.1