diff options
Diffstat (limited to 'ext/opcache')
-rw-r--r-- | ext/opcache/Optimizer/block_pass.c | 83 | ||||
-rw-r--r-- | ext/opcache/Optimizer/nop_removal.c | 16 | ||||
-rw-r--r-- | ext/opcache/Optimizer/pass1_5.c | 1 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer.c | 40 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer_internal.h | 3 | ||||
-rw-r--r-- | ext/opcache/zend_file_cache.c | 6 | ||||
-rw-r--r-- | ext/opcache/zend_persist.c | 9 | ||||
-rw-r--r-- | ext/opcache/zend_persist_calc.c | 8 |
8 files changed, 140 insertions, 26 deletions
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index dfe0e4baef..e1e07ea01b 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -123,6 +123,10 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz blocks[0].start_opline_no = 0; while (opline < end) { switch((unsigned)opline->opcode) { + case ZEND_GOTO: + /* would not optimize GOTOs - we cannot really know where it jumps, + * so these optimizations are too dangerous */ + return 0; case ZEND_FAST_CALL: START_BLOCK_OP(ZEND_OP1(opline).opline_num); if (opline->extended_value) { @@ -193,6 +197,65 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz blocks[op_array->try_catch_array[i].try_op].protected = 1; } } + /* Currently, we don't optimize op_arrays with BRK/CONT/GOTO opcodes, + * but, we have to keep brk_cont_array to avoid memory leaks during + * exception handling */ + if (op_array->last_brk_cont) { + int i, j; + + j = 0; + for (i = 0; i< op_array->last_brk_cont; i++) { + if (op_array->brk_cont_array[i].start >= 0 && + (op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE || + op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE || + op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_ROPE_END || + op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) { + int parent = op_array->brk_cont_array[i].parent; + + while (parent >= 0 && + op_array->brk_cont_array[parent].start < 0 && + (op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FREE || + op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FE_FREE || + op_array->opcodes[op_array->brk_cont_array[i].brk].opcode != ZEND_ROPE_END || + op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_END_SILENCE)) { + parent = op_array->brk_cont_array[parent].parent; + } + op_array->brk_cont_array[i].parent = parent; + j++; + } + } + if (j) { + cfg->loop_start = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *)); + cfg->loop_cont = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *)); + cfg->loop_brk = zend_arena_calloc(&ctx->arena, op_array->last_brk_cont, sizeof(zend_code_block *)); + j = 0; + for (i = 0; i< op_array->last_brk_cont; i++) { + if (op_array->brk_cont_array[i].start >= 0 && + (op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE || + op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE || + op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_ROPE_END || + op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) { + if (i != j) { + op_array->brk_cont_array[j] = op_array->brk_cont_array[i]; + } + cfg->loop_start[j] = &blocks[op_array->brk_cont_array[j].start]; + cfg->loop_cont[j] = &blocks[op_array->brk_cont_array[j].cont]; + cfg->loop_brk[j] = &blocks[op_array->brk_cont_array[j].brk]; + START_BLOCK_OP(op_array->brk_cont_array[j].start); + START_BLOCK_OP(op_array->brk_cont_array[j].cont); + START_BLOCK_OP(op_array->brk_cont_array[j].brk); + blocks[op_array->brk_cont_array[j].start].protected = 1; + blocks[op_array->brk_cont_array[j].brk].protected = 1; + j++; + } + } + op_array->last_brk_cont = j; + } else { + efree(op_array->brk_cont_array); + op_array->brk_cont_array = NULL; + op_array->last_brk_cont = 0; + } + } /* Build CFG (Control Flow Graph) */ cur_block = blocks; @@ -460,6 +523,16 @@ static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int /* Walk thorough all paths */ zend_access_path(start, ctx); + /* Add brk/cont paths */ + if (op_array->last_brk_cont) { + int i; + for (i=0; i< op_array->last_brk_cont; i++) { + zend_access_path(cfg->loop_start[i], ctx); + zend_access_path(cfg->loop_cont[i], ctx); + zend_access_path(cfg->loop_brk[i], ctx); + } + } + /* Add exception paths */ if (op_array->last_try_catch) { int i; @@ -1123,6 +1196,16 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) op_array->last_try_catch = j; } + /* adjust loop jump targets */ + if (op_array->last_brk_cont) { + int i; + for (i = 0; i< op_array->last_brk_cont; i++) { + op_array->brk_cont_array[i].start = cfg->loop_start[i]->start_opline - new_opcodes; + op_array->brk_cont_array[i].cont = cfg->loop_cont[i]->start_opline - new_opcodes; + op_array->brk_cont_array[i].brk = cfg->loop_brk[i]->start_opline - new_opcodes; + } + } + /* adjust jump targets */ for (cur_block = blocks; cur_block; cur_block = cur_block->next) { if (!cur_block->access) { diff --git a/ext/opcache/Optimizer/nop_removal.c b/ext/opcache/Optimizer/nop_removal.c index 9983ff4f60..20510b4163 100644 --- a/ext/opcache/Optimizer/nop_removal.c +++ b/ext/opcache/Optimizer/nop_removal.c @@ -44,6 +44,14 @@ void zend_optimizer_nop_removal(zend_op_array *op_array) end = op_array->opcodes + op_array->last; for (opline = op_array->opcodes; opline < end; opline++) { + /* GOTO target is unresolved yet. We can't optimize. */ + if (opline->opcode == ZEND_GOTO && + Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) { + /* TODO: in general we can avoid this restriction */ + FREE_ALLOCA(shiftlist); + return; + } + /* Kill JMP-over-NOP-s */ if (opline->opcode == ZEND_JMP && ZEND_OP1(opline).opline_num > i) { /* check if there are only NOPs under the branch */ @@ -77,6 +85,7 @@ void zend_optimizer_nop_removal(zend_op_array *op_array) for (opline = op_array->opcodes; opline<end; opline++) { switch (opline->opcode) { case ZEND_JMP: + case ZEND_GOTO: case ZEND_FAST_CALL: case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_ANON_INHERITED_CLASS: @@ -108,6 +117,13 @@ void zend_optimizer_nop_removal(zend_op_array *op_array) } } + /* update brk/cont array */ + for (j = 0; j < op_array->last_brk_cont; j++) { + op_array->brk_cont_array[j].brk -= shiftlist[op_array->brk_cont_array[j].brk]; + op_array->brk_cont_array[j].cont -= shiftlist[op_array->brk_cont_array[j].cont]; + op_array->brk_cont_array[j].start -= shiftlist[op_array->brk_cont_array[j].start]; + } + /* update try/catch array */ for (j = 0; j < op_array->last_try_catch; j++) { op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op]; diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c index 766eb2c2d4..6fcdc3e47a 100644 --- a/ext/opcache/Optimizer/pass1_5.c +++ b/ext/opcache/Optimizer/pass1_5.c @@ -624,6 +624,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx) case ZEND_EXIT: case ZEND_THROW: case ZEND_CATCH: + case ZEND_GOTO: case ZEND_FAST_CALL: case ZEND_FAST_RET: case ZEND_JMP: diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 86b0837137..dc69d2511e 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -340,11 +340,29 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, */ case ZEND_FREE: case ZEND_CASE: { - zend_op *m = opline; - zend_op *end = op_array->opcodes + op_array->last; + zend_op *m, *n; + int brk = op_array->last_brk_cont; + zend_bool in_switch = 0; + while (brk--) { + if (op_array->brk_cont_array[brk].start <= (opline - op_array->opcodes) && + op_array->brk_cont_array[brk].brk > (opline - op_array->opcodes)) { + in_switch = 1; + break; + } + } - while (m < end) { - if (ZEND_OP1_TYPE(m) == type && ZEND_OP1(m).var == var) { + if (!in_switch) { + ZEND_ASSERT(opline->opcode == ZEND_FREE); + MAKE_NOP(opline); + zval_dtor(val); + return 1; + } + + m = opline; + n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1; + while (m < n) { + if (ZEND_OP1_TYPE(m) == type && + ZEND_OP1(m).var == var) { if (m->opcode == ZEND_CASE) { zval old_val; ZVAL_COPY_VALUE(&old_val, val); @@ -353,7 +371,6 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, ZVAL_COPY_VALUE(val, &old_val); } else if (m->opcode == ZEND_FREE) { MAKE_NOP(m); - break; } else { ZEND_ASSERT(0); } @@ -458,17 +475,6 @@ static void zend_optimize(zend_op_array *op_array, if (ZEND_OPTIMIZER_PASS_11 & OPTIMIZATION_LEVEL) { zend_optimizer_compact_literals(op_array, ctx); } - - if ((ZEND_OPTIMIZER_PASS_1 - |ZEND_OPTIMIZER_PASS_2 - |ZEND_OPTIMIZER_PASS_3 - |ZEND_OPTIMIZER_PASS_4 - |ZEND_OPTIMIZER_PASS_5 - |ZEND_OPTIMIZER_PASS_9 - |ZEND_OPTIMIZER_PASS_10 - |ZEND_OPTIMIZER_PASS_11) & OPTIMIZATION_LEVEL) { - zend_regenerate_var_liveliness_info(op_array); - } } static void zend_accel_optimize(zend_op_array *op_array, @@ -488,6 +494,7 @@ static void zend_accel_optimize(zend_op_array *op_array, } switch (opline->opcode) { case ZEND_JMP: + case ZEND_GOTO: case ZEND_FAST_CALL: case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_ANON_INHERITED_CLASS: @@ -532,6 +539,7 @@ static void zend_accel_optimize(zend_op_array *op_array, } switch (opline->opcode) { case ZEND_JMP: + case ZEND_GOTO: case ZEND_FAST_CALL: case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_ANON_INHERITED_CLASS: diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 69288c7228..c2f97ff715 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -73,6 +73,9 @@ typedef struct _zend_cfg { zend_code_block *blocks; zend_code_block **try; zend_code_block **catch; + zend_code_block **loop_start; + zend_code_block **loop_cont; + zend_code_block **loop_brk; zend_op **Tsource; char *same_t; } zend_cfg; diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 54e2ab639a..0781b91c9d 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -386,6 +386,7 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra # if ZEND_USE_ABS_JMP_ADDR switch (opline->opcode) { case ZEND_JMP: + case ZEND_GOTO: case ZEND_FAST_CALL: case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_ANON_INHERITED_CLASS: @@ -458,11 +459,11 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra SERIALIZE_STR(op_array->function_name); SERIALIZE_STR(op_array->filename); + SERIALIZE_PTR(op_array->brk_cont_array); SERIALIZE_PTR(op_array->scope); SERIALIZE_STR(op_array->doc_comment); SERIALIZE_PTR(op_array->try_catch_array); SERIALIZE_PTR(op_array->prototype); - SERIALIZE_PTR(op_array->T_liveliness); } } @@ -912,6 +913,7 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr # if ZEND_USE_ABS_JMP_ADDR switch (opline->opcode) { case ZEND_JMP: + case ZEND_GOTO: case ZEND_FAST_CALL: case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_ANON_INHERITED_CLASS: @@ -980,11 +982,11 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr UNSERIALIZE_STR(op_array->function_name); UNSERIALIZE_STR(op_array->filename); + UNSERIALIZE_PTR(op_array->brk_cont_array); UNSERIALIZE_PTR(op_array->scope); UNSERIALIZE_STR(op_array->doc_comment); UNSERIALIZE_PTR(op_array->try_catch_array); UNSERIALIZE_PTR(op_array->prototype); - UNSERIALIZE_PTR(op_array->T_liveliness); } } diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 0f789090cd..bbcb20713b 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -501,6 +501,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc /* fix jumps to point to new array */ switch (opline->opcode) { case ZEND_JMP: + case ZEND_GOTO: case ZEND_FAST_CALL: case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_ANON_INHERITED_CLASS: @@ -589,6 +590,10 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc op_array->arg_info = arg_info; } + if (op_array->brk_cont_array) { + zend_accel_store(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont); + } + if (op_array->scope) { op_array->scope = zend_shared_alloc_get_xlat_entry(op_array->scope); } @@ -613,10 +618,6 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc zend_accel_store(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch); } - if (op_array->T_liveliness) { - zend_accel_store(op_array->T_liveliness, sizeof(uint32_t) * op_array->T_liveliness[op_array->last]); - } - if (op_array->vars) { if (already_stored) { persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->vars); diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 9265ba5ce9..d78cc59259 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -229,6 +229,10 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array) } } + if (op_array->brk_cont_array) { + ADD_DUP_SIZE(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont); + } + if (ZCG(accel_directives).save_comments && op_array->doc_comment) { ADD_STRING(op_array->doc_comment); } @@ -237,10 +241,6 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array) ADD_DUP_SIZE(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch); } - if (op_array->T_liveliness) { - ADD_DUP_SIZE(op_array->T_liveliness, sizeof(uint32_t) * op_array->T_liveliness[op_array->last]); - } - if (op_array->vars) { int i; |