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