summaryrefslogtreecommitdiff
path: root/ext/opcache/Optimizer/zend_cfg.c
diff options
context:
space:
mode:
authorJakub Zelenka <bukka@php.net>2016-06-19 17:05:48 +0100
committerJakub Zelenka <bukka@php.net>2016-06-19 17:05:48 +0100
commite63a8540a60e95aa5bd8e269add1b02afcc1b79b (patch)
treeb83a144eec24cc81adab0b9a778f7a730d8df79e /ext/opcache/Optimizer/zend_cfg.c
parent7a4cc73641bb3eb878f7184bcbd026ee663cf2a9 (diff)
parent53071e647049f099f7f7a0771ddb63fc2cdd621c (diff)
downloadphp-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.c155
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);