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:
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
18
ext/opcache/tests/sccp_loop_var_free.phpt
Normal file
18
ext/opcache/tests/sccp_loop_var_free.phpt
Normal 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)
|
||||
Reference in New Issue
Block a user