readd commit 3bb70fe2903acf2caf2600345f07943f34a3b23c
authorAnatol Belski <ab@php.net>
Tue, 21 Jul 2015 12:49:36 +0000 (05:49 -0700)
committerAnatol Belski <ab@php.net>
Tue, 21 Jul 2015 12:49:36 +0000 (05:49 -0700)
14 files changed:
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_opcodes.c
Zend/zend_vm_opcodes.h
ext/opcache/Optimizer/block_pass.c
ext/opcache/Optimizer/nop_removal.c
ext/opcache/Optimizer/pass1_5.c
ext/opcache/Optimizer/zend_optimizer.c
ext/opcache/zend_file_cache.c
ext/opcache/zend_persist.c
sapi/phpdbg/phpdbg_opcode.c

index 91175af6b391683c8d8024f1a50d7bbdc273666c..7377aa077d5885e191a144668efed0a76de58c53 100644 (file)
@@ -32,6 +32,7 @@
 #include "zend_multibyte.h"
 #include "zend_language_scanner.h"
 #include "zend_inheritance.h"
+#include "zend_vm.h"
 
 #define SET_NODE(target, src) do { \
                target ## _type = (src)->op_type; \
@@ -874,61 +875,6 @@ static void str_dtor(zval *zv)  /* {{{ */ {
 }
 /* }}} */
 
-void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2) /* {{{ */
-{
-       zend_label *dest;
-       int current, distance;
-       zval *label;
-
-       if (pass2) {
-               label = RT_CONSTANT(op_array, opline->op2);
-       } else {
-               label = CT_CONSTANT_EX(op_array, opline->op2.constant);
-       }
-       if (CG(context).labels == NULL ||
-           (dest = zend_hash_find_ptr(CG(context).labels, Z_STR_P(label))) == NULL) {
-
-               if (pass2) {
-                       CG(in_compilation) = 1;
-                       CG(active_op_array) = op_array;
-                       CG(zend_lineno) = opline->lineno;
-                       zend_error_noreturn(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label));
-               } else {
-                       /* Label is not defined. Delay to pass 2. */
-                       return;
-               }
-       }
-
-       opline->op1.opline_num = dest->opline_num;
-       zval_dtor(label);
-       ZVAL_NULL(label);
-
-       /* Check that we are not moving into loop or switch */
-       current = opline->extended_value;
-       for (distance = 0; current != dest->brk_cont; distance++) {
-               if (current == -1) {
-                       if (pass2) {
-                               CG(in_compilation) = 1;
-                               CG(active_op_array) = op_array;
-                               CG(zend_lineno) = opline->lineno;
-                       }
-                       zend_error_noreturn(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed");
-               }
-               current = op_array->brk_cont_array[current].parent;
-       }
-
-       if (distance == 0) {
-               /* Nothing to break out of, optimize to ZEND_JMP */
-               opline->opcode = ZEND_JMP;
-               opline->extended_value = 0;
-               SET_UNUSED(opline->op2);
-       } else {
-               /* Set real break distance */
-               ZVAL_LONG(label, distance);
-       }
-}
-/* }}} */
-
 static zend_bool zend_is_call(zend_ast *ast);
 
 static int generate_free_loop_var(znode *var) /* {{{ */
@@ -3764,16 +3710,125 @@ void zend_resolve_goto_label(zend_op_array *op_array, znode *label_node, zend_op
 }
 /* }}} */
 
