1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

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.
This commit is contained in:
Nikita Popov
2019-12-12 09:39:52 +01:00
parent 86aac3eed2
commit 2d03b638dc
5 changed files with 26 additions and 7 deletions

View File

@@ -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;

View File

@@ -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];

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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)