diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-12-12 09:39:52 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-12-12 09:39:52 +0100 |
commit | 2d03b638dcde1d41d8a35b13e2fb6ca64c745f16 (patch) | |
tree | 62f8b04b4cbfda07d06ca497eb168c8440968280 | |
parent | 86aac3eed24ddc8ace3661ea1c3b50aa3d45f883 (diff) | |
download | php-git-2d03b638dcde1d41d8a35b13e2fb6ca64c745f16.tar.gz |
Fix handling of non-final loop var free in sccp
We only need to preserve the FE_FREE that marks the end of the
loop range. Skip FE_FREEs with the FREE_ON_RETURN flag.
-rw-r--r-- | ext/opcache/Optimizer/scdf.c | 3 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_cfg.c | 4 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer.c | 3 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer_internal.h | 5 | ||||
-rw-r--r-- | ext/opcache/tests/sccp_loop_var_free.phpt | 18 |
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 a922d0f597..0b4181c051 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -918,8 +918,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 9ab18f6398..df7be73d4f 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) |