]> granicus.if.org Git - php/commitdiff
Improved "finally" im[plementation
authorDmitry Stogov <dmitry@zend.com>
Thu, 22 Nov 2012 11:17:05 +0000 (15:17 +0400)
committerDmitry Stogov <dmitry@zend.com>
Thu, 22 Nov 2012 11:17:05 +0000 (15:17 +0400)
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_generators.c
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_execute.skl
Zend/zend_vm_opcodes.h

index c9714e5a0d26d8399028e20f5b0ff6ef4f6fc566..de77068db55fe99d4f7a6b278fc75840af721ae4 100644 (file)
@@ -2709,6 +2709,7 @@ static int zend_add_try_element(zend_uint try_op TSRMLS_DC) /* {{{ */
 
        CG(active_op_array)->try_catch_array = erealloc(CG(active_op_array)->try_catch_array, sizeof(zend_try_catch_element)*CG(active_op_array)->last_try_catch);
        CG(active_op_array)->try_catch_array[try_catch_offset].try_op = try_op;
+       CG(active_op_array)->try_catch_array[try_catch_offset].catch_op = 0;
        CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = 0;
        CG(active_op_array)->try_catch_array[try_catch_offset].finally_end = 0;
        return try_catch_offset;
@@ -2770,9 +2771,25 @@ void zend_do_try(znode *try_token TSRMLS_DC) /* {{{ */
 }
 /* }}} */
 
-void zend_do_finally(znode *finally_token TSRMLS_DC) /* {{{ */ {
+void zend_do_finally(znode *finally_token TSRMLS_DC) /* {{{ */
+{
+       zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+
        finally_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
-} /* }}} */
+       /* call the the "finally" block */
+       opline->opcode = ZEND_FAST_CALL;
+       SET_UNUSED(opline->op1);
+       opline->op1.opline_num = finally_token->u.op.opline_num + 1;
+       SET_UNUSED(opline->op2);
+       /* jump to code after the "finally" block,
+        * the actual jump address is going to be set in zend_do_end_finally()
+        */
+       opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+       opline->opcode = ZEND_JMP;
+       SET_UNUSED(opline->op1);
+       SET_UNUSED(opline->op2);
+}
+/* }}} */
 
 void zend_do_begin_catch(znode *catch_token, znode *class_name, znode *catch_var, znode *first_catch TSRMLS_DC) /* {{{ */
 {
@@ -2837,18 +2854,19 @@ void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_to
                zend_error(E_COMPILE_ERROR, "Cannot use try without catch or finally");
        } 
        if (finally_token->op_type != IS_UNUSED) {
-               zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
-               CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_op = finally_token->u.op.opline_num;
+               zend_op *opline;
+               
+               CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_op = finally_token->u.op.opline_num + 1;
                CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_end = get_next_op_number(CG(active_op_array));
                CG(active_op_array)->has_finally_block = 1;
 
-               opline->opcode = ZEND_LEAVE;
+               opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+               opline->opcode = ZEND_FAST_RET;
                SET_UNUSED(opline->op1);
                SET_UNUSED(opline->op2);
+               
+               CG(active_op_array)->opcodes[finally_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array));
        } 
-       if (catch_token->op_type == IS_UNUSED) {
-               CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].catch_op = 0;
-       }
 }
 /* }}} */
 
index 77809dae5aaadbffae9cc6e571116ff97bbcfdeb..e46c1a39ce764c048a7d45550a5e06bad91563bc 100644 (file)
@@ -387,8 +387,7 @@ struct _zend_execute_data {
        zend_class_entry *current_called_scope;
        zval *current_this;
        zval *current_object;
-       zend_uint leaving;
-       zend_uint leaving_dest;
+       struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
 };
 
 #define EX(element) execute_data.element
@@ -826,6 +825,9 @@ int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC);
 #define ZEND_RETURNS_FUNCTION 1<<0
 #define ZEND_RETURNS_NEW      1<<1
 
+#define ZEND_FAST_RET_TO_CATCH         1
+#define ZEND_FAST_RET_TO_FINALLY       2
+
 END_EXTERN_C()
 
 #define ZEND_CLONE_FUNC_NAME           "__clone"
index 87f0644e81e5fd0daf319f06265b6826d9881e6e..516ff0b6ebb194d1599fad5c3c3a43dd9af1010f 100644 (file)
@@ -60,7 +60,6 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
                                 * the resume. */
                                if (finally_op_num) {
                                        execute_data->opline = &op_array->opcodes[finally_op_num];
-                                       execute_data->leaving = ZEND_RETURN;
                                        generator->flags |= ZEND_GENERATOR_FORCED_CLOSE;
                                        zend_generator_resume(generator TSRMLS_CC);
                                        return;
index 224c7a209bb64b4d3c1292be2c2a2436b2f4a4b8..563c84301daa1462cc8ffe61cafc1f9b51dd48d7 100644 (file)
@@ -499,24 +499,168 @@ static void zend_extension_op_array_handler(zend_extension *extension, zend_op_a
        }
 }
 
