diff options
Diffstat (limited to 'Zend/zend_compile.c')
-rw-r--r-- | Zend/zend_compile.c | 29 |
1 files changed, 23 insertions, 6 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0994681c20..c6da34732a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -234,6 +234,7 @@ void zend_oparray_context_begin(zend_oparray_context *prev_context) /* {{{ */ CG(context).backpatch_count = 0; CG(context).in_finally = 0; CG(context).fast_call_var = -1; + CG(context).try_catch_offset = -1; CG(context).current_brk_cont = -1; CG(context).last_brk_cont = 0; CG(context).brk_cont_array = NULL; @@ -4008,6 +4009,12 @@ static int zend_handle_loops_and_finally_ex(zend_long depth) /* {{{ */ SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); opline->op1.num = loop_var->u.try_catch_offset; + } else if (loop_var->opcode == ZEND_DISCARD_EXCEPTION) { + zend_op *opline = get_next_op(CG(active_op_array)); + opline->opcode = ZEND_DISCARD_EXCEPTION; + opline->op1_type = IS_TMP_VAR; + opline->op1.var = loop_var->var_num; + SET_UNUSED(opline->op2); } else if (loop_var->opcode == ZEND_RETURN) { /* Stack separator */ break; @@ -4057,12 +4064,6 @@ void zend_compile_return(zend_ast *ast) /* {{{ */ zend_compile_expr(&expr_node, expr_ast); } - if (CG(context).in_finally) { - opline = zend_emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL); - opline->op1_type = IS_TMP_VAR; - opline->op1.var = CG(context).fast_call_var; - } - /* Generator return types are handled separately */ if (!(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) && CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { zend_emit_return_type_check(expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1); @@ -4573,6 +4574,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */ uint32_t try_catch_offset; uint32_t *jmp_opnums = safe_emalloc(sizeof(uint32_t), catches->children, 0); uint32_t orig_fast_call_var = CG(context).fast_call_var; + uint32_t orig_try_catch_offset = CG(context).try_catch_offset; if (catches->children == 0 && !finally_ast) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use try without catch or finally"); @@ -4606,6 +4608,8 @@ void zend_compile_try(zend_ast *ast) /* {{{ */ zend_stack_push(&CG(loop_var_stack), &fast_call); } + CG(context).try_catch_offset = try_catch_offset; + zend_compile_stmt(try_ast); if (catches->children != 0) { @@ -4679,11 +4683,18 @@ void zend_compile_try(zend_ast *ast) /* {{{ */ } if (finally_ast) { + zend_loop_var discard_exception; uint32_t opnum_jmp = get_next_op_number(CG(active_op_array)) + 1; /* Pop FAST_CALL from unwind stack */ zend_stack_del_top(&CG(loop_var_stack)); + /* Push DISCARD_EXCEPTION on unwind stack */ + discard_exception.opcode = ZEND_DISCARD_EXCEPTION; + discard_exception.var_type = IS_TMP_VAR; + discard_exception.var_num = CG(context).fast_call_var; + zend_stack_push(&CG(loop_var_stack), &discard_exception); + CG(zend_lineno) = finally_ast->lineno; opline = zend_emit_op(NULL, ZEND_FAST_CALL, NULL, NULL); @@ -4704,12 +4715,18 @@ void zend_compile_try(zend_ast *ast) /* {{{ */ opline = zend_emit_op(NULL, ZEND_FAST_RET, NULL, NULL); opline->op1_type = IS_TMP_VAR; opline->op1.var = CG(context).fast_call_var; + opline->op2.num = orig_try_catch_offset; zend_update_jump_target_to_next(opnum_jmp); CG(context).fast_call_var = orig_fast_call_var; + + /* Pop DISCARD_EXCEPTION from unwind stack */ + zend_stack_del_top(&CG(loop_var_stack)); } + CG(context).try_catch_offset = orig_try_catch_offset; + efree(jmp_opnums); } /* }}} */ |