+void zend_resolve_goto_label(zend_op_array *op_array, znode *label_node, zend_op *pass2_opline) /* {{{ */
+{
+       zend_label *dest;
+       int current, distance, free_vars;
+       zval *label;
+       znode *loop_var = NULL;
+
+       if (pass2_opline) {
+               label = RT_CONSTANT(op_array, pass2_opline->op2);
+       } else {
+               label = &label_node->u.constant;
+       }
+       if (CG(context).labels == NULL ||
+           (dest = zend_hash_find_ptr(CG(context).labels, Z_STR_P(label))) == NULL) {
+
+               if (pass2_opline) {
+                       CG(in_compilation) = 1;
+                       CG(active_op_array) = op_array;
+                       CG(zend_lineno) = pass2_opline->lineno;
+                       zend_error_noreturn(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label));
+               } else {
+                       /* Label is not defined. Delay to pass 2. */
+                       zend_op *opline;
+
+                       current = CG(context).current_brk_cont;
+                       while (current != -1) {
+                               if (op_array->brk_cont_array[current].start >= 0) {
+                                       zend_emit_op(NULL, ZEND_NOP, NULL, NULL);
+                               }
+                               current = op_array->brk_cont_array[current].parent;
+                       }
+                       opline = zend_emit_op(NULL, ZEND_GOTO, NULL, label_node);
+                       opline->extended_value = CG(context).current_brk_cont;
+                       return;
+               }
+       }
+
+       zval_dtor(label);
+       ZVAL_NULL(label);
+
+       /* Check that we are not moving into loop or switch */
+       if (pass2_opline) {
+               current = pass2_opline->extended_value;
+       } else {
+               current = CG(context).current_brk_cont;
+       }
+       if (!pass2_opline) {
+               loop_var = zend_stack_top(&CG(loop_var_stack));
+       }
+       for (distance = 0, free_vars = 0; current != dest->brk_cont; distance++) {
+               if (current == -1) {
+                       if (pass2_opline) {
+                               CG(in_compilation) = 1;
+                               CG(active_op_array) = op_array;
+                               CG(zend_lineno) = pass2_opline->lineno;
+                       }
+                       zend_error_noreturn(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed");
+               }
+               if (op_array->brk_cont_array[current].start >= 0) {
+                       if (pass2_opline) {
+                               free_vars++;
+                       } else {
+                               generate_free_loop_var(loop_var);
+                               loop_var--;
+                       }
+               }
+               current = op_array->brk_cont_array[current].parent;
+       }
+
+       if (pass2_opline) {
+               if (free_vars) {
+                       current = pass2_opline->extended_value;
+                       while (current != dest->brk_cont) {
+                               if (op_array->brk_cont_array[current].start >= 0) {
+                                       zend_op *brk_opline = &op_array->opcodes[op_array->brk_cont_array[current].brk];
+
+                                       if (brk_opline->opcode == ZEND_FREE) {
+                                               (pass2_opline - free_vars)->opcode = ZEND_FREE;
+                                               (pass2_opline - free_vars)->op1_type = brk_opline->op1_type;
+                                               if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
+                                                       (pass2_opline - free_vars)->op1.var = brk_opline->op1.var;
+                                               } else {
+                                                       (pass2_opline - free_vars)->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + brk_opline->op1.var);
+                                                       ZEND_VM_SET_OPCODE_HANDLER(pass2_opline - free_vars);
+                                               }
+                                               free_vars--;
+                                       } else if (brk_opline->opcode == ZEND_FE_FREE) {
+                                               (pass2_opline - free_vars)->opcode = ZEND_FE_FREE;
+                                               (pass2_opline - free_vars)->op1_type = brk_opline->op1_type;
+                                               if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
+                                                       (pass2_opline - free_vars)->op1.var = brk_opline->op1.var;
+                                               } else {
+                                                       (pass2_opline - free_vars)->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + brk_opline->op1.var);
+                                                       ZEND_VM_SET_OPCODE_HANDLER(pass2_opline - free_vars);
+                                               }
+                                               free_vars--;
+                                       }
+                               }
+                               current = op_array->brk_cont_array[current].parent;
+                       }
+               }
+               pass2_opline->opcode = ZEND_JMP;
+               pass2_opline->op1.opline_num = dest->opline_num;
+               SET_UNUSED(pass2_opline->op2);
+               pass2_opline->extended_value = 0;
+       } else {
+               zend_op *opline = zend_emit_op(NULL, ZEND_JMP, NULL, NULL);
+               opline->op1.opline_num = dest->opline_num;
+       }
+}
+/* }}} */
+
 void zend_compile_goto(zend_ast *ast) /* {{{ */
 {
        zend_ast *label_ast = ast->child[0];
        znode label_node;
-       zend_op *opline;
 
        zend_compile_expr(&label_node, label_ast);
-       opline = zend_emit_op(NULL, ZEND_GOTO, NULL, &label_node);
-       opline->extended_value = CG(context).current_brk_cont;
-       zend_resolve_goto_label(CG(active_op_array), opline, 0);
+       zend_resolve_goto_label(CG(active_op_array), &label_node, NULL);
 }
 /* }}} */
 
index 74a72f5c84507b4fd10ef82d10adf484687dd8c5..a5e5ddece5862dd9783bba9e2c9a018e919e0e50 100644 (file)
@@ -712,7 +712,7 @@ void zend_do_extended_fcall_end(void);
 
 void zend_verify_namespace(void);
 
-void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2);
+void zend_resolve_goto_label(zend_op_array *op_array, znode *label_node, zend_op *pass2_opline);
 
 ZEND_API void function_add_ref(zend_function *function);
 
index a971a5e90047da8fff99973aff571e4cb6f78c5a..62b58b4e57b0bd4baa0c944bbd06f7c95aa36b89 100644 (file)
@@ -700,11 +700,8 @@ static void zend_resolve_finally_calls(zend_op_array *op_array)
                                break;
                        case ZEND_GOTO:
                                if (Z_TYPE_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) != IS_LONG) {
-                                       uint32_t num = opline->op2.constant;
-
                                        ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
-                                       zend_resolve_goto_label(op_array, opline, 1);
-                                       opline->op2.constant = num;
+                                       zend_resolve_goto_label(op_array, NULL, opline);
                                }
                                /* break omitted intentionally */
                        case ZEND_JMP:
@@ -787,7 +784,7 @@ ZEND_API int pass_two(zend_op_array *op_array)
                                break;
                        case ZEND_GOTO:
                                if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op2)) != IS_LONG) {
-                                       zend_resolve_goto_label(op_array, opline, 1);
+                                       zend_resolve_goto_label(op_array, NULL, opline);
                                }
                                /* break omitted intentionally */
                        case ZEND_JMP:
index 3000e5ddfe51716d4845c95b4fe38d070593ab8a..8a6cd782feb1b18343e2f70ad7833c27bf1c1eb3 100644 (file)
@@ -4788,31 +4788,6 @@ ZEND_VM_HANDLER(52, ZEND_BOOL, CONST|TMPVAR|CV, ANY)
        ZEND_VM_NEXT_OPCODE();
 }
 
-ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
-{
-       USE_OPLINE
-       zend_brk_cont_element *el;
-
-       SAVE_OPLINE();
-       el = zend_brk_cont(Z_LVAL_P(EX_CONSTANT(opline->op2)), opline->extended_value,
-                          &EX(func)->op_array, execute_data);
-
-       if (el->start >= 0) {
-               zend_op *brk_opline = EX(func)->op_array.opcodes + el->brk;
-
-               if (brk_opline->opcode == ZEND_FREE) {
-                       zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
-               } 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));
-                       }
-                       zval_ptr_dtor_nogc(var);
-               }
-       }
-       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op1));
-}
-
 ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
 {
        USE_OPLINE
index 130c2cf5ab0a7486ba88a26245cb8a497b5c77e6..2be1016018d751ffdb39240ae1375944f0e75801 100644 (file)
@@ -2228,31 +2228,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(Z
        ZEND_VM_NEXT_OPCODE();
 }
 
-static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
-{
-       USE_OPLINE
-       zend_brk_cont_element *el;
-
-       SAVE_OPLINE();
-       el = zend_brk_cont(Z_LVAL_P(EX_CONSTANT(opline->op2)), opline->extended_value,
-                          &EX(func)->op_array, execute_data);
-
-       if (el->start >= 0) {
-               zend_op *brk_opline = EX(func)->op_array.opcodes + el->brk;
-
-               if (brk_opline->opcode == ZEND_FREE) {
-                       zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
-               } 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));
-                       }
-                       zval_ptr_dtor_nogc(var);
-               }
-       }
-       ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op1));
-}
-
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_INTERFACE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -47688,27 +47663,27 @@ void zend_init_opcodes_handlers(void)
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
-       ZEND_GOTO_SPEC_CONST_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
-       ZEND_GOTO_SPEC_CONST_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
-       ZEND_GOTO_SPEC_CONST_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
-       ZEND_GOTO_SPEC_CONST_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
-       ZEND_GOTO_SPEC_CONST_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
        ZEND_NULL_HANDLER,