-static void zend_check_finally_breakout(zend_op_array *op_array, zend_op *opline, zend_uint dst_num TSRMLS_DC) {
-       zend_uint i, op_num = opline - op_array->opcodes;
-       for (i=0; i < op_array->last_try_catch; i++) {
+static void zend_check_finally_breakout(zend_op_array *op_array, zend_uint op_num, zend_uint dst_num TSRMLS_DC)
+{
+       zend_uint i;
+
+       for (i = 0; i < op_array->last_try_catch; i++) {
                if (op_array->try_catch_array[i].try_op > op_num) {
                        break;
                }
                if ((op_num >= op_array->try_catch_array[i].finally_op 
-                                       && op_num < op_array->try_catch_array[i].finally_end)
-                               && (dst_num >= op_array->try_catch_array[i].finally_end 
+                                       && op_num <= op_array->try_catch_array[i].finally_end)
+                               && (dst_num > op_array->try_catch_array[i].finally_end 
                                        || dst_num < op_array->try_catch_array[i].finally_op)) {
                        CG(in_compilation) = 1;
                        CG(active_op_array) = op_array;
-                       CG(zend_lineno) = opline->lineno;
+                       CG(zend_lineno) = op_array->opcodes[op_num].lineno;
                        zend_error(E_COMPILE_ERROR, "jump out of a finally block is disallowed");
                }
        } 
 }
 
+static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, zend_uint dst_num TSRMLS_DC)
+{
+       zend_uint start_op;
+       zend_op *opline;
+       zend_uint i = op_array->last_try_catch;
+
+       if (dst_num != (zend_uint)-1) {
+               zend_check_finally_breakout(op_array, op_num, dst_num TSRMLS_CC);
+       }
+
+       /* the backward order is mater */
+       while (i > 0) {
+               i--;
+               if (op_array->try_catch_array[i].finally_op &&
+                   op_num >= op_array->try_catch_array[i].try_op &&
+                   op_num < op_array->try_catch_array[i].finally_op - 1 &&
+                   (dst_num < op_array->try_catch_array[i].try_op ||
+                    dst_num > op_array->try_catch_array[i].finally_end)) {
+                       /* we have a jump out of try block that needs executing finally */
+
+                       /* generate a FAST_CALL to finaly block */
+                   start_op = get_next_op_number(op_array);
+                       opline = get_next_op(op_array TSRMLS_CC);
+                       opline->opcode = ZEND_FAST_CALL;
+                       SET_UNUSED(opline->op1);
+                       SET_UNUSED(opline->op2);
+                       opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
+                       if (op_array->try_catch_array[i].catch_op) {
+                               opline->extended_value = 1;
+                               opline->op2.opline_num = op_array->try_catch_array[i].catch_op;
+                       }
+
+                       /* generate a sequence of FAST_CALL to upward finaly block */
+                       while (i > 0) {
+                               i--;
+                               if (op_array->try_catch_array[i].finally_op &&
+                                   op_num >= op_array->try_catch_array[i].try_op &&
+                                   op_num < op_array->try_catch_array[i].finally_op - 1 &&
+                                   (dst_num < op_array->try_catch_array[i].try_op ||
+                                    dst_num > op_array->try_catch_array[i].finally_end)) {
+                                       
+                                       opline = get_next_op(op_array TSRMLS_CC);
+                                       opline->opcode = ZEND_FAST_CALL;
+                                       SET_UNUSED(opline->op1);
+                                       SET_UNUSED(opline->op2);
+                                       opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
+                               }
+                       }
+
+                       /* Finish the sequence with original opcode */
+                       opline = get_next_op(op_array TSRMLS_CC);
+                       *opline = op_array->opcodes[op_num];
+
+                       /* Replace original opcode with jump to this sequence */
+                       opline = op_array->opcodes + op_num;
+                       opline->opcode = ZEND_JMP;
+                       SET_UNUSED(opline->op1);
+                       SET_UNUSED(opline->op2);
+                       opline->op1.opline_num = start_op;
+
+                   break;
+               }
+       }       
+}
+
+static void zend_resolve_finally_ret(zend_op_array *op_array, zend_uint op_num TSRMLS_DC)
+{
+       int i;
+       zend_uint catch_op_num = 0, finally_op_num = 0;
+
+       for (i = 0; i < op_array->last_try_catch; i++) {
+               if (op_array->try_catch_array[i].try_op > op_num) {
+                       break;
+               }
+               if (op_num < op_array->try_catch_array[i].finally_op) {
+                       finally_op_num = op_array->try_catch_array[i].finally_op;
+               }
+               if (op_num < op_array->try_catch_array[i].catch_op) {
+                       catch_op_num = op_array->try_catch_array[i].catch_op;
+               }
+       }
+
+       if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
+               /* in case of unhandled exception return to upward finally block */
+               op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_FINALLY;
+               op_array->opcodes[op_num].op2.opline_num = finally_op_num;
+       } else if (catch_op_num) {
+               /* in case of unhandled exception return to upward catch block */
+               op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_CATCH;
+               op_array->opcodes[op_num].op2.opline_num = catch_op_num;
+       }
+}
+
+static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC)
+{
+       zend_uint i;
+       zend_op *opline;
+
+       for (i = 0; i < op_array->last; i++) {
+               opline = op_array->opcodes + i;
+               switch (opline->opcode) {
+                       case ZEND_RETURN:
+                       case ZEND_RETURN_BY_REF:
+                               zend_resolve_finally_call(op_array, i, (zend_uint)-1 TSRMLS_CC);
+                               break;
+                       case ZEND_BRK:
+                       case ZEND_CONT:
+                       {
+                               int nest_levels, array_offset;
+                               zend_brk_cont_element *jmp_to;
+
+                               nest_levels = Z_LVAL(op_array->literals[opline->op2.constant].constant);
+                               array_offset = opline->op1.opline_num;
+                               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 TSRMLS_CC);
+                               break;
+                       }
+                       case ZEND_GOTO:
+                               if (Z_TYPE(op_array->literals[opline->op2.constant].constant) != IS_LONG) {
+                                       zend_uint num = opline->op2.constant;
+                                       opline->op2.zv = &op_array->literals[opline->op2.constant].constant;
+                                       zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC);
+                                       opline->op2.constant = num;                                     
+                               }
+                               /* break omitted intentionally */
+                       case ZEND_JMP:
+                               zend_resolve_finally_call(op_array, i, opline->op1.opline_num TSRMLS_CC);
+                               break;
+                       case ZEND_FAST_RET:
+                               zend_resolve_finally_ret(op_array, i TSRMLS_CC);
+                               break;
+                       default:
+                               break;
+               }
+       }
+}
+
 ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
 {
        zend_op *opline, *end;
@@ -524,6 +668,9 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
        if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) {
                return 0;
        }
