diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 036f52b004a..bff37d4c67e 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -732,7 +732,8 @@ ZEND_API int zend_execute_scripts(int type, zval *retval, int file_count, ...); ZEND_API int open_file_for_scanning(zend_file_handle *file_handle); ZEND_API void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size); ZEND_API void destroy_op_array(zend_op_array *op_array); -ZEND_API uint32_t *generate_var_liveliness_info(zend_op_array *op_array); +ZEND_API void zend_generate_var_liveliness_info(zend_op_array *op_array); +ZEND_API void zend_regenerate_var_liveliness_info(zend_op_array *op_array); ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle); ZEND_API void zend_cleanup_user_class_data(zend_class_entry *ce); ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index df89a42d60d..56de9ccc0f5 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -751,7 +751,7 @@ ZEND_API int pass_two(zend_op_array *op_array) CG(context).literals_size = op_array->last_literal; } - op_array->T_liveliness = generate_var_liveliness_info(op_array); + zend_generate_var_liveliness_info(op_array); opline = op_array->opcodes; end = opline + op_array->last; @@ -889,9 +889,9 @@ static zend_always_inline uint32_t liveliness_kill_var(zend_op_array *op_array, return count; } -ZEND_API uint32_t *generate_var_liveliness_info(zend_op_array *op_array) +static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_array *op_array, zend_bool done_pass_two) { - uint32_t i, op_live_total = 0; + uint32_t i, op_live_total = 0, var; void *checkpoint = zend_arena_checkpoint(CG(arena)); uint32_t *info, info_off = op_array->last + 1; uint32_t *Tstart = zend_arena_alloc(&CG(arena), sizeof(uint32_t) * op_array->T); @@ -919,25 +919,42 @@ ZEND_API uint32_t *generate_var_liveliness_info(zend_op_array *op_array) && cur_op->opcode != ZEND_DECLARE_INHERITED_CLASS_DELAYED && cur_op->opcode != ZEND_DECLARE_ANON_CLASS && cur_op->opcode != ZEND_DECLARE_ANON_INHERITED_CLASS) { + if (done_pass_two) { + var = EX_VAR_TO_NUM(cur_op->result.var) - op_array->last_var; + } else { + var = cur_op->result.var; + } /* Objects created via ZEND_NEW are only fully initialized after the DO_FCALL (constructor call) */ if (cur_op->opcode == ZEND_NEW) { - Tstart[cur_op->result.var] = cur_op->op2.opline_num - 1; + Tstart[var] = cur_op->op2.opline_num - 1; } else { - Tstart[cur_op->result.var] = cur_op - op_array->opcodes; + Tstart[var] = cur_op - op_array->opcodes; } } - if ((cur_op->op1_type & (IS_VAR | IS_TMP_VAR)) - && Tstart[cur_op->op1.var] != (uint32_t)-1 - && cur_op->opcode != ZEND_ROPE_ADD /* the following opcodes don't free TMP */ - && cur_op->opcode != ZEND_FETCH_LIST - && cur_op->opcode != ZEND_CASE - && cur_op->opcode != ZEND_FE_FETCH_R - && cur_op->opcode != ZEND_FE_FETCH_RW) { - op_live_total += liveliness_kill_var(op_array, cur_op, cur_op->op1.var, Tstart, opTs); + if (cur_op->op1_type & (IS_VAR | IS_TMP_VAR)) { + if (done_pass_two) { + var = EX_VAR_TO_NUM(cur_op->op1.var) - op_array->last_var; + } else { + var = cur_op->op1.var; + } + if (Tstart[var] != (uint32_t)-1 + && cur_op->opcode != ZEND_ROPE_ADD /* the following opcodes don't free TMP */ + && cur_op->opcode != ZEND_FETCH_LIST + && cur_op->opcode != ZEND_CASE + && cur_op->opcode != ZEND_FE_FETCH_R + && cur_op->opcode != ZEND_FE_FETCH_RW) { + op_live_total += liveliness_kill_var(op_array, cur_op, var, Tstart, opTs); + } } - if (cur_op->op2_type & (IS_VAR | IS_TMP_VAR) - && Tstart[cur_op->op2.var] != (uint32_t)-1) { - op_live_total += liveliness_kill_var(op_array, cur_op, cur_op->op2.var, Tstart, opTs); + if (cur_op->op2_type & (IS_VAR | IS_TMP_VAR)) { + if (done_pass_two) { + var = EX_VAR_TO_NUM(cur_op->op2.var) - op_array->last_var; + } else { + var = cur_op->op2.var; + } + if (Tstart[var] != (uint32_t)-1) { + op_live_total += liveliness_kill_var(op_array, cur_op, var, Tstart, opTs); + } } } @@ -965,10 +982,22 @@ ZEND_API uint32_t *generate_var_liveliness_info(zend_op_array *op_array) } zend_arena_release(&CG(arena), checkpoint); - return info; } +ZEND_API void zend_generate_var_liveliness_info(zend_op_array *op_array) +{ + op_array->T_liveliness = generate_var_liveliness_info_ex(op_array, 0); +} + +ZEND_API void zend_regenerate_var_liveliness_info(zend_op_array *op_array) +{ + if (op_array->T_liveliness) { + efree(op_array->T_liveliness); + } + op_array->T_liveliness = generate_var_liveliness_info_ex(op_array, 1); +} + int print_class(zend_class_entry *class_entry) { printf("Class %s:\n", ZSTR_VAL(class_entry->name)); diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index ffe23f30afd..5a2325191fe 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -458,6 +458,17 @@ 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, @@ -465,8 +476,6 @@ static void zend_accel_optimize(zend_op_array *op_array, { zend_op *opline, *end; - efree(op_array->T_liveliness); - /* Revert pass_two() */ opline = op_array->opcodes; end = opline + op_array->last; @@ -512,39 +521,15 @@ static void zend_accel_optimize(zend_op_array *op_array, /* Do actual optimizations */ zend_optimize(op_array, ctx); - opline = op_array->opcodes; - end = opline + op_array->last; - while (opline < end) { - if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) { - opline->op1.var = EX_VAR_TO_NUM(opline->op1.var) - op_array->last_var; - } - if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) { - opline->op2.var = EX_VAR_TO_NUM(opline->op2.var) - op_array->last_var; - } - if (opline->result_type & (IS_VAR|IS_TMP_VAR)) { - opline->result.var = EX_VAR_TO_NUM(opline->result.var) - op_array->last_var; - } - opline++; - } - - op_array->T_liveliness = generate_var_liveliness_info(op_array); - /* Redo pass_two() */ opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { if (opline->op1_type == IS_CONST) { ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op1); - } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) { - opline->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, opline->op1.var + op_array->last_var); } if (opline->op2_type == IS_CONST) { ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2); - } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) { - opline->op2.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, opline->op2.var + op_array->last_var); - } - if (opline->result_type & (IS_VAR|IS_TMP_VAR)) { - opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, opline->result.var + op_array->last_var); } switch (opline->opcode) { case ZEND_JMP: