diff options
| author | Jakub Zelenka <bukka@php.net> | 2016-02-29 19:31:20 +0000 |
|---|---|---|
| committer | Jakub Zelenka <bukka@php.net> | 2016-02-29 19:31:20 +0000 |
| commit | 70141093a731049ee9220e9e965f61ded56ed4d5 (patch) | |
| tree | 6e67b382253a186889bfdc37c31062d6fb9880d9 /ext/opcache/Optimizer/zend_cfg.c | |
| parent | e453af3851daf08f5af9b45fc7819c3a9c336f1e (diff) | |
| parent | 97294aca7e066443291cc2d77f8674ac23eabb32 (diff) | |
| download | php-git-70141093a731049ee9220e9e965f61ded56ed4d5.tar.gz | |
Merge branch 'master' into openssl_aead
Diffstat (limited to 'ext/opcache/Optimizer/zend_cfg.c')
| -rw-r--r-- | ext/opcache/Optimizer/zend_cfg.c | 139 |
1 files changed, 89 insertions, 50 deletions
diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index 728d586026..63f14634cb 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -91,33 +91,35 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg * do { changed = 0; - /* Add brk/cont paths */ - for (j = 0; j < op_array->last_live_range; j++) { - if (op_array->live_range[j].var == (uint32_t)-1) { - /* this live range already removed */ - continue; - } - b = blocks + block_map[op_array->live_range[j].start]; - if (b->flags & ZEND_BB_REACHABLE) { - while (op_array->opcodes[b->start].opcode == ZEND_NOP && b->start != b->end) { - b->start++; - } - if (op_array->opcodes[b->start].opcode == ZEND_NOP && - b->start == b->end && - b->successors[0] == block_map[op_array->live_range[j].end]) { - /* mark as removed (empty live range) */ - op_array->live_range[j].var = (uint32_t)-1; + if (cfg->split_at_live_ranges) { + /* Add live range paths */ + for (j = 0; j < op_array->last_live_range; j++) { + if (op_array->live_range[j].var == (uint32_t)-1) { + /* this live range already removed */ continue; } - b->flags |= ZEND_BB_GEN_VAR; - b = blocks + block_map[op_array->live_range[j].end]; - b->flags |= ZEND_BB_KILL_VAR; - if (!(b->flags & ZEND_BB_REACHABLE)) { - changed = 1; - zend_mark_reachable(op_array->opcodes, blocks, b); + b = blocks + block_map[op_array->live_range[j].start]; + if (b->flags & ZEND_BB_REACHABLE) { + while (op_array->opcodes[b->start].opcode == ZEND_NOP && b->start != b->end) { + b->start++; + } + if (op_array->opcodes[b->start].opcode == ZEND_NOP && + b->start == b->end && + b->successors[0] == block_map[op_array->live_range[j].end]) { + /* mark as removed (empty live range) */ + op_array->live_range[j].var = (uint32_t)-1; + continue; + } + b->flags |= ZEND_BB_GEN_VAR; + b = blocks + block_map[op_array->live_range[j].end]; + b->flags |= ZEND_BB_KILL_VAR; + if (!(b->flags & ZEND_BB_REACHABLE)) { + changed = 1; + zend_mark_reachable(op_array->opcodes, blocks, b); + } + } else { + ZEND_ASSERT(!(blocks[block_map[op_array->live_range[j].end]].flags & ZEND_BB_REACHABLE)); } - } else { - ZEND_ASSERT(!(blocks[block_map[op_array->live_range[j].end]].flags & ZEND_BB_REACHABLE)); } } @@ -244,6 +246,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b zend_basic_block *blocks; zval *zv; + cfg->split_at_live_ranges = (build_flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES) != 0; cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t)); if (!block_map) { return FAILURE; @@ -251,10 +254,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 +267,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_ACCESS; case ZEND_YIELD: case ZEND_YIELD_FROM: - flags |= ZEND_FUNC_TOO_DYNAMIC; if (build_flags & ZEND_CFG_STACKLESS) { BB_START(i + 1); } @@ -296,15 +295,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_ACCESS; } 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_ACCESS; + } else if (zend_string_equals_literal(Z_STR_P(zv), "parse_str") && + opline->extended_value == 1) { + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; + } else if (zend_string_equals_literal(Z_STR_P(zv), "mb_parse_str") && + opline->extended_value == 1) { + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; } else if (zend_string_equals_literal(Z_STR_P(zv), "get_defined_vars")) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; } 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 +317,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 +349,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)); } @@ -370,8 +368,14 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b BB_START(i + 1); break; case ZEND_UNSET_VAR: - if (!(opline->extended_value & ZEND_QUICK_SET)) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + case ZEND_ISSET_ISEMPTY_VAR: + if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL) && + !(opline->extended_value & ZEND_QUICK_SET)) { + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; + } 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_INDIRECT_VAR_ACCESS; } break; case ZEND_FETCH_R: @@ -381,19 +385,23 @@ 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_ACCESS; } 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_ACCESS; } break; } } - for (j = 0; j < op_array->last_live_range; j++) { - BB_START(op_array->live_range[j].start); - BB_START(op_array->live_range[j].end); + + if (cfg->split_at_live_ranges) { + for (j = 0; j < op_array->last_live_range; j++) { + BB_START(op_array->live_range[j].start); + BB_START(op_array->live_range[j].end); + } } + if (op_array->last_try_catch) { for (j = 0; j < op_array->last_try_catch; j++) { BB_START(op_array->try_catch_array[j].try_op); @@ -534,7 +542,7 @@ int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg) /* {{{ */ if (b->successors[0] >= 0) { edges++; blocks[b->successors[0]].predecessors_count++; - if (b->successors[1] >= 0) { + if (b->successors[1] >= 0 && b->successors[1] != b->successors[0]) { edges++; blocks[b->successors[1]].predecessors_count++; } @@ -563,7 +571,8 @@ int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg) /* {{{ */ zend_basic_block *b = blocks + blocks[j].successors[0]; predecessors[b->predecessor_offset + b->predecessors_count] = j; b->predecessors_count++; - if (blocks[j].successors[1] >= 0) { + if (blocks[j].successors[1] >= 0 + && blocks[j].successors[1] != blocks[j].successors[0]) { zend_basic_block *b = blocks + blocks[j].successors[1]; predecessors[b->predecessor_offset + b->predecessors_count] = j; b->predecessors_count++; @@ -576,16 +585,45 @@ int zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg) /* {{{ */ } /* }}} */ +/* Computes a postorder numbering of the CFG */ +static void compute_postnum_recursive( + int *postnum, int *cur, const zend_cfg *cfg, int block_num) /* {{{ */ +{ + zend_basic_block *block = &cfg->blocks[block_num]; + if (postnum[block_num] != -1) { + return; + } + + postnum[block_num] = -2; /* Marker for "currently visiting" */ + if (block->successors[0] >= 0) { + compute_postnum_recursive(postnum, cur, cfg, block->successors[0]); + if (block->successors[1] >= 0) { + compute_postnum_recursive(postnum, cur, cfg, block->successors[1]); + } + } + postnum[block_num] = (*cur)++; +} +/* }}} */ + +/* Computes dominator tree using algorithm from "A Simple, Fast Dominance Algorithm" by + * Cooper, Harvey and Kennedy. */ int zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cfg) /* {{{ */ { zend_basic_block *blocks = cfg->blocks; int blocks_count = cfg->blocks_count; int j, k, changed; + ALLOCA_FLAG(use_heap) + int *postnum = do_alloca(sizeof(int) * cfg->blocks_count, use_heap); + memset(postnum, -1, sizeof(int) * cfg->blocks_count); + j = 0; + compute_postnum_recursive(postnum, &j, cfg, 0); + /* FIXME: move declarations */ blocks[0].idom = 0; do { changed = 0; + /* Iterating in RPO here would converge faster */ for (j = 1; j < blocks_count; j++) { int idom = -1; @@ -603,8 +641,8 @@ int zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cf if (blocks[pred].idom >= 0) { while (idom != pred) { - while (pred > idom) pred = blocks[pred].idom; - while (idom > pred) idom = blocks[idom].idom; + while (postnum[pred] < postnum[idom]) pred = blocks[pred].idom; + while (postnum[idom] < postnum[pred]) idom = blocks[idom].idom; } } } @@ -655,6 +693,7 @@ int zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cf blocks[j].level = level; } + free_alloca(postnum, use_heap); return SUCCESS; } /* }}} */ |