+       if (op_array->has_finally_block) {
+               zend_resolve_finally_calls(op_array TSRMLS_CC);
+       }
        if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
                zend_update_extended_info(op_array TSRMLS_CC);
        }
@@ -560,30 +707,9 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
                                }
                                /* break omitted intentionally */
                        case ZEND_JMP:
-                               if (op_array->last_try_catch) {
-                                       zend_check_finally_breakout(op_array, opline, opline->op1.opline_num TSRMLS_CC);
-                               }
+                       case ZEND_FAST_CALL:
                                opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num];
                                break;
-                       case ZEND_BRK:
-                       case ZEND_CONT:
-                               if (op_array->last_try_catch) {
-                                       int nest_levels, array_offset;
-                                       zend_brk_cont_element *jmp_to;
-
-                                       nest_levels = Z_LVAL_P(opline->op2.zv);
-                                       array_offset = opline->op1.opline_num;
-                                       do {
-                                               jmp_to = &op_array->brk_cont_array[array_offset];
-                                               if (nest_levels > 1) {
-                                                       array_offset = jmp_to->parent;
-                                               }
-                                       } while (--nest_levels > 0);
-                                       if (op_array->last_try_catch) {
-                                               zend_check_finally_breakout(op_array, opline, jmp_to->brk TSRMLS_CC);
-                                       }
-                               }
-                               break;
                        case ZEND_JMPZ:
                        case ZEND_JMPNZ:
                        case ZEND_JMPZ_EX:
index b06c09f483a343b3cef95a1db4c6d6b44fe2e2d7..4ae4ca1267592f1633d03c761bed93713466a7ae 100644 (file)
@@ -1845,6 +1845,12 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
        zend_bool nested;
        zend_op_array *op_array = EX(op_array);
 
+       if (EXPECTED(EG(exception) == NULL) &&
+           UNEXPECTED(EG(prev_exception) != NULL)) {
+               /* return from finally block called because of unhandled exception */
+               zend_exception_restore(TSRMLS_C);               
+       }
+       
        /* Generators go throw a different cleanup process */
        if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) {
                /* The generator object is stored in return_value_ptr_ptr */
@@ -2125,101 +2131,6 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
        ZEND_VM_NEXT_OPCODE();
 }
 
