diff options
| author | Jakub Zelenka <bukka@php.net> | 2016-06-19 17:05:48 +0100 |
|---|---|---|
| committer | Jakub Zelenka <bukka@php.net> | 2016-06-19 17:05:48 +0100 |
| commit | e63a8540a60e95aa5bd8e269add1b02afcc1b79b (patch) | |
| tree | b83a144eec24cc81adab0b9a778f7a730d8df79e /ext/opcache/Optimizer/zend_cfg.c | |
| parent | 7a4cc73641bb3eb878f7184bcbd026ee663cf2a9 (diff) | |
| parent | 53071e647049f099f7f7a0771ddb63fc2cdd621c (diff) | |
| download | php-git-e63a8540a60e95aa5bd8e269add1b02afcc1b79b.tar.gz | |
Merge branch 'openssl_error_store' into openssl_aead
Diffstat (limited to 'ext/opcache/Optimizer/zend_cfg.c')
| -rw-r--r-- | ext/opcache/Optimizer/zend_cfg.c | 155 |
1 files changed, 87 insertions, 68 deletions
diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index 63f14634cb..e986ac0c20 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -21,6 +21,8 @@ #include "zend_cfg.h" #include "zend_func_info.h" #include "zend_worklist.h" +#include "zend_optimizer.h" +#include "zend_optimizer_internal.h" static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend_basic_block *b) /* {{{ */ { @@ -39,15 +41,17 @@ static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend if (!(b0->flags & ZEND_BB_REACHABLE)) { zend_mark_reachable(opcodes, blocks, b0); } - opcode = opcodes[b->end].opcode; + + ZEND_ASSERT(b->len != 0); + opcode = opcodes[b->start + b->len - 1].opcode; b = blocks + successor_1; if (opcode == ZEND_JMPZNZ) { b->flags |= ZEND_BB_TARGET; } else { b->flags |= ZEND_BB_FOLLOW; } - } else { - opcode = opcodes[b->end].opcode; + } else if (b->len != 0) { + opcode = opcodes[b->start + b->len - 1].opcode; b = blocks + successor_0; if (opcode == ZEND_JMP) { b->flags |= ZEND_BB_TARGET; @@ -57,6 +61,7 @@ static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend //TODO: support for stackless CFG??? if (0/*stackless*/) { if (opcode == ZEND_INCLUDE_OR_EVAL || + opcode == ZEND_GENERATOR_CREATE || opcode == ZEND_YIELD || opcode == ZEND_YIELD_FROM || opcode == ZEND_DO_FCALL || @@ -66,6 +71,9 @@ static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend } } } + } else { + b = blocks + successor_0; + b->flags |= ZEND_BB_FOLLOW; } if (b->flags & ZEND_BB_REACHABLE) return; } else { @@ -91,35 +99,39 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg * do { changed = 0; - 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 */ + /* Add live range paths */ + for (j = 0; j < op_array->last_live_range; j++) { + zend_live_range *live_range = &op_array->live_range[j]; + if (live_range->var == (uint32_t)-1) { + /* this live range already removed */ + continue; + } + b = blocks + block_map[live_range->start]; + if (b->flags & ZEND_BB_REACHABLE) { + while (b->len > 0 && op_array->opcodes[b->start].opcode == ZEND_NOP) { + b->start++; + b->len--; + } + if (b->len == 0 && b->successors[0] == block_map[live_range->end]) { + /* mark as removed (empty live range) */ + live_range->var = (uint32_t)-1; 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; - 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)) { + b->flags |= ZEND_BB_GEN_VAR; + b = blocks + block_map[live_range->end]; + b->flags |= ZEND_BB_KILL_VAR; + if (!(b->flags & ZEND_BB_REACHABLE)) { + if (cfg->split_at_live_ranges) { changed = 1; zend_mark_reachable(op_array->opcodes, blocks, b); + } else { + ZEND_ASSERT(!(b->flags & ZEND_BB_UNREACHABLE_FREE)); + ZEND_ASSERT(b->start == live_range->end); + b->flags |= ZEND_BB_UNREACHABLE_FREE; } - } else { - ZEND_ASSERT(!(blocks[block_map[op_array->live_range[j].end]].flags & ZEND_BB_REACHABLE)); } + } else { + ZEND_ASSERT(!(blocks[block_map[live_range->end]].flags & ZEND_BB_REACHABLE)); } } @@ -230,9 +242,22 @@ static void record_successor(zend_basic_block *blocks, int pred, int n, int succ blocks[pred].successors[n] = succ; } +static void initialize_block(zend_basic_block *block) { + block->flags = 0; + block->successors[0] = -1; + block->successors[1] = -1; + block->predecessors_count = 0; + block->predecessor_offset = -1; + block->idom = -1; + block->loop_header = -1; + block->level = -1; + block->children = -1; + block->next_child = -1; +} + #define BB_START(i) do { \ if (!block_map[i]) { blocks_count++;} \ - block_map[i] = 1; \ + block_map[i]++; \ } while (0) int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg, uint32_t *func_flags) /* {{{ */ @@ -245,6 +270,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b int blocks_count = 0; zend_basic_block *blocks; zval *zv; + zend_bool extra_entry_block = 0; 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)); @@ -268,6 +294,7 @@ 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_GENERATOR_CREATE: case ZEND_YIELD: case ZEND_YIELD_FROM: if (build_flags & ZEND_CFG_STACKLESS) { @@ -294,25 +321,8 @@ 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_INDIRECT_VAR_ACCESS; - } else if (zend_string_equals_literal(Z_STR_P(zv), "compact")) { - 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_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")) { - flags |= ZEND_FUNC_VARARG; - } else if (zend_string_equals_literal(Z_STR_P(zv), "func_get_args")) { - flags |= ZEND_FUNC_VARARG; - } + flags |= zend_optimizer_classify_function( + Z_STR_P(zv), opline->extended_value); } } break; @@ -363,7 +373,6 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b break; case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - case ZEND_NEW: BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes); BB_START(i + 1); break; @@ -395,6 +404,12 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b } } + /* If the entry block has predecessors, we may need to split it */ + if ((build_flags & ZEND_CFG_NO_ENTRY_PREDECESSORS) + && op_array->last > 0 && block_map[0] > 1) { + extra_entry_block = 1; + } + if (cfg->split_at_live_ranges) { for (j = 0; j < op_array->last_live_range; j++) { BB_START(op_array->live_range[j].start); @@ -417,6 +432,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b } } + blocks_count += extra_entry_block; cfg->blocks_count = blocks_count; /* Build CFG, Step 2: Build Array of Basic Blocks */ @@ -425,36 +441,40 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b return FAILURE; } - for (i = 0, blocks_count = -1; i < op_array->last; i++) { + blocks_count = -1; + + if (extra_entry_block) { + initialize_block(&blocks[0]); + blocks[0].start = 0; + blocks[0].len = 0; + blocks_count++; + } + + for (i = 0; i < op_array->last; i++) { if (block_map[i]) { if (blocks_count >= 0) { - blocks[blocks_count].end = i - 1; + blocks[blocks_count].len = i - blocks[blocks_count].start; } blocks_count++; - blocks[blocks_count].flags = 0; + initialize_block(&blocks[blocks_count]); blocks[blocks_count].start = i; - blocks[blocks_count].successors[0] = -1; - blocks[blocks_count].successors[1] = -1; - blocks[blocks_count].predecessors_count = 0; - blocks[blocks_count].predecessor_offset = -1; - blocks[blocks_count].idom = -1; - blocks[blocks_count].loop_header = -1; - blocks[blocks_count].level = -1; - blocks[blocks_count].children = -1; - blocks[blocks_count].next_child = -1; - block_map[i] = blocks_count; - } else { - block_map[i] = (uint32_t)-1; } + block_map[i] = blocks_count; } - blocks[blocks_count].end = i - 1; + blocks[blocks_count].len = i - blocks[blocks_count].start; blocks_count++; /* Build CFG, Step 3: Calculate successors */ for (j = 0; j < blocks_count; j++) { - zend_op *opline = op_array->opcodes + blocks[j].end; - switch(opline->opcode) { + zend_op *opline; + if (blocks[j].len == 0) { + record_successor(blocks, j, 0, j + 1); + continue; + } + + opline = op_array->opcodes + blocks[j].start + blocks[j].len - 1; + switch (opline->opcode) { case ZEND_FAST_RET: case ZEND_RETURN: case ZEND_RETURN_BY_REF: @@ -496,7 +516,6 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b break; case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - case ZEND_NEW: record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]); record_successor(blocks, j, 1, j + 1); break; @@ -715,8 +734,8 @@ int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32 int *dj_spanning_tree; zend_worklist work; int flag = ZEND_FUNC_NO_LOOPS; - ALLOCA_FLAG(list_use_heap); - ALLOCA_FLAG(tree_use_heap); + ALLOCA_FLAG(list_use_heap) + ALLOCA_FLAG(tree_use_heap) ZEND_WORKLIST_ALLOCA(&work, cfg->blocks_count, list_use_heap); dj_spanning_tree = do_alloca(sizeof(int) * cfg->blocks_count, tree_use_heap); |
