From: Nikita Popov Date: Fri, 22 May 2015 20:17:40 +0000 (+0200) Subject: Use ZEND_JMP instead of ZEND_BRK/ZEND_CONT X-Git-Tag: PRE_PHP7_NSAPI_REMOVAL~36^2~8 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7a88d16cf318c877d56c71756da95b57249c134a;p=php Use ZEND_JMP instead of ZEND_BRK/ZEND_CONT Emit necessary FREEs during compilation, convert to JMP during pass_two (we may not know target opline beforehand). --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 2ea4451b09..3c23888aa9 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3557,6 +3557,7 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */ } else { int array_offset = CG(context).current_brk_cont; zend_long nest_level = depth; + znode *loop_var = zend_stack_top(&CG(loop_var_stack)); do { if (array_offset == -1) { @@ -3564,6 +3565,12 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */ ast->kind == ZEND_AST_BREAK ? "break" : "continue", depth, depth == 1 ? "" : "s"); } + + if (nest_level > 1 && CG(active_op_array)->brk_cont_array[array_offset].start >= 0) { + generate_free_loop_var(loop_var); + loop_var--; + } + array_offset = CG(active_op_array)->brk_cont_array[array_offset].parent; } while (--nest_level > 0); } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 933c75a706..7365d6a518 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -666,6 +666,20 @@ static void zend_resolve_finally_ret(zend_op_array *op_array, uint32_t op_num) } } +static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const zend_op *opline) { + int nest_levels = opline->op2.num; + int array_offset = opline->op1.num; + zend_brk_cont_element *jmp_to; + do { + jmp_to = &op_array->brk_cont_array[array_offset]; + if (nest_levels > 1) { + array_offset = jmp_to->parent; + } + } while (--nest_levels > 0); + + return opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont; +} + static void zend_resolve_finally_calls(zend_op_array *op_array) { uint32_t i, j; @@ -681,22 +695,8 @@ static void zend_resolve_finally_calls(zend_op_array *op_array) break; case ZEND_BRK: case ZEND_CONT: - { - int nest_levels = opline->op2.num; - int array_offset = opline->op1.num; - zend_brk_cont_element *jmp_to; - - if (array_offset != -1) { - do { - jmp_to = &op_array->brk_cont_array[array_offset]; - if (nest_levels > 1) { - array_offset = jmp_to->parent; - } - } while (--nest_levels > 0); - zend_resolve_finally_call(op_array, i, opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont); - break; - } - } + zend_resolve_finally_call(op_array, i, zend_get_brk_cont_target(op_array, opline)); + break; case ZEND_GOTO: if (Z_TYPE_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) != IS_LONG) { uint32_t num = opline->op2.constant; @@ -774,6 +774,16 @@ ZEND_API int pass_two(zend_op_array *op_array) case ZEND_DECLARE_INHERITED_CLASS_DELAYED: opline->extended_value = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->extended_value); break; + case ZEND_BRK: + case ZEND_CONT: + { + uint32_t jmp_target = zend_get_brk_cont_target(op_array, opline); + opline->opcode = ZEND_JMP; + opline->op1.opline_num = jmp_target; + opline->op2.num = 0; + ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1); + } + break; case ZEND_GOTO: if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op2)) != IS_LONG) { zend_resolve_goto_label(op_array, opline, 1);