-ZEND_VM_HELPER_EX(zend_finally_handler_leaving, ANY, ANY, int type)
-{
-       USE_OPLINE
-       zend_uint i, op_num = opline - EX(op_array)->opcodes;
-       zend_uint catch_op_num = 0, finally_op_num = 0;
-
-       SAVE_OPLINE();
-
-       switch (type) {
-               case ZEND_THROW:
-               case ZEND_RETURN:
-               case ZEND_RETURN_BY_REF:
-               case ZEND_LEAVE:
-                       {
-                               if (EG(prev_exception) || (type == ZEND_LEAVE && EG(exception))) {
-                                       for (i=0; i<EX(op_array)->last_try_catch; i++) {
-                                               if (EX(op_array)->try_catch_array[i].try_op > op_num) {
-                                                       break;
-                                               }
-                                               if (op_num < EX(op_array)->try_catch_array[i].finally_op) {
-                                                       finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
-                                               }
-                                               if (op_num < EX(op_array)->try_catch_array[i].catch_op) {
-                                                       catch_op_num = EX(op_array)->try_catch_array[i].catch_op;
-                                               }
-                                       }
-                               } else {
-                                       for (i=0; i<EX(op_array)->last_try_catch; i++) {
-                                               if (EX(op_array)->try_catch_array[i].try_op > op_num) {
-                                                       break;
-                                               }
-                                               if (op_num < EX(op_array)->try_catch_array[i].finally_op) {
-                                                       finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
-                                               }
-                                       }
-                               }
-
-                               if (catch_op_num && finally_op_num) {
-                                       /* EG(exception) || EG(prev_exception) */
-                                       if (catch_op_num > finally_op_num) {
-                                               zend_exception_save(TSRMLS_C);
-                                               EX(leaving) = ZEND_THROW;
-                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                                       } else {
-                                               EX(leaving) = 0;
-                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                                       }
-                               } else if (catch_op_num) {
-                                       EX(leaving) = 0;
-                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                               } else if (finally_op_num) {
-                                       zend_exception_save(TSRMLS_C);
-                                       if (type != ZEND_LEAVE) {
-                                               EX(leaving) = type;
-                                       }
-                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                               } else if (EX(leaving) && type != ZEND_LEAVE) {
-                                       /* leave it to ZEND_LEAVE */
-                                       EX(leaving) = type;
-                                       ZEND_VM_NEXT_OPCODE();
-                               } else {
-                                       ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
-                               }
-                       }
-                       break;
-               case ZEND_JMP:
-               case ZEND_BRK:
-               case ZEND_CONT:
-               case ZEND_GOTO:
-                       {
-                 /* these can not occurred in exception context */
-                 for (i=0; i<EG(active_op_array)->last_try_catch; i++) {
-                         if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
-                                 break;
-                         }
-                         if (op_num < EG(active_op_array)->try_catch_array[i].finally_op
-                                         && (EX(leaving_dest) < EG(active_op_array)->try_catch_array[i].try_op
-                                                 || EX(leaving_dest) >= EG(active_op_array)->try_catch_array[i].finally_end)) {
-                                 finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
-                         }
-                 }
-
-                 if (finally_op_num) {
-                         EX(leaving) = type;
-                         ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                 } else {
-                         EX(leaving) = 0;
-                         ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EX(leaving_dest)]);
-                 }
-         }
-                       break;
-       }
-       ZEND_VM_CONTINUE();
-}
-
 ZEND_VM_HANDLER(42, ZEND_JMP, ANY, ANY)
 {
        USE_OPLINE
@@ -2227,12 +2138,8 @@ ZEND_VM_HANDLER(42, ZEND_JMP, ANY, ANY)
 #if DEBUG_ZEND>=2
        printf("Jumping to %d\n", opline->op1.opline_num);
 #endif
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
-               ZEND_VM_CONTINUE(); /* CHECK_ME */
-       }
-       EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes;
-       ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_JMP);
+       ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
+       ZEND_VM_CONTINUE();
 }
 
 ZEND_VM_HANDLER(43, ZEND_JMPZ, CONST|TMP|VAR|CV, ANY)
@@ -2972,11 +2879,7 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY)
                *EG(return_value_ptr_ptr) = ret;
        }
        FREE_OP1_IF_VAR();
-
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
-       }
-       ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_RETURN);
+       ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
 }
 
 ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY)
@@ -3048,18 +2951,11 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY)
        } while (0);
 
        FREE_OP1_IF_VAR();
-
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
-       }
-       ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_RETURN_BY_REF);
+       ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
 }
 
 ZEND_VM_HANDLER(161, ZEND_GENERATOR_RETURN, ANY, ANY)
 {
-       if (EX(op_array)->has_finally_block) {
-               ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_RETURN);
-       }
        ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
 }
 
@@ -3404,11 +3300,7 @@ ZEND_VM_HANDLER(50, ZEND_BRK, ANY, CONST)
        el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num,
                           EX(op_array), EX_Ts() TSRMLS_CC);
        FREE_OP2();
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               ZEND_VM_JMP(EX(op_array)->opcodes + el->brk);
-       }
-       EX(leaving_dest) = el->brk;
-       ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_BRK);
+       ZEND_VM_JMP(EX(op_array)->opcodes + el->brk);
 }
 
 ZEND_VM_HANDLER(51, ZEND_CONT, ANY, CONST)
