From baf97b1fcc0f8458955f33bcfd325e3130e1161f Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 10 Nov 2015 21:48:03 +0300 Subject: [PATCH] We don't nees zend_op_array->brk_cont_array at run-time anymore. Move zend_op_array->brk_cont_array into CG(context).brk_cont_array. Use more compact zend_op_array->live_range instead of zend_op_array->brk_cont_array. Semantic is kept unchanged. --- Zend/tests/temporary_cleaning_008.phpt | 15 ++++ Zend/zend_compile.c | 64 +++++++++----- Zend/zend_compile.h | 37 ++++---- Zend/zend_execute.c | 41 ++++----- Zend/zend_opcode.c | 18 ++-- ext/opcache/Optimizer/block_pass.c | 84 +++++-------------- ext/opcache/Optimizer/nop_removal.c | 7 +- ext/opcache/Optimizer/zend_optimizer.c | 50 +++++++++-- .../Optimizer/zend_optimizer_internal.h | 6 +- ext/opcache/zend_file_cache.c | 4 +- ext/opcache/zend_persist.c | 4 +- ext/opcache/zend_persist_calc.c | 4 +- 12 files changed, 186 insertions(+), 148 deletions(-) create mode 100644 Zend/tests/temporary_cleaning_008.phpt diff --git a/Zend/tests/temporary_cleaning_008.phpt b/Zend/tests/temporary_cleaning_008.phpt new file mode 100644 index 0000000000..fabd3b4b38 --- /dev/null +++ b/Zend/tests/temporary_cleaning_008.phpt @@ -0,0 +1,15 @@ +--TEST-- +Optimization of constant switch expression +--FILE-- + +--EXPECT-- +exception diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 42225638c1..4f4701189c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -218,16 +218,22 @@ void zend_oparray_context_begin(zend_oparray_context *prev_context) /* {{{ */ CG(context).opcodes_size = INITIAL_OP_ARRAY_SIZE; CG(context).vars_size = 0; CG(context).literals_size = 0; - CG(context).current_brk_cont = -1; CG(context).backpatch_count = 0; CG(context).in_finally = 0; CG(context).fast_call_var = -1; + CG(context).current_brk_cont = -1; + CG(context).last_brk_cont = 0; + CG(context).brk_cont_array = NULL; CG(context).labels = NULL; } /* }}} */ void zend_oparray_context_end(zend_oparray_context *prev_context) /* {{{ */ { + if (CG(context).brk_cont_array) { + efree(CG(context).brk_cont_array); + CG(context).brk_cont_array = NULL; + } if (CG(context).labels) { zend_hash_destroy(CG(context).labels); FREE_HASHTABLE(CG(context).labels); @@ -567,14 +573,28 @@ void zend_stop_lexing(void) LANG_SCNG(yy_cursor) = LANG_SCNG(yy_limit); } +static void zend_add_live_range(zend_op_array *op_array, uint32_t start, uint32_t end) /* {{{ */ +{ + zend_live_range *range; + + if (start != end) { + op_array->last_live_range++; + op_array->live_range = erealloc(op_array->live_range, sizeof(zend_live_range) * op_array->last_live_range); + range = op_array->live_range + op_array->last_live_range - 1; + range->start = start; + range->end = end; + } +} +/* }}} */ + static inline void zend_begin_loop(zend_uchar free_opcode, const znode *loop_var) /* {{{ */ { zend_brk_cont_element *brk_cont_element; int parent = CG(context).current_brk_cont; zend_loop_var info = {0}; - CG(context).current_brk_cont = CG(active_op_array)->last_brk_cont; - brk_cont_element = get_next_brk_cont_element(CG(active_op_array)); + CG(context).current_brk_cont = CG(context).last_brk_cont; + brk_cont_element = get_next_brk_cont_element(); brk_cont_element->parent = parent; if (loop_var && (loop_var->op_type & (IS_VAR|IS_TMP_VAR))) { @@ -597,7 +617,7 @@ static inline void zend_begin_loop(zend_uchar free_opcode, const znode *loop_var static inline void zend_end_loop(int cont_addr) /* {{{ */ { zend_brk_cont_element *brk_cont_element - = &CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont]; + = &CG(context).brk_cont_array[CG(context).current_brk_cont]; brk_cont_element->cont = cont_addr; brk_cont_element->brk = get_next_op_number(CG(active_op_array)); CG(context).current_brk_cont = brk_cont_element->parent; @@ -3734,14 +3754,14 @@ void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline) /* {{{ */ ZVAL_NULL(label); current = opline->extended_value; - for (; current != dest->brk_cont; current = op_array->brk_cont_array[current].parent) { + for (; current != dest->brk_cont; current = CG(context).brk_cont_array[current].parent) { if (current == -1) { CG(in_compilation) = 1; CG(active_op_array) = op_array; CG(zend_lineno) = opline->lineno; zend_error_noreturn(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed"); } - if (op_array->brk_cont_array[current].start >= 0) { + if (CG(context).brk_cont_array[current].start >= 0) { remove_oplines--; } } @@ -3989,7 +4009,9 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ zend_end_loop(opnum_fetch); - zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL); + opline = zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL); + zend_add_live_range(CG(active_op_array), + opnum_fetch, opline - CG(active_op_array)->opcodes); } /* }}} */ @@ -4046,10 +4068,11 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */ znode expr_node, case_node; zend_op *opline; uint32_t *jmpnz_opnums = safe_emalloc(sizeof(uint32_t), cases->children, 0); - uint32_t opnum_default_jmp; + uint32_t opnum_default_jmp, opnum_start; zend_compile_expr(&expr_node, expr_ast); + opnum_start = get_next_op_number(CG(active_op_array)); zend_begin_loop(ZEND_FREE, &expr_node); case_node.op_type = IS_TMP_VAR; @@ -4112,7 +4135,9 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */ zend_end_loop(get_next_op_number(CG(active_op_array))); if (expr_node.op_type == IS_VAR || expr_node.op_type == IS_TMP_VAR) { - zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL); + opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL); + zend_add_live_range(CG(active_op_array), + opnum_start, opline - CG(active_op_array)->opcodes); } else if (expr_node.op_type == IS_CONST) { zval_dtor(&expr_node.u.constant); } @@ -6426,8 +6451,8 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */ { zend_ast *expr_ast = ast->child[0]; znode silence_node; - uint32_t begin_opline_num, end_opline_num; - zend_brk_cont_element *brk_cont_element; + uint32_t begin_opline_num; + zend_op *opline; begin_opline_num = get_next_op_number(CG(active_op_array)); zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL); @@ -6440,15 +6465,12 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */ zend_compile_expr(result, expr_ast); } - end_opline_num = get_next_op_number(CG(active_op_array)); - zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL); + opline = zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL); /* Store BEGIN_SILENCE/END_SILENCE pair to restore previous * EG(error_reporting) value on exception */ - brk_cont_element = get_next_brk_cont_element(CG(active_op_array)); - brk_cont_element->start = begin_opline_num; - brk_cont_element->cont = brk_cont_element->brk = end_opline_num; - brk_cont_element->parent = -1; + zend_add_live_range(CG(active_op_array), + begin_opline_num + 1, opline - CG(active_op_array)->opcodes); } /* }}} */ @@ -6768,10 +6790,6 @@ static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */ GET_NODE(result, opline->result); } else { uint32_t var; - zend_brk_cont_element *info = get_next_brk_cont_element(CG(active_op_array)); - info->start = rope_init_lineno; - info->parent = CG(context).current_brk_cont; - info->cont = info->brk = opline - CG(active_op_array)->opcodes; init_opline->extended_value = j; opline->opcode = ZEND_ROPE_END; @@ -6785,6 +6803,10 @@ static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */ get_temporary_variable(CG(active_op_array)); i--; } + + zend_add_live_range(CG(active_op_array), + rope_init_lineno, opline - CG(active_op_array)->opcodes); + /* Update all the previous opcodes to use the same variable */ while (opline != init_opline) { opline--; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index b777a0ba8c..46838def59 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -111,18 +111,6 @@ typedef struct _zend_declarables { zend_long ticks; } zend_declarables; -/* Compilation context that is different for each op array. */ -typedef struct _zend_oparray_context { - uint32_t opcodes_size; - int vars_size; - int literals_size; - int current_brk_cont; - int backpatch_count; - int in_finally; - uint32_t fast_call_var; - HashTable *labels; -} zend_oparray_context; - /* Compilation context that is different for each file, but shared between op arrays. */ typedef struct _zend_file_context { zend_declarables declarables; @@ -185,6 +173,25 @@ typedef struct _zend_try_catch_element { uint32_t finally_end; } zend_try_catch_element; +typedef struct _zend_live_range { + uint32_t start; + uint32_t end; +} zend_live_range; + +/* Compilation context that is different for each op array. */ +typedef struct _zend_oparray_context { + uint32_t opcodes_size; + int vars_size; + int literals_size; + int backpatch_count; + int in_finally; + uint32_t fast_call_var; + int current_brk_cont; + int last_brk_cont; + zend_brk_cont_element *brk_cont_array; + HashTable *labels; +} zend_oparray_context; + /* method flags (types) */ #define ZEND_ACC_STATIC 0x01 #define ZEND_ACC_ABSTRACT 0x02 @@ -354,9 +361,9 @@ struct _zend_op_array { uint32_t T; zend_string **vars; - int last_brk_cont; + int last_live_range; int last_try_catch; - zend_brk_cont_element *brk_cont_array; + zend_live_range *live_range; zend_try_catch_element *try_catch_array; /* static variables support */ @@ -755,7 +762,7 @@ zend_op *get_next_op(zend_op_array *op_array); void init_op(zend_op *op); int get_next_op_number(zend_op_array *op_array); ZEND_API int pass_two(zend_op_array *op_array); -zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array); +zend_brk_cont_element *get_next_brk_cont_element(void); ZEND_API zend_bool zend_is_compiling(void); ZEND_API char *zend_make_compiled_string_description(const char *name); ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index f851833a2d..0fd99e9f73 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2549,30 +2549,33 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, { int i; - for (i = 0; i < EX(func)->op_array.last_brk_cont; i++) { - const zend_brk_cont_element *brk_cont = &EX(func)->op_array.brk_cont_array[i]; - if (brk_cont->start < 0) { - continue; - } else if (brk_cont->start > op_num) { + i = EX(func)->op_array.last_live_range; + while (i) { + const zend_live_range *range; + + i--; + range = &EX(func)->op_array.live_range[i]; + if (range->end <= op_num) { /* further blocks will not be relevant... */ break; - } else if (op_num < brk_cont->brk) { - if (!catch_op_num || catch_op_num >= brk_cont->brk) { - zend_op *brk_opline = &EX(func)->op_array.opcodes[brk_cont->brk]; - - if (brk_opline->opcode == ZEND_FREE) { - zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var)); - } else if (brk_opline->opcode == ZEND_FE_FREE) { - zval *var = EX_VAR(brk_opline->op1.var); + } else if (op_num >= range->start) { + if (!catch_op_num || catch_op_num >= range->end) { + zend_op *opline = &EX(func)->op_array.opcodes[range->end]; + uint32_t var_num = opline->op1.var; + zval *var = EX_VAR(var_num); + + if (opline->opcode == ZEND_FREE) { + zval_ptr_dtor_nogc(var); + } else if (opline->opcode == ZEND_FE_FREE) { if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) { zend_hash_iterator_del(Z_FE_ITER_P(var)); } zval_ptr_dtor_nogc(var); - } else if (brk_opline->opcode == ZEND_ROPE_END) { - zend_string **rope = (zend_string **) EX_VAR(brk_opline->op1.var); + } else if (opline->opcode == ZEND_ROPE_END) { + zend_string **rope = (zend_string **)var; zend_op *last = EX(func)->op_array.opcodes + op_num; while ((last->opcode != ZEND_ROPE_ADD && last->opcode != ZEND_ROPE_INIT) - || last->result.var != brk_opline->op1.var) { + || last->result.var != var_num) { ZEND_ASSERT(last >= EX(func)->op_array.opcodes); last--; } @@ -2584,10 +2587,10 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, zend_string_release(rope[j]); } while (j--); } - } else if (brk_opline->opcode == ZEND_END_SILENCE) { + } else if (opline->opcode == ZEND_END_SILENCE) { /* restore previous error_reporting value */ - if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) { - EG(error_reporting) = Z_LVAL_P(EX_VAR(brk_opline->op1.var)); + if (!EG(error_reporting) && Z_LVAL_P(var) != 0) { + EG(error_reporting) = Z_LVAL_P(var); } } } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 524eb5cb67..73f3744341 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -78,9 +78,9 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->scope = NULL; op_array->prototype = NULL; - op_array->brk_cont_array = NULL; + op_array->live_range = NULL; op_array->try_catch_array = NULL; - op_array->last_brk_cont = 0; + op_array->last_live_range = 0; op_array->static_variables = NULL; op_array->last_try_catch = 0; @@ -387,8 +387,8 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) if (op_array->doc_comment) { zend_string_release(op_array->doc_comment); } - if (op_array->brk_cont_array) { - efree(op_array->brk_cont_array); + if (op_array->live_range) { + efree(op_array->live_range); } if (op_array->try_catch_array) { efree(op_array->try_catch_array); @@ -451,11 +451,11 @@ int get_next_op_number(zend_op_array *op_array) return op_array->last; } -zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array) +zend_brk_cont_element *get_next_brk_cont_element(void) { - op_array->last_brk_cont++; - op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont); - return &op_array->brk_cont_array[op_array->last_brk_cont-1]; + CG(context).last_brk_cont++; + CG(context).brk_cont_array = erealloc(CG(context).brk_cont_array, sizeof(zend_brk_cont_element) * CG(context).last_brk_cont); + return &CG(context).brk_cont_array[CG(context).last_brk_cont-1]; } static void zend_update_extended_info(zend_op_array *op_array) @@ -570,7 +570,7 @@ static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const ze int array_offset = opline->op1.num; zend_brk_cont_element *jmp_to; do { - jmp_to = &op_array->brk_cont_array[array_offset]; + jmp_to = &CG(context).brk_cont_array[array_offset]; if (nest_levels > 1) { array_offset = jmp_to->parent; } diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 4053fe7da4..1d172b2a5e 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -186,60 +186,18 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz /* 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; + if (op_array->last_live_range) { + int i; - 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; + cfg->live_range_start = zend_arena_calloc(&ctx->arena, op_array->last_live_range, sizeof(zend_code_block *)); + cfg->live_range_end = zend_arena_calloc(&ctx->arena, op_array->last_live_range, sizeof(zend_code_block *)); + for (i = 0; i< op_array->last_live_range; i++) { + cfg->live_range_start[i] = &blocks[op_array->live_range[i].start]; + cfg->live_range_end[i] = &blocks[op_array->live_range[i].end]; + START_BLOCK_OP(op_array->live_range[i].start); + START_BLOCK_OP(op_array->live_range[i].end); + blocks[op_array->live_range[i].start].protected = 1; + blocks[op_array->live_range[i].end].protected = 1; } } @@ -505,12 +463,11 @@ static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int zend_access_path(start, ctx); /* Add brk/cont paths */ - if (op_array->last_brk_cont) { + if (op_array->last_live_range) { 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); + for (i=0; i< op_array->last_live_range; i++) { + zend_access_path(cfg->live_range_start[i], ctx); + zend_access_path(cfg->live_range_end[i], ctx); } } @@ -628,6 +585,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, zval c = ZEND_OP1_LITERAL(src); zval_copy_ctor(&c); if (zend_optimizer_update_op1_const(op_array, opline, &c)) { + zend_optimizer_remove_live_range(op_array, op1.var); VAR_SOURCE(op1) = NULL; literal_dtor(&ZEND_OP1_LITERAL(src)); MAKE_NOP(src); @@ -644,6 +602,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, zval c = ZEND_OP1_LITERAL(src); zval_copy_ctor(&c); if (zend_optimizer_update_op2_const(op_array, opline, &c)) { + zend_optimizer_remove_live_range(op_array, op2.var); VAR_SOURCE(op2) = NULL; literal_dtor(&ZEND_OP1_LITERAL(src)); MAKE_NOP(src); @@ -1185,12 +1144,11 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) } /* adjust loop jump targets */ - if (op_array->last_brk_cont) { + if (op_array->last_live_range) { 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; + for (i = 0; i< op_array->last_live_range; i++) { + op_array->live_range[i].start = cfg->live_range_start[i]->start_opline - new_opcodes; + op_array->live_range[i].end = cfg->live_range_end[i]->start_opline - new_opcodes; } } diff --git a/ext/opcache/Optimizer/nop_removal.c b/ext/opcache/Optimizer/nop_removal.c index 0869bc715c..8a20eb2007 100644 --- a/ext/opcache/Optimizer/nop_removal.c +++ b/ext/opcache/Optimizer/nop_removal.c @@ -109,10 +109,9 @@ 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]; + for (j = 0; j < op_array->last_live_range; j++) { + op_array->live_range[j].start -= shiftlist[op_array->live_range[j].start]; + op_array->live_range[j].end -= shiftlist[op_array->live_range[j].end]; } /* update try/catch array */ diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 70cf4ccfe1..20b7a75f56 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -347,6 +347,25 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array, return 1; } +void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var) +{ + if (op_array->last_live_range) { + int i = 0; + int j = 0; + + do { + if (op_array->opcodes[op_array->live_range[i].end].op1.var != var) { + if (i != j) { + op_array->live_range[j] = op_array->live_range[i]; + } + j++; + } + i++; + } while (i < op_array->last_live_range); + op_array->last_live_range = j; + } +} + int zend_optimizer_replace_by_const(zend_op_array *op_array, zend_op *opline, zend_uchar type, @@ -401,11 +420,11 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, case ZEND_FREE: case ZEND_CASE: { zend_op *m, *n; - int brk = op_array->last_brk_cont; + int brk = op_array->last_live_range; 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)) { + if (op_array->live_range[brk].start <= (opline - op_array->opcodes) && + op_array->live_range[brk].end > (opline - op_array->opcodes)) { in_switch = 1; break; } @@ -419,7 +438,13 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, } m = opline; - n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1; + n = op_array->opcodes + op_array->live_range[brk].end; + if (n->opcode == ZEND_FREE && + !(n->extended_value & ZEND_FREE_ON_RETURN)) { + n++; + } else { + n = op_array->opcodes + op_array->last; + } while (m < n) { if (ZEND_OP1_TYPE(m) == type && ZEND_OP1(m).var == var) { @@ -438,6 +463,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, m++; } zval_dtor(val); + zend_optimizer_remove_live_range(op_array, var); return 1; } case ZEND_VERIFY_RETURN_TYPE: { @@ -451,18 +477,26 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, return 0; } MAKE_NOP(opline); - zend_optimizer_update_op1_const(op_array, opline + 1, val); - return 1; + opline++; + break; } default: break; } - return zend_optimizer_update_op1_const(op_array, opline, val); + if (zend_optimizer_update_op1_const(op_array, opline, val)) { + zend_optimizer_remove_live_range(op_array, var); + return 1; + } + return 0; } if (ZEND_OP2_TYPE(opline) == type && ZEND_OP2(opline).var == var) { - return zend_optimizer_update_op2_const(op_array, opline, val); + if (zend_optimizer_update_op2_const(op_array, opline, val)) { + zend_optimizer_remove_live_range(op_array, var); + return 1; + } + return 0; } opline++; } diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 90df3cfadc..c20634087f 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -76,9 +76,8 @@ 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_code_block **live_range_start; + zend_code_block **live_range_end; zend_op **Tsource; char *same_t; } zend_cfg; @@ -130,6 +129,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, uint32_t var, zval *val); +void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var); void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx); void zend_optimizer_pass2(zend_op_array *op_array); void zend_optimizer_pass3(zend_op_array *op_array); diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 7c615e927b..3fb3c7be2c 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -463,7 +463,7 @@ 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->live_range); SERIALIZE_PTR(op_array->scope); SERIALIZE_STR(op_array->doc_comment); SERIALIZE_PTR(op_array->try_catch_array); @@ -1014,7 +1014,7 @@ 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->live_range); UNSERIALIZE_PTR(op_array->scope); UNSERIALIZE_STR(op_array->doc_comment); UNSERIALIZE_PTR(op_array->try_catch_array); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 1f5abb4652..97757142fc 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -617,8 +617,8 @@ 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->live_range) { + zend_accel_store(op_array->live_range, sizeof(zend_live_range) * op_array->last_live_range); } if (op_array->scope) { diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 42d962b7cb..51664f28d4 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -234,8 +234,8 @@ 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 (op_array->live_range) { + ADD_DUP_SIZE(op_array->live_range, sizeof(zend_live_range) * op_array->last_live_range); } if (ZCG(accel_directives).save_comments && op_array->doc_comment) { -- 2.50.1