index 705ab9cd29c8fc8527b0f7690321beae0e17e662..1f26f0439e42d2a90cb83919b9663b96acfc889b 100644 (file)
@@ -122,7 +122,7 @@ const char *zend_vm_opcodes_map[173] = {
        "ZEND_FETCH_OBJ_UNSET",
        "ZEND_FETCH_LIST",
        "ZEND_FETCH_CONSTANT",
-       "ZEND_GOTO",
+       NULL,
        "ZEND_EXT_STMT",
        "ZEND_EXT_FCALL_BEGIN",
        "ZEND_EXT_FCALL_END",
index f6de5b1b577ea293d0ff52d688e4d9fc6e018d1f..bb2d7717bdc179b1195bf5ec099713f290c679c0 100644 (file)
@@ -130,7 +130,6 @@ END_EXTERN_C()
 #define ZEND_FETCH_OBJ_UNSET                  97
 #define ZEND_FETCH_LIST                       98
 #define ZEND_FETCH_CONSTANT                   99
-#define ZEND_GOTO                            100
 #define ZEND_EXT_STMT                        101
 #define ZEND_EXT_FCALL_BEGIN                 102
 #define ZEND_EXT_FCALL_END                   103
index e1e07ea01b69a4d4908e4294caa643c048f738a6..8b29d21f7968c96f7e6661c65f10fab1c5ce730b 100644 (file)
@@ -123,10 +123,6 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
        blocks[0].start_opline_no = 0;
        while (opline < end) {
                switch((unsigned)opline->opcode) {
-                       case ZEND_GOTO:
-                               /* would not optimize GOTOs - we cannot really know where it jumps,
-                                * so these optimizations are too dangerous */
-                               return 0;
                        case ZEND_FAST_CALL:
                                START_BLOCK_OP(ZEND_OP1(opline).opline_num);
                                if (opline->extended_value) {
index 20510b416352da3a46479a1beac362348934a156..0869bc715c695122e1989b66118cdf245d394c67 100644 (file)
@@ -44,14 +44,6 @@ void zend_optimizer_nop_removal(zend_op_array *op_array)
        end = op_array->opcodes + op_array->last;
        for (opline = op_array->opcodes; opline < end; opline++) {
 
-               /* GOTO target is unresolved yet. We can't optimize. */
-               if (opline->opcode == ZEND_GOTO &&
-                       Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
-                       /* TODO: in general we can avoid this restriction */
-                       FREE_ALLOCA(shiftlist);
-                       return;
-               }
-
                /* Kill JMP-over-NOP-s */
                if (opline->opcode == ZEND_JMP && ZEND_OP1(opline).opline_num > i) {
                        /* check if there are only NOPs under the branch */
@@ -85,7 +77,6 @@ void zend_optimizer_nop_removal(zend_op_array *op_array)
                for (opline = op_array->opcodes; opline<end; opline++) {
                        switch (opline->opcode) {
                                case ZEND_JMP:
-                               case ZEND_GOTO:
                                case ZEND_FAST_CALL:
                                case ZEND_DECLARE_ANON_CLASS:
                                case ZEND_DECLARE_ANON_INHERITED_CLASS:
index 6fcdc3e47a6aad21348bd06430d63d0df5467370..766eb2c2d4bc7f973d76a8ae2e89e3946627c6ec 100644 (file)
@@ -624,7 +624,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
                case ZEND_EXIT:
                case ZEND_THROW:
                case ZEND_CATCH:
-               case ZEND_GOTO:
                case ZEND_FAST_CALL:
                case ZEND_FAST_RET:
                case ZEND_JMP:
index dc69d2511ec2e4a0cd5667350721e7bec52cf06f..9437a22ed0af8423673ed41b534ef0431ac91304 100644 (file)
@@ -494,7 +494,6 @@ static void zend_accel_optimize(zend_op_array      *op_array,
                }
                switch (opline->opcode) {
                        case ZEND_JMP:
-                       case ZEND_GOTO:
                        case ZEND_FAST_CALL:
                        case ZEND_DECLARE_ANON_CLASS:
                        case ZEND_DECLARE_ANON_INHERITED_CLASS:
@@ -539,7 +538,6 @@ static void zend_accel_optimize(zend_op_array      *op_array,
                }
                switch (opline->opcode) {
                        case ZEND_JMP:
-                       case ZEND_GOTO:
                        case ZEND_FAST_CALL:
                        case ZEND_DECLARE_ANON_CLASS:
                        case ZEND_DECLARE_ANON_INHERITED_CLASS:
index c3ee95960a66b665aa333ea440fe2671dbc724ca..a2a5343deba6a11c15137c799b6223734682138d 100644 (file)
@@ -386,7 +386,6 @@ static void zend_file_cache_serialize_op_array(zend_op_array            *op_arra
 # if ZEND_USE_ABS_JMP_ADDR
                        switch (opline->opcode) {
                                case ZEND_JMP:
-                               case ZEND_GOTO:
                                case ZEND_FAST_CALL:
                                case ZEND_DECLARE_ANON_CLASS:
                                case ZEND_DECLARE_ANON_INHERITED_CLASS:
@@ -938,7 +937,6 @@ static void zend_file_cache_unserialize_op_array(zend_op_array           *op_arr
 # if ZEND_USE_ABS_JMP_ADDR
                        switch (opline->opcode) {
                                case ZEND_JMP:
-                               case ZEND_GOTO:
                                case ZEND_FAST_CALL:
                                case ZEND_DECLARE_ANON_CLASS:
                                case ZEND_DECLARE_ANON_INHERITED_CLASS:
index bbcb20713b0f18e1bf2eafcef23e724af2b900b5..243d99e2557882baeb30ade9c96cacb878cff077 100644 (file)
@@ -501,7 +501,6 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                                /* fix jumps to point to new array */
                                switch (opline->opcode) {
                                        case ZEND_JMP:
-                                       case ZEND_GOTO:
                                        case ZEND_FAST_CALL:
                                        case ZEND_DECLARE_ANON_CLASS:
                                        case ZEND_DECLARE_ANON_INHERITED_CLASS:
index 128dc591cfdcbe0314f9f956b05972c5cb3ab03d..75c91e0cf555f72f025b1b39640b9b11f4e5d56d 100644 (file)
@@ -84,7 +84,6 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op) /*{{{ */
        /* OP1 */
        switch (op->opcode) {
        case ZEND_JMP:
-       case ZEND_GOTO:
        case ZEND_FAST_CALL:
                spprintf(&decode[1], 0, "J%td", OP_JMP_ADDR(op, op->op1) - ops->opcodes);
                break;