]> granicus.if.org Git - php/commitdiff
Use ZEND_JMP instead of ZEND_BRK/ZEND_CONT
authorNikita Popov <nikic@php.net>
Fri, 22 May 2015 20:17:40 +0000 (22:17 +0200)
committerNikita Popov <nikic@php.net>
Sat, 23 May 2015 08:51:33 +0000 (10:51 +0200)
Emit necessary FREEs during compilation, convert to JMP during
pass_two (we may not know target opline beforehand).

Zend/zend_compile.c
Zend/zend_opcode.c

index 2ea4451b09b9411a4775f5ac2cdfd959fa80d13a..3c23888aa9c95027ec98373d1d276f36932af939 100644 (file)
@@ -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);
        }
index 933c75a706d445f0cf9be35eddf0981cd16cd6de..7365d6a518017169de1c5276b31d7470728df3e1 100644 (file)
@@ -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);