Hi Laruence, Please take a look into the "finally" improvement patch. It resolves most the jump addresses at compile time and makes executor cleaner and faster.
Attached the patch for PHP 5.5 (it requires zend_vm_execute.h regeneration). Thanks. Dmitry.
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c9714e5..fc6b623 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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)); + 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)); + 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) TSRMLS_CC); } - if (catch_token->op_type == IS_UNUSED) { - CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].catch_op = 0; - } } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 77809da..e46c1a3 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -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" diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 87f0644..516ff0b 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -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; diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 224c7a2..4e55859 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -499,24 +499,161 @@ 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); + } + 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)) { + + start_op = get_next_op_number(op_array TSRMLS_CC); + 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; + } + + 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; + } + } + + opline = get_next_op(op_array TSRMLS_CC); + *opline = op_array->opcodes[op_num]; + + 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 +661,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 +700,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: diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b06c09f..e346965 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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) @@ -5231,26 +5115,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 && (!catched || 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 (catched) { + 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 +5243,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 +5400,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)) { + /* oin 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) diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 2a6fd71..e2d5dd1 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -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*));
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php