summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2014-11-27 09:56:43 +0300
committerDmitry Stogov <dmitry@zend.com>2014-11-27 09:56:43 +0300
commit216ef321730f40e87397f38138504a91e09ae287 (patch)
tree263fc44cace90b09b3a32ca7d9f6e2a08931856f
parentc0a4561fb434237699bbbdc733987e2954811e59 (diff)
downloadphp-git-216ef321730f40e87397f38138504a91e09ae287.tar.gz
Changed "finally" handling. Removed EX(fast_ret) and EX(delayed_exception). Allocate and use additional IS_TMP_VAR slot on VM stack instead.
-rw-r--r--Zend/zend_compile.c17
-rw-r--r--Zend/zend_compile.h3
-rw-r--r--Zend/zend_execute.c3
-rw-r--r--Zend/zend_generators.c8
-rw-r--r--Zend/zend_opcode.c11
-rw-r--r--Zend/zend_vm_def.h62
-rw-r--r--Zend/zend_vm_execute.h62
7 files changed, 114 insertions, 52 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 0905c3ce5f..ea4b355b92 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -159,6 +159,7 @@ void zend_init_compiler_context(TSRMLS_D) /* {{{ */
CG(context).current_brk_cont = -1;
CG(context).backpatch_count = 0;
CG(context).in_finally = 0;
+ CG(context).fast_call_var = -1;
CG(context).labels = NULL;
}
/* }}} */
@@ -3126,7 +3127,9 @@ void zend_compile_return(zend_ast *ast TSRMLS_DC) /* {{{ */
zend_free_foreach_and_switch_variables(TSRMLS_C);
if (CG(context).in_finally) {
- zend_emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL TSRMLS_CC);
+ opline = zend_emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL TSRMLS_CC);
+ opline->op1_type = IS_TMP_VAR;
+ opline->op1.var = CG(context).fast_call_var;
}
opline = zend_emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN,
@@ -3621,8 +3624,15 @@ void zend_compile_try(zend_ast *ast TSRMLS_DC) /* {{{ */
if (finally_ast) {
uint32_t opnum_jmp = get_next_op_number(CG(active_op_array)) + 1;
+ if (!(CG(active_op_array)->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
+ CG(active_op_array)->fn_flags |= ZEND_ACC_HAS_FINALLY_BLOCK;
+ CG(context).fast_call_var = get_temporary_variable(CG(active_op_array));
+ }
+
opline = zend_emit_op(NULL, ZEND_FAST_CALL, NULL, NULL TSRMLS_CC);
opline->op1.opline_num = opnum_jmp + 1;
+ opline->result_type = IS_TMP_VAR;
+ opline->result.var = CG(context).fast_call_var;
zend_emit_op(NULL, ZEND_JMP, NULL, NULL TSRMLS_CC);
@@ -3633,9 +3643,10 @@ void zend_compile_try(zend_ast *ast TSRMLS_DC) /* {{{ */
CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = opnum_jmp + 1;
CG(active_op_array)->try_catch_array[try_catch_offset].finally_end
= get_next_op_number(CG(active_op_array));
- CG(active_op_array)->fn_flags |= ZEND_ACC_HAS_FINALLY_BLOCK;
- zend_emit_op(NULL, ZEND_FAST_RET, NULL, NULL TSRMLS_CC);
+ opline = zend_emit_op(NULL, ZEND_FAST_RET, NULL, NULL TSRMLS_CC);
+ opline->op1_type = IS_TMP_VAR;
+ opline->op1.var = CG(context).fast_call_var;
zend_update_jump_target_to_next(opnum_jmp TSRMLS_CC);
}
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index d6184c9dc3..4cf60c6181 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -52,6 +52,7 @@ typedef struct _zend_compiler_context {
int current_brk_cont;
int backpatch_count;
int in_finally;
+ uint32_t fast_call_var;
HashTable *labels;
} zend_compiler_context;
@@ -376,8 +377,6 @@ struct _zend_execute_data {
zval *return_value;
zend_class_entry *scope; /* function scope (self) */
zend_array *symbol_table;
- const zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
- zend_object *delayed_exception;
};
#define VM_FRAME_KIND_MASK 0x000000ff
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index fc8cd57ced..94197857f4 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -1485,7 +1485,6 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu
EX(opline) = op_array->opcodes;
EX(call) = NULL;
EX(return_value) = return_value;
- EX(delayed_exception) = NULL;
/* Handle arguments */
first_extra_arg = op_array->num_args;
@@ -1551,7 +1550,6 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu
EX(call) = NULL;
EX(return_value) = return_value;
EX(scope) = EG(scope);
- EX(delayed_exception) = NULL;
zend_attach_symbol_table(execute_data);
@@ -1577,7 +1575,6 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
EX(call) = NULL;
EX(return_value) = return_value;
EX(scope) = EG(scope);
- EX(delayed_exception) = NULL;
if (UNEXPECTED(EX(symbol_table) != NULL)) {
zend_attach_symbol_table(execute_data);
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index b38657f7b7..ef0b520eb0 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -133,7 +133,7 @@ static void zend_generator_dtor_storage(zend_object *object TSRMLS_DC) /* {{{ */
{
zend_generator *generator = (zend_generator*) object;
zend_execute_data *ex = generator->execute_data;
- uint32_t op_num, finally_op_num;
+ uint32_t op_num, finally_op_num, finally_op_end;
int i;
if (!ex || !(ex->func->op_array.fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
@@ -146,6 +146,7 @@ static void zend_generator_dtor_storage(zend_object *object TSRMLS_DC) /* {{{ */
/* Find next finally block */
finally_op_num = 0;
+ finally_op_end = 0;
for (i = 0; i < ex->func->op_array.last_try_catch; i++) {
zend_try_catch_element *try_catch = &ex->func->op_array.try_catch_array[i];
@@ -155,14 +156,17 @@ static void zend_generator_dtor_storage(zend_object *object TSRMLS_DC) /* {{{ */
if (op_num < try_catch->finally_op) {
finally_op_num = try_catch->finally_op;
+ finally_op_end = try_catch->finally_end;
}
}
/* If a finally block was found we jump directly to it and
* resume the generator. */
if (finally_op_num) {
+ zval *fast_call = EX_VAR_2(ex, ex->func->op_array.opcodes[finally_op_end].op1.var);
+
+ fast_call->u2.lineno = (uint32_t)-1;
ex->opline = &ex->func->op_array.opcodes[finally_op_num];
- ex->fast_ret = NULL;
generator->flags |= ZEND_GENERATOR_FORCED_CLOSE;
zend_generator_resume(generator TSRMLS_CC);
}
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index 5902abd4c5..1bbd35f40f 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -532,12 +532,19 @@ static void zend_resolve_finally_call(zend_op_array *op_array, uint32_t op_num,
(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 */
+ uint32_t fast_call_var;
+
+ /* Must be ZEND_FAST_RET */
+ ZEND_ASSERT(op_array->opcodes[op_array->try_catch_array[i].finally_end].opcode == ZEND_FAST_RET);
+ fast_call_var = op_array->opcodes[op_array->try_catch_array[i].finally_end].op1.var;
/* generate a FAST_CALL to finally block */
start_op = get_next_op_number(op_array);
opline = get_next_op(op_array TSRMLS_CC);
opline->opcode = ZEND_FAST_CALL;
+ opline->result_type = IS_TMP_VAR;
+ opline->result.var = fast_call_var;
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
zend_adjust_fast_call(op_array, start_op,
@@ -550,6 +557,8 @@ static void zend_resolve_finally_call(zend_op_array *op_array, uint32_t op_num,
/* generate a FAST_CALL to hole CALL_FROM_FINALLY */
opline = get_next_op(op_array TSRMLS_CC);
opline->opcode = ZEND_FAST_CALL;
+ opline->result_type = IS_TMP_VAR;
+ opline->result.var = fast_call_var;
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
zend_resolve_fast_call(op_array, start_op + 1, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC);
@@ -569,6 +578,8 @@ static void zend_resolve_finally_call(zend_op_array *op_array, uint32_t op_num,
opline = get_next_op(op_array TSRMLS_CC);
opline->opcode = ZEND_FAST_CALL;
+ opline->result_type = IS_TMP_VAR;
+ opline->result.var = fast_call_var;
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 85342eaf43..760f5f99f7 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -5469,6 +5469,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
}
if (op_num < EX(func)->op_array.try_catch_array[i].finally_op) {
finally_op_num = EX(func)->op_array.try_catch_array[i].finally_op;
+ finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end;
}
if (op_num >= EX(func)->op_array.try_catch_array[i].finally_op &&
op_num < EX(func)->op_array.try_catch_array[i].finally_end) {
@@ -5526,28 +5527,36 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
}
if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
- if (EX(delayed_exception)) {
- zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
+ zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
+
+ if (Z_OBJ_P(fast_call)) {
+ zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call) TSRMLS_CC);
}
- EX(delayed_exception) = EG(exception);
+ Z_OBJ_P(fast_call) = EG(exception);
EG(exception) = NULL;
- EX(fast_ret) = NULL;
+ fast_call->u2.lineno = (uint32_t)-1;
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op_num]);
ZEND_VM_CONTINUE();
} else if (catch_op_num) {
if (finally_op_end && catch_op_num > finally_op_end) {
/* we are going out of current finally scope */
- if (EX(delayed_exception)) {
- zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
- EX(delayed_exception) = NULL;
+ zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
+
+ if (Z_OBJ_P(fast_call)) {
+ zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call) TSRMLS_CC);
+ Z_OBJ_P(fast_call) = NULL;
}
}
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op_num]);
ZEND_VM_CONTINUE();
} else {
- if (EX(delayed_exception)) {
- zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
- EX(delayed_exception) = NULL;
+ if (finally_op_end) {
+ zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
+
+ if (Z_OBJ_P(fast_call)) {
+ zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call) TSRMLS_CC);
+ Z_OBJ_P(fast_call) = NULL;
+ }
}
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN);
@@ -5807,10 +5816,14 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, ANY)
{
- if (EX(delayed_exception) != NULL) {
+ USE_OPLINE
+ zval *fast_call = EX_VAR(opline->op1.var);
+
+ /* check for delayed exception */
+ if (Z_OBJ_P(fast_call) != NULL) {
/* discard the previously thrown exception */
- OBJ_RELEASE(EX(delayed_exception));
- EX(delayed_exception) = NULL;
+ OBJ_RELEASE(Z_OBJ_P(fast_call));
+ Z_OBJ_P(fast_call) = NULL;
}
ZEND_VM_NEXT_OPCODE();
@@ -5819,6 +5832,7 @@ ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, ANY)
ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY)
{
USE_OPLINE
+ zval *fast_call = EX_VAR(opline->result.var);
if ((opline->extended_value & ZEND_FAST_CALL_FROM_CATCH) &&
UNEXPECTED(EG(prev_exception) != NULL)) {
@@ -5826,18 +5840,24 @@ ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY)
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
ZEND_VM_CONTINUE();
}
- EX(fast_ret) = opline;
- EX(delayed_exception) = NULL;
+ /* set no delayed exception */
+ Z_OBJ_P(fast_call) = NULL;
+ /* set return address */
+ fast_call->u2.lineno = opline - EX(func)->op_array.opcodes;
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) + 1);
- if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FROM_FINALLY)) {
- EX(fast_ret) = &EX(func)->op_array.opcodes[EX(fast_ret)->op2.opline_num];
+ USE_OPLINE
+ zval *fast_call = EX_VAR(opline->op1.var);
+
+ if (fast_call->u2.lineno != (uint32_t)-1) {
+ const zend_op *fast_ret = EX(func)->op_array.opcodes + fast_call->u2.lineno;
+ ZEND_VM_SET_OPCODE(fast_ret + 1);
+ if (fast_ret->extended_value & ZEND_FAST_CALL_FROM_FINALLY) {
+ fast_call->u2.lineno = fast_ret->op2.opline_num;
}
ZEND_VM_CONTINUE();
} else {
@@ -5848,8 +5868,8 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY)
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
ZEND_VM_CONTINUE();
} else {
- EG(exception) = EX(delayed_exception);
- EX(delayed_exception) = NULL;
+ EG(exception) = Z_OBJ_P(fast_call);
+ Z_OBJ_P(fast_call) = NULL;
if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
ZEND_VM_CONTINUE();
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index c80229f738..dc3ee25c52 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1214,6 +1214,7 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
}
if (op_num < EX(func)->op_array.try_catch_array[i].finally_op) {
finally_op_num = EX(func)->op_array.try_catch_array[i].finally_op;
+ finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end;
}
if (op_num >= EX(func)->op_array.try_catch_array[i].finally_op &&
op_num < EX(func)->op_array.try_catch_array[i].finally_end) {
@@ -1271,28 +1272,36 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
}
if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
- if (EX(delayed_exception)) {
- zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
+ zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
+
+ if (Z_OBJ_P(fast_call)) {
+ zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call) TSRMLS_CC);
}
- EX(delayed_exception) = EG(exception);
+ Z_OBJ_P(fast_call) = EG(exception);
EG(exception) = NULL;
- EX(fast_ret) = NULL;
+ fast_call->u2.lineno = (uint32_t)-1;
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op_num]);
ZEND_VM_CONTINUE();
} else if (catch_op_num) {
if (finally_op_end && catch_op_num > finally_op_end) {
/* we are going out of current finally scope */
- if (EX(delayed_exception)) {
- zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
- EX(delayed_exception) = NULL;
+ zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
+
+ if (Z_OBJ_P(fast_call)) {
+ zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call) TSRMLS_CC);
+ Z_OBJ_P(fast_call) = NULL;
}
}
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op_num]);
ZEND_VM_CONTINUE();
} else {
- if (EX(delayed_exception)) {
- zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
- EX(delayed_exception) = NULL;
+ if (finally_op_end) {
+ zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var);
+
+ if (Z_OBJ_P(fast_call)) {
+ zend_exception_set_previous(EG(exception), Z_OBJ_P(fast_call) TSRMLS_CC);
+ Z_OBJ_P(fast_call) = NULL;
+ }
}
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
@@ -1343,10 +1352,14 @@ static int ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS
static int ZEND_FASTCALL ZEND_DISCARD_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
- if (EX(delayed_exception) != NULL) {
+ USE_OPLINE
+ zval *fast_call = EX_VAR(opline->op1.var);
+
+ /* check for delayed exception */
+ if (Z_OBJ_P(fast_call) != NULL) {
/* discard the previously thrown exception */
- OBJ_RELEASE(EX(delayed_exception));
- EX(delayed_exception) = NULL;
+ OBJ_RELEASE(Z_OBJ_P(fast_call));
+ Z_OBJ_P(fast_call) = NULL;
}
ZEND_VM_NEXT_OPCODE();
@@ -1355,6 +1368,7 @@ static int ZEND_FASTCALL ZEND_DISCARD_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLE
static int ZEND_FASTCALL ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
+ zval *fast_call = EX_VAR(opline->result.var);
if ((opline->extended_value & ZEND_FAST_CALL_FROM_CATCH) &&
UNEXPECTED(EG(prev_exception) != NULL)) {
@@ -1362,18 +1376,24 @@ static int ZEND_FASTCALL ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
ZEND_VM_CONTINUE();
}
- EX(fast_ret) = opline;
- EX(delayed_exception) = NULL;
+ /* set no delayed exception */
+ Z_OBJ_P(fast_call) = NULL;
+ /* set return address */
+ fast_call->u2.lineno = opline - EX(func)->op_array.opcodes;
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) + 1);
- if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FROM_FINALLY)) {
- EX(fast_ret) = &EX(func)->op_array.opcodes[EX(fast_ret)->op2.opline_num];
+ USE_OPLINE
+ zval *fast_call = EX_VAR(opline->op1.var);
+
+ if (fast_call->u2.lineno != (uint32_t)-1) {
+ const zend_op *fast_ret = EX(func)->op_array.opcodes + fast_call->u2.lineno;
+ ZEND_VM_SET_OPCODE(fast_ret + 1);
+ if (fast_ret->extended_value & ZEND_FAST_CALL_FROM_FINALLY) {
+ fast_call->u2.lineno = fast_ret->op2.opline_num;
}
ZEND_VM_CONTINUE();
} else {
@@ -1384,8 +1404,8 @@ static int ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
ZEND_VM_CONTINUE();
} else {
- EG(exception) = EX(delayed_exception);
- EX(delayed_exception) = NULL;
+ EG(exception) = Z_OBJ_P(fast_call);
+ Z_OBJ_P(fast_call) = NULL;
if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
ZEND_VM_CONTINUE();