summaryrefslogtreecommitdiff
path: root/ext/opcache/Optimizer/zend_cfg.c
diff options
context:
space:
mode:
authorJakub Zelenka <bukka@php.net>2016-02-29 19:31:20 +0000
committerJakub Zelenka <bukka@php.net>2016-02-29 19:31:20 +0000
commit70141093a731049ee9220e9e965f61ded56ed4d5 (patch)
tree6e67b382253a186889bfdc37c31062d6fb9880d9 /ext/opcache/Optimizer/zend_cfg.c
parente453af3851daf08f5af9b45fc7819c3a9c336f1e (diff)
parent97294aca7e066443291cc2d77f8674ac23eabb32 (diff)
downloadphp-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.c139
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;
}
/* }}} */