From: Nikita Popov Date: Fri, 22 May 2015 19:05:47 +0000 (+0200) Subject: Drop FREE_ON_RETURN flag, check brk_cont->start instead X-Git-Tag: PRE_PHP7_NSAPI_REMOVAL~36^2~11 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d0e265392fdb41d34984fa9794e4aad65e44d86b;p=php Drop FREE_ON_RETURN flag, check brk_cont->start instead 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. --- diff --git a/Zend/tests/loop_free_on_return.phpt b/Zend/tests/loop_free_on_return.phpt new file mode 100644 index 0000000000..525a50955a --- /dev/null +++ b/Zend/tests/loop_free_on_return.phpt @@ -0,0 +1,16 @@ +--TEST-- +Break out of while loop that is followed by a return statement and inside a foreach loop +--FILE-- + +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 5647523f36..db1f30a233 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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; - } } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index e2a73997f8..3c3569b9f0 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -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) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 1be3de41a2..da91b40106 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -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; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index a1d308e442..d3e7dfece1 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 9da4546b78..2fa1079f27 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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));