@@ -3420,11 +3312,7 @@ ZEND_VM_HANDLER(51, ZEND_CONT, ANY, CONST)
        el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num,
                           EX(op_array), EX_Ts() TSRMLS_CC);
        FREE_OP2();
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               ZEND_VM_JMP(EX(op_array)->opcodes + el->cont);
-       }
-       EX(leaving_dest) = el->cont;
-       ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_CONT);
+       ZEND_VM_JMP(EX(op_array)->opcodes + el->cont);
 }
 
 ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
@@ -3451,11 +3339,7 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
                        }
                        break;
        }
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               ZEND_VM_JMP(opline->op1.jmp_addr);
-       }
-       EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes;
-       ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, ZEND_GOTO);
+       ZEND_VM_JMP(opline->op1.jmp_addr);
 }
 
 ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)
@@ -5134,7 +5018,6 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
        zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes;
        int i;
        zend_uint catch_op_num = 0, finally_op_num = 0;
-       int catched = 0, finally = 0;
        void **stack_frame;
 
        /* Figure out where the next stack frame (which maybe contains pushed
@@ -5167,11 +5050,9 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                }
                if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) {
                        catch_op_num = EX(op_array)->try_catch_array[i].catch_op;
-                       catched = i + 1;
                }
                if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
                        finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
-                       finally = i + 1;
                }
        }
 
@@ -5199,7 +5080,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
                        /* further blocks will not be relevant... */
                        break;
                } else if (op_num < EX(op_array)->brk_cont_array[i].brk) {
-                       if (!catched ||
+                       if (!catch_op_num ||
                            catch_op_num >= EX(op_array)->brk_cont_array[i].brk) {
                                zend_op *brk_opline = &EX(op_array)->opcodes[EX(op_array)->brk_cont_array[i].brk];
 
@@ -5231,26 +5112,14 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
        }
        EX(old_error_reporting) = NULL;
 
-       if (catched && finally) {
-               if (finally_op_num > catch_op_num) {
-                       EX(leaving) = 0;
-                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                       ZEND_VM_CONTINUE();
-               } else {
-                       zend_exception_save(TSRMLS_C);
-                       EX(leaving) = ZEND_THROW;
-                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                       ZEND_VM_CONTINUE();
-               }
-       } else if (catched) {
-               EX(leaving) = 0;
-               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-               ZEND_VM_CONTINUE();
-       } else if (finally) {
+       if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
                zend_exception_save(TSRMLS_C);
-               EX(leaving) = ZEND_THROW;
+               EX(fast_ret) = NULL;
                ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
                ZEND_VM_CONTINUE();
+       } else if (catch_op_num) {
+               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
+               ZEND_VM_CONTINUE();
        } else {
                ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
        }
@@ -5371,30 +5240,6 @@ ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED)
        ZEND_VM_NEXT_OPCODE();
 }
 
-ZEND_VM_HANDLER(159, ZEND_LEAVE, ANY, ANY)
-{
-       zend_exception_restore(TSRMLS_C);
-       if (!EX(leaving)) {
-               ZEND_VM_NEXT_OPCODE();
-       } else {
-               zend_uint leaving = EX(leaving);
-               switch (leaving) {
-                       case ZEND_RETURN:
-                       case ZEND_RETURN_BY_REF:
-                       case ZEND_THROW:
-                               leaving = ZEND_LEAVE;
-                       case ZEND_JMP:
-                       case ZEND_BRK:
-                       case ZEND_CONT:
-                       case ZEND_GOTO:
-                                ZEND_VM_DISPATCH_TO_HELPER_EX(zend_finally_handler_leaving, type, leaving);
-                       break;
-               }
-       }
-
-       ZEND_VM_CONTINUE();
-}
-
 ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSED)
 {
        USE_OPLINE
@@ -5552,4 +5397,42 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
        ZEND_VM_RETURN();
 }
 
+ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY)
+{
+       USE_OPLINE
+
+       if (opline->extended_value &&
+           UNEXPECTED(EG(prev_exception) != NULL)) { 
+           /* in case of unhandled exception jump to catch block instead of finally */
+               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
+               ZEND_VM_CONTINUE();
+       }
+       EX(fast_ret) = opline + 1;
+       ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
+       ZEND_VM_CONTINUE();
+}
+
+ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY)
+{
+       if (EX(fast_ret)) {
+               ZEND_VM_SET_OPCODE(EX(fast_ret));
+               ZEND_VM_CONTINUE();
+       } else {
+               /* special case for unhandled exceptions */
+               USE_OPLINE
+
+               if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
+                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
+                       ZEND_VM_CONTINUE();
+               } else if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
+                       zend_exception_restore(TSRMLS_C);
+                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
+                       ZEND_VM_CONTINUE();
+               } else {
+                       zend_exception_restore(TSRMLS_C);
+                       ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
+               }
+       }
+}
+
 ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper)
index 7a2cfc88d90ded6d6c54b193a1a1be2bbfc57424..582962cfcf5bb61affe6c0383a47313358f96837 100644 (file)
@@ -385,7 +385,6 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra
        EX(prev_execute_data) = EG(current_execute_data);
        EG(current_execute_data) = execute_data;
        EX(nested) = nested;
-    EX(leaving) = 0;
 
        if (!op_array->run_time_cache && op_array->last_cache_slot) {
                op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*));
@@ -466,6 +465,12 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
        zend_bool nested;
        zend_op_array *op_array = EX(op_array);
 
+       if (EXPECTED(EG(exception) == NULL) &&
+           UNEXPECTED(EG(prev_exception) != NULL)) {
+               /* return from finally block called because of unhandled exception */
+               zend_exception_restore(TSRMLS_C);
+       }
+
        /* Generators go throw a different cleanup process */
        if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) {
                /* The generator object is stored in return_value_ptr_ptr */
@@ -746,101 +751,6 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR
        ZEND_VM_NEXT_OPCODE();
 }
 
-static int ZEND_FASTCALL zend_finally_handler_leaving_SPEC(int type, ZEND_OPCODE_HANDLER_ARGS)
-{
-       USE_OPLINE
-       zend_uint i, op_num = opline - EX(op_array)->opcodes;
-       zend_uint catch_op_num = 0, finally_op_num = 0;
-
-       SAVE_OPLINE();
-
-       switch (type) {
-               case ZEND_THROW:
-               case ZEND_RETURN:
-               case ZEND_RETURN_BY_REF:
-               case ZEND_LEAVE:
-                       {
-                               if (EG(prev_exception) || (type == ZEND_LEAVE && EG(exception))) {
-                                       for (i=0; i<EX(op_array)->last_try_catch; i++) {
-                                               if (EX(op_array)->try_catch_array[i].try_op > op_num) {
-                                                       break;
-                                               }
-                                               if (op_num < EX(op_array)->try_catch_array[i].finally_op) {
-                                                       finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
-                                               }
-                                               if (op_num < EX(op_array)->try_catch_array[i].catch_op) {
-                                                       catch_op_num = EX(op_array)->try_catch_array[i].catch_op;
-                                               }
-                                       }
-                               } else {
-                                       for (i=0; i<EX(op_array)->last_try_catch; i++) {
-                                               if (EX(op_array)->try_catch_array[i].try_op > op_num) {
-                                                       break;
-                                               }
-                                               if (op_num < EX(op_array)->try_catch_array[i].finally_op) {
-                                                       finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
-                                               }
-                                       }
-                               }
-
-                               if (catch_op_num && finally_op_num) {
-                                       /* EG(exception) || EG(prev_exception) */
-                                       if (catch_op_num > finally_op_num) {
-                                               zend_exception_save(TSRMLS_C);
-                                               EX(leaving) = ZEND_THROW;
-                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                                       } else {
-                                               EX(leaving) = 0;
-                                               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                                       }
-                               } else if (catch_op_num) {
-                                       EX(leaving) = 0;
-                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                               } else if (finally_op_num) {
-                                       zend_exception_save(TSRMLS_C);
-                                       if (type != ZEND_LEAVE) {
-                                               EX(leaving) = type;
-                                       }
-                                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                               } else if (EX(leaving) && type != ZEND_LEAVE) {
-                                       /* leave it to ZEND_LEAVE */
-                                       EX(leaving) = type;
-                                       ZEND_VM_NEXT_OPCODE();
-                               } else {
-                                       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-                               }
-                       }
-                       break;
-               case ZEND_JMP:
-               case ZEND_BRK:
-               case ZEND_CONT:
-               case ZEND_GOTO:
-                       {
-                 /* these can not occurred in exception context */
-                 for (i=0; i<EG(active_op_array)->last_try_catch; i++) {
-                         if (EG(active_op_array)->try_catch_array[i].try_op > op_num) {
-                                 break;
-                         }
-                         if (op_num < EG(active_op_array)->try_catch_array[i].finally_op
-                                         && (EX(leaving_dest) < EG(active_op_array)->try_catch_array[i].try_op
-                                                 || EX(leaving_dest) >= EG(active_op_array)->try_catch_array[i].finally_end)) {
-                                 finally_op_num = EG(active_op_array)->try_catch_array[i].finally_op;
-                         }
-                 }
-
-                 if (finally_op_num) {
-                         EX(leaving) = type;
-                         ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                 } else {
-                         EX(leaving) = 0;
-                         ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[EX(leaving_dest)]);
-                 }
-         }
-                       break;
-       }
-       ZEND_VM_CONTINUE();
-}
-
 static int ZEND_FASTCALL  ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
        USE_OPLINE
