Skip to content

Instantly share code, notes, and snippets.

@krakjoe
Created April 14, 2017 10:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krakjoe/9213861ffb2a9950a5abbceb2b8543cf to your computer and use it in GitHub Desktop.
Save krakjoe/9213861ffb2a9950a5abbceb2b8543cf to your computer and use it in GitHub Desktop.
7.1.0 ... 7.1.4 ext/opcache
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c
index 77b02cc99f..38c2ecb124 100644
--- a/ext/opcache/Optimizer/block_pass.c
+++ b/ext/opcache/Optimizer/block_pass.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -157,17 +157,23 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
src = VAR_SOURCE(opline->op1);
if (src &&
src->opcode == ZEND_QM_ASSIGN &&
- src->op1_type == IS_CONST) {
-
+ src->op1_type == IS_CONST
+ ) {
znode_op op1 = opline->op1;
- zval c = ZEND_OP1_LITERAL(src);
-
- zval_copy_ctor(&c);
- if (zend_optimizer_update_op1_const(op_array, opline, &c)) {
- zend_optimizer_remove_live_range(op_array, op1.var);
+ if (opline->opcode == ZEND_VERIFY_RETURN_TYPE) {
+ COPY_NODE(opline->result, opline->op1);
+ COPY_NODE(opline->op1, src->op1);
VAR_SOURCE(op1) = NULL;
- literal_dtor(&ZEND_OP1_LITERAL(src));
MAKE_NOP(src);
+ } else {
+ zval c = ZEND_OP1_LITERAL(src);
+ zval_copy_ctor(&c);
+ if (zend_optimizer_update_op1_const(op_array, opline, &c)) {
+ zend_optimizer_remove_live_range(op_array, op1.var);
+ VAR_SOURCE(op1) = NULL;
+ literal_dtor(&ZEND_OP1_LITERAL(src));
+ MAKE_NOP(src);
+ }
}
}
}
@@ -1788,6 +1794,11 @@ void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
return;
}
+ if (cfg.blocks_count * (op_array->last_var + op_array->T) > 64 * 1024 * 1024) {
+ zend_arena_release(&ctx->arena, checkpoint);
+ return;
+ }
+
if (ctx->debug_level & ZEND_DUMP_BEFORE_BLOCK_PASS) {
zend_dump_op_array(op_array, ZEND_DUMP_CFG, "before block pass", &cfg);
}
diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c
index 445b579f59..6d549220ab 100644
--- a/ext/opcache/Optimizer/compact_literals.c
+++ b/ext/opcache/Optimizer/compact_literals.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -292,7 +292,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
case ZEND_DECLARE_CLASS:
case ZEND_DECLARE_INHERITED_CLASS:
case ZEND_DECLARE_INHERITED_CLASS_DELAYED:
- LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 2);
+ LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 0, 0, 2);
break;
case ZEND_RECV:
case ZEND_RECV_VARIADIC:
diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c
index b7a0f065f7..55915e70a9 100644
--- a/ext/opcache/Optimizer/dfa_pass.c
+++ b/ext/opcache/Optimizer/dfa_pass.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -356,6 +356,12 @@ static zend_bool opline_supports_assign_contraction(
return opline->op1_type != IS_CV || opline->op1.var != cv_var;
}
+ if (opline->opcode == ZEND_INIT_ARRAY) {
+ /* INIT_ARRAY initializes the result array before reading key/value. */
+ return (opline->op1_type != IS_CV || opline->op1.var != cv_var)
+ && (opline->op2_type != IS_CV || opline->op2.var != cv_var);
+ }
+
return 1;
}
@@ -569,19 +575,23 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
// op_1: VERIFY_RETURN_TYPE #orig_var.CV [T] -> #v.CV [T] => NOP
int orig_var = ssa->ops[op_1].op1_use;
- int ret = ssa->vars[v].use_chain;
+ if (zend_ssa_unlink_use_chain(ssa, op_1, orig_var)) {
- ssa->vars[orig_var].use_chain = ret;
- ssa->ops[ret].op1_use = orig_var;
+ int ret = ssa->vars[v].use_chain;
- ssa->vars[v].definition = -1;
- ssa->vars[v].use_chain = -1;
+ ssa->ops[ret].op1_use = orig_var;
+ ssa->ops[ret].op1_use_chain = ssa->vars[orig_var].use_chain;
+ ssa->vars[orig_var].use_chain = ret;
- ssa->ops[op_1].op1_def = -1;
- ssa->ops[op_1].op1_use = -1;
+ ssa->vars[v].definition = -1;
+ ssa->vars[v].use_chain = -1;
- MAKE_NOP(opline);
- remove_nops = 1;
+ ssa->ops[op_1].op1_def = -1;
+ ssa->ops[op_1].op1_use = -1;
+
+ MAKE_NOP(opline);
+ remove_nops = 1;
+ }
} else if (ssa->ops[op_1].op1_def == v
&& !RETURN_VALUE_USED(opline)
diff --git a/ext/opcache/Optimizer/nop_removal.c b/ext/opcache/Optimizer/nop_removal.c
index 3ebbdad8cf..c7ff73a61b 100644
--- a/ext/opcache/Optimizer/nop_removal.c
+++ b/ext/opcache/Optimizer/nop_removal.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c
index 3480a9a6ee..5d477c1a73 100644
--- a/ext/opcache/Optimizer/optimize_func_calls.c
+++ b/ext/opcache/Optimizer/optimize_func_calls.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/optimize_temp_vars_5.c b/ext/opcache/Optimizer/optimize_temp_vars_5.c
index f0e5747dc6..08ab915e92 100644
--- a/ext/opcache/Optimizer/optimize_temp_vars_5.c
+++ b/ext/opcache/Optimizer/optimize_temp_vars_5.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c
index e8399ccc90..ee883f447a 100644
--- a/ext/opcache/Optimizer/pass1_5.c
+++ b/ext/opcache/Optimizer/pass1_5.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/pass2.c b/ext/opcache/Optimizer/pass2.c
index c24d87a4ad..41ab7c6045 100644
--- a/ext/opcache/Optimizer/pass2.c
+++ b/ext/opcache/Optimizer/pass2.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/pass3.c b/ext/opcache/Optimizer/pass3.c
index ce04e4f7cb..e5d032cd29 100644
--- a/ext/opcache/Optimizer/pass3.c
+++ b/ext/opcache/Optimizer/pass3.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_call_graph.c b/ext/opcache/Optimizer/zend_call_graph.c
index e892c35672..5800a220bc 100644
--- a/ext/opcache/Optimizer/zend_call_graph.c
+++ b/ext/opcache/Optimizer/zend_call_graph.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, Call Graph |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -266,6 +266,29 @@ int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t buil
}
/* }}} */
+zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, zend_op_array *op_array) /* {{{ */
+{
+ zend_call_info **map, *call;
+ if (!info->callee_info) {
+ /* Don't build call map if function contains no calls */
+ return NULL;
+ }
+
+ map = zend_arena_calloc(arena, sizeof(zend_call_info *), op_array->last);
+ for (call = info->callee_info; call; call = call->next_callee) {
+ int i;
+ map[call->caller_init_opline - op_array->opcodes] = call;
+ map[call->caller_call_opline - op_array->opcodes] = call;
+ for (i = 0; i < call->num_args; i++) {
+ if (call->arg_info[i].opline) {
+ map[call->arg_info[i].opline - op_array->opcodes] = call;
+ }
+ }
+ }
+ return map;
+}
+/* }}} */
+
/*
* Local variables:
* tab-width: 4
diff --git a/ext/opcache/Optimizer/zend_call_graph.h b/ext/opcache/Optimizer/zend_call_graph.h
index a5f47f12f0..49c7217c40 100644
--- a/ext/opcache/Optimizer/zend_call_graph.h
+++ b/ext/opcache/Optimizer/zend_call_graph.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, Call Graph |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -51,6 +51,7 @@ struct _zend_func_info {
zend_ssa ssa; /* Static Single Assignmnt Form */
zend_call_info *caller_info; /* where this function is called from */
zend_call_info *callee_info; /* which functions are called from this one */
+ zend_call_info **call_map; /* Call info associated with init/call/send opnum */
int num_args; /* (-1 - unknown) */
zend_recv_arg_info *arg_info;
zend_ssa_var_info return_info;
@@ -69,6 +70,7 @@ typedef struct _zend_call_graph {
BEGIN_EXTERN_C()
int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_call_graph *call_graph);
+zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, zend_op_array *op_array);
int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_op_array *op_array, zend_func_info *func_info);
END_EXTERN_C()
diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c
index f39f9650ae..2163d7c3a2 100644
--- a/ext/opcache/Optimizer/zend_cfg.c
+++ b/ext/opcache/Optimizer/zend_cfg.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, CFG - Control Flow Graph |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -135,12 +135,11 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg *
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 (!(b->flags & (ZEND_BB_REACHABLE|ZEND_BB_UNREACHABLE_FREE))) {
if (cfg->split_at_live_ranges) {
changed = 1;
zend_mark_reachable(op_array->opcodes, cfg, b);
} else {
- ZEND_ASSERT(!(b->flags & ZEND_BB_UNREACHABLE_FREE));
ZEND_ASSERT(b->start == live_range->end);
b->flags |= ZEND_BB_UNREACHABLE_FREE;
}
@@ -750,31 +749,51 @@ static int dominates(zend_basic_block *blocks, int a, int b) /* {{{ */
}
/* }}} */
+typedef struct {
+ int id;
+ int level;
+} block_info;
+static int compare_block_level(const block_info *a, const block_info *b) {
+ return b->level - a->level;
+}
+static void swap_blocks(block_info *a, block_info *b) {
+ block_info tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32_t *flags) /* {{{ */
{
- int i, j, k;
- int depth;
+ int i, j, k, n;
+ int depth, time;
zend_basic_block *blocks = cfg->blocks;
- int *dj_spanning_tree;
+ int *entry_times, *exit_times;
zend_worklist work;
int flag = ZEND_FUNC_NO_LOOPS;
+ block_info *sorted_blocks;
ALLOCA_FLAG(list_use_heap)
ALLOCA_FLAG(tree_use_heap)
+ ALLOCA_FLAG(sorted_blocks_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);
- for (i = 0; i < cfg->blocks_count; i++) {
- dj_spanning_tree[i] = -1;
- }
+ /* We don't materialize the DJ spanning tree explicitly, as we are only interested in ancestor
+ * queries. These are implemented by checking entry/exit times of the DFS search. */
+ entry_times = do_alloca(2 * sizeof(int) * cfg->blocks_count, tree_use_heap);
+ exit_times = entry_times + cfg->blocks_count;
+ memset(entry_times, -1, 2 * sizeof(int) * cfg->blocks_count);
+
zend_worklist_push(&work, 0);
+ time = 0;
while (zend_worklist_len(&work)) {
next:
i = zend_worklist_peek(&work);
+ if (entry_times[i] == -1) {
+ entry_times[i] = time++;
+ }
/* Visit blocks immediately dominated by i. */
for (j = blocks[i].children; j >= 0; j = blocks[j].next_child) {
if (zend_worklist_push(&work, j)) {
- dj_spanning_tree[j] = i;
goto next;
}
}
@@ -786,72 +805,67 @@ int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32
} else if (blocks[succ].idom == i) {
continue;
} else if (zend_worklist_push(&work, succ)) {
- dj_spanning_tree[succ] = i;
goto next;
}
}
+ exit_times[i] = time++;
zend_worklist_pop(&work);
}
+ /* Sort blocks by decreasing level, which is the order in which we want to process them */
+ sorted_blocks = do_alloca(sizeof(block_info) * cfg->blocks_count, sorted_blocks_use_heap);
+ for (i = 0; i < cfg->blocks_count; i++) {
+ sorted_blocks[i].id = i;
+ sorted_blocks[i].level = blocks[i].level;
+ }
+ zend_sort(sorted_blocks, cfg->blocks_count, sizeof(block_info),
+ (compare_func_t) compare_block_level, (swap_func_t) swap_blocks);
+
/* Identify loops. See Sreedhar et al, "Identifying Loops Using DJ
Graphs". */
- for (i = 0, depth = 0; i < cfg->blocks_count; i++) {
- if (blocks[i].level > depth) {
- depth = blocks[i].level;
- }
- }
- for (; depth >= 0; depth--) {
- for (i = 0; i < cfg->blocks_count; i++) {
- if (blocks[i].level != depth) {
+ for (n = 0; n < cfg->blocks_count; n++) {
+ i = sorted_blocks[n].id;
+
+ zend_bitset_clear(work.visited, zend_bitset_len(cfg->blocks_count));
+ for (j = 0; j < blocks[i].predecessors_count; j++) {
+ int pred = cfg->predecessors[blocks[i].predecessor_offset + j];
+
+ /* A join edge is one for which the predecessor does not
+ immediately dominate the successor. */
+ if (blocks[i].idom == pred) {
continue;
}
- zend_bitset_clear(work.visited, zend_bitset_len(cfg->blocks_count));
- for (j = 0; j < blocks[i].predecessors_count; j++) {
- int pred = cfg->predecessors[blocks[i].predecessor_offset + j];
- /* A join edge is one for which the predecessor does not
- immediately dominate the successor. */
- if (blocks[i].idom == pred) {
- continue;
- }
-
- /* In a loop back-edge (back-join edge), the successor dominates
- the predecessor. */
- if (dominates(blocks, i, pred)) {
- blocks[i].flags |= ZEND_BB_LOOP_HEADER;
+ /* In a loop back-edge (back-join edge), the successor dominates
+ the predecessor. */
+ if (dominates(blocks, i, pred)) {
+ blocks[i].flags |= ZEND_BB_LOOP_HEADER;
+ flag &= ~ZEND_FUNC_NO_LOOPS;
+ zend_worklist_push(&work, pred);
+ } else {
+ /* Otherwise it's a cross-join edge. See if it's a branch
+ to an ancestor on the DJ spanning tree. */
+ if (entry_times[pred] > entry_times[i] && exit_times[pred] < exit_times[i]) {
+ blocks[i].flags |= ZEND_BB_IRREDUCIBLE_LOOP;
+ flag |= ZEND_FUNC_IRREDUCIBLE;
flag &= ~ZEND_FUNC_NO_LOOPS;
- zend_worklist_push(&work, pred);
- } else {
- /* Otherwise it's a cross-join edge. See if it's a branch
- to an ancestor on the dominator spanning tree. */
- int dj_parent = pred;
- while (dj_parent >= 0) {
- if (dj_parent == i) {
- /* An sp-back edge: mark as irreducible. */
- blocks[i].flags |= ZEND_BB_IRREDUCIBLE_LOOP;
- flag |= ZEND_FUNC_IRREDUCIBLE;
- flag &= ~ZEND_FUNC_NO_LOOPS;
- break;
- } else {
- dj_parent = dj_spanning_tree[dj_parent];
- }
- }
}
}
- while (zend_worklist_len(&work)) {
- j = zend_worklist_pop(&work);
- if (blocks[j].loop_header < 0 && j != i) {
- blocks[j].loop_header = i;
- for (k = 0; k < blocks[j].predecessors_count; k++) {
- zend_worklist_push(&work, cfg->predecessors[blocks[j].predecessor_offset + k]);
- }
+ }
+ while (zend_worklist_len(&work)) {
+ j = zend_worklist_pop(&work);
+ if (blocks[j].loop_header < 0 && j != i) {
+ blocks[j].loop_header = i;
+ for (k = 0; k < blocks[j].predecessors_count; k++) {
+ zend_worklist_push(&work, cfg->predecessors[blocks[j].predecessor_offset + k]);
}
}
}
}
- free_alloca(dj_spanning_tree, tree_use_heap);
+ free_alloca(sorted_blocks, sorted_blocks_use_heap);
+ free_alloca(entry_times, tree_use_heap);
ZEND_WORKLIST_FREE_ALLOCA(&work, list_use_heap);
*flags |= flag;
diff --git a/ext/opcache/Optimizer/zend_cfg.h b/ext/opcache/Optimizer/zend_cfg.h
index 4f570b7fd6..7b80d83f11 100644
--- a/ext/opcache/Optimizer/zend_cfg.h
+++ b/ext/opcache/Optimizer/zend_cfg.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, CFG - Control Flow Graph |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_dfg.c b/ext/opcache/Optimizer/zend_dfg.c
index 6c52d6eb58..374c8146c8 100644
--- a/ext/opcache/Optimizer/zend_dfg.c
+++ b/ext/opcache/Optimizer/zend_dfg.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, DFG - Data Flow Graph |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_dfg.h b/ext/opcache/Optimizer/zend_dfg.h
index 5ed8cfc5d0..06ee46be32 100644
--- a/ext/opcache/Optimizer/zend_dfg.h
+++ b/ext/opcache/Optimizer/zend_dfg.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, DFG - Data Flow Graph |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c
index cd07309df8..2167fa6e6b 100644
--- a/ext/opcache/Optimizer/zend_dump.c
+++ b/ext/opcache/Optimizer/zend_dump.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, Bytecode Visualisation |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_dump.h b/ext/opcache/Optimizer/zend_dump.h
index 38b955c3a1..11646d9a82 100644
--- a/ext/opcache/Optimizer/zend_dump.h
+++ b/ext/opcache/Optimizer/zend_dump.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, Bytecode Visualisation |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c
index 60954e0c19..7a1e65f625 100644
--- a/ext/opcache/Optimizer/zend_func_info.c
+++ b/ext/opcache/Optimizer/zend_func_info.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, Func Info |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_func_info.h b/ext/opcache/Optimizer/zend_func_info.h
index 13fae8ff0b..a126bef708 100644
--- a/ext/opcache/Optimizer/zend_func_info.h
+++ b/ext/opcache/Optimizer/zend_func_info.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, Func Info |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c
index d0e5d84e89..f572616567 100644
--- a/ext/opcache/Optimizer/zend_inference.c
+++ b/ext/opcache/Optimizer/zend_inference.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, e-SSA based Type & Range Inference |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -58,6 +58,20 @@
#define LOG_NEG_RANGE(...)
#endif
+/* Pop elements in unspecified order from worklist until it is empty */
+#define WHILE_WORKLIST(worklist, len, i) do { \
+ zend_bool _done = 0; \
+ while (!_done) { \
+ _done = 1; \
+ ZEND_BITSET_FOREACH(worklist, len, i) { \
+ zend_bitset_excl(worklist, i); \
+ _done = 0;
+
+#define WHILE_WORKLIST_END() \
+ } ZEND_BITSET_FOREACH_END(); \
+ } \
+} while (0)
+
#define CHECK_SCC_VAR(var2) \
do { \
if (!ssa->vars[var2].no_val) { \
@@ -269,9 +283,7 @@ int zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ss
}
}
- while (!zend_bitset_empty(worklist, zend_bitset_len(ssa_vars_count))) {
- i = zend_bitset_first(worklist, zend_bitset_len(ssa_vars_count));
- zend_bitset_excl(worklist, i);
+ WHILE_WORKLIST(worklist, zend_bitset_len(ssa_vars_count), i) {
if (ssa_vars[i].definition_phi) {
/* mark all possible sources as used */
p = ssa_vars[i].definition_phi;
@@ -289,7 +301,7 @@ int zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ss
}
}
}
- }
+ } WHILE_WORKLIST_END();
free_alloca(worklist, use_heap);
@@ -500,11 +512,266 @@ static void zend_ssa_range_and(zend_long a, zend_long b, zend_long c, zend_long
}
}
+/* Get the normal op corresponding to a compound assignment op */
+static inline zend_uchar get_compound_assign_op(zend_uchar opcode) {
+ switch (opcode) {
+ case ZEND_ASSIGN_ADD: return ZEND_ADD;
+ case ZEND_ASSIGN_SUB: return ZEND_SUB;
+ case ZEND_ASSIGN_MUL: return ZEND_MUL;
+ case ZEND_ASSIGN_DIV: return ZEND_DIV;
+ case ZEND_ASSIGN_MOD: return ZEND_MOD;
+ case ZEND_ASSIGN_SL: return ZEND_SL;
+ case ZEND_ASSIGN_SR: return ZEND_SR;
+ case ZEND_ASSIGN_CONCAT: return ZEND_CONCAT;
+ case ZEND_ASSIGN_BW_OR: return ZEND_BW_OR;
+ case ZEND_ASSIGN_BW_AND: return ZEND_BW_AND;
+ case ZEND_ASSIGN_BW_XOR: return ZEND_BW_XOR;
+ case ZEND_ASSIGN_POW: return ZEND_POW;
+ EMPTY_SWITCH_DEFAULT_CASE()
+ }
+}
+
+static int zend_inference_calc_binary_op_range(
+ const zend_op_array *op_array, zend_ssa *ssa,
+ zend_op *opline, zend_ssa_op *ssa_op, zend_uchar opcode, zend_ssa_range *tmp) {
+ zend_long op1_min, op2_min, op1_max, op2_max, t1, t2, t3, t4;
+
+ switch (opcode) {
+ case ZEND_ADD:
+ if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
+ op1_min = OP1_MIN_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ op1_max = OP1_MAX_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ tmp->min = op1_min + op2_min;
+ tmp->max = op1_max + op2_max;
+ if (OP1_RANGE_UNDERFLOW() ||
+ OP2_RANGE_UNDERFLOW() ||
+ (op1_min < 0 && op2_min < 0 && tmp->min >= 0)) {
+ tmp->underflow = 1;
+ tmp->min = ZEND_LONG_MIN;
+ }
+ if (OP1_RANGE_OVERFLOW() ||
+ OP2_RANGE_OVERFLOW() ||
+ (op1_max > 0 && op2_max > 0 && tmp->max <= 0)) {
+ tmp->overflow = 1;
+ tmp->max = ZEND_LONG_MAX;
+ }
+ return 1;
+ }
+ break;
+ case ZEND_SUB:
+ if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
+ op1_min = OP1_MIN_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ op1_max = OP1_MAX_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ tmp->min = op1_min - op2_max;
+ tmp->max = op1_max - op2_min;
+ if (OP1_RANGE_UNDERFLOW() ||
+ OP2_RANGE_OVERFLOW() ||
+ (op1_min < 0 && op2_max > 0 && tmp->min >= 0)) {
+ tmp->underflow = 1;
+ tmp->min = ZEND_LONG_MIN;
+ }
+ if (OP1_RANGE_OVERFLOW() ||
+ OP2_RANGE_UNDERFLOW() ||
+ (op1_max > 0 && op2_min < 0 && tmp->max <= 0)) {
+ tmp->overflow = 1;
+ tmp->max = ZEND_LONG_MAX;
+ }
+ return 1;
+ }
+ break;
+ case ZEND_MUL:
+ if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
+ op1_min = OP1_MIN_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ op1_max = OP1_MAX_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ t1 = op1_min * op2_min;
+ t2 = op1_min * op2_max;
+ t3 = op1_max * op2_min;
+ t4 = op1_max * op2_max;
+ // FIXME: more careful overflow checks?
+ if (OP1_RANGE_UNDERFLOW() ||
+ OP2_RANGE_UNDERFLOW() ||
+ OP1_RANGE_OVERFLOW() ||
+ OP2_RANGE_OVERFLOW() ||
+ (double)t1 != (double)op1_min * (double)op2_min ||
+ (double)t2 != (double)op1_min * (double)op2_max ||
+ (double)t3 != (double)op1_max * (double)op2_min ||
+ (double)t4 != (double)op1_max * (double)op2_max) {
+ tmp->underflow = 1;
+ tmp->overflow = 1;
+ tmp->min = ZEND_LONG_MIN;
+ tmp->max = ZEND_LONG_MAX;
+ } else {
+ tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
+ tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
+ }
+ return 1;
+ }
+ break;
+ case ZEND_DIV:
+ if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
+ op1_min = OP1_MIN_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ op1_max = OP1_MAX_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ if (op2_min <= 0 && op2_max >= 0) {
+ break;
+ }
+ if (op1_min == ZEND_LONG_MIN && op2_max == -1) {
+ /* Avoid ill-defined division, which may trigger SIGFPE. */
+ break;
+ }
+ t1 = op1_min / op2_min;
+ t2 = op1_min / op2_max;
+ t3 = op1_max / op2_min;
+ t4 = op1_max / op2_max;
+ // FIXME: more careful overflow checks?
+ if (OP1_RANGE_UNDERFLOW() ||
+ OP2_RANGE_UNDERFLOW() ||
+ OP1_RANGE_OVERFLOW() ||
+ OP2_RANGE_OVERFLOW() ||
+ t1 != (zend_long)((double)op1_min / (double)op2_min) ||
+ t2 != (zend_long)((double)op1_min / (double)op2_max) ||
+ t3 != (zend_long)((double)op1_max / (double)op2_min) ||
+ t4 != (zend_long)((double)op1_max / (double)op2_max)) {
+ tmp->underflow = 1;
+ tmp->overflow = 1;
+ tmp->min = ZEND_LONG_MIN;
+ tmp->max = ZEND_LONG_MAX;
+ } else {
+ tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
+ tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
+ }
+ return 1;
+ }
+ break;
+ case ZEND_MOD:
+ if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
+ if (OP1_RANGE_UNDERFLOW() ||
+ OP2_RANGE_UNDERFLOW() ||
+ OP1_RANGE_OVERFLOW() ||
+ OP2_RANGE_OVERFLOW()) {
+ tmp->min = ZEND_LONG_MIN;
+ tmp->max = ZEND_LONG_MAX;
+ } else {
+ op1_min = OP1_MIN_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ op1_max = OP1_MAX_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ if (op2_min == 0 || op2_max == 0) {
+ /* avoid division by zero */
+ break;
+ }
+ t1 = (op2_min == -1) ? 0 : (op1_min % op2_min);
+ t2 = (op2_max == -1) ? 0 : (op1_min % op2_max);
+ t3 = (op2_min == -1) ? 0 : (op1_max % op2_min);
+ t4 = (op2_max == -1) ? 0 : (op1_max % op2_max);
+ tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
+ tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
+ }
+ return 1;
+ }
+ break;
+ case ZEND_SL:
+ if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
+ if (OP1_RANGE_UNDERFLOW() ||
+ OP2_RANGE_UNDERFLOW() ||
+ OP1_RANGE_OVERFLOW() ||
+ OP2_RANGE_OVERFLOW()) {
+ tmp->min = ZEND_LONG_MIN;
+ tmp->max = ZEND_LONG_MAX;
+ } else {
+ op1_min = OP1_MIN_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ op1_max = OP1_MAX_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ t1 = op1_min << op2_min;
+ t2 = op1_min << op2_max;
+ t3 = op1_max << op2_min;
+ t4 = op1_max << op2_max;
+ tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
+ tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
+ }
+ return 1;
+ }
+ break;
+ case ZEND_SR:
+ if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
+ if (OP1_RANGE_UNDERFLOW() ||
+ OP2_RANGE_UNDERFLOW() ||
+ OP1_RANGE_OVERFLOW() ||
+ OP2_RANGE_OVERFLOW()) {
+ tmp->min = ZEND_LONG_MIN;
+ tmp->max = ZEND_LONG_MAX;
+ } else {
+ op1_min = OP1_MIN_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ op1_max = OP1_MAX_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ t1 = op1_min >> op2_min;
+ t2 = op1_min >> op2_max;
+ t3 = op1_max >> op2_min;
+ t4 = op1_max >> op2_max;
+ tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
+ tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
+ }
+ return 1;
+ }
+ break;
+ case ZEND_BW_OR:
+ if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
+ if (OP1_RANGE_UNDERFLOW() ||
+ OP2_RANGE_UNDERFLOW() ||
+ OP1_RANGE_OVERFLOW() ||
+ OP2_RANGE_OVERFLOW()) {
+ tmp->min = ZEND_LONG_MIN;
+ tmp->max = ZEND_LONG_MAX;
+ } else {
+ op1_min = OP1_MIN_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ op1_max = OP1_MAX_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ zend_ssa_range_or(op1_min, op1_max, op2_min, op2_max, tmp);
+ }
+ return 1;
+ }
+ break;
+ case ZEND_BW_AND:
+ if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
+ if (OP1_RANGE_UNDERFLOW() ||
+ OP2_RANGE_UNDERFLOW() ||
+ OP1_RANGE_OVERFLOW() ||
+ OP2_RANGE_OVERFLOW()) {
+ tmp->min = ZEND_LONG_MIN;
+ tmp->max = ZEND_LONG_MAX;
+ } else {
+ op1_min = OP1_MIN_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ op1_max = OP1_MAX_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ zend_ssa_range_and(op1_min, op1_max, op2_min, op2_max, tmp);
+ }
+ return 1;
+ }
+ break;
+ case ZEND_BW_XOR:
+ // TODO
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE()
+ }
+ return 0;
+}
+
int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int var, int widening, int narrowing, zend_ssa_range *tmp)
{
uint32_t line;
zend_op *opline;
- zend_long op1_min, op2_min, op1_max, op2_max, t1, t2, t3, t4;
+ zend_long op1_min, op2_min, op1_max, op2_max;
if (ssa->vars[var].definition_phi) {
zend_ssa_phi *p = ssa->vars[var].definition_phi;
@@ -633,241 +900,21 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
tmp->overflow = 0;
switch (opline->opcode) {
case ZEND_ADD:
- if (ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- tmp->min = op1_min + op2_min;
- tmp->max = op1_max + op2_max;
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- (op1_min < 0 && op2_min < 0 && tmp->min >= 0)) {
- tmp->underflow = 1;
- tmp->min = ZEND_LONG_MIN;
- }
- if (OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW() ||
- (op1_max > 0 && op2_max > 0 && tmp->max <= 0)) {
- tmp->overflow = 1;
- tmp->max = ZEND_LONG_MAX;
- }
- return 1;
- }
- }
- break;
case ZEND_SUB:
- if (ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- tmp->min = op1_min - op2_max;
- tmp->max = op1_max - op2_min;
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_OVERFLOW() ||
- (op1_min < 0 && op2_max > 0 && tmp->min >= 0)) {
- tmp->underflow = 1;
- tmp->min = ZEND_LONG_MIN;
- }
- if (OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- (op1_max > 0 && op2_min < 0 && tmp->max <= 0)) {
- tmp->overflow = 1;
- tmp->max = ZEND_LONG_MAX;
- }
- return 1;
- }
- }
- break;
case ZEND_MUL:
- if (ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- t1 = op1_min * op2_min;
- t2 = op1_min * op2_max;
- t3 = op1_max * op2_min;
- t4 = op1_max * op2_max;
- // FIXME: more careful overflow checks?
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW() ||
- (double)t1 != (double)op1_min * (double)op2_min ||
- (double)t2 != (double)op1_min * (double)op2_max ||
- (double)t3 != (double)op1_max * (double)op2_min ||
- (double)t4 != (double)op1_max * (double)op2_max) {
- tmp->underflow = 1;
- tmp->overflow = 1;
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
- tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
- }
- return 1;
- }
- }
- break;
case ZEND_DIV:
- if (ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- if (op2_min <= 0 && op2_max >= 0) {
- break;
- }
- t1 = op1_min / op2_min;
- t2 = op1_min / op2_max;
- t3 = op1_max / op2_min;
- t4 = op1_max / op2_max;
- // FIXME: more careful overflow checks?
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW() ||
- t1 != (zend_long)((double)op1_min / (double)op2_min) ||
- t2 != (zend_long)((double)op1_min / (double)op2_max) ||
- t3 != (zend_long)((double)op1_max / (double)op2_min) ||
- t4 != (zend_long)((double)op1_max / (double)op2_max)) {
- tmp->underflow = 1;
- tmp->overflow = 1;
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
- tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
- }
- return 1;
- }
- }
- break;
case ZEND_MOD:
- if (ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW()) {
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- if (op2_min == 0 || op2_max == 0) {
- /* avoid division by zero */
- break;
- }
- t1 = (op2_min == -1) ? 0 : (op1_min % op2_min);
- t2 = (op2_max == -1) ? 0 : (op1_min % op2_max);
- t3 = (op2_min == -1) ? 0 : (op1_max % op2_min);
- t4 = (op2_max == -1) ? 0 : (op1_max % op2_max);
- tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
- tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
- }
- }
- }
- break;
case ZEND_SL:
- if (ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW()) {
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- t1 = op1_min << op2_min;
- t2 = op1_min << op2_max;
- t3 = op1_max << op2_min;
- t4 = op1_max << op2_max;
- tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
- tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
- }
- return 1;
- }
- }
- break;
case ZEND_SR:
- if (ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW()) {
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- t1 = op1_min >> op2_min;
- t2 = op1_min >> op2_max;
- t3 = op1_max >> op2_min;
- t4 = op1_max >> op2_max;
- tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
- tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
- }
- return 1;
- }
- }
- break;
case ZEND_BW_OR:
- if (ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW()) {
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- zend_ssa_range_or(op1_min, op1_max, op2_min, op2_max, tmp);
- }
- return 1;
- }
- }
- break;
case ZEND_BW_AND:
+ case ZEND_BW_XOR:
if (ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW()) {
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- zend_ssa_range_and(op1_min, op1_max, op2_min, op2_max, tmp);
- }
- return 1;
- }
+ return zend_inference_calc_binary_op_range(
+ op_array, ssa, opline, &ssa->ops[line], opline->opcode, tmp);
}
break;
-// case ZEND_BW_XOR:
+
case ZEND_BW_NOT:
if (ssa->ops[line].result_def == var) {
if (OP1_HAS_RANGE()) {
@@ -1229,349 +1276,25 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
}
break;
case ZEND_ASSIGN_ADD:
- if (opline->extended_value == 0) {
- if (ssa->ops[line].op1_def == var || ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- tmp->min = op1_min + op2_min;
- tmp->max = op1_max + op2_max;
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- (op1_min < 0 && op2_min < 0 && tmp->min >= 0)) {
- tmp->underflow = 1;
- tmp->min = ZEND_LONG_MIN;
- }
- if (OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW() ||
- (op1_max > 0 && op2_max > 0 && tmp->max <= 0)) {
- tmp->overflow = 1;
- tmp->max = ZEND_LONG_MAX;
- }
- return 1;
- }
- }
- } else if ((opline+1)->opcode == ZEND_OP_DATA) {
- if (ssa->ops[line+1].op1_def == var) {
- opline++;
- if (OP1_HAS_RANGE()) {
- tmp->min = OP1_MIN_RANGE();
- tmp->max = OP1_MAX_RANGE();
- tmp->underflow = OP1_RANGE_UNDERFLOW();
- tmp->overflow = OP1_RANGE_OVERFLOW();
- return 1;
- }
- }
- }
- break;
case ZEND_ASSIGN_SUB:
- if (opline->extended_value == 0) {
- if (ssa->ops[line].op1_def == var || ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- tmp->min = op1_min - op2_max;
- tmp->max = op1_max - op2_min;
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_OVERFLOW() ||
- (op1_min < 0 && op2_max > 0 && tmp->min >= 0)) {
- tmp->underflow = 1;
- tmp->min = ZEND_LONG_MIN;
- }
- if (OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- (op1_max > 0 && op2_min < 0 && tmp->max <= 0)) {
- tmp->overflow = 1;
- tmp->max = ZEND_LONG_MAX;
- }
- return 1;
- }
- }
- } else if ((opline+1)->opcode == ZEND_OP_DATA) {
- if (ssa->ops[line+1].op1_def == var) {
- opline++;
- if (OP1_HAS_RANGE()) {
- tmp->min = OP1_MIN_RANGE();
- tmp->max = OP1_MAX_RANGE();
- tmp->underflow = OP1_RANGE_UNDERFLOW();
- tmp->overflow = OP1_RANGE_OVERFLOW();
- return 1;
- }
- }
- }
- break;
case ZEND_ASSIGN_MUL:
- if (opline->extended_value == 0) {
- if (ssa->ops[line].op1_def == var || ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- t1 = op1_min * op2_min;
- t2 = op1_min * op2_max;
- t3 = op1_max * op2_min;
- t4 = op1_max * op2_max;
- // FIXME: more careful overflow checks?
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW() ||
- (double)t1 != (double)op1_min * (double)op2_min ||
- (double)t2 != (double)op1_min * (double)op2_min ||
- (double)t3 != (double)op1_min * (double)op2_min ||
- (double)t4 != (double)op1_min * (double)op2_min) {
- tmp->underflow = 1;
- tmp->overflow = 1;
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
- tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
- }
- return 1;
- }
- }
- } else if ((opline+1)->opcode == ZEND_OP_DATA) {
- if (ssa->ops[line+1].op1_def == var) {
- if (OP1_HAS_RANGE()) {
- opline++;
- tmp->min = OP1_MIN_RANGE();
- tmp->max = OP1_MAX_RANGE();
- tmp->underflow = OP1_RANGE_UNDERFLOW();
- tmp->overflow = OP1_RANGE_OVERFLOW();
- return 1;
- }
- }
- }
- break;
case ZEND_ASSIGN_DIV:
- if (opline->extended_value == 0) {
- if (ssa->ops[line].op1_def == var || ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- if (op2_min <= 0 && op2_max >= 0) {
- break;
- }
- t1 = op1_min / op2_min;
- t2 = op1_min / op2_max;
- t3 = op1_max / op2_min;
- t4 = op1_max / op2_max;
- // FIXME: more careful overflow checks?
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW() ||
- t1 != (zend_long)((double)op1_min / (double)op2_min) ||
- t2 != (zend_long)((double)op1_min / (double)op2_max) ||
- t3 != (zend_long)((double)op1_max / (double)op2_min) ||
- t4 != (zend_long)((double)op1_max / (double)op2_max)) {
- tmp->underflow = 1;
- tmp->overflow = 1;
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
- tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
- }
- return 1;
- }
- }
- } else if ((opline+1)->opcode == ZEND_OP_DATA) {
- if (ssa->ops[line+1].op1_def == var) {
- if (OP1_HAS_RANGE()) {
- opline++;
- tmp->min = OP1_MIN_RANGE();
- tmp->max = OP1_MAX_RANGE();
- tmp->underflow = OP1_RANGE_UNDERFLOW();
- tmp->overflow = OP1_RANGE_OVERFLOW();
- return 1;
- }
- }
- }
- break;
case ZEND_ASSIGN_MOD:
- if (opline->extended_value == 0) {
- if (ssa->ops[line].op1_def == var || ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW()) {
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- if (op2_min == 0 || op2_max == 0) {
- /* avoid division by zero */
- break;
- }
- t1 = op1_min % op2_min;
- t2 = op1_min % op2_max;
- t3 = op1_max % op2_min;
- t4 = op1_max % op2_max;
- tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
- tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
- }
- return 1;
- }
- }
- } else if ((opline+1)->opcode == ZEND_OP_DATA) {
- if (ssa->ops[line+1].op1_def == var) {
- if (OP1_HAS_RANGE()) {
- opline++;
- tmp->min = OP1_MIN_RANGE();
- tmp->max = OP1_MAX_RANGE();
- tmp->underflow = OP1_RANGE_UNDERFLOW();
- tmp->overflow = OP1_RANGE_OVERFLOW();
- return 1;
- }
- }
- }
- break;
case ZEND_ASSIGN_SL:
- if (opline->extended_value == 0) {
- if (ssa->ops[line].op1_def == var || ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW()) {
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- t1 = op1_min << op2_min;
- t2 = op1_min << op2_max;
- t3 = op1_max << op2_min;
- t4 = op1_max << op2_max;
- tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
- tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
- }
- return 1;
- }
- }
- } else if ((opline+1)->opcode == ZEND_OP_DATA) {
- if (ssa->ops[line+1].op1_def == var) {
- if (OP1_HAS_RANGE()) {
- opline++;
- tmp->min = OP1_MIN_RANGE();
- tmp->max = OP1_MAX_RANGE();
- tmp->underflow = OP1_RANGE_UNDERFLOW();
- tmp->overflow = OP1_RANGE_OVERFLOW();
- return 1;
- }
- }
- }
- break;
case ZEND_ASSIGN_SR:
- if (opline->extended_value == 0) {
- if (ssa->ops[line].op1_def == var || ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW()) {
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- t1 = op1_min >> op2_min;
- t2 = op1_min >> op2_max;
- t3 = op1_max >> op2_min;
- t4 = op1_max >> op2_max;
- tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
- tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
- }
- return 1;
- }
- }
- } else if ((opline+1)->opcode == ZEND_OP_DATA) {
- if (ssa->ops[line+1].op1_def == var) {
- if (OP1_HAS_RANGE()) {
- opline++;
- tmp->min = OP1_MIN_RANGE();
- tmp->max = OP1_MAX_RANGE();
- tmp->underflow = OP1_RANGE_UNDERFLOW();
- tmp->overflow = OP1_RANGE_OVERFLOW();
- return 1;
- }
- }
- }
- break;
case ZEND_ASSIGN_BW_OR:
- if (opline->extended_value == 0) {
- if (ssa->ops[line].op1_def == var || ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW()) {
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- zend_ssa_range_or(op1_min, op1_max, op2_min, op2_max, tmp);
- }
- return 1;
- }
- }
- } else if ((opline+1)->opcode == ZEND_OP_DATA) {
- if (ssa->ops[line+1].op1_def == var) {
- if (OP1_HAS_RANGE()) {
- opline++;
- tmp->min = OP1_MIN_RANGE();
- tmp->max = OP1_MAX_RANGE();
- tmp->underflow = OP1_RANGE_UNDERFLOW();
- tmp->overflow = OP1_RANGE_OVERFLOW();
- return 1;
- }
- }
- }
- break;
case ZEND_ASSIGN_BW_AND:
+ case ZEND_ASSIGN_BW_XOR:
if (opline->extended_value == 0) {
if (ssa->ops[line].op1_def == var || ssa->ops[line].result_def == var) {
- if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
- if (OP1_RANGE_UNDERFLOW() ||
- OP2_RANGE_UNDERFLOW() ||
- OP1_RANGE_OVERFLOW() ||
- OP2_RANGE_OVERFLOW()) {
- tmp->min = ZEND_LONG_MIN;
- tmp->max = ZEND_LONG_MAX;
- } else {
- op1_min = OP1_MIN_RANGE();
- op2_min = OP2_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- op2_max = OP2_MAX_RANGE();
- zend_ssa_range_and(op1_min, op1_max, op2_min, op2_max, tmp);
- }
- return 1;
- }
+ return zend_inference_calc_binary_op_range(
+ op_array, ssa, opline, &ssa->ops[line],
+ get_compound_assign_op(opline->opcode), tmp);
}
} else if ((opline+1)->opcode == ZEND_OP_DATA) {
if (ssa->ops[line+1].op1_def == var) {
+ opline++;
if (OP1_HAS_RANGE()) {
- opline++;
tmp->min = OP1_MIN_RANGE();
tmp->max = OP1_MAX_RANGE();
tmp->underflow = OP1_RANGE_UNDERFLOW();
@@ -1581,7 +1304,6 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
}
}
break;
-// case ZEND_ASSIGN_BW_XOR:
// case ZEND_ASSIGN_CONCAT:
case ZEND_OP_DATA:
if ((opline-1)->opcode == ZEND_ASSIGN_DIM ||
@@ -1647,21 +1369,24 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
case ZEND_DO_ICALL:
case ZEND_DO_UCALL:
case ZEND_DO_FCALL_BY_NAME:
- if (ssa->ops[line].result_def == var && ZEND_FUNC_INFO(op_array)) {
+ if (ssa->ops[line].result_def == var) {
zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
- zend_call_info *call_info = func_info->callee_info;
+ zend_call_info *call_info;
+ if (!func_info || !func_info->call_map) {
+ break;
+ }
- while (call_info && call_info->caller_call_opline != opline) {
- call_info = call_info->next_callee;
+ call_info = func_info->call_map[opline - op_array->opcodes];
+ if (!call_info) {
+ break;
}
- if (call_info) {
- if (call_info->callee_func->type == ZEND_USER_FUNCTION) {
- func_info = ZEND_FUNC_INFO(&call_info->callee_func->op_array);
- if (func_info && func_info->return_info.has_range) {
- *tmp = func_info->return_info.range;
- return 1;
- }
+ if (call_info->callee_func->type == ZEND_USER_FUNCTION) {
+ func_info = ZEND_FUNC_INFO(&call_info->callee_func->op_array);
+ if (func_info && func_info->return_info.has_range) {
+ *tmp = func_info->return_info.range;
+ return 1;
}
+ }
//TODO: we can't use type inference for internal functions at this point ???
#if 0
uint32_t type;
@@ -1684,7 +1409,6 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
return 1;
}
#endif
- }
}
break;
// FIXME: support for more opcodes
@@ -1856,9 +1580,7 @@ static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ss
memset(visited, 0, sizeof(zend_ulong) * worklist_len);
- while (!zend_bitset_empty(worklist, worklist_len)) {
- j = zend_bitset_first(worklist, worklist_len);
- zend_bitset_excl(worklist, j);
+ WHILE_WORKLIST(worklist, worklist_len, j) {
if (zend_inference_calc_range(op_array, ssa, j, 0, 0, &tmp)) {
#ifdef NEG_RANGE
if (!has_inner_cycles &&
@@ -1913,7 +1635,7 @@ static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ss
FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR_1);
}
}
- }
+ } WHILE_WORKLIST_END();
}
free_alloca(worklist, use_heap);
}
@@ -1930,11 +1652,11 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
ALLOCA_FLAG(use_heap);
worklist = do_alloca(
- sizeof(zend_ulong) * worklist_len +
- sizeof(int) * ssa->vars_count +
+ ZEND_MM_ALIGNED_SIZE(sizeof(zend_ulong) * worklist_len) +
+ ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->vars_count) +
sizeof(int) * ssa->sccs, use_heap);
- next_scc_var = (int*)(worklist + worklist_len);
- scc_var = next_scc_var + ssa->vars_count;
+ next_scc_var = (int*)((char*)worklist + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ulong) * worklist_len));
+ scc_var = (int*)((char*)next_scc_var + ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->vars_count));
LOG_SSA_RANGE("Range Inference\n");
@@ -1976,13 +1698,11 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
#endif
/* widening */
- while (!zend_bitset_empty(worklist, worklist_len)) {
- j = zend_bitset_first(worklist, worklist_len);
- zend_bitset_excl(worklist, j);
+ WHILE_WORKLIST(worklist, worklist_len, j) {
if (zend_ssa_range_widening(op_array, ssa, j, scc)) {
FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR);
}
- }
+ } WHILE_WORKLIST_END();
/* Add all SCC entry variables into worklist for narrowing */
for (j = scc_var[scc]; j >= 0; j = next_scc_var[j]) {
@@ -1993,9 +1713,7 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
}
/* narrowing */
- while (!zend_bitset_empty(worklist, worklist_len)) {
- j = zend_bitset_first(worklist, worklist_len);
- zend_bitset_excl(worklist, j);
+ WHILE_WORKLIST(worklist, worklist_len, j) {
if (zend_ssa_range_narrowing(op_array, ssa, j, scc)) {
FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR);
#ifdef SYM_RANGE
@@ -2007,7 +1725,7 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
}
#endif
}
- }
+ } WHILE_WORKLIST_END();
}
}
@@ -2358,25 +2076,6 @@ static uint32_t binary_op_result_type(
return tmp;
}
-/* Get the normal op corresponding to a compound assignment op */
-static inline zend_uchar get_compound_assign_op(zend_uchar opcode) {
- switch (opcode) {
- case ZEND_ASSIGN_ADD: return ZEND_ADD;
- case ZEND_ASSIGN_SUB: return ZEND_SUB;
- case ZEND_ASSIGN_MUL: return ZEND_MUL;
- case ZEND_ASSIGN_DIV: return ZEND_DIV;
- case ZEND_ASSIGN_MOD: return ZEND_MOD;
- case ZEND_ASSIGN_SL: return ZEND_SL;
- case ZEND_ASSIGN_SR: return ZEND_SR;
- case ZEND_ASSIGN_CONCAT: return ZEND_CONCAT;
- case ZEND_ASSIGN_BW_OR: return ZEND_BW_OR;
- case ZEND_ASSIGN_BW_AND: return ZEND_BW_AND;
- case ZEND_ASSIGN_BW_XOR: return ZEND_BW_XOR;
- case ZEND_ASSIGN_POW: return ZEND_POW;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
-}
-
static inline zend_class_entry *get_class_entry(const zend_script *script, zend_string *lcname) {
zend_class_entry *ce = script ? zend_hash_find_ptr(&script->class_table, lcname) : NULL;
if (ce) {
@@ -3435,13 +3134,10 @@ static void zend_update_type_info(const zend_op_array *op_array,
zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
zend_call_info *call_info;
- if (!func_info) {
+ if (!func_info || !func_info->call_map) {
goto unknown_opcode;
}
- call_info = func_info->callee_info;
- while (call_info && call_info->caller_call_opline != opline) {
- call_info = call_info->next_callee;
- }
+ call_info = func_info->call_map[opline - op_array->opcodes];
if (!call_info) {
goto unknown_opcode;
}
@@ -3476,6 +3172,7 @@ static void zend_update_type_info(const zend_op_array *op_array,
case ZEND_VERIFY_RETURN_TYPE:
if (t1 & MAY_BE_REF) {
tmp = t1;
+ ce = NULL;
} else {
zend_arg_info *ret_info = op_array->arg_info - 1;
@@ -3577,9 +3274,7 @@ int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script
int i, j;
uint32_t tmp;
- while (!zend_bitset_empty(worklist, zend_bitset_len(ssa_vars_count))) {
- j = zend_bitset_first(worklist, zend_bitset_len(ssa_vars_count));
- zend_bitset_excl(worklist, j);
+ WHILE_WORKLIST(worklist, zend_bitset_len(ssa_vars_count), j) {
if (ssa_vars[j].definition_phi) {
zend_ssa_phi *p = ssa_vars[j].definition_phi;
if (p->pi >= 0) {
@@ -3636,7 +3331,7 @@ int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script
i = ssa_vars[j].definition;
zend_update_type_info(op_array, ssa, script, worklist, i);
}
- }
+ } WHILE_WORKLIST_END();
return SUCCESS;
}
@@ -3862,18 +3557,14 @@ static int is_recursive_tail_call(const zend_op_array *op_array,
{
zend_func_info *info = ZEND_FUNC_INFO(op_array);
- if (info->ssa.ops && info->ssa.vars &&
+ if (info->ssa.ops && info->ssa.vars && info->call_map &&
info->ssa.ops[opline - op_array->opcodes].op1_use >= 0 &&
info->ssa.vars[info->ssa.ops[opline - op_array->opcodes].op1_use].definition >= 0) {
zend_op *op = op_array->opcodes + info->ssa.vars[info->ssa.ops[opline - op_array->opcodes].op1_use].definition;
if (op->opcode == ZEND_DO_UCALL) {
- zend_call_info *call_info = info->callee_info;
-
- while (call_info && call_info->caller_call_opline != op) {
- call_info = call_info->next_callee;
- }
+ zend_call_info *call_info = info->call_map[op - op_array->opcodes];
if (call_info && op_array == &call_info->callee_func->op_array) {
return 1;
}
@@ -4195,7 +3886,7 @@ void zend_inference_check_recursive_dependencies(zend_op_array *op_array)
zend_func_info *info = ZEND_FUNC_INFO(op_array);
zend_call_info *call_info;
zend_bitset worklist;
- int worklist_len;
+ int worklist_len, i;
ALLOCA_FLAG(use_heap);
if (!info->ssa.var_info || !(info->flags & ZEND_FUNC_RECURSIVE)) {
@@ -4212,14 +3903,12 @@ void zend_inference_check_recursive_dependencies(zend_op_array *op_array)
}
call_info = call_info->next_callee;
}
- while (!zend_bitset_empty(worklist, worklist_len)) {
- int i = zend_bitset_first(worklist, worklist_len);
- zend_bitset_excl(worklist, i);
+ WHILE_WORKLIST(worklist, worklist_len, i) {
if (!info->ssa.var_info[i].recursive) {
info->ssa.var_info[i].recursive = 1;
add_usages(op_array, &info->ssa, worklist, i);
}
- }
+ } WHILE_WORKLIST_END();
free_alloca(worklist, use_heap);
}
diff --git a/ext/opcache/Optimizer/zend_inference.h b/ext/opcache/Optimizer/zend_inference.h
index 4febc99cea..25b5cba4ca 100644
--- a/ext/opcache/Optimizer/zend_inference.h
+++ b/ext/opcache/Optimizer/zend_inference.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, e-SSA based Type & Range Inference |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index c88821e0e3..08ac084713 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -200,6 +200,11 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array,
case ZEND_SEND_VAR_NO_REF_EX:
zval_ptr_dtor(val);
return 0;
+ case ZEND_VERIFY_RETURN_TYPE:
+ /* This would require a non-local change.
+ * zend_optimizer_replace_by_const() supports this. */
+ zval_ptr_dtor(val);
+ return 0;
case ZEND_CONCAT:
case ZEND_FAST_CONCAT:
case ZEND_FETCH_R:
@@ -446,12 +451,27 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
break;
/* In most cases IS_TMP_VAR operand may be used only once.
* The operands are usually destroyed by the opcode handler.
- * ZEND_CASE is an exception, that keeps operand unchanged,
- * and allows its reuse. The number of ZEND_CASE instructions
+ * ZEND_CASE and ZEND_FETCH_LIST are exceptions, they keeps operand
+ * unchanged, and allows its reuse. these instructions
* usually terminated by ZEND_FREE that finally kills the value.
*/
- case ZEND_FREE:
- case ZEND_CASE: {
+ case ZEND_FETCH_LIST: {
+ zend_op *m = opline;
+ do {
+ if (m->opcode == ZEND_FETCH_LIST &&
+ ZEND_OP1_TYPE(m) == type &&
+ ZEND_OP1(m).var == var) {
+ zend_optimizer_update_op1_const(op_array, m, val);
+ }
+ m++;
+ } while (m->opcode != ZEND_FREE || ZEND_OP1_TYPE(m) != type || ZEND_OP1(m).var != var);
+ ZEND_ASSERT(m->opcode == ZEND_FREE && ZEND_OP1_TYPE(m) == type && ZEND_OP1(m).var == var);
+ MAKE_NOP(m);
+ zend_optimizer_remove_live_range(op_array, var);
+ return 1;
+ }
+ case ZEND_CASE:
+ case ZEND_FREE: {
zend_op *m, *n;
int brk = op_array->last_live_range;
zend_bool in_switch = 0;
@@ -501,7 +521,6 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
}
case ZEND_VERIFY_RETURN_TYPE: {
zend_arg_info *ret_info = op_array->arg_info - 1;
- ZEND_ASSERT((opline + 1)->opcode == ZEND_RETURN || (opline + 1)->opcode == ZEND_RETURN_BY_REF);
if (ret_info->class_name
|| ret_info->type_hint == IS_CALLABLE
|| !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(val))
@@ -510,7 +529,13 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
return 0;
}
MAKE_NOP(opline);
- opline++;
+
+ /* zend_handle_loops_and_finally may inserts other oplines */
+ do {
+ ++opline;
+ } while (opline->opcode != ZEND_RETURN && opline->opcode != ZEND_RETURN_BY_REF);
+ ZEND_ASSERT(ZEND_OP1(opline).var == var);
+
break;
}
default:
@@ -953,9 +978,10 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
}
for (i = 0; i < call_graph.op_arrays_count; i++) {
- if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
- func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
- if (func_info) {
+ func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
+ if (func_info) {
+ func_info->call_map = zend_build_call_map(&ctx.arena, func_info, call_graph.op_arrays[i]);
+ if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
zend_init_func_return_info(call_graph.op_arrays[i], script, &func_info->return_info);
}
}
diff --git a/ext/opcache/Optimizer/zend_optimizer.h b/ext/opcache/Optimizer/zend_optimizer.h
index 41896b0afe..69c89d7234 100644
--- a/ext/opcache/Optimizer/zend_optimizer.h
+++ b/ext/opcache/Optimizer/zend_optimizer.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h
index e2e9823c78..90297ad816 100644
--- a/ext/opcache/Optimizer/zend_optimizer_internal.h
+++ b/ext/opcache/Optimizer/zend_optimizer_internal.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c
index 80de03b698..c902e51766 100644
--- a/ext/opcache/Optimizer/zend_ssa.c
+++ b/ext/opcache/Optimizer/zend_ssa.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, SSA - Static Single Assignment Form |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -77,12 +77,12 @@ static zend_ssa_phi *add_pi(
}
phi = zend_arena_calloc(arena, 1,
- sizeof(zend_ssa_phi) +
- sizeof(int) * ssa->cfg.blocks[to].predecessors_count +
+ ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
+ ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->cfg.blocks[to].predecessors_count) +
sizeof(void*) * ssa->cfg.blocks[to].predecessors_count);
- phi->sources = (int*)(((char*)phi) + sizeof(zend_ssa_phi));
+ phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
memset(phi->sources, 0xff, sizeof(int) * ssa->cfg.blocks[to].predecessors_count);
- phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + sizeof(int) * ssa->cfg.blocks[to].predecessors_count);
+ phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->cfg.blocks[to].predecessors_count));
phi->pi = from;
phi->var = var;
@@ -947,13 +947,13 @@ int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_
if (!zend_bitset_empty(phi + j * set_size, set_size)) {
ZEND_BITSET_REVERSE_FOREACH(phi + j * set_size, set_size, i) {
zend_ssa_phi *phi = zend_arena_calloc(arena, 1,
- sizeof(zend_ssa_phi) +
- sizeof(int) * blocks[j].predecessors_count +
+ ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
+ ZEND_MM_ALIGNED_SIZE(sizeof(int) * blocks[j].predecessors_count) +
sizeof(void*) * blocks[j].predecessors_count);
- phi->sources = (int*)(((char*)phi) + sizeof(zend_ssa_phi));
+ phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
memset(phi->sources, 0xff, sizeof(int) * blocks[j].predecessors_count);
- phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + sizeof(int) * ssa->cfg.blocks[j].predecessors_count);
+ phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->cfg.blocks[j].predecessors_count));
phi->pi = -1;
phi->var = i;
diff --git a/ext/opcache/Optimizer/zend_ssa.h b/ext/opcache/Optimizer/zend_ssa.h
index 653a61fc10..5e03f8ba69 100644
--- a/ext/opcache/Optimizer/zend_ssa.h
+++ b/ext/opcache/Optimizer/zend_ssa.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine, SSA - Static Single Assignment Form |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/Optimizer/zend_worklist.h b/ext/opcache/Optimizer/zend_worklist.h
index a1db05482b..73c0bca854 100644
--- a/ext/opcache/Optimizer/zend_worklist.h
+++ b/ext/opcache/Optimizer/zend_worklist.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -77,10 +77,10 @@ typedef struct _zend_worklist {
} zend_worklist;
#define ZEND_WORKLIST_ALLOCA(w, _len, use_heap) do { \
- (w)->stack.buf = (int*)do_alloca(sizeof(int) * _len + sizeof(zend_ulong) * zend_bitset_len(_len), use_heap); \
+ (w)->stack.buf = (int*)do_alloca(ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len) + sizeof(zend_ulong) * zend_bitset_len(_len), use_heap); \
(w)->stack.len = 0; \
(w)->stack.capacity = _len; \
- (w)->visited = (zend_bitset)((w)->stack.buf + _len); \
+ (w)->visited = (zend_bitset)((char*)(w)->stack.buf + ZEND_MM_ALIGNED_SIZE(sizeof(int) * _len)); \
memset((w)->visited, 0, sizeof(zend_ulong) * zend_bitset_len(_len)); \
} while (0)
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 0a2304bbc9..d316fd83f4 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -118,6 +118,8 @@ static zend_string *(*accelerator_orig_zend_resolve_path)(const char *filename,
static void (*orig_chdir)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
+static void accel_gen_system_id(void);
+
#ifdef ZEND_WIN32
# define INCREMENT(v) InterlockedIncrement64(&ZCSG(v))
# define DECREMENT(v) InterlockedDecrement64(&ZCSG(v))
@@ -585,7 +587,7 @@ static void accel_use_shm_interned_strings(void)
for (j = 0; j < ce->constants_table.nNumUsed; j++) {
q = ce->constants_table.arData + j;
- if (!Z_TYPE(q->val) == IS_UNDEF) continue;
+ if (Z_TYPE(q->val) == IS_UNDEF) continue;
if (q->key) {
q->key = accel_new_interned_string(q->key);
}
@@ -595,7 +597,7 @@ static void accel_use_shm_interned_strings(void)
/* constant hash keys */
for (idx = 0; idx < EG(zend_constants)->nNumUsed; idx++) {
p = EG(zend_constants)->arData + idx;
- if (!Z_TYPE(p->val) == IS_UNDEF) continue;
+ if (Z_TYPE(p->val) == IS_UNDEF) continue;
if (p->key) {
p->key = accel_new_interned_string(p->key);
}
@@ -1777,10 +1779,10 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
file_handle->type == ZEND_HANDLE_FILENAME &&
UNEXPECTED(access(ZSTR_VAL(persistent_script->script.filename), R_OK) != 0)) {
if (type == ZEND_REQUIRE) {
- zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
+ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
zend_bailout();
} else {
- zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
+ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
}
return NULL;
}
@@ -2557,6 +2559,9 @@ static void accel_globals_ctor(zend_accel_globals *accel_globals)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
memset(accel_globals, 0, sizeof(zend_accel_globals));
+
+ /* TODO refactor to init this just once. */
+ accel_gen_system_id();
}
static void accel_globals_internal_func_dtor(zval *zv)
@@ -2941,11 +2946,18 @@ void accel_shutdown(void)
void zend_accel_schedule_restart(zend_accel_restart_reason reason)
{
+ const char *zend_accel_restart_reason_text[ACCEL_RESTART_USER + 1] = {
+ "out of memory",
+ "hash overflow",
+ "user",
+ };
+
if (ZCSG(restart_pending)) {
/* don't schedule twice */
return;
}
- zend_accel_error(ACCEL_LOG_DEBUG, "Restart Scheduled!");
+ zend_accel_error(ACCEL_LOG_DEBUG, "Restart Scheduled! Reason: %s",
+ zend_accel_restart_reason_text[reason]);
HANDLE_BLOCK_INTERRUPTIONS();
SHM_UNPROTECT();
@@ -3011,7 +3023,7 @@ ZEND_EXT_API zend_extension zend_extension_entry = {
PHP_VERSION, /* version */
"Zend Technologies", /* author */
"http://www.zend.com/", /* URL */
- "Copyright (c) 1999-2016", /* copyright */
+ "Copyright (c) 1999-2017", /* copyright */
accel_startup, /* startup */
NULL, /* shutdown */
accel_activate, /* per-script activation */
diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h
index aa357ecab2..c527911926 100644
--- a/ext/opcache/ZendAccelerator.h
+++ b/ext/opcache/ZendAccelerator.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c
index 2c3dc58125..24e40c2ae0 100644
--- a/ext/opcache/shared_alloc_mmap.c
+++ b/ext/opcache/shared_alloc_mmap.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/shared_alloc_posix.c b/ext/opcache/shared_alloc_posix.c
index 994f3ca609..94854f1c9d 100644
--- a/ext/opcache/shared_alloc_posix.c
+++ b/ext/opcache/shared_alloc_posix.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/shared_alloc_shm.c b/ext/opcache/shared_alloc_shm.c
index 6e23ded836..36b93b0fef 100644
--- a/ext/opcache/shared_alloc_shm.c
+++ b/ext/opcache/shared_alloc_shm.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/shared_alloc_win32.c b/ext/opcache/shared_alloc_win32.c
index cdfd90c14b..0cf65cf90a 100644
--- a/ext/opcache/shared_alloc_win32.c
+++ b/ext/opcache/shared_alloc_win32.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -102,6 +102,9 @@ static char *get_mmap_base_file(void)
}
GetTempPath(MAXPATHLEN, windir);
l = strlen(windir);
+ if ('\\' == windir[l-1]) {
+ l--;
+ }
snprintf(windir + l, sizeof(windir) - l - 1, "\\%s@%s@%.32s", ACCEL_FILEMAP_BASE, uname, ZCG(system_id));
free(uname);
diff --git a/ext/opcache/tests/blacklist-win32.phpt b/ext/opcache/tests/blacklist-win32.phpt
index 1e479b6c2e..fab0698f7f 100644
--- a/ext/opcache/tests/blacklist-win32.phpt
+++ b/ext/opcache/tests/blacklist-win32.phpt
@@ -18,7 +18,7 @@ $conf[4] = preg_replace("!^\\Q".dirname(__FILE__)."\\E!", "__DIR__", $conf[4]);
print_r($conf);
include("blacklist.inc");
$status = opcache_get_status();
-print_r(count($status['scripts']));
+print_r(count($status['scripts']) > 0);
?>
--EXPECTF--
Array
diff --git a/ext/opcache/tests/bug73583.phpt b/ext/opcache/tests/bug73583.phpt
new file mode 100644
index 0000000000..e947b451c9
--- /dev/null
+++ b/ext/opcache/tests/bug73583.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Bug #73583 (Segfaults when conditionally declared class and function have the same name)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=0x4ff
+opcache.file_update_protection=0
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+if (true) {
+ class A { }
+ function A() { }
+ function A() { }
+}
+?>
+--EXPECTF--
+Fatal error: Cannot redeclare A() (previously declared in %sbug73583.php:4) in %sbug73583.php on line 5
diff --git a/ext/opcache/tests/bug73654.phpt b/ext/opcache/tests/bug73654.phpt
new file mode 100644
index 0000000000..164e10829c
--- /dev/null
+++ b/ext/opcache/tests/bug73654.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Bug #73654: Segmentation fault in zend_call_function
+--FILE--
+<?php
+echo xyz();
+
+function x () : string {
+ return 'x';
+}
+
+function xyz() : string {
+ return x().'yz';
+}
+
+?>
+--EXPECT--
+xyz
diff --git a/ext/opcache/tests/bug73668.phpt b/ext/opcache/tests/bug73668.phpt
new file mode 100644
index 0000000000..aac5c9e65c
--- /dev/null
+++ b/ext/opcache/tests/bug73668.phpt
@@ -0,0 +1,8 @@
+--TEST--
+Bug #73668: "SIGFPE Arithmetic exception" in opcache when divide by minus 1
+--FILE--
+<?php
+$a/-1;
+?>
+--EXPECTF--
+Notice: Undefined variable: a in %s on line %d
diff --git a/ext/opcache/tests/bug73746.phpt b/ext/opcache/tests/bug73746.phpt
new file mode 100644
index 0000000000..c97833abcc
--- /dev/null
+++ b/ext/opcache/tests/bug73746.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Bug #73746 (Method that returns string returns UNKNOWN:0 instead)
+--FILE--
+<?php
+namespace Core\Bundle\Service\Property\Room\Rooms;
+
+class CountryMapping
+{
+ const CZ = 'CZ';
+ const EN = 'EN';
+
+ public function get(string $countryIsoCode = null) : string // Works correctly if return type is removed
+ {
+ switch (strtoupper($countryIsoCode)) {
+ case 'CZ':
+ case 'SK':
+ return self::CZ; // Works correctly if changed to CountryMapping::CZ
+ default:
+ return self::EN; // Works correctly if changed to CountryMapping::EN
+ }
+ }
+}
+
+$mapping = new CountryMapping();
+var_dump($mapping->get('CZ'));
+?>
+--EXPECT--
+string(2) "CZ"
diff --git a/ext/opcache/tests/bug73789.phpt b/ext/opcache/tests/bug73789.phpt
new file mode 100644
index 0000000000..142d5229f9
--- /dev/null
+++ b/ext/opcache/tests/bug73789.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Bug #73789 (Strange behavior of class constants in switch/case block)
+--FILE--
+<?php
+class Lexer
+{
+ const T_NONE = 1;
+ const T_STRING = 2;
+ const T_DOT = 8;
+ public function getType($value): int
+ {
+ $type = self::T_NONE;
+ switch (true) {
+ case ctype_alpha($value[0]):
+ $name = 'Lexer::T_' . strtoupper($value);
+ $type = constant($name);
+ if ($type > 100) {
+ return $type;
+ }
+ return self::T_STRING;
+ case $value === '.':
+ return self::T_DOT;
+ default:
+ }
+ return $type;
+ }
+}
+var_dump((new Lexer())->getType("dot"));
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/bug73847.phpt b/ext/opcache/tests/bug73847.phpt
new file mode 100644
index 0000000000..7010dfbfb7
--- /dev/null
+++ b/ext/opcache/tests/bug73847.phpt
@@ -0,0 +1,44 @@
+--TEST--
+Bug #73847: Recursion when a variable is redefined as array
+--FILE--
+<?php
+function test() {
+ $a = 42;
+ $a = array($a);
+ var_dump($a);
+
+ $a = 42;
+ $a = array($a => 24);
+ var_dump($a);
+
+ $a = 42;
+ $a = array($a, 24);
+ var_dump($a);
+
+ $a = 42;
+ $a = array(24, $a);
+ var_dump($a);
+}
+test();
+?>
+--EXPECT--
+array(1) {
+ [0]=>
+ int(42)
+}
+array(1) {
+ [42]=>
+ int(24)
+}
+array(2) {
+ [0]=>
+ int(42)
+ [1]=>
+ int(24)
+}
+array(2) {
+ [0]=>
+ int(24)
+ [1]=>
+ int(42)
+}
diff --git a/ext/opcache/tests/bug74019.phpt b/ext/opcache/tests/bug74019.phpt
new file mode 100644
index 0000000000..210e223c82
--- /dev/null
+++ b/ext/opcache/tests/bug74019.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #74019 (Segfault with list)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+
+class A {
+ public function seg() {
+ list($a, $b) = A::CONSTS;
+ var_dump($a, $b);
+ return;
+ }
+ const CONSTS = [1, 2];
+}
+
+$a = new A;
+$a->seg();
+?>
+--EXPECT--
+int(1)
+int(2)
diff --git a/ext/opcache/tests/bug74152.phpt b/ext/opcache/tests/bug74152.phpt
new file mode 100644
index 0000000000..f51c26b621
--- /dev/null
+++ b/ext/opcache/tests/bug74152.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #74152 (if statement says true to a null variable)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+
+$foo = 'foo';
+
+$bar = null;
+
+switch ($foo) {
+default:
+case 'foo':
+ if ($bar) {
+ echo 'true';
+ } else {
+ echo 'false';
+ }
+}
+?>
+--EXPECT--
+false
diff --git a/ext/opcache/tests/issue0115.phpt b/ext/opcache/tests/issue0115.phpt
index 0dfdd9f0eb..26d99080eb 100644
--- a/ext/opcache/tests/issue0115.phpt
+++ b/ext/opcache/tests/issue0115.phpt
@@ -16,28 +16,28 @@ require "phar://this/index.php";
__HALT_COMPILER(); ?>';
$p = new Phar(__DIR__ . '/issue0115_1.phar.php', 0, 'this');
$p['index.php'] = '<?php
-echo "Hello from Index 1.\n";
-require_once "phar://this/hello.php";
+ echo "Hello from Index 1.\n";
+ require_once "phar://this/hello.php";
';
-$p['hello.php'] = "Hello World 1!\n";
+$p['hello.php'] = "Hello World 1!\n";
$p->setStub($stub);
unset($p);
$p = new Phar(__DIR__ . '/issue0115_2.phar.php', 0, 'this');
$p['index.php'] = '<?php
-echo "Hello from Index 2.\n";
-require_once "phar://this/hello.php";
+ echo "Hello from Index 2.\n";
+ require_once "phar://this/hello.php";
';
-$p['hello.php'] = "Hello World 2!\n";
+$p['hello.php'] = "Hello World 2!\n";
$p->setStub($stub);
unset($p);
include "php_cli_server.inc";
-php_cli_server_start('-d opcache.enable=1 -d opcache.enable_cli=1');
+php_cli_server_start('-d opcache.enable=1 -d opcache.enable_cli=1 -d extension=phar.'.PHP_SHLIB_SUFFIX);
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/issue0115_1.phar.php');
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/issue0115_2.phar.php');
?>
--CLEAN--
-<?php
+<?php
@unlink(__DIR__ . '/issue0115_1.phar.php');
@unlink(__DIR__ . '/issue0115_2.phar.php');
?>
diff --git a/ext/opcache/tests/issue0149.phpt b/ext/opcache/tests/issue0149.phpt
index 8c7f1bb7e0..ba57623fce 100644
--- a/ext/opcache/tests/issue0149.phpt
+++ b/ext/opcache/tests/issue0149.phpt
@@ -20,13 +20,13 @@ $p->setStub($stub);
unset($p);
include "php_cli_server.inc";
-php_cli_server_start('-d opcache.enable=1 -d opcache.enable_cli=1');
+php_cli_server_start('-d opcache.enable=1 -d opcache.enable_cli=1 -d extension=phar.'.PHP_SHLIB_SUFFIX);
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/issue0149.phar.php');
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/issue0149.phar.php');
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/issue0149.phar.php');
?>
--CLEAN--
-<?php
+<?php
@unlink(__DIR__ . '/issue0149.phar.php');
?>
--EXPECT--
diff --git a/ext/opcache/tests/log_verbosity_bug.phpt b/ext/opcache/tests/log_verbosity_bug.phpt
index 725b8889f4..2e5d7a9add 100644
--- a/ext/opcache/tests/log_verbosity_bug.phpt
+++ b/ext/opcache/tests/log_verbosity_bug.phpt
@@ -7,6 +7,7 @@ The process should die regardless of the log_verbosity_level.
--INI--
opcache.enable=1
opcache.enable_cli=1
+opcache.file_cache_only=0
opcache.memory_consumption=999999999
opcache.log_verbosity_level=-1
--SKIPIF--
diff --git a/ext/opcache/tests/php_cli_server.inc b/ext/opcache/tests/php_cli_server.inc
index 0878bfafc0..456ed663b8 100644
--- a/ext/opcache/tests/php_cli_server.inc
+++ b/ext/opcache/tests/php_cli_server.inc
@@ -20,28 +20,51 @@ function php_cli_server_start($ini = "") {
$cmd = "exec {$php_executable} -t {$doc_root} $ini -S " . PHP_CLI_SERVER_ADDRESS . " 2>/dev/null";
$handle = proc_open($cmd, $descriptorspec, $pipes, $doc_root);
}
-
+
// note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.'
// it might not be listening yet...need to wait until fsockopen() call returns
- $i = 0;
- while (($i++ < 30) && !($fp = @fsockopen(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT))) {
- usleep(10000);
- }
+ $error = "Unable to connect to server\n";
+ for ($i=0; $i < 60; $i++) {
+ usleep(50000); // 50ms per try
+ $status = proc_get_status($handle);
+ $fp = @fsockopen(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT);
+ // Failure, the server is no longer running
+ if (!($status && $status['running'])) {
+ $error = "Server is not running\n";
+ break;
+ }
+ // Success, Connected to servers
+ if ($fp) {
+ $error = '';
+ break;
+ }
+ }
- if ($fp) {
- fclose($fp);
- }
+ if ($fp) {
+ fclose($fp);
+ }
+
+ if ($error) {
+ echo $error;
+ proc_terminate($handle);
+ exit(1);
+ }
register_shutdown_function(
function($handle) {
proc_terminate($handle);
+ /* Wait for server to shutdown */
+ for ($i = 0; $i < 60; $i++) {
+ $status = proc_get_status($handle);
+ if (!($status && $status['running'])) {
+ break;
+ }
+ usleep(50000);
+ }
},
- $handle
- );
- // don't bother sleeping, server is already up
- // server can take a variable amount of time to be up, so just sleeping a guessed amount of time
- // does not work. this is why tests sometimes pass and sometimes fail. to get a reliable pass
- // sleeping doesn't work.
+ $handle
+ );
+
}
?>
diff --git a/ext/opcache/tests/basic_logging.phpt b/ext/opcache/tests/zzz_basic_logging.phpt
similarity index 77%
rename from ext/opcache/tests/basic_logging.phpt
rename to ext/opcache/tests/zzz_basic_logging.phpt
index c62ea039a5..f0ecd6fbaa 100644
--- a/ext/opcache/tests/basic_logging.phpt
+++ b/ext/opcache/tests/zzz_basic_logging.phpt
@@ -7,13 +7,18 @@ outputs the correct logging at the highest log_verbosity_level
--INI--
opcache.enable=1
opcache.enable_cli=1
+opcache.file_cache_only=0
opcache.log_verbosity_level=4
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
<?php
echo "Foo Bar\n";
+opcache_reset();
+echo "Opcache reset";
?>
--EXPECTF--
%s Message Cached script '%sbasic_logging%s'
Foo Bar
+%s Debug Restart Scheduled! Reason: user
+Opcache reset
diff --git a/ext/opcache/zend_accelerator_blacklist.c b/ext/opcache/zend_accelerator_blacklist.c
index db61e1e9d3..bb4a5d22c8 100644
--- a/ext/opcache/zend_accelerator_blacklist.c
+++ b/ext/opcache/zend_accelerator_blacklist.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_accelerator_blacklist.h b/ext/opcache/zend_accelerator_blacklist.h
index 13197a661c..863f9ed165 100644
--- a/ext/opcache/zend_accelerator_blacklist.h
+++ b/ext/opcache/zend_accelerator_blacklist.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_accelerator_debug.c b/ext/opcache/zend_accelerator_debug.c
index 12f80ab79b..4932999b62 100644
--- a/ext/opcache/zend_accelerator_debug.c
+++ b/ext/opcache/zend_accelerator_debug.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_accelerator_debug.h b/ext/opcache/zend_accelerator_debug.h
index 4b8d82b4ac..6445254232 100644
--- a/ext/opcache/zend_accelerator_debug.h
+++ b/ext/opcache/zend_accelerator_debug.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_accelerator_hash.c b/ext/opcache/zend_accelerator_hash.c
index 7ec64cec1f..803dc6a25e 100644
--- a/ext/opcache/zend_accelerator_hash.c
+++ b/ext/opcache/zend_accelerator_hash.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_accelerator_hash.h b/ext/opcache/zend_accelerator_hash.h
index 3aa2451d1c..1c5b82280a 100644
--- a/ext/opcache/zend_accelerator_hash.h
+++ b/ext/opcache/zend_accelerator_hash.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c
index 6eace96398..bd83855e7d 100644
--- a/ext/opcache/zend_accelerator_module.c
+++ b/ext/opcache/zend_accelerator_module.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -107,8 +107,6 @@ static ZEND_INI_MH(OnUpdateMemoryConsumption)
#else
char *base = (char *) ts_resource(*((int *) mh_arg2));
#endif
- zend_long megabyte, overflow;
- double dummy;
/* keep the compiler happy */
(void)entry; (void)mh_arg2; (void)mh_arg3; (void)stage;
@@ -132,10 +130,10 @@ static ZEND_INI_MH(OnUpdateMemoryConsumption)
ini_entry->value = zend_string_init(new_new_value, 1, 1);
}
- megabyte = 1024 * 1024;
- ZEND_SIGNED_MULTIPLY_LONG(memsize, megabyte, *p, dummy, overflow);
- if (UNEXPECTED(overflow)) {
+ if (UNEXPECTED(memsize > ZEND_ULONG_MAX / (1024 * 1024))) {
*p = ZEND_ULONG_MAX;
+ } else {
+ *p = memsize * (1024 * 1024);
}
return SUCCESS;
}
@@ -287,9 +285,9 @@ ZEND_INI_BEGIN()
STD_PHP_INI_BOOLEAN("opcache.revalidate_path" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.revalidate_path , zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.log_verbosity_level" , "1" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.log_verbosity_level, zend_accel_globals, accel_globals)
- STD_PHP_INI_ENTRY("opcache.memory_consumption" , "64" , PHP_INI_SYSTEM, OnUpdateMemoryConsumption, accel_directives.memory_consumption, zend_accel_globals, accel_globals)
- STD_PHP_INI_ENTRY("opcache.interned_strings_buffer", "4" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.interned_strings_buffer, zend_accel_globals, accel_globals)
- STD_PHP_INI_ENTRY("opcache.max_accelerated_files" , "2000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles, accel_directives.max_accelerated_files, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.memory_consumption" , "128" , PHP_INI_SYSTEM, OnUpdateMemoryConsumption, accel_directives.memory_consumption, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.interned_strings_buffer", "8" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.interned_strings_buffer, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.max_accelerated_files" , "10000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles, accel_directives.max_accelerated_files, zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.max_wasted_percentage" , "5" , PHP_INI_SYSTEM, OnUpdateMaxWastedPercentage, accel_directives.max_wasted_percentage, zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.consistency_checks" , "0" , PHP_INI_ALL , OnUpdateLong, accel_directives.consistency_checks, zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.force_restart_timeout" , "180" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.force_restart_timeout, zend_accel_globals, accel_globals)
@@ -306,7 +304,7 @@ ZEND_INI_BEGIN()
STD_PHP_INI_ENTRY("opcache.optimization_level" , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level, zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.opt_debug_level" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.opt_debug_level, zend_accel_globals, accel_globals)
STD_PHP_INI_BOOLEAN("opcache.enable_file_override" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_override_enabled, zend_accel_globals, accel_globals)
- STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals)
+ STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.restrict_api" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.restrict_api, zend_accel_globals, accel_globals)
diff --git a/ext/opcache/zend_accelerator_module.h b/ext/opcache/zend_accelerator_module.h
index f519eba718..00321ceb67 100644
--- a/ext/opcache/zend_accelerator_module.h
+++ b/ext/opcache/zend_accelerator_module.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c
index 61c9c15d2b..3d845f389e 100644
--- a/ext/opcache/zend_accelerator_util_funcs.c
+++ b/ext/opcache/zend_accelerator_util_funcs.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_accelerator_util_funcs.h b/ext/opcache/zend_accelerator_util_funcs.h
index 4cfd77d4ed..ef5f0eb9e2 100644
--- a/ext/opcache/zend_accelerator_util_funcs.h
+++ b/ext/opcache/zend_accelerator_util_funcs.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c
index 6d34851352..dea427fcaf 100644
--- a/ext/opcache/zend_file_cache.c
+++ b/ext/opcache/zend_file_cache.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -359,6 +359,25 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra
zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_zval);
}
+ if (op_array->scope && !IS_SERIALIZED(op_array->opcodes)) {
+ if (UNEXPECTED(zend_shared_alloc_get_xlat_entry(op_array->opcodes))) {
+ op_array->refcount = (uint32_t*)(intptr_t)-1;
+ SERIALIZE_PTR(op_array->literals);
+ SERIALIZE_PTR(op_array->opcodes);
+ SERIALIZE_PTR(op_array->arg_info);
+ SERIALIZE_PTR(op_array->vars);
+ SERIALIZE_STR(op_array->function_name);
+ SERIALIZE_STR(op_array->filename);
+ SERIALIZE_PTR(op_array->live_range);
+ SERIALIZE_PTR(op_array->scope);
+ SERIALIZE_STR(op_array->doc_comment);
+ SERIALIZE_PTR(op_array->try_catch_array);
+ SERIALIZE_PTR(op_array->prototype);
+ return;
+ }
+ zend_shared_alloc_register_xlat_entry(op_array->opcodes, op_array->opcodes);
+ }
+
if (op_array->literals && !IS_SERIALIZED(op_array->literals)) {
zval *p, *end;
@@ -937,6 +956,22 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr
script, buf, zend_file_cache_unserialize_zval, ZVAL_PTR_DTOR);
}
+ if (op_array->refcount) {
+ op_array->refcount = NULL;
+ UNSERIALIZE_PTR(op_array->literals);
+ UNSERIALIZE_PTR(op_array->opcodes);
+ UNSERIALIZE_PTR(op_array->arg_info);
+ UNSERIALIZE_PTR(op_array->vars);
+ UNSERIALIZE_STR(op_array->function_name);
+ UNSERIALIZE_STR(op_array->filename);
+ UNSERIALIZE_PTR(op_array->live_range);
+ UNSERIALIZE_PTR(op_array->scope);
+ UNSERIALIZE_STR(op_array->doc_comment);
+ UNSERIALIZE_PTR(op_array->try_catch_array);
+ UNSERIALIZE_PTR(op_array->prototype);
+ return;
+ }
+
if (op_array->literals && !IS_UNSERIALIZED(op_array->literals)) {
zval *p, *end;
diff --git a/ext/opcache/zend_file_cache.h b/ext/opcache/zend_file_cache.h
index 69e8acd1d3..a47410dda4 100644
--- a/ext/opcache/zend_file_cache.h
+++ b/ext/opcache/zend_file_cache.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c
index 24a3d21ca2..9574e43d6f 100644
--- a/ext/opcache/zend_persist.c
+++ b/ext/opcache/zend_persist.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -33,6 +33,18 @@
#define zend_accel_memdup(p, size) \
_zend_shared_memdup((void*)p, size, 0)
+#ifdef HAVE_OPCACHE_FILE_CACHE
+#define zend_set_str_gc_flags(str) do { \
+ if (ZCG(accel_directives).file_cache_only) { \
+ GC_FLAGS(str) = IS_STR_INTERNED; \
+ } else { \
+ GC_FLAGS(str) = IS_STR_INTERNED | IS_STR_PERMANENT; \
+ } \
+} while (0)
+#else
+#define zend_set_str_gc_flags(str) GC_FLAGS(str) = IS_STR_INTERNED | IS_STR_PERMANENT
+#endif
+
#define zend_accel_store_string(str) do { \
zend_string *new_str = zend_shared_alloc_get_xlat_entry(str); \
if (new_str) { \
@@ -43,13 +55,13 @@
zend_string_release(str); \
str = new_str; \
zend_string_hash_val(str); \
- GC_FLAGS(str) = IS_STR_INTERNED | IS_STR_PERMANENT; \
+ zend_set_str_gc_flags(str); \
} \
} while (0)
#define zend_accel_memdup_string(str) do { \
str = zend_accel_memdup(str, _ZSTR_STRUCT_SIZE(ZSTR_LEN(str))); \
zend_string_hash_val(str); \
- GC_FLAGS(str) = IS_STR_INTERNED | IS_STR_PERMANENT; \
+ zend_set_str_gc_flags(str); \
} while (0)
#define zend_accel_store_interned_string(str) do { \
if (!IS_ACCEL_INTERNED(str)) { \
diff --git a/ext/opcache/zend_persist.h b/ext/opcache/zend_persist.h
index a03689ee44..cb98cee187 100644
--- a/ext/opcache/zend_persist.h
+++ b/ext/opcache/zend_persist.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c
index 84cd417204..d4f1e56c4f 100644
--- a/ext/opcache/zend_persist_calc.c
+++ b/ext/opcache/zend_persist_calc.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c
index 92e1ed7b1a..b7940ad39b 100644
--- a/ext/opcache/zend_shared_alloc.c
+++ b/ext/opcache/zend_shared_alloc.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
diff --git a/ext/opcache/zend_shared_alloc.h b/ext/opcache/zend_shared_alloc.h
index 03b82d16ac..55acefe664 100644
--- a/ext/opcache/zend_shared_alloc.h
+++ b/ext/opcache/zend_shared_alloc.h
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend OPcache |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 The PHP Group |
+ | Copyright (c) 1998-2017 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment