]> granicus.if.org Git - php/commitdiff
Drop FREE_ON_RETURN flag, check brk_cont->start instead
authorNikita Popov <nikic@php.net>
Fri, 22 May 2015 19:05:47 +0000 (21:05 +0200)
committerNikita Popov <nikic@php.net>
Sat, 23 May 2015 08:51:33 +0000 (10:51 +0200)
Start >= 0 already tells us whether or not the loop has a loop
variable, no need to add extra flags to opcodes.

Also added a test for a case where FREE_ON_RETURN is relevant,
we didn't seem to have any coverage for this.

Zend/tests/loop_free_on_return.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/loop_free_on_return.phpt b/Zend/tests/loop_free_on_return.phpt
new file mode 100644 (file)
index 0000000..525a509
--- /dev/null
@@ -0,0 +1,16 @@
+--TEST--
+Break out of while loop that is followed by a return statement and inside a foreach loop
+--FILE--
+<?php
+
+$a = [42];
+foreach ($a as $b) {
+    while (1) {
+        break 2;
+    }
+    return;
+}
+?>
+===DONE===
+--EXPECT--
+===DONE===
index 5647523f36c995186d948d5a1e8d349d6814080d..db1f30a233eda3c3f7cf81eaedc02790d7d55a74 100644 (file)
@@ -3448,17 +3448,7 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */
 
 static void zend_free_foreach_and_switch_variables(void) /* {{{ */
 {
-       uint32_t opnum_start, opnum_end, i;
-
-       opnum_start = get_next_op_number(CG(active_op_array));
-
        zend_stack_apply(&CG(loop_var_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_loop_var);
-
-       opnum_end = get_next_op_number(CG(active_op_array));
-
-       for (i = opnum_start; i < opnum_end; ++i) {
-               CG(active_op_array)->opcodes[i].extended_value |= EXT_TYPE_FREE_ON_RETURN;
-       }
 }
 /* }}} */
 
index e2a73997f840872331ff92fb8abfb399d1146ace..3c3569b9f09fcfc06449dddfe639dc10e8003d14 100644 (file)
@@ -874,8 +874,6 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name);
 
 #define ZEND_FETCH_ARG_MASK         0x000fffff
 
-#define EXT_TYPE_FREE_ON_RETURN                (1<<2)
-
 #define ZEND_MEMBER_FUNC_CALL  1<<0
 
 #define ZEND_ARG_SEND_BY_REF (1<<0)
index 1be3de41a2a77e6091b07ae1891cf7c3b9115c6b..da91b40106514fba8f170d814e6eff89396dc446 100644 (file)
@@ -1732,21 +1732,17 @@ static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_of
        do {
                ZEND_ASSERT(array_offset != -1);
                jmp_to = &op_array->brk_cont_array[array_offset];
-               if (nest_levels>1) {
+               if (nest_levels > 1 && jmp_to->start >= 0) {
                        zend_op *brk_opline = &op_array->opcodes[jmp_to->brk];
 
                        if (brk_opline->opcode == ZEND_FREE) {
-                               if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
-                                       zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
-                               }
+                               zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
                        } else if (brk_opline->opcode == ZEND_FE_FREE) {
-                               if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
-                                       zval *var = EX_VAR(brk_opline->op1.var);
-                                       if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
-                                               zend_hash_iterator_del(Z_FE_ITER_P(var));
-                                       }
-                                       zval_ptr_dtor_nogc(var);
+                               zval *var = EX_VAR(brk_opline->op1.var);
+                               if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
+                                       zend_hash_iterator_del(Z_FE_ITER_P(var));
                                }
+                               zval_ptr_dtor_nogc(var);
                        }
                }
                array_offset = jmp_to->parent;
index a1d308e44299ce069c53cbc08b4ff3e3def1f5de..d3e7dfece1ed4733475b5c56469248a1d2e62fec 100644 (file)
@@ -4840,7 +4840,6 @@ ZEND_VM_HANDLER(51, ZEND_CONT, ANY, CONST)
 
 ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
 {
-       zend_op *brk_opline;
        USE_OPLINE
        zend_brk_cont_element *el;
 
@@ -4848,14 +4847,12 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
        el = zend_brk_cont(Z_LVAL_P(EX_CONSTANT(opline->op2)), opline->extended_value,
                           &EX(func)->op_array, execute_data);
 
-       brk_opline = EX(func)->op_array.opcodes + el->brk;
+       if (el->start >= 0) {
+               zend_op *brk_opline = EX(func)->op_array.opcodes + el->brk;
 
-       if (brk_opline->opcode == ZEND_FREE) {
-               if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+               if (brk_opline->opcode == ZEND_FREE) {
                        zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
-               }
-       } else if (brk_opline->opcode == ZEND_FE_FREE) {
-               if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+               } else if (brk_opline->opcode == ZEND_FE_FREE) {
                        zval *var = EX_VAR(brk_opline->op1.var);
                        if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
                                zend_hash_iterator_del(Z_FE_ITER_P(var));
@@ -7264,17 +7261,13 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                                zend_op *brk_opline = &EX(func)->op_array.opcodes[EX(func)->op_array.brk_cont_array[i].brk];
 
                                if (brk_opline->opcode == ZEND_FREE) {
-                                       if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
-                                               zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
-                                       }
+                                       zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
                                } else if (brk_opline->opcode == ZEND_FE_FREE) {
-                                       if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
-                                               zval *var = EX_VAR(brk_opline->op1.var);
-                                               if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
-                                                       zend_hash_iterator_del(Z_FE_ITER_P(var));
-                                               }
-                                               zval_ptr_dtor_nogc(var);
+                                       zval *var = EX_VAR(brk_opline->op1.var);
+                                       if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
+                                               zend_hash_iterator_del(Z_FE_ITER_P(var));
                                        }
+                                       zval_ptr_dtor_nogc(var);
                                } else if (brk_opline->opcode == ZEND_END_SILENCE) {
                                        /* restore previous error_reporting value */
                                        if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) {
index 9da4546b78610af70d3324414a733818d4212764..2fa1079f27360c2f9266bc350baf69979b4fef28 100644 (file)
@@ -1615,17 +1615,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
                                zend_op *brk_opline = &EX(func)->op_array.opcodes[EX(func)->op_array.brk_cont_array[i].brk];
 
                                if (brk_opline->opcode == ZEND_FREE) {
-                                       if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
-                                               zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
-                                       }
+                                       zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
                                } else if (brk_opline->opcode == ZEND_FE_FREE) {
-                                       if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
-                                               zval *var = EX_VAR(brk_opline->op1.var);
-                                               if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
-                                                       zend_hash_iterator_del(Z_FE_ITER_P(var));
-                                               }
-                                               zval_ptr_dtor_nogc(var);
+                                       zval *var = EX_VAR(brk_opline->op1.var);
+                                       if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
+                                               zend_hash_iterator_del(Z_FE_ITER_P(var));
                                        }
+                                       zval_ptr_dtor_nogc(var);
                                } else if (brk_opline->opcode == ZEND_END_SILENCE) {
                                        /* restore previous error_reporting value */
                                        if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) {
@@ -2376,7 +2372,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CONT_SPEC_CONST_HANDLER(ZEND_O
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
-       zend_op *brk_opline;
        USE_OPLINE
        zend_brk_cont_element *el;
 
@@ -2384,14 +2379,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_O
        el = zend_brk_cont(Z_LVAL_P(EX_CONSTANT(opline->op2)), opline->extended_value,
                           &EX(func)->op_array, execute_data);
 
-       brk_opline = EX(func)->op_array.opcodes + el->brk;
+       if (el->start >= 0) {
+               zend_op *brk_opline = EX(func)->op_array.opcodes + el->brk;
 
-       if (brk_opline->opcode == ZEND_FREE) {
-               if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+               if (brk_opline->opcode == ZEND_FREE) {
                        zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
-               }
-       } else if (brk_opline->opcode == ZEND_FE_FREE) {
-               if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
+               } else if (brk_opline->opcode == ZEND_FE_FREE) {
                        zval *var = EX_VAR(brk_opline->op1.var);
                        if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
                                zend_hash_iterator_del(Z_FE_ITER_P(var));