@@ -848,12 +758,8 @@ static int ZEND_FASTCALL  ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 #if DEBUG_ZEND>=2
        printf("Jumping to %d\n", opline->op1.opline_num);
 #endif
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
-               ZEND_VM_CONTINUE(); /* CHECK_ME */
-       }
-       EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes;
-       return zend_finally_handler_leaving_SPEC(ZEND_JMP, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
+       ZEND_VM_CONTINUE();
 }
 
 static int ZEND_FASTCALL  ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -880,9 +786,6 @@ static int ZEND_FASTCALL  ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(ZEND_OPCODE_HANDLER
 
 static int ZEND_FASTCALL  ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
-       if (EX(op_array)->has_finally_block) {
-               return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-       }
        return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
@@ -1168,7 +1071,6 @@ static int ZEND_FASTCALL  ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
        zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes;
        int i;
        zend_uint catch_op_num = 0, finally_op_num = 0;
-       int catched = 0, finally = 0;
        void **stack_frame;
 
        /* Figure out where the next stack frame (which maybe contains pushed
@@ -1201,11 +1103,9 @@ static int ZEND_FASTCALL  ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
                }
                if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) {
                        catch_op_num = EX(op_array)->try_catch_array[i].catch_op;
-                       catched = i + 1;
                }
                if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
                        finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
-                       finally = i + 1;
                }
        }
 
@@ -1233,7 +1133,7 @@ static int ZEND_FASTCALL  ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
                        /* further blocks will not be relevant... */
                        break;
                } else if (op_num < EX(op_array)->brk_cont_array[i].brk) {
-                       if (!catched ||
+                       if (!catch_op_num ||
                            catch_op_num >= EX(op_array)->brk_cont_array[i].brk) {
                                zend_op *brk_opline = &EX(op_array)->opcodes[EX(op_array)->brk_cont_array[i].brk];
 
@@ -1265,26 +1165,14 @@ static int ZEND_FASTCALL  ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
        }
        EX(old_error_reporting) = NULL;
 
-       if (catched && finally) {
-               if (finally_op_num > catch_op_num) {
-                       EX(leaving) = 0;
-                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-                       ZEND_VM_CONTINUE();
-               } else {
-                       zend_exception_save(TSRMLS_C);
-                       EX(leaving) = ZEND_THROW;
-                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
-                       ZEND_VM_CONTINUE();
-               }
-       } else if (catched) {
-               EX(leaving) = 0;
-               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
-               ZEND_VM_CONTINUE();
-       } else if (finally) {
+       if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
                zend_exception_save(TSRMLS_C);
-               EX(leaving) = ZEND_THROW;
+               EX(fast_ret) = NULL;
                ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
                ZEND_VM_CONTINUE();
+       } else if (catch_op_num) {
+               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
+               ZEND_VM_CONTINUE();
        } else {
                return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
        }
@@ -1325,28 +1213,42 @@ static int ZEND_FASTCALL  ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        }
 }
 
-static int ZEND_FASTCALL  ZEND_LEAVE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static int ZEND_FASTCALL  ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
-       zend_exception_restore(TSRMLS_C);
-       if (!EX(leaving)) {
-               ZEND_VM_NEXT_OPCODE();
+       USE_OPLINE
+
+       if (opline->extended_value &&
+           UNEXPECTED(EG(prev_exception) != NULL)) {
+           /* in case of unhandled exception jump to catch block instead of finally */
+               ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
+               ZEND_VM_CONTINUE();
+       }
+       EX(fast_ret) = opline + 1;
+       ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
+       ZEND_VM_CONTINUE();
+}
+
+static int ZEND_FASTCALL  ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+       if (EX(fast_ret)) {
+               ZEND_VM_SET_OPCODE(EX(fast_ret));
+               ZEND_VM_CONTINUE();
        } else {
-               zend_uint leaving = EX(leaving);
-               switch (leaving) {
-                       case ZEND_RETURN:
-                       case ZEND_RETURN_BY_REF:
-                       case ZEND_THROW:
-                               leaving = ZEND_LEAVE;
-                       case ZEND_JMP:
-                       case ZEND_BRK:
-                       case ZEND_CONT:
-                       case ZEND_GOTO:
-                                return zend_finally_handler_leaving_SPEC(leaving, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-                       break;
+               /* special case for unhandled exceptions */
+               USE_OPLINE
+
+               if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
+                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
+                       ZEND_VM_CONTINUE();
+               } else if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
+                       zend_exception_restore(TSRMLS_C);
+                       ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
+                       ZEND_VM_CONTINUE();
+               } else {
+                       zend_exception_restore(TSRMLS_C);
+                       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
                }
        }
