summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-12-12 09:40:54 +0100
committerNikita Popov <nikita.ppv@gmail.com>2019-12-12 09:40:54 +0100
commitcf9362195bdd790f5da1f5d37b336f900fdb022b (patch)
treeac9a7dc4b659e0b8958ce0966e7f659b0276d1e1
parent1695d3ed07018cd711a70582165dd8c1b765a66b (diff)
parent2d03b638dcde1d41d8a35b13e2fb6ca64c745f16 (diff)
downloadphp-git-cf9362195bdd790f5da1f5d37b336f900fdb022b.tar.gz
Merge branch 'PHP-7.4'
* PHP-7.4: Fix handling of non-final loop var free in sccp
-rw-r--r--ext/opcache/Optimizer/scdf.c3
-rw-r--r--ext/opcache/Optimizer/zend_cfg.c4
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c3
-rw-r--r--ext/opcache/Optimizer/zend_optimizer_internal.h5
-rw-r--r--ext/opcache/tests/sccp_loop_var_free.phpt18
5 files changed, 26 insertions, 7 deletions
diff --git a/ext/opcache/Optimizer/scdf.c b/ext/opcache/Optimizer/scdf.c
index 1c7cbc7e55..aa7ea3a1a2 100644
--- a/ext/opcache/Optimizer/scdf.c
+++ b/ext/opcache/Optimizer/scdf.c
@@ -195,8 +195,7 @@ static zend_bool kept_alive_by_loop_var_free(scdf_ctx *scdf, uint32_t block_idx)
}
for (i = block->start; i < block->start + block->len; i++) {
zend_op *opline = &op_array->opcodes[i];
- if (opline->opcode == ZEND_FE_FREE ||
- (opline->opcode == ZEND_FREE && opline->extended_value == ZEND_FREE_SWITCH)) {
+ if (zend_optimizer_is_loop_var_free(opline)) {
int ssa_var = scdf->ssa->ops[i].op1_use;
if (ssa_var >= 0) {
int op_num = scdf->ssa->vars[ssa_var].definition;
diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c
index 5e0f137024..66c15be311 100644
--- a/ext/opcache/Optimizer/zend_cfg.c
+++ b/ext/opcache/Optimizer/zend_cfg.c
@@ -208,9 +208,7 @@ static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg *
for (j = b->start; j < b->start + b->len; j++) {
zend_op *opline = &op_array->opcodes[j];
- if (opline->opcode == ZEND_FE_FREE ||
- (opline->opcode == ZEND_FREE && opline->extended_value == ZEND_FREE_SWITCH)
- ) {
+ if (zend_optimizer_is_loop_var_free(opline)) {
zend_op *def_opline = zend_optimizer_get_loop_var_def(op_array, opline);
if (def_opline) {
uint32_t def_block = block_map[def_opline - op_array->opcodes];
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index 08879734a8..84d4c61831 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -904,8 +904,7 @@ uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args)
zend_op *zend_optimizer_get_loop_var_def(const zend_op_array *op_array, zend_op *free_opline) {
uint32_t var = free_opline->op1.var;
- ZEND_ASSERT(free_opline->opcode == ZEND_FE_FREE ||
- (free_opline->opcode == ZEND_FREE && free_opline->extended_value == ZEND_FREE_SWITCH));
+ ZEND_ASSERT(zend_optimizer_is_loop_var_free(free_opline));
while (--free_opline >= op_array->opcodes) {
if ((free_opline->result_type & (IS_TMP_VAR|IS_VAR)) && free_opline->result.var == var) {
diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h
index 43ac1ea07f..270a85c89a 100644
--- a/ext/opcache/Optimizer/zend_optimizer_internal.h
+++ b/ext/opcache/Optimizer/zend_optimizer_internal.h
@@ -71,6 +71,11 @@ typedef struct _zend_optimizer_ctx {
target = src; \
} while (0)
+static inline zend_bool zend_optimizer_is_loop_var_free(const zend_op *opline) {
+ return (opline->opcode == ZEND_FE_FREE && opline->extended_value != ZEND_FREE_ON_RETURN)
+ || (opline->opcode == ZEND_FREE && opline->extended_value == ZEND_FREE_SWITCH);
+}
+
int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv);
int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy);
void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval* value);
diff --git a/ext/opcache/tests/sccp_loop_var_free.phpt b/ext/opcache/tests/sccp_loop_var_free.phpt
new file mode 100644
index 0000000000..5166823b0b
--- /dev/null
+++ b/ext/opcache/tests/sccp_loop_var_free.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Check that SCCP correctly handles non-terminating frees of loop variables
+--FILE--
+<?php
+function test() {
+ $arr = [];
+ foreach ($arr as $item) {
+ if (!empty($result)) {
+ return $result;
+ }
+ }
+ return 2;
+}
+
+var_dump(test());
+?>
+--EXPECT--
+int(2)