From a2ff3a46a4c9b064b0866729f0a4a24fba834c1d Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 19 Jan 2016 15:33:08 +0300 Subject: [PATCH] Use ZEND_FUNC_INDIRECT_VAR_ASSESS instead of ZEND_FUNC_TOO_DYNAMIC. Handle function with exceptions handlers and generators separately. --- ext/opcache/Optimizer/dfa_pass.c | 8 ++++++- ext/opcache/Optimizer/zend_cfg.c | 31 +++++++++++--------------- ext/opcache/Optimizer/zend_dump.c | 3 +++ ext/opcache/Optimizer/zend_func_info.h | 2 +- ext/opcache/Optimizer/zend_inference.c | 28 ++++++++++++++--------- 5 files changed, 42 insertions(+), 30 deletions(-) diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index a1872e3d81..9dbfb7a56e 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -34,6 +34,11 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, { uint32_t build_flags; + if (op_array->last_try_catch) { + /* TODO: we can't analyze functions with try/catch/finally ??? */ + return FAILURE; + } + /* Build SSA */ memset(ssa, 0, sizeof(zend_ssa)); @@ -41,7 +46,8 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, return FAILURE; } - if (*flags & ZEND_FUNC_TOO_DYNAMIC) { + if (*flags & ZEND_FUNC_INDIRECT_VAR_ASSESS) { + /* TODO: we can't analyze functions with indirect variable access ??? */ return FAILURE; } diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index 728d586026..8258e0e25a 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -251,10 +251,6 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b /* Build CFG, Step 1: Find basic blocks starts, calculate number of blocks */ BB_START(0); - if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->static_variables) { - // FIXME: Really we should try to perform variable initialization - flags |= ZEND_FUNC_TOO_DYNAMIC; - } for (i = 0; i < op_array->last; i++) { zend_op *opline = op_array->opcodes + i; switch(opline->opcode) { @@ -268,9 +264,9 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b } break; case ZEND_INCLUDE_OR_EVAL: + flags |= ZEND_FUNC_INDIRECT_VAR_ASSESS; case ZEND_YIELD: case ZEND_YIELD_FROM: - flags |= ZEND_FUNC_TOO_DYNAMIC; if (build_flags & ZEND_CFG_STACKLESS) { BB_START(i + 1); } @@ -296,15 +292,17 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) { if (fn->type == ZEND_INTERNAL_FUNCTION) { if (zend_string_equals_literal(Z_STR_P(zv), "extract")) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ASSESS; } else if (zend_string_equals_literal(Z_STR_P(zv), "compact")) { - flags |= ZEND_FUNC_TOO_DYNAMIC; - } else if (zend_string_equals_literal(Z_STR_P(zv), "parse_str")) { - flags |= ZEND_FUNC_TOO_DYNAMIC; - } else if (zend_string_equals_literal(Z_STR_P(zv), "mb_parse_str")) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ASSESS; + } else if (zend_string_equals_literal(Z_STR_P(zv), "parse_str") && + opline->extended_value == 1) { + flags |= ZEND_FUNC_INDIRECT_VAR_ASSESS; + } else if (zend_string_equals_literal(Z_STR_P(zv), "mb_parse_str") && + opline->extended_value == 1) { + flags |= ZEND_FUNC_INDIRECT_VAR_ASSESS; } else if (zend_string_equals_literal(Z_STR_P(zv), "get_defined_vars")) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ASSESS; } else if (zend_string_equals_literal(Z_STR_P(zv), "func_num_args")) { flags |= ZEND_FUNC_VARARG; } else if (zend_string_equals_literal(Z_STR_P(zv), "func_get_arg")) { @@ -316,12 +314,10 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b } break; case ZEND_FAST_CALL: - flags |= ZEND_FUNC_TOO_DYNAMIC; BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes); BB_START(i + 1); break; case ZEND_FAST_RET: - flags |= ZEND_FUNC_TOO_DYNAMIC; if (i + 1 < op_array->last) { BB_START(i + 1); } @@ -350,7 +346,6 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b BB_START(i + 1); break; case ZEND_CATCH: - flags |= ZEND_FUNC_TOO_DYNAMIC; if (!opline->result.num) { BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)); } @@ -371,7 +366,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b break; case ZEND_UNSET_VAR: if (!(opline->extended_value & ZEND_QUICK_SET)) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ASSESS; } break; case ZEND_FETCH_R: @@ -381,11 +376,11 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b case ZEND_FETCH_IS: case ZEND_FETCH_UNSET: if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ASSESS; } else if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL || (opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL_LOCK) && !op_array->function_name) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ASSESS; } break; } diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index 53458644fc..06f4423a1b 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -853,6 +853,9 @@ void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, cons if (ssa) { fprintf(stderr, ", ssa_vars=%d", ssa->vars_count); } + if (func_flags & ZEND_FUNC_INDIRECT_VAR_ASSESS) { + fprintf(stderr, ", dynamic"); + } if (func_flags & ZEND_FUNC_RECURSIVE) { fprintf(stderr, ", recursive"); if (func_flags & ZEND_FUNC_RECURSIVE_DIRECTLY) { diff --git a/ext/opcache/Optimizer/zend_func_info.h b/ext/opcache/Optimizer/zend_func_info.h index 4b0aadd4ee..ee4afebf8c 100644 --- a/ext/opcache/Optimizer/zend_func_info.h +++ b/ext/opcache/Optimizer/zend_func_info.h @@ -22,7 +22,7 @@ #include "zend_ssa.h" /* func flags */ -#define ZEND_FUNC_TOO_DYNAMIC (1<<0) +#define ZEND_FUNC_INDIRECT_VAR_ASSESS (1<<0) #define ZEND_FUNC_HAS_CALLS (1<<1) #define ZEND_FUNC_VARARG (1<<2) #define ZEND_FUNC_NO_LOOPS (1<<3) diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 41bd4eebb0..2ff9727254 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -3067,8 +3067,11 @@ static void zend_update_type_info(const zend_op_array *op_array, } break; case ZEND_BIND_GLOBAL: + tmp = (MAY_BE_REF | MAY_BE_ANY); + UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + break; case ZEND_BIND_STATIC: - tmp = (MAY_BE_REF | MAY_BE_ANY ); + tmp = MAY_BE_ANY | (opline->extended_value ? MAY_BE_REF : (MAY_BE_RC1 | MAY_BE_RCN)); UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); break; case ZEND_SEND_VAR: @@ -4071,17 +4074,22 @@ int zend_ssa_inference(zend_arena **arena, const zend_op_array *op_array, const } ssa_var_info = ssa->var_info; - for (i = 0; i < op_array->last_var; i++) { - if (!op_array->function_name) { + if (!op_array->function_name) { + for (i = 0; i < op_array->last_var; i++) { ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; - } else if (i == EX_VAR_TO_NUM(op_array->this_var)) { - ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_OBJECT; - ssa_var_info[i].ce = op_array->scope; - ssa_var_info[i].is_instanceof = 1; - } else { - ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RCN; + ssa_var_info[i].has_range = 0; + } + } else { + for (i = 0; i < op_array->last_var; i++) { + if (i == EX_VAR_TO_NUM(op_array->this_var)) { + ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_OBJECT; + ssa_var_info[i].ce = op_array->scope; + ssa_var_info[i].is_instanceof = 1; + } else { + ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RCN; + } + ssa_var_info[i].has_range = 0; } - ssa_var_info[i].has_range = 0; } for (i = op_array->last_var; i < ssa->vars_count; i++) { ssa_var_info[i].type = 0; -- 2.50.1