-
-       ZEND_VM_CONTINUE();
 }
 
 static int ZEND_FASTCALL  ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -1587,11 +1489,7 @@ static int ZEND_FASTCALL  ZEND_BRK_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num,
                           EX(op_array), EX_Ts() TSRMLS_CC);
 
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               ZEND_VM_JMP(EX(op_array)->opcodes + el->brk);
-       }
-       EX(leaving_dest) = el->brk;
-       return zend_finally_handler_leaving_SPEC(ZEND_BRK, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       ZEND_VM_JMP(EX(op_array)->opcodes + el->brk);
 }
 
 static int ZEND_FASTCALL  ZEND_CONT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -1603,11 +1501,7 @@ static int ZEND_FASTCALL  ZEND_CONT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num,
                           EX(op_array), EX_Ts() TSRMLS_CC);
 
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               ZEND_VM_JMP(EX(op_array)->opcodes + el->cont);
-       }
-       EX(leaving_dest) = el->cont;
-       return zend_finally_handler_leaving_SPEC(ZEND_CONT, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       ZEND_VM_JMP(EX(op_array)->opcodes + el->cont);
 }
 
 static int ZEND_FASTCALL  ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -1634,11 +1528,7 @@ static int ZEND_FASTCALL  ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                        }
                        break;
        }
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               ZEND_VM_JMP(opline->op1.jmp_addr);
-       }
-       EX(leaving_dest) = opline->op1.jmp_addr - EX(op_array)->opcodes;
-       return zend_finally_handler_leaving_SPEC(ZEND_GOTO, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       ZEND_VM_JMP(opline->op1.jmp_addr);
 }
 
 static int ZEND_FASTCALL  ZEND_ADD_INTERFACE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -2501,10 +2391,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG
                *EG(return_value_ptr_ptr) = ret;
        }
 
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-       }
-       return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -2575,10 +2462,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND
                }
        } while (0);
 
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-       }
-       return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -7822,10 +7706,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                *EG(return_value_ptr_ptr) = ret;
        }
 
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-       }
-       return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -7896,10 +7777,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLE
                }
        } while (0);
 
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-       }
-       return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -13048,11 +12926,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                *EG(return_value_ptr_ptr) = ret;
        }
        if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
-
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-       }
-       return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -13124,11 +12998,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLE
        } while (0);
 
        if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
-
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-       }
-       return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -30620,10 +30490,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                *EG(return_value_ptr_ptr) = ret;
        }
 
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-       }
-       return zend_finally_handler_leaving_SPEC(ZEND_RETURN, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -30694,10 +30561,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER
                }
        } while (0);
 
-       if (EXPECTED(!EX(op_array)->has_finally_block)) {
-               return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
-       }
-       return zend_finally_handler_leaving_SPEC(ZEND_RETURN_BY_REF, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+       return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
 }
 
 static int ZEND_FASTCALL  ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -44964,31 +44828,31 @@ void zend_init_opcodes_handlers(void)
        ZEND_JMP_SET_VAR_SPEC_CV_HANDLER,
        ZEND_JMP_SET_VAR_SPEC_CV_HANDLER,
        ZEND_JMP_SET_VAR_SPEC_CV_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_HANDLER,
-       ZEND_LEAVE_SPEC_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,
+       ZEND_NULL_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,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
+       ZEND_NULL_HANDLER,
        ZEND_YIELD_SPEC_CONST_CONST_HANDLER,
        ZEND_YIELD_SPEC_CONST_TMP_HANDLER,
        ZEND_YIELD_SPEC_CONST_VAR_HANDLER,
@@ -45039,6 +44903,56 @@ void zend_init_opcodes_handlers(void)
        ZEND_GENERATOR_RETURN_SPEC_HANDLER,
        ZEND_GENERATOR_RETURN_SPEC_HANDLER,
        ZEND_GENERATOR_RETURN_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_CALL_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
+       ZEND_FAST_RET_SPEC_HANDLER,
        ZEND_NULL_HANDLER
   };
   zend_opcode_handlers = (opcode_handler_t*)labels;
index 2a6fd71ecb5a4de9746f9d5e705b5e04fa80b50d..e2d5dd12b039b2c9e917b40a1991e4b1737d72dc 100644 (file)
@@ -46,7 +46,6 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra
        EX(prev_execute_data) = EG(current_execute_data);
        EG(current_execute_data) = execute_data;
        EX(nested) = nested;
-    EX(leaving) = 0;
 
        if (!op_array->run_time_cache && op_array->last_cache_slot) {
                op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*));
index 7f9434995483e772fe889dc4db660978f06204b7..52f6cde59e71fc5a1c6a263a4f79c1e0c2213ca7 100644 (file)
 #define ZEND_SEPARATE                        156
 #define ZEND_QM_ASSIGN_VAR                   157
 #define ZEND_JMP_SET_VAR                     158
-#define ZEND_LEAVE                           159
 #define ZEND_YIELD                           160
 #define ZEND_GENERATOR_RETURN                161
+#define ZEND_FAST_CALL                       162
+#define ZEND_FAST_RET                        163