From c69781393cd42db7479d24f39e0f55f1b7f1d355 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 26 Jun 2014 23:51:14 +0400 Subject: [PATCH] Refactoring: merge call_frame and end_execute_data into single data structure. Keep only single copy of each argument on VM stack (previously ZE kept two copies of each arguments for user functions) --- Zend/zend_API.c | 2 +- Zend/zend_builtin_functions.c | 114 +++--- Zend/zend_closures.c | 2 +- Zend/zend_compile.c | 42 +-- Zend/zend_compile.h | 60 ++- Zend/zend_execute.c | 285 +++++++------- Zend/zend_execute.h | 132 +++---- Zend/zend_execute_API.c | 88 +++-- Zend/zend_generators.c | 81 ++-- Zend/zend_opcode.c | 2 - Zend/zend_vm_def.h | 413 ++++++++++---------- Zend/zend_vm_execute.h | 685 +++++++++++++++++----------------- Zend/zend_vm_execute.skl | 15 +- ext/phar/phar_object.c | 4 + ext/spl/php_spl.c | 4 + sapi/fpm/fpm/fpm_php_trace.c | 10 +- 16 files changed, 996 insertions(+), 943 deletions(-) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 569a21fdc4..a3d37793db 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -142,7 +142,7 @@ ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array TS if (Z_REFCOUNTED_P(param_ptr)) { Z_ADDREF_P(param_ptr); } - add_next_index_zval(argument_array, param_ptr); + zend_hash_next_index_insert_new(Z_ARRVAL_P(argument_array), param_ptr); param_ptr++; } diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index f0ed68b703..15c1d68970 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -394,10 +394,10 @@ ZEND_FUNCTION(gc_disable) Get the number of arguments that were passed to the function */ ZEND_FUNCTION(func_num_args) { - zend_execute_data *ex = EG(current_execute_data)->prev_execute_data; + zend_execute_data *ex = EG(current_execute_data); - if (ex && ex->call) { - RETURN_LONG(ex->call->num_args); + if (ex->frame_kind == VM_FRAME_NESTED_FUNCTION || ex->frame_kind == VM_FRAME_TOP_FUNCTION) { + RETURN_LONG(ex->num_args); } else { zend_error(E_WARNING, "func_num_args(): Called from the global scope - no function context"); RETURN_LONG(-1); @@ -412,7 +412,7 @@ ZEND_FUNCTION(func_get_arg) int arg_count; zval *arg; long requested_offset; - zend_execute_data *ex = EG(current_execute_data)->prev_execute_data; + zend_execute_data *ex; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &requested_offset) == FAILURE) { return; @@ -423,19 +423,24 @@ ZEND_FUNCTION(func_get_arg) RETURN_FALSE; } - if (!ex || !ex->call) { + ex = EG(current_execute_data); + if (ex->frame_kind != VM_FRAME_NESTED_FUNCTION && ex->frame_kind != VM_FRAME_TOP_FUNCTION) { zend_error(E_WARNING, "func_get_arg(): Called from the global scope - no function context"); RETURN_FALSE; } - arg_count = ex->call->num_args; + arg_count = ex->num_args; if (requested_offset >= arg_count) { zend_error(E_WARNING, "func_get_arg(): Argument %ld not passed to function", requested_offset); RETURN_FALSE; } - arg = ZEND_CALL_ARG(ex->call, requested_offset + 1); + if (ex->extra_args && requested_offset >= ex->func->op_array.num_args) { + arg = ex->extra_args + (requested_offset - ex->func->op_array.num_args); + } else { + arg = ZEND_CALL_ARG(ex, requested_offset + 1); + } RETURN_ZVAL_FAST(arg); } /* }}} */ @@ -447,23 +452,39 @@ ZEND_FUNCTION(func_get_args) zval *p; int arg_count; int i; - zend_execute_data *ex = EG(current_execute_data)->prev_execute_data; + zend_execute_data *ex = EG(current_execute_data); - if (!ex || !ex->call) { + if (ex->frame_kind != VM_FRAME_NESTED_FUNCTION && ex->frame_kind != VM_FRAME_TOP_FUNCTION) { zend_error(E_WARNING, "func_get_args(): Called from the global scope - no function context"); RETURN_FALSE; } - arg_count = ex->call->num_args; + arg_count = ex->num_args; array_init_size(return_value, arg_count); if (arg_count) { Bucket *q; - p = ZEND_CALL_ARG(ex->call, 1); zend_hash_real_init(Z_ARRVAL_P(return_value), 1); + i = 0; q = Z_ARRVAL_P(return_value)->arData; - for (i=0; iextra_args) { + while (i < ex->func->op_array.num_args) { + q->h = i; + q->key = NULL; + if (!Z_ISREF_P(p)) { + ZVAL_COPY(&q->val, p); + } else { + ZVAL_DUP(&q->val, Z_REFVAL_P(p)); + } + p++; + q++; + i++; + } + p = ex->extra_args; + } + while (i < arg_count) { q->h = i; q->key = NULL; if (!Z_ISREF_P(p)) { @@ -473,6 +494,7 @@ ZEND_FUNCTION(func_get_args) } p++; q++; + i++; } Z_ARRVAL_P(return_value)->nNumUsed = i; Z_ARRVAL_P(return_value)->nNumOfElements = i; @@ -1954,24 +1976,30 @@ ZEND_FUNCTION(get_defined_constants) /* }}} */ -static void debug_backtrace_get_args(zend_call_frame *call, zval *arg_array TSRMLS_DC) +static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array TSRMLS_DC) { - zval *p; - zval *arg; - int arg_count = call->num_args; + int num_args = call->num_args; - array_init_size(arg_array, arg_count); - if (arg_count > 0) { - p = ZEND_CALL_ARG(call, 1); + array_init_size(arg_array, num_args); + if (num_args) { + int i = 0; + zval *p = ZEND_CALL_ARG(call, 1); - while (--arg_count >= 0) { - arg = p++; - if (arg) { - if (Z_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); - add_next_index_zval(arg_array, arg); - } else { - add_next_index_null(arg_array); + if (call->extra_args) { + while (i < call->func->op_array.num_args) { + if (Z_REFCOUNTED_P(p)) Z_ADDREF_P(p); + zend_hash_next_index_insert_new(Z_ARRVAL_P(arg_array), p); + p++; + i++; } + p = call->extra_args; + } + + while (i < num_args) { + if (Z_REFCOUNTED_P(p)) Z_ADDREF_P(p); + zend_hash_next_index_insert_new(Z_ARRVAL_P(arg_array), p); + p++; + i++; } } } @@ -2025,7 +2053,7 @@ ZEND_FUNCTION(debug_print_backtrace) skip = ptr; /* skip internal handler */ - if (!skip->op_array && + if ((!skip->func || (skip->func->common.type != ZEND_USER_FUNCTION && skip->func->common.type != ZEND_EVAL_CODE)) && skip->prev_execute_data && skip->prev_execute_data->opline && skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL && @@ -2033,8 +2061,8 @@ ZEND_FUNCTION(debug_print_backtrace) skip = skip->prev_execute_data; } - if (skip->op_array) { - filename = skip->op_array->filename->val; + if (skip->func && (skip->func->common.type == ZEND_USER_FUNCTION || skip->func->common.type == ZEND_EVAL_CODE)) { + filename = skip->func->op_array.filename->val; lineno = skip->opline->lineno; } else { filename = NULL; @@ -2060,7 +2088,7 @@ ZEND_FUNCTION(debug_print_backtrace) (func->common.function_name ? func->common.function_name->val : NULL); } else { - func = (zend_function*)(ptr->op_array); + func = ptr->func; function_name = func && func->common.function_name ? func->common.function_name->val : NULL; } @@ -2081,7 +2109,7 @@ ZEND_FUNCTION(debug_print_backtrace) class_name = NULL; call_type = NULL; } - if (!ptr->opline || ptr->opline->opcode == ZEND_DO_FCALL) { + if (func->type != ZEND_EVAL_CODE) { if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0) { debug_backtrace_get_args(ptr->call, &arg_array TSRMLS_CC); } @@ -2144,12 +2172,13 @@ ZEND_FUNCTION(debug_print_backtrace) while (prev) { if (prev->call && prev->call->func && - prev->call->func->common.type != ZEND_USER_FUNCTION) { + prev->call->func->common.type != ZEND_USER_FUNCTION && + prev->call->func->common.type != ZEND_EVAL_CODE) { prev = NULL; break; } - if (prev->op_array) { - zend_printf(") called at [%s:%d]\n", prev->op_array->filename->val, prev->opline->lineno); + if (prev->func && (prev->func->common.type == ZEND_USER_FUNCTION || prev->func->common.type == ZEND_EVAL_CODE)) { + zend_printf(") called at [%s:%d]\n", prev->func->op_array.filename->val, prev->opline->lineno); break; } prev = prev->prev_execute_data; @@ -2201,7 +2230,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int skip = ptr; /* skip internal handler */ - if (!skip->op_array && + if ((!skip->func || (skip->func->common.type != ZEND_USER_FUNCTION && skip->func->common.type != ZEND_EVAL_CODE)) && skip->prev_execute_data && skip->prev_execute_data->opline && skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL && @@ -2209,8 +2238,8 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int skip = skip->prev_execute_data; } - if (skip->op_array) { - filename = skip->op_array->filename->val; + if (skip->func && (skip->func->common.type == ZEND_USER_FUNCTION || skip->func->common.type == ZEND_EVAL_CODE)) { + filename = skip->func->op_array.filename->val; lineno = skip->opline->lineno; add_assoc_string_ex(&stack_frame, "file", sizeof("file")-1, (char*)filename); add_assoc_long_ex(&stack_frame, "line", sizeof("line")-1, lineno); @@ -2225,13 +2254,14 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int if (prev->call && prev->call->func && prev->call->func->common.type != ZEND_USER_FUNCTION && + prev->call->func->common.type != ZEND_EVAL_CODE && !(prev->call->func->common.type == ZEND_INTERNAL_FUNCTION && (prev->call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER))) { break; } - if (prev->op_array) { + if (prev->func && (prev->func->common.type == ZEND_USER_FUNCTION || prev->func->common.type == ZEND_EVAL_CODE)) { // TODO: we have to duplicate it, becaise it may be stored in opcache SHM ??? - add_assoc_str_ex(&stack_frame, "file", sizeof("file")-1, STR_DUP(prev->op_array->filename, 0)); + add_assoc_str_ex(&stack_frame, "file", sizeof("file")-1, STR_DUP(prev->func->op_array.filename, 0)); add_assoc_long_ex(&stack_frame, "line", sizeof("line")-1, prev->opline->lineno); break; } @@ -2259,7 +2289,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int (func->common.function_name ? func->common.function_name->val : NULL); } else { - func = (zend_function*)(ptr->op_array); + func = ptr->func; function_name = func && func->common.function_name ? func->common.function_name->val : NULL; } @@ -2289,7 +2319,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int } if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0 && - (!ptr->opline || ptr->opline->opcode == ZEND_DO_FCALL)) { + func->type != ZEND_EVAL_CODE) { if (ptr->call) { zval args; debug_backtrace_get_args(ptr->call, &args TSRMLS_CC); @@ -2346,7 +2376,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int add_assoc_string_ex(&stack_frame, "function", sizeof("function")-1, (char*)function_name); } - add_next_index_zval(return_value, &stack_frame); + zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &stack_frame); include_filename = filename; diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 85056d3cd5..053a5eb199 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -213,7 +213,7 @@ static void zend_closure_free_storage(zend_object *object TSRMLS_DC) /* {{{ */ if (closure->func.type == ZEND_USER_FUNCTION) { zend_execute_data *ex = EG(current_execute_data); while (ex) { - if (ex->op_array == &closure->func.op_array) { + if (ex->func == &closure->func) { zend_error(E_ERROR, "Cannot destroy active lambda function"); } ex = ex->prev_execute_data; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 690020a67d..0434e7c754 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -97,9 +97,9 @@ ZEND_API zend_compiler_globals compiler_globals; ZEND_API zend_executor_globals executor_globals; #endif -static void zend_push_function_call_entry(zend_function *fbc TSRMLS_DC) /* {{{ */ +static void zend_push_function_call_entry(zend_function *fbc, zend_uint opline_num TSRMLS_DC) /* {{{ */ { - zend_function_call_entry fcall = { fbc }; + zend_function_call_entry fcall = { fbc, opline_num }; zend_stack_push(&CG(function_call_stack), &fcall); } /* }}} */ @@ -182,7 +182,6 @@ void zend_init_compiler_context(TSRMLS_D) /* {{{ */ CG(context).literals_size = 0; CG(context).current_brk_cont = -1; CG(context).backpatch_count = 0; - CG(context).used_stack = 0; CG(context).in_finally = 0; CG(context).labels = NULL; } @@ -1949,6 +1948,7 @@ void zend_do_receive_param(zend_uchar op, znode *varname, znode *initialization, int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ { zend_op *opline; + zend_uint op_number; zend_function *function; zend_string *lcname; char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant)); @@ -1977,14 +1977,14 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace STR_RELEASE(Z_STR(function_name->u.constant)); Z_STR(function_name->u.constant) = lcname; + op_number = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_FCALL; SET_UNUSED(opline->op1); SET_NODE(opline->op2, function_name); GET_CACHE_SLOT(opline->op2.constant); - zend_push_function_call_entry(function TSRMLS_CC); - CG(context).used_stack += ZEND_CALL_FRAME_SLOT; + zend_push_function_call_entry(function, op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); return 0; } @@ -2035,8 +2035,7 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ } } - zend_push_function_call_entry(NULL TSRMLS_CC); - CG(context).used_stack += ZEND_CALL_FRAME_SLOT; + zend_push_function_call_entry(NULL, last_op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); } /* }}} */ @@ -2056,8 +2055,10 @@ void zend_do_clone(znode *result, znode *expr TSRMLS_DC) /* {{{ */ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRMLS_DC) /* {{{ */ { + zend_uint op_number; zend_op *opline; + op_number = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); if (ns_call) { /* In run-time PHP will check for function with full name and @@ -2079,8 +2080,7 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML } } - zend_push_function_call_entry(NULL TSRMLS_CC); - CG(context).used_stack += ZEND_CALL_FRAME_SLOT; + zend_push_function_call_entry(NULL, op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); } /* }}} */ @@ -2477,6 +2477,7 @@ void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_c int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */ { znode class_node; + zend_uint op_number; zend_op *opline; if (method_name->op_type == IS_CONST) { @@ -2497,11 +2498,12 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) { zend_resolve_class_name(class_name TSRMLS_CC); class_node = *class_name; + op_number = get_next_op_number(CG(active_op_array) TSRMLS_CC); opline = get_next_op(CG(active_op_array) TSRMLS_CC); } else { zend_do_fetch_class(&class_node, class_name TSRMLS_CC); + op_number = get_next_op_number(CG(active_op_array) TSRMLS_CC); opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->extended_value = class_node.EA ; } opline->opcode = ZEND_INIT_STATIC_METHOD_CALL; if (class_node.op_type == IS_CONST) { @@ -2524,8 +2526,7 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na SET_NODE(opline->op2, method_name); } - zend_push_function_call_entry(NULL TSRMLS_CC); - CG(context).used_stack += ZEND_CALL_FRAME_SLOT; + zend_push_function_call_entry(NULL, op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); return 1; /* Dynamic */ } @@ -2543,6 +2544,9 @@ void zend_do_end_function_call(znode *function_name, znode *result, int is_metho } opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)]; } else { + opline = &CG(active_op_array)->opcodes[fcall->op_number]; + opline->extended_value = fcall->arg_num; + opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_DO_FCALL; SET_UNUSED(opline->op1); @@ -2554,10 +2558,6 @@ void zend_do_end_function_call(znode *function_name, znode *result, int is_metho GET_NODE(result, opline->result); opline->extended_value = fcall->arg_num; - if (CG(context).used_stack > CG(active_op_array)->used_stack) { - CG(active_op_array)->used_stack = CG(context).used_stack; - } - CG(context).used_stack -= ZEND_CALL_FRAME_SLOT + fcall->arg_num; zend_stack_del_top(&CG(function_call_stack)); } /* }}} */ @@ -2666,8 +2666,6 @@ void zend_do_pass_param(znode *param, zend_uchar op TSRMLS_DC) /* {{{ */ SET_NODE(opline->op1, param); opline->op2.opline_num = fcall->arg_num; SET_UNUSED(opline->op2); - - CG(context).used_stack++; } /* }}} */ @@ -5578,8 +5576,7 @@ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /* SET_NODE(opline->op1, class_type); SET_UNUSED(opline->op2); - zend_push_function_call_entry(NULL TSRMLS_CC); - CG(context).used_stack += ZEND_CALL_FRAME_SLOT; + zend_push_function_call_entry(NULL, new_token->u.op.opline_num TSRMLS_CC); } /* }}} */ @@ -5771,6 +5768,7 @@ void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC) /* {{{ */ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_FCALL; + opline->extended_value = 1; SET_UNUSED(opline->op1); opline->op2_type = IS_CONST; LITERAL_STR(opline->op2, STR_INIT("shell_exec", sizeof("shell_exec")-1, 0)); @@ -5800,10 +5798,6 @@ void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC) /* {{{ */ SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); GET_NODE(result, opline->result); - - if (CG(context).used_stack + ZEND_CALL_FRAME_SLOT + 1 > CG(active_op_array)->used_stack) { - CG(active_op_array)->used_stack = CG(context).used_stack + ZEND_CALL_FRAME_SLOT + 1; - } } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 35be52f2f7..46732f25d0 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -59,7 +59,6 @@ typedef struct _zend_compiler_context { int literals_size; int current_brk_cont; int backpatch_count; - int used_stack; int in_finally; HashTable *labels; } zend_compiler_context; @@ -265,8 +264,6 @@ struct _zend_op_array { zend_uint T; - zend_uint used_stack; - zend_brk_cont_element *brk_cont_array; int last_brk_cont; @@ -336,6 +333,7 @@ union _zend_function { typedef struct _zend_function_call_entry { zend_function *fbc; + zend_uint op_number; zend_uint arg_num; zend_bool uses_argument_unpacking; } zend_function_call_entry; @@ -353,27 +351,6 @@ typedef struct _list_llist_element { znode value; } list_llist_element; -typedef struct _zend_call_frame zend_call_frame; - -struct _zend_call_frame { - zend_function *func; - zend_uint num_args; - zend_uint flags; - zend_class_entry *called_scope; - zend_object *object; - zend_call_frame *prev; -}; - -#define ZEND_CALL_CTOR (1 << 0) -#define ZEND_CALL_CTOR_RESULT_USED (1 << 1) -#define ZEND_CALL_DONE (1 << 2) - -#define ZEND_CALL_FRAME_SLOT \ - ((ZEND_MM_ALIGNED_SIZE(sizeof(zend_call_frame)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))) - -#define ZEND_CALL_ARG(call, n) \ - (((zval*)(call)) + ((n) + (ZEND_CALL_FRAME_SLOT - 1))) - typedef enum _vm_frame_kind { VM_FRAME_NESTED_FUNCTION, /* stackless VM call to function */ VM_FRAME_NESTED_CODE, /* stackless VM call to include/require/eval */ @@ -383,26 +360,39 @@ typedef enum _vm_frame_kind { struct _zend_execute_data { struct _zend_op *opline; /* executed opline */ - zend_op_array *op_array; /* executed op_array */ - zend_call_frame *call; /* current call */ - zend_object *object; /* current $this */ + zend_function *func; /* executed op_array */ + zend_execute_data *call; /* current call */ + zend_uint num_args; + zend_uint flags; + zend_class_entry *called_scope; + zend_object *object; + zend_execute_data *prev_nested_call; zend_class_entry *scope; /* function scope (self) */ - zend_class_entry *called_scope; /* function called scope (static) */ zend_array *symbol_table; void **run_time_cache; zend_execute_data *prev_execute_data; zval *return_value; + zval *extra_args; vm_frame_kind frame_kind; - // TODO: simplify call sequence and remove call_* ??? - zval old_error_reporting; - struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */ - zend_object *delayed_exception; + zval old_error_reporting; + struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */ + zend_object *delayed_exception; }; +#define ZEND_CALL_CTOR (1 << 0) +#define ZEND_CALL_CTOR_RESULT_USED (1 << 1) +#define ZEND_CALL_DONE (1 << 2) + +#define ZEND_CALL_FRAME_SLOT \ + ((ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))) + +#define ZEND_CALL_ARG(call, n) \ + (((zval*)(call)) + ((n) + (ZEND_CALL_FRAME_SLOT - 1))) + #define EX(element) execute_data.element #define EX_VAR_2(ex, n) ((zval*)(((char*)(ex)) + ((int)(n)))) -#define EX_VAR_NUM_2(ex, n) (((zval*)(((char*)(ex))+ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data))))+(n)) +#define EX_VAR_NUM_2(ex, n) (((zval*)(ex)) + (ZEND_CALL_FRAME_SLOT + ((int)(n)))) #define EX_VAR(n) EX_VAR_2(execute_data, n) #define EX_VAR_NUM(n) EX_VAR_NUM_2(execute_data, n) @@ -732,8 +722,8 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC); #define ZEND_FETCH_CLASS_DEFAULT 0 #define ZEND_FETCH_CLASS_SELF 1 #define ZEND_FETCH_CLASS_PARENT 2 -#define ZEND_FETCH_CLASS_MAIN 3 /* unused */ -#define ZEND_FETCH_CLASS_GLOBAL 4 /* unused */ +#define ZEND_FETCH_CLASS_MAIN 3 /* unused ??? */ +#define ZEND_FETCH_CLASS_GLOBAL 4 /* unused ??? */ #define ZEND_FETCH_CLASS_AUTO 5 #define ZEND_FETCH_CLASS_INTERFACE 6 #define ZEND_FETCH_CLASS_STATIC 7 diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 4e5b811d7e..e6e45674d0 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -525,12 +525,13 @@ ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ul } } -ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind TSRMLS_DC) +ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC) { zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data; const char *fname = zf->common.function_name->val; const char *fsep; const char *fclass; + zval old_arg; if (zf->common.scope) { fsep = "::"; @@ -540,11 +541,20 @@ ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zen fclass = ""; } - if (ptr && ptr->op_array) { - zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind, ptr->op_array->filename->val, ptr->opline->lineno); + if (arg && zf->common.type == ZEND_USER_FUNCTION) { + ZVAL_COPY_VALUE(&old_arg, arg); + ZVAL_UNDEF(arg); + } + + if (ptr && ptr->func && (ptr->func->common.type == ZEND_USER_FUNCTION || ptr->func->common.type == ZEND_EVAL_CODE)) { + zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind, ptr->func->op_array.filename->val, ptr->opline->lineno); } else { zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind); } + + if (arg && zf->common.type == ZEND_USER_FUNCTION) { + ZVAL_COPY_VALUE(arg, &old_arg); + } } static void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type TSRMLS_DC) @@ -572,21 +582,21 @@ static void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg if (Z_TYPE_P(arg) == IS_OBJECT) { need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg TSRMLS_CC); } } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) { need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg TSRMLS_CC); } } else if (cur_arg_info->type_hint) { if (cur_arg_info->type_hint == IS_ARRAY) { ZVAL_DEREF(arg); if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg TSRMLS_CC); } } else if (cur_arg_info->type_hint == IS_CALLABLE) { if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg TSRMLS_CC); } #if ZEND_DEBUG } else { @@ -618,12 +628,12 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, zend_uint arg_ char *class_name; need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "", NULL TSRMLS_CC); } else if (cur_arg_info->type_hint) { if (cur_arg_info->type_hint == IS_ARRAY) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "", NULL TSRMLS_CC); } else if (cur_arg_info->type_hint == IS_CALLABLE) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "", NULL TSRMLS_CC); #if ZEND_DEBUG } else { zend_error(E_ERROR, "Unknown typehint"); @@ -635,15 +645,15 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, zend_uint arg_ static void zend_verify_missing_arg(zend_execute_data *execute_data, zend_uint arg_num TSRMLS_DC) { - if (EXPECTED(!(EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) || - zend_verify_missing_arg_type((zend_function *) EX(op_array), arg_num, EX(opline)->extended_value TSRMLS_CC)) { - const char *class_name = EX(op_array)->scope ? EX(op_array)->scope->name->val : ""; - const char *space = EX(op_array)->scope ? "::" : ""; - const char *func_name = EX(op_array)->function_name ? EX(op_array)->function_name->val : "main"; + if (EXPECTED(!(EX(func)->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) || + zend_verify_missing_arg_type(EX(func), arg_num, EX(opline)->extended_value TSRMLS_CC)) { + const char *class_name = EX(func)->common.scope ? EX(func)->common.scope->name->val : ""; + const char *space = EX(func)->common.scope ? "::" : ""; + const char *func_name = EX(func)->common.function_name ? EX(func)->common.function_name->val : "main"; zend_execute_data *ptr = EX(prev_execute_data); - if(ptr && ptr->op_array) { - zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", arg_num, class_name, space, func_name, ptr->op_array->filename->val, ptr->opline->lineno); + if (ptr && ptr->func && (ptr->func->common.type == ZEND_USER_FUNCTION || ptr->func->common.type == ZEND_EVAL_CODE)) { + zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", arg_num, class_name, space, func_name, ptr->func->op_array.filename->val, ptr->opline->lineno); } else { zend_error(E_WARNING, "Missing argument %u for %s%s%s()", arg_num, class_name, space, func_name); } @@ -1495,9 +1505,9 @@ void zend_clean_and_cache_symbol_table(zend_array *symbol_table TSRMLS_DC) /* {{ static zend_always_inline void i_free_compiled_variables(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */ { - if (EXPECTED(EX(op_array)->last_var > 0)) { + if (EXPECTED(EX(func)->op_array.last_var > 0)) { zval *cv = EX_VAR_NUM(0); - zval *end = cv + EX(op_array)->last_var; + zval *end = cv + EX(func)->op_array.last_var; do { zval_ptr_dtor(cv); cv++; @@ -1517,104 +1527,22 @@ void zend_free_compiled_variables(zend_execute_data *execute_data TSRMLS_DC) /* * ================== * * +========================================+ - * | zend_execute_data |<---+ - * | EX(function_state).arguments |--+ | - * | ... | | | - * | ARGUMENT [1] | | | - * | ... | | | - * | ARGUMENT [ARGS_NUMBER] | | | - * | ARGS_NUMBER |<-+ | - * +========================================+ | - * | - * +========================================+ | - * EG(current_execute_data) -> | zend_execute_data | | - * | EX(prev_execute_data) |----+ + * EG(current_execute_data) -> | zend_execute_data | * +----------------------------------------+ - * EX_CV_NUM(0) ---------> | VAR[0] | + * EX_CV_NUM(0) ---------> | VAR[0] = ARG[1] | * | ... | * | VAR[op_array->last_var-1] | * | VAR[op_array->last_var] | * | ... | * | VAR[op_array->last_var+op_array->T-1] | - * zend_vm_stack_frame_base -> +----------------------------------------+ - * EX(call_slot) -> | CALL_SLOT | - * +----------------------------------------+ - * | ARGUMENTS STACK [0] | - * | ... | - * zend_vm_stack_top --------> | ... | - * | ... | - * | ARGUMENTS STACK [op_array->used_stack] | * +----------------------------------------+ */ -static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */ +static zend_always_inline void i_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */ { - zend_execute_data *execute_data; - - /* - * When allocating the execute_data, memory for compiled variables and - * temporary variables is also allocated before and after the actual - * zend_execute_data struct. In addition we also allocate space to store - * information about syntactically nested called functions and actual - * parameters. op_array->last_var specifies the number of compiled - * variables and op_array->T is the number of temporary variables. If there - * is no symbol table, then twice as much memory is allocated for compiled - * variables. In that case the first half contains zval**s and the second - * half the actual zval*s (which would otherwise be in the symbol table). - */ - size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)); - size_t vars_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval)) * (op_array->last_var + op_array->T); - size_t stack_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval)) * op_array->used_stack; - size_t total_size = execute_data_size + vars_size + stack_size; - - /* - * Normally the execute_data is allocated on the VM stack (because it does - * not actually do any allocation and thus is faster). For generators - * though this behavior would be suboptimal, because the (rather large) - * structure would have to be copied back and forth every time execution is - * suspended or resumed. That's why for generators the execution context - * is allocated using a separate VM stack, thus allowing to save and - * restore it simply by replacing a pointer. The same segment also keeps - * a copy of previous execute_data and passed parameters. - */ - if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_GENERATOR) != 0)) { - /* Prepend the regular stack frame with a copy of prev_execute_data - * and the passed arguments - */ - int args_count = zend_vm_stack_get_args_count_ex(EG(current_execute_data)); - size_t args_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval)) * (ZEND_CALL_FRAME_SLOT + args_count); - - total_size += args_size + execute_data_size; - - EG(argument_stack) = zend_vm_stack_new_page((total_size + (sizeof(zval) - 1)) / sizeof(zval)); - EG(argument_stack)->prev = NULL; - execute_data = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + execute_data_size + args_size); - - /* copy prev_execute_data */ - EX(prev_execute_data) = (zend_execute_data*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)); - memset(EX(prev_execute_data), 0, sizeof(zend_execute_data)); - EX(prev_execute_data)->call = (zend_call_frame*)(((char*)EX(prev_execute_data)) + sizeof(zend_execute_data)); - EX(prev_execute_data)->call->func = (zend_function*)op_array; - EX(prev_execute_data)->call->num_args = args_count; - EX(prev_execute_data)->call->flags = ZEND_CALL_DONE; - EX(prev_execute_data)->call->called_scope = NULL; - EX(prev_execute_data)->call->object = NULL; - EX(prev_execute_data)->call->prev = NULL; - - /* copy arguments */ - if (args_count > 0) { - zval *arg_src = zend_vm_stack_get_arg_ex(EG(current_execute_data), 1); - zval *arg_dst = zend_vm_stack_get_arg_ex(EX(prev_execute_data), 1); - int i; - - for (i = 0; i < args_count; i++) { - ZVAL_COPY(arg_dst + i, arg_src + i); - } - } - } else { - execute_data = zend_vm_stack_alloc(total_size TSRMLS_CC); - EX(prev_execute_data) = EG(current_execute_data); - } + ZEND_ASSERT(EX(func) == (zend_function*)op_array); + ZEND_ASSERT(EX(object) == Z_OBJ(EG(This))); + ZEND_ASSERT(EX(called_scope) == EG(called_scope)); EX(return_value) = return_value; EX(frame_kind) = frame_kind; @@ -1624,23 +1552,32 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array EG(opline_ptr) = &EX(opline); EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes; - EX(op_array) = op_array; - EX(object) = Z_OBJ(EG(This)); +//??? EX(func) = (zend_function*)op_array; EX(scope) = EG(scope); - EX(called_scope) = EG(called_scope); EX(symbol_table) = EG(active_symbol_table); - if (EX(symbol_table)) { + if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_attach_symbol_table(execute_data); } else { + + if (UNEXPECTED(EX(num_args) > op_array->num_args)) { + /* move extra args into separate array */ + EX(extra_args) = safe_emalloc(EX(num_args) - op_array->num_args, sizeof(zval), 0); + memcpy(EX(extra_args), EX_VAR_NUM(op_array->num_args), sizeof(zval) * (EX(num_args) - op_array->num_args)); + } + do { - /* Initialize CV variables */ - zval *var = EX_VAR_NUM(0); - zval *end = var + op_array->last_var; + /* Initialize CV variables (skip arguments) */ + int num_args = MIN(op_array->num_args, EX(num_args)); + + if (EXPECTED(num_args < op_array->last_var)) { + zval *var = EX_VAR_NUM(num_args); + zval *end = EX_VAR_NUM(op_array->last_var); - while (var != end) { - ZVAL_UNDEF(var); - var++; + do { + ZVAL_UNDEF(var); + var++; + } while (var != end); } } while (0); @@ -1659,64 +1596,120 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array } EX(run_time_cache) = op_array->run_time_cache; - EG(argument_stack)->top = (zval*)zend_vm_stack_frame_base(execute_data); EG(current_execute_data) = execute_data; +} +/* }}} */ + +ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_op_array *op_array, zval *return_value TSRMLS_DC) /* {{{ */ +{ + /* + * Normally the execute_data is allocated on the VM stack (because it does + * not actually do any allocation and thus is faster). For generators + * though this behavior would be suboptimal, because the (rather large) + * structure would have to be copied back and forth every time execution is + * suspended or resumed. That's why for generators the execution context + * is allocated using a separate VM stack, thus allowing to save and + * restore it simply by replacing a pointer. + */ + zend_execute_data *execute_data; + zend_uint num_args = EG(current_execute_data)->call->num_args; + + EG(argument_stack) = zend_vm_stack_new_page( + MAX(ZEND_VM_STACK_PAGE_SIZE, + ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args))); + EG(argument_stack)->prev = NULL; + + execute_data = zend_vm_stack_push_call_frame( + (zend_function*)op_array, + num_args, + EG(current_execute_data)->call->flags, + EG(current_execute_data)->call->called_scope, + EG(current_execute_data)->call->object, + NULL TSRMLS_CC); + execute_data->num_args = num_args; + + /* copy arguments */ + if (num_args > 0) { + zval *arg_src = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); + zval *arg_dst = ZEND_CALL_ARG(execute_data, 1); + int i; + + for (i = 0; i < num_args; i++) { + ZVAL_COPY_VALUE(arg_dst + i, arg_src + i); + } + } + + i_init_execute_data(execute_data, op_array, return_value, VM_FRAME_TOP_FUNCTION TSRMLS_CC); return execute_data; } /* }}} */ -ZEND_API zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */ +ZEND_API zend_execute_data *zend_create_execute_data(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */ { - return i_create_execute_data_from_op_array(op_array, return_value, frame_kind TSRMLS_CC); + zend_execute_data *execute_data; + + execute_data = EG(current_execute_data)->call; + EX(prev_execute_data) = EG(current_execute_data); + i_init_execute_data(execute_data, op_array, return_value, frame_kind TSRMLS_CC); + + return execute_data; } /* }}} */ -static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(zend_op *opline, zend_call_frame *call TSRMLS_DC) /* {{{ */ +static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(zend_op *opline, zend_execute_data *call TSRMLS_DC) /* {{{ */ { zend_uint arg_num = opline->extended_value & ZEND_FETCH_ARG_MASK; return ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num); } /* }}} */ -static zend_call_frame *zend_vm_stack_copy_call_frame(zend_call_frame *call TSRMLS_DC) /* {{{ */ +static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, zend_uint passed_args, zend_uint additional_args TSRMLS_DC) /* {{{ */ { - zend_uint count; - zend_call_frame *new_call; - zend_vm_stack p = EG(argument_stack); + zend_execute_data *new_call; + int used_stack = (EG(argument_stack)->top - (zval*)call) + additional_args; + + /* copy call frame into new stack segment */ + zend_vm_stack_extend(used_stack TSRMLS_CC); + new_call = (zend_execute_data*)EG(argument_stack)->top; + EG(argument_stack)->top += used_stack; + *new_call = *call; + if (passed_args) { + zval *src = ZEND_CALL_ARG(call, 1); + zval *dst = ZEND_CALL_ARG(new_call, 1); + do { + ZVAL_COPY_VALUE(dst, src); + passed_args--; + src++; + dst++; + } while (passed_args); + } - zend_vm_stack_extend(ZEND_CALL_FRAME_SLOT + call->num_args TSRMLS_CC); + /* delete old call_frame from previous stack segment */ + EG(argument_stack)->prev->top = (zval*)call; - new_call = (zend_call_frame*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)); - *new_call = *call; - EG(argument_stack)->top += ZEND_CALL_FRAME_SLOT + call->num_args; - count = call->num_args; - while (count-- > 0) { - zval *data = --p->top; - ZVAL_COPY_VALUE(ZEND_CALL_ARG(new_call, count), data); - - if (UNEXPECTED(p->top == ZEND_VM_STACK_ELEMETS(p))) { - zend_vm_stack r = p; - - EG(argument_stack)->prev = p->prev; - p = p->prev; - efree(r); - } + /* delete previous stack segment if it becames empty */ + if (UNEXPECTED(EG(argument_stack)->prev->top == ZEND_VM_STACK_ELEMETS(EG(argument_stack)->prev))) { + zend_vm_stack r = EG(argument_stack)->prev; + + EG(argument_stack)->prev = r->prev; + efree(r); } + return new_call; } /* }}} */ -static zend_always_inline void zend_vm_stack_adjust_call_frame(zend_call_frame **call TSRMLS_DC) /* {{{ */ +static zend_always_inline void zend_vm_stack_extend_call_frame(zend_execute_data **call, zend_uint passed_args, zend_uint additional_args TSRMLS_DC) /* {{{ */ { - if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < ZEND_CALL_FRAME_SLOT + (*call)->num_args) - || UNEXPECTED(EG(argument_stack)->top == EG(argument_stack)->end)) { - *call = zend_vm_stack_copy_call_frame(*call TSRMLS_CC); + if (EXPECTED(EG(argument_stack)->end - EG(argument_stack)->top > additional_args)) { + EG(argument_stack)->top += additional_args; + } else { + *call = zend_vm_stack_copy_call_frame(*call, passed_args, additional_args TSRMLS_CC); } } /* }}} */ - #define ZEND_VM_NEXT_OPCODE() \ CHECK_SYMBOL_TABLES() \ ZEND_VM_INC_OPCODE(); \ diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 49d9275bfa..2127e1f2a1 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -35,7 +35,8 @@ ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data_pt void init_executor(TSRMLS_D); void shutdown_executor(TSRMLS_D); void shutdown_destructors(TSRMLS_D); -ZEND_API zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC); +ZEND_API zend_execute_data *zend_create_execute_data(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC); +ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_op_array *op_array, zval *return_value TSRMLS_DC); ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value TSRMLS_DC); ZEND_API void execute_ex(zend_execute_data *execute_data TSRMLS_DC); ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, struct _zend_fcall_info *fci TSRMLS_DC); @@ -48,7 +49,7 @@ ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, ZEND_API int zend_eval_stringl_ex(char *str, int str_len, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ulong fetch_type, char **class_name, zend_class_entry **pce TSRMLS_DC); -ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind TSRMLS_DC); +ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC); static zend_always_inline void i_zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC TSRMLS_DC) { @@ -149,7 +150,7 @@ ZEND_API int zval_update_constant_no_inline_change(zval *pp, zend_class_entry *s ZEND_API int zval_update_constant_ex(zval *pp, zend_bool inline_change, zend_class_entry *scope TSRMLS_DC); /* dedicated Zend executor functions - do not use! */ -#define ZEND_VM_STACK_PAGE_SIZE ((16 * 1024) - 16) +#define ZEND_VM_STACK_PAGE_SIZE (16 * 1024) /* should be a power of 2 */ struct _zend_vm_stack { zval *top; @@ -157,8 +158,11 @@ struct _zend_vm_stack { zend_vm_stack prev; }; +#define ZEND_VM_STACK_HEADER_SLOT \ + ((ZEND_MM_ALIGNED_SIZE(sizeof(struct _zend_vm_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))) + #define ZEND_VM_STACK_ELEMETS(stack) \ - ((zval*)(((char*)(stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(struct _zend_vm_stack)))) + (((zval*)(stack)) + ZEND_VM_STACK_HEADER_SLOT) #define ZEND_VM_STACK_GROW_IF_NEEDED(count) \ do { \ @@ -169,10 +173,10 @@ struct _zend_vm_stack { } while (0) static zend_always_inline zend_vm_stack zend_vm_stack_new_page(int count) { - zend_vm_stack page = (zend_vm_stack)emalloc(ZEND_MM_ALIGNED_SIZE(sizeof(*page)) + sizeof(zval) * count); + zend_vm_stack page = (zend_vm_stack)emalloc(count * ZEND_MM_ALIGNED_SIZE(sizeof(zval))); page->top = ZEND_VM_STACK_ELEMETS(page); - page->end = page->top + count; + page->end = (zval*)page + count; page->prev = NULL; return page; } @@ -180,6 +184,7 @@ static zend_always_inline zend_vm_stack zend_vm_stack_new_page(int count) { static zend_always_inline void zend_vm_stack_init(TSRMLS_D) { EG(argument_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE); + EG(argument_stack)->top++; } static zend_always_inline void zend_vm_stack_destroy(TSRMLS_D) @@ -195,90 +200,87 @@ static zend_always_inline void zend_vm_stack_destroy(TSRMLS_D) static zend_always_inline void zend_vm_stack_extend(int count TSRMLS_DC) { - zend_vm_stack p = zend_vm_stack_new_page(count >= ZEND_VM_STACK_PAGE_SIZE ? count : ZEND_VM_STACK_PAGE_SIZE); + zend_vm_stack p = zend_vm_stack_new_page( + (count >= ZEND_VM_STACK_PAGE_SIZE - ZEND_VM_STACK_HEADER_SLOT) ? + ((count + ZEND_VM_STACK_HEADER_SLOT + ZEND_VM_STACK_PAGE_SIZE - 1) & ~(ZEND_VM_STACK_PAGE_SIZE-1)) : + ZEND_VM_STACK_PAGE_SIZE); p->prev = EG(argument_stack); EG(argument_stack) = p; } -static zend_always_inline zval *zend_vm_stack_top(TSRMLS_D) -{ - return EG(argument_stack)->top; -} - -static zend_always_inline zval *zend_vm_stack_top_inc(TSRMLS_D) -{ - return EG(argument_stack)->top++; -} - -static zend_always_inline void zend_vm_stack_push(zval *ptr TSRMLS_DC) -{ - ZVAL_COPY_VALUE(EG(argument_stack)->top, ptr); - EG(argument_stack)->top++; -} - -static zend_always_inline zval *zend_vm_stack_pop(TSRMLS_D) -{ - return --EG(argument_stack)->top; -} - -static zend_always_inline zend_call_frame *zend_vm_stack_push_call_frame(zend_function *func, zend_uint num_args, zend_uint flags, zend_class_entry *called_scope, zend_object *object, zend_call_frame *prev TSRMLS_DC) +static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_function *func, zend_uint num_args, zend_uint flags, zend_class_entry *called_scope, zend_object *object, zend_execute_data *prev TSRMLS_DC) { - zend_call_frame * call = (zend_call_frame*)EG(argument_stack)->top; + int used_stack = ZEND_CALL_FRAME_SLOT; + zend_execute_data *call; + + if (func && (func->type == ZEND_USER_FUNCTION || func->type == ZEND_EVAL_CODE)) { + used_stack += MAX(func->op_array.last_var + func->op_array.T, num_args); + } else { + used_stack += num_args; + } + ZEND_VM_STACK_GROW_IF_NEEDED(used_stack); + call = (zend_execute_data*)EG(argument_stack)->top; call->func = func; - call->num_args = num_args; + call->num_args = 0; //??? num_args; call->flags = flags; call->called_scope = called_scope; call->object = object; - call->prev = prev; - EG(argument_stack)->top += ZEND_CALL_FRAME_SLOT; + call->prev_nested_call = prev; + call->extra_args = NULL; + EG(argument_stack)->top += used_stack; return call; } -static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC) -{ - zval *ret; - int count = (size + (sizeof(zval) - 1)) / sizeof(zval); - - ZEND_VM_STACK_GROW_IF_NEEDED(count); - ret = (void*)EG(argument_stack)->top; - EG(argument_stack)->top += count; - return ret; -} - -static zend_always_inline zval* zend_vm_stack_frame_base(zend_execute_data *ex) -{ - return EX_VAR_NUM_2(ex, ex->op_array->last_var + ex->op_array->T); -} - -static zend_always_inline void zend_vm_stack_free(void *ptr TSRMLS_DC) +static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call TSRMLS_DC) { - if (UNEXPECTED((void*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == ptr)) { - zend_vm_stack p = EG(argument_stack); - - EG(argument_stack) = p->prev; - efree(p); - } else { - EG(argument_stack)->top = (zval*)ptr; - } + if (UNEXPECTED(call->extra_args != NULL)) { + zval *p = call->extra_args + (call->num_args - call->func->op_array.num_args); + zval *end = call->extra_args; + do { + p--; + i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC); + } while (p != end); + efree(end); + } } -static zend_always_inline void zend_vm_stack_free_call_frame(zend_call_frame *call, int nested TSRMLS_DC) +static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call TSRMLS_DC) { zend_uint num_args = call->num_args; if (num_args > 0) { - zval *p = ZEND_CALL_ARG(call, num_args + 1); - zval *end = p - num_args; - + zval *p; + zval *end; + + if (UNEXPECTED(call->extra_args != NULL)) { + p = call->extra_args + (num_args - call->func->op_array.num_args); + end = call->extra_args; + do { + p--; + i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC); + } while (p != end); + efree(end); + num_args = call->func->op_array.num_args; + } + + p = ZEND_CALL_ARG(call, num_args + 1); + end = p - num_args; do { p--; i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC); } while (p != end); } - if (nested) { - EG(argument_stack)->top = (zval*)call; +} + +static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call TSRMLS_DC) +{ + if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (zval*)call)) { + zend_vm_stack p = EG(argument_stack); + + EG(argument_stack) = p->prev; + efree(p); } else { - zend_vm_stack_free((zval*)call TSRMLS_CC); + EG(argument_stack)->top = (zval*)call; } } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index d326037b15..1efed55eb3 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -156,7 +156,6 @@ void init_executor(TSRMLS_D) /* {{{ */ EG(error_handling) = EH_NORMAL; zend_vm_stack_init(TSRMLS_C); - ZVAL_LONG(zend_vm_stack_top_inc(TSRMLS_C), 0); zend_hash_init(&EG(symbol_table).ht, 64, NULL, ZVAL_PTR_DTOR, 0); GC_REFCOUNT(&EG(symbol_table)) = 1; @@ -401,10 +400,11 @@ ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{ } return ""; } + if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) { func = EG(current_execute_data)->call->func; } else { - func = (zend_function*)EG(current_execute_data)->op_array; + func = EG(current_execute_data)->func; } switch (func->type) { case ZEND_USER_FUNCTION: @@ -436,7 +436,7 @@ ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */ if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) { func = EG(current_execute_data)->call->func; } else { - func = (zend_function*)EG(current_execute_data)->op_array; + func = EG(current_execute_data)->func; } switch (func->type) { case ZEND_USER_FUNCTION: { @@ -696,7 +696,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS EX(object) = Z_OBJ(EG(This)); EX(scope) = EG(scope); EX(called_scope) = EG(called_scope); - EX(op_array) = NULL; + EX(func) = NULL; EX(opline) = NULL; } else { /* This only happens when we're called outside any execute()'s @@ -734,8 +734,6 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS STR_RELEASE(callable_name); } - ZEND_VM_STACK_GROW_IF_NEEDED(ZEND_CALL_FRAME_SLOT + fci->param_count); - func = fci_cache->function_handler; EX(call) = zend_vm_stack_push_call_frame(func, fci->param_count, ZEND_CALL_DONE, fci_cache->called_scope, fci_cache->object, NULL TSRMLS_CC); calling_scope = fci_cache->calling_scope; @@ -783,12 +781,12 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS if (fci->no_separation && !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { - if (i || UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (EG(argument_stack)->top))) { + if (i) { /* hack to clean up the stack */ - ZVAL_LONG(&tmp, i); - zend_vm_stack_push(&tmp TSRMLS_CC); - zend_vm_stack_free_call_frame(EX(call), 0 TSRMLS_CC); + EX(call)->num_args = i; + zend_vm_stack_free_args(EX(call) TSRMLS_CC); } + zend_vm_stack_free_call_frame(EX(call) TSRMLS_CC); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", i+1, @@ -810,24 +808,26 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } else if (Z_REFCOUNTED(fci->params[i])) { Z_ADDREF(fci->params[i]); } - param = &fci->params[i]; + param = ZEND_CALL_ARG(EX(call), i+1); + ZVAL_COPY_VALUE(param, &fci->params[i]); } else if (Z_ISREF(fci->params[i]) && /* don't separate references for __call */ (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) { param = &tmp; + param = ZEND_CALL_ARG(EX(call), i+1); ZVAL_DUP(param, Z_REFVAL(fci->params[i])); } else { - param = &tmp; + param = ZEND_CALL_ARG(EX(call), i+1); ZVAL_COPY(param, &fci->params[i]); } - zend_vm_stack_push(param TSRMLS_CC); } + EX(call)->num_args = fci->param_count; EG(scope) = calling_scope; EG(called_scope) = called_scope; if (!fci->object || (func->common.fn_flags & ZEND_ACC_STATIC)) { - Z_OBJ(EG(This)) = NULL; + Z_OBJ(EG(This)) = EX(call)->object = NULL; } else { Z_OBJ(EG(This)) = fci->object; Z_ADDREF(EG(This)); @@ -873,6 +873,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } else { zend_execute_internal(&execute_data, fci TSRMLS_CC); } + zend_vm_stack_free_args(EX(call) TSRMLS_CC); + zend_vm_stack_free_call_frame(EX(call) TSRMLS_CC); + /* We shouldn't fix bad extensions here, because it can break proper ones (Bug #34045) if (!EX(function_state).function->common.return_reference) @@ -908,7 +911,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS ZVAL_UNDEF(fci->retval); } } - zend_vm_stack_free_call_frame(EX(call), 0 TSRMLS_CC); +//??? zend_vm_stack_free_call_frame(EX(call), 0 TSRMLS_CC); if (Z_OBJ(EG(This))) { zval_ptr_dtor(&EG(This)); @@ -1093,6 +1096,10 @@ ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *s zend_try { ZVAL_UNDEF(&local_retval); + if (EG(current_execute_data)) { + EG(current_execute_data)->call = zend_vm_stack_push_call_frame( + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EG(current_execute_data)->call TSRMLS_CC); + } zend_execute(new_op_array, &local_retval TSRMLS_CC); } zend_catch { destroy_op_array(new_op_array TSRMLS_CC); @@ -1596,33 +1603,34 @@ ZEND_API void zend_rebuild_symbol_table(TSRMLS_D) /* {{{ */ /* Search for last called user function */ ex = EG(current_execute_data); - while (ex && !ex->op_array) { + while (ex && (!ex->func || (ex->func->common.type != ZEND_USER_FUNCTION && ex->func->common.type != ZEND_EVAL_CODE))) { ex = ex->prev_execute_data; } - if (ex && ex->symbol_table) { + if (!ex) { + return; + } + if (ex->symbol_table) { EG(active_symbol_table) = ex->symbol_table; return; } - if (ex && ex->op_array) { - if (EG(symtable_cache_ptr)>=EG(symtable_cache)) { - /*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/ - EG(active_symbol_table) = *(EG(symtable_cache_ptr)--); - } else { - EG(active_symbol_table) = emalloc(sizeof(zend_array)); - GC_REFCOUNT(EG(active_symbol_table)) = 0; - GC_TYPE_INFO(EG(active_symbol_table)) = IS_ARRAY; - zend_hash_init(&EG(active_symbol_table)->ht, ex->op_array->last_var, NULL, ZVAL_PTR_DTOR, 0); - /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/ - } - ex->symbol_table = EG(active_symbol_table); - for (i = 0; i < ex->op_array->last_var; i++) { - zval zv; - - ZVAL_INDIRECT(&zv, EX_VAR_NUM_2(ex, i)); - zend_hash_add_new(&EG(active_symbol_table)->ht, - ex->op_array->vars[i], &zv); - } + if (EG(symtable_cache_ptr)>=EG(symtable_cache)) { + /*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/ + EG(active_symbol_table) = *(EG(symtable_cache_ptr)--); + } else { + EG(active_symbol_table) = emalloc(sizeof(zend_array)); + GC_REFCOUNT(EG(active_symbol_table)) = 0; + GC_TYPE_INFO(EG(active_symbol_table)) = IS_ARRAY; + zend_hash_init(&EG(active_symbol_table)->ht, ex->func->op_array.last_var, NULL, ZVAL_PTR_DTOR, 0); + /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/ + } + ex->symbol_table = EG(active_symbol_table); + for (i = 0; i < ex->func->op_array.last_var; i++) { + zval zv; + + ZVAL_INDIRECT(&zv, EX_VAR_NUM_2(ex, i)); + zend_hash_add_new(&EG(active_symbol_table)->ht, + ex->func->op_array.vars[i], &zv); } } } @@ -1631,7 +1639,7 @@ ZEND_API void zend_rebuild_symbol_table(TSRMLS_D) /* {{{ */ ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ */ { int i; - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; HashTable *ht = &execute_data->symbol_table->ht; /* copy real values from symbol table into CV slots and create @@ -1662,7 +1670,7 @@ ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ * ZEND_API void zend_detach_symbol_table(zend_execute_data *execute_data) /* {{{ */ { int i; - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; HashTable *ht = &execute_data->symbol_table->ht; /* copy real values from CV slots into symbol table */ @@ -1682,7 +1690,7 @@ ZEND_API int zend_set_local_var(zend_string *name, zval *value, int force TSRMLS if (!EG(active_symbol_table)) { int i; zend_execute_data *execute_data = EG(current_execute_data); - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; zend_ulong h = STR_HASH_VAL(name); if (op_array) { @@ -1715,7 +1723,7 @@ ZEND_API int zend_set_local_var_str(const char *name, int len, zval *value, int if (!EG(active_symbol_table)) { int i; zend_execute_data *execute_data = EG(current_execute_data); - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; zend_ulong h = zend_hash_func(name, len); if (op_array) { diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 2f82922b7a..f4847b0839 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -32,7 +32,7 @@ static zend_object *zend_generator_create(zend_class_entry *class_type TSRMLS_DC static void zend_generator_cleanup_unfinished_execution(zend_generator *generator TSRMLS_DC) /* {{{ */ { zend_execute_data *execute_data = generator->execute_data; - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; if (generator->send_target) { if (Z_REFCOUNTED_P(generator->send_target)) Z_DELREF_P(generator->send_target); @@ -75,23 +75,13 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato } } - /* Clear any backed up stack arguments */ - { - zval *ptr = generator->stack->top - 1; - zval *end = zend_vm_stack_frame_base(execute_data); - - for (; ptr >= end; --ptr) { - zval_ptr_dtor((zval*) ptr); - } - } - /* If yield was used as a function argument there may be active * method calls those objects need to be freed */ while (execute_data->call) { if (execute_data->call->object) { OBJ_RELEASE(execute_data->call->object); } - execute_data->call = execute_data->call->prev; + execute_data->call = execute_data->call->prev_nested_call; } } /* }}} */ @@ -110,7 +100,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished if (generator->execute_data) { zend_execute_data *execute_data = generator->execute_data; - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; if (!execute_data->symbol_table) { zend_free_compiled_variables(execute_data TSRMLS_CC); @@ -128,22 +118,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished return; } - /* We have added an additional stack frame in prev_execute_data, so we - * have to free it. It also contains the arguments passed to the - * generator (for func_get_args) so those have to be freed too. */ - { - zend_execute_data *prev_execute_data = execute_data->prev_execute_data; - - if (prev_execute_data->call) { - int arguments_count = prev_execute_data->call->num_args; - zval *arguments_start = ZEND_CALL_ARG(prev_execute_data->call, 1); - int i; - - for (i = 0; i < arguments_count; ++i) { - zval_ptr_dtor(arguments_start + i); - } - } - } + zend_vm_stack_free_extra_args(generator->execute_data TSRMLS_CC); /* Some cleanups are only necessary if the generator was closued * before it could finish execution (reach a return statement). */ @@ -157,6 +132,10 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished efree(op_array); } + if (generator->execute_data->prev_execute_data) { + generator->execute_data->prev_execute_data->call = generator->execute_data->prev_nested_call; + } + efree(generator->stack); generator->execute_data = NULL; } @@ -170,18 +149,18 @@ static void zend_generator_dtor_storage(zend_object *object TSRMLS_DC) /* {{{ */ zend_uint op_num, finally_op_num; int i; - if (!ex || !ex->op_array->has_finally_block) { + if (!ex || !ex->func->op_array.has_finally_block) { return; } /* -1 required because we want the last run opcode, not the * next to-be-run one. */ - op_num = ex->opline - ex->op_array->opcodes - 1; + op_num = ex->opline - ex->func->op_array.opcodes - 1; /* Find next finally block */ finally_op_num = 0; - for (i = 0; i < ex->op_array->last_try_catch; i++) { - zend_try_catch_element *try_catch = &ex->op_array->try_catch_array[i]; + 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]; if (op_num < try_catch->try_op) { break; @@ -195,7 +174,7 @@ static void zend_generator_dtor_storage(zend_object *object TSRMLS_DC) /* {{{ */ /* If a finally block was found we jump directly to it and * resume the generator. */ if (finally_op_num) { - ex->opline = &ex->op_array->opcodes[finally_op_num]; + 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); @@ -287,7 +266,7 @@ ZEND_API void zend_generator_create_zval(zend_op_array *op_array, zval *return_v opline_ptr = EG(opline_ptr); current_symbol_table = EG(active_symbol_table); EG(active_symbol_table) = NULL; - execute_data = zend_create_execute_data_from_op_array(op_array, return_value, VM_FRAME_TOP_FUNCTION TSRMLS_CC); + execute_data = zend_create_generator_execute_data(op_array, return_value TSRMLS_CC); EG(active_symbol_table) = current_symbol_table; EG(current_execute_data) = current_execute_data; EG(opline_ptr) = opline_ptr; @@ -299,8 +278,8 @@ ZEND_API void zend_generator_create_zval(zend_op_array *op_array, zval *return_v } /* Save execution context in generator object. */ - execute_data->prev_execute_data->object = Z_OBJ_P(return_value); generator = (zend_generator *) Z_OBJ_P(return_value); + execute_data->prev_execute_data = NULL; generator->execute_data = execute_data; generator->stack = EG(argument_stack); EG(argument_stack) = current_stack; @@ -342,13 +321,14 @@ ZEND_API void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ zend_class_entry *original_scope = EG(scope); zend_class_entry *original_called_scope = EG(called_scope); zend_vm_stack original_stack = EG(argument_stack); + zend_execute_data *prev_execute_data; original_This = Z_OBJ(EG(This)); /* Set executor globals */ EG(current_execute_data) = generator->execute_data; EG(opline_ptr) = &generator->execute_data->opline; - EG(active_op_array) = generator->execute_data->op_array; + EG(active_op_array) = &generator->execute_data->func->op_array; EG(active_symbol_table) = generator->execute_data->symbol_table; Z_OBJ(EG(This)) = generator->execute_data->object; EG(scope) = generator->execute_data->scope; @@ -357,17 +337,32 @@ ZEND_API void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ /* We want the backtrace to look as if the generator function was * called from whatever method we are current running (e.g. next()). - * The first prev_execute_data contains an additional stack frame, - * which makes the generator function show up in the backtrace and - * makes the arguments available to func_get_args(). So we have to - * set the prev_execute_data of that prev_execute_data :) */ - generator->execute_data->prev_execute_data->prev_execute_data = original_execute_data; + * So we have to link generator call frame with caller call frames */ + + prev_execute_data = original_execute_data; + if (prev_execute_data && + prev_execute_data->call && + (prev_execute_data->call->flags & ZEND_CALL_DONE)) { + prev_execute_data->call->prev_execute_data = prev_execute_data; + prev_execute_data = prev_execute_data->call; + } + generator->execute_data->prev_execute_data = prev_execute_data; + if (prev_execute_data) { + generator->execute_data->prev_nested_call = prev_execute_data->call; + prev_execute_data->call = generator->execute_data; + } /* Resume execution */ generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING; zend_execute_ex(generator->execute_data TSRMLS_CC); generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING; + /* Unlink generator call_frame from the caller */ + if (generator->execute_data && generator->execute_data->prev_execute_data) { + generator->execute_data->prev_execute_data->call = generator->execute_data->prev_nested_call; + generator->execute_data->prev_execute_data = NULL; + } + /* Restore executor globals */ EG(current_execute_data) = original_execute_data; EG(opline_ptr) = original_opline_ptr; @@ -669,7 +664,7 @@ zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *ob return NULL; } - if (by_ref && !(generator->execute_data->op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) { + if (by_ref && !(generator->execute_data->func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { zend_throw_exception(NULL, "You can only iterate a generator by-reference if it declared that it yields by-reference", 0 TSRMLS_CC); return NULL; } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 7fb1d9d878..713d1e2c41 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -70,8 +70,6 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->T = 0; - op_array->used_stack = 0; - op_array->function_name = NULL; op_array->filename = zend_get_compiled_filename(TSRMLS_C); op_array->doc_comment = NULL; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f6153d80ec..e8ae1341fd 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1772,7 +1772,8 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV) ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) { vm_frame_kind frame_kind = EX(frame_kind); - zend_call_frame *call; + zend_execute_data *prev_nested_call; + zend_uint call_flags; EG(current_execute_data) = EX(prev_execute_data); @@ -1781,19 +1782,23 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table) TSRMLS_CC); } - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(op_array)->prototype) { - zval_ptr_dtor((zval*)EX(op_array)->prototype); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(func)->op_array.prototype) { + zval_ptr_dtor((zval*)EX(func)->op_array.prototype); } - zend_vm_stack_free((char*)execute_data TSRMLS_CC); + call_flags = EX(flags); + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); execute_data = EG(current_execute_data); + EX(call) = prev_nested_call; EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; EG(active_symbol_table) = EX(symbol_table); if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && (EX(call)->flags & ZEND_CALL_CTOR)) { - if (EX(call)->flags & ZEND_CALL_CTOR_RESULT_USED) { + if (UNEXPECTED(EG(exception) != NULL) && (call_flags & ZEND_CALL_CTOR)) { + if (call_flags & ZEND_CALL_CTOR_RESULT_USED) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -1810,10 +1815,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) EG(scope) = EX(scope); EG(called_scope) = EX(called_scope); - call = EX(call); - EX(call) = EX(call)->prev; - zend_vm_stack_free_call_frame(call, 1 TSRMLS_CC); - if (UNEXPECTED(EG(exception) != NULL)) { zend_op *opline = EX(opline); zend_throw_exception_internal(NULL TSRMLS_CC); @@ -1828,17 +1829,16 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) ZEND_VM_LEAVE(); } else if (frame_kind == VM_FRAME_NESTED_CODE) { zend_detach_symbol_table(execute_data); - destroy_op_array(EX(op_array) TSRMLS_CC); - efree(EX(op_array)); - zend_vm_stack_free((char*)execute_data TSRMLS_CC); + destroy_op_array(&EX(func)->op_array TSRMLS_CC); + efree(EX(func)); + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); execute_data = EG(current_execute_data); + EX(call) = prev_nested_call; zend_attach_symbol_table(execute_data); EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); - call = EX(call); - EX(call) = EX(call)->prev; - zend_vm_stack_free((zval*)call TSRMLS_CC); + EG(active_op_array) = &EX(func)->op_array; if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION_LEAVE(); @@ -1850,6 +1850,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } else { if (frame_kind == VM_FRAME_TOP_FUNCTION) { i_free_compiled_variables(execute_data TSRMLS_CC); + zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); } else /* if (frame_kind == VM_FRAME_TOP_CODE) */ { zend_array *symbol_table = EX(symbol_table); zend_execute_data *old_execute_data; @@ -1857,7 +1858,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) zend_detach_symbol_table(execute_data); old_execute_data = EX(prev_execute_data); while (old_execute_data) { - if (old_execute_data->op_array) { + if (old_execute_data->func && (old_execute_data->func->op_array.type == ZEND_USER_FUNCTION || old_execute_data->func->op_array.type == ZEND_EVAL_CODE)) { if (old_execute_data->symbol_table == symbol_table) { zend_attach_symbol_table(old_execute_data); } @@ -1866,10 +1867,15 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) old_execute_data = old_execute_data->prev_execute_data; } } - if ((EX(op_array)->fn_flags & ZEND_ACC_CLOSURE) && EX(op_array)->prototype) { - zval_ptr_dtor((zval*)EX(op_array)->prototype); + if ((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) && EX(func)->op_array.prototype) { + zval_ptr_dtor((zval*)EX(func)->op_array.prototype); + } + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); + + if (EG(current_execute_data)) { + EG(current_execute_data)->call = prev_nested_call; } - zend_vm_stack_free((char*)execute_data TSRMLS_CC); EG(opline_ptr) = NULL; ZEND_VM_RETURN(); } @@ -2255,7 +2261,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); FREE_OP2(); FREE_OP1_IF_VAR(); @@ -2279,7 +2285,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -2365,13 +2371,14 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS } if (OP1_TYPE != IS_CONST) { - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { ce = EG(called_scope); } } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2398,7 +2405,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); @@ -2425,7 +2432,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) FREE_OP2(); EX(call) = zend_vm_stack_push_call_frame( - Z_FUNC_P(func), 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + Z_FUNC_P(func), opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2445,7 +2452,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2503,7 +2510,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); FREE_OP2(); CHECK_EXCEPTION(); @@ -2544,7 +2551,7 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); } @@ -2568,7 +2575,7 @@ ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, ANY, CONST) } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); FREE_OP2(); @@ -2578,14 +2585,12 @@ ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, ANY, CONST) ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) { USE_OPLINE - zend_function *fbc = EX(call)->func; - zend_object *object; - zend_uint num_args; - zend_call_frame *call; + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; + zend_uint call_flags = call->flags; SAVE_OPLINE(); - EX(call)->flags |= ZEND_CALL_DONE; - object = EX(call)->object; + call->flags |= ZEND_CALL_DONE; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name->val, fbc->common.function_name->val); @@ -2602,7 +2607,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) } if (fbc->common.scope && !(fbc->common.fn_flags & ZEND_ACC_STATIC) && - !object) { + !call->object) { if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { /* FIXME: output identifiers properly */ @@ -2617,37 +2622,33 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) } } - if (EXPECTED(EX(call)->num_args == 0)) { - EX(call)->num_args = num_args = opline->extended_value; - } else { - EX(call)->num_args += opline->extended_value; - num_args = EX(call)->num_args; - zend_vm_stack_adjust_call_frame(&EX(call) TSRMLS_CC); - } +//??? + call->num_args += opline->extended_value; + LOAD_OPLINE(); - if (fbc->type == ZEND_INTERNAL_FUNCTION) { + if (UNEXPECTED(fbc->type == ZEND_INTERNAL_FUNCTION)) { int should_change_scope = 0; zval *ret; if (fbc->common.scope) { should_change_scope = 1; - Z_OBJ(EG(This)) = object; + Z_OBJ(EG(This)) = call->object; /* TODO: we don't set scope if we call an object method ??? */ /* See: ext/pdo_sqlite/tests/pdo_fetch_func_001.phpt */ #if 1 - EG(scope) = (object) ? NULL : fbc->common.scope; + EG(scope) = (call->object) ? NULL : fbc->common.scope; #else EG(scope) = fbc->common.scope; #endif - EG(called_scope) = EX(call)->called_scope; + EG(called_scope) = call->called_scope; } if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { zend_uint i; - zval *p = ZEND_CALL_ARG(EX(call), 1); + zval *p = ZEND_CALL_ARG(call, 1); - for (i = 0; i < num_args; ++i) { + for (i = 0; i < call->num_args; ++i) { zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); p++; } @@ -2669,10 +2670,15 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) if (!zend_execute_internal) { /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(num_args, ret TSRMLS_CC); + fbc->internal_function.handler(call->num_args, ret TSRMLS_CC); } else { zend_execute_internal(execute_data, NULL TSRMLS_CC); } + + zend_vm_stack_free_args(call TSRMLS_CC); + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); if (!RETURN_VALUE_USED(opline)) { zval_ptr_dtor(ret); @@ -2683,12 +2689,12 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) } else { ZEND_VM_C_GOTO(fcall_end); } - } else if (fbc->type == ZEND_USER_FUNCTION) { + } else if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { zval *return_value = NULL; - Z_OBJ(EG(This)) = object; + Z_OBJ(EG(This)) = call->object; EG(scope) = fbc->common.scope; - EG(called_scope) = EX(call)->called_scope; + EG(called_scope) = call->called_scope; EG(active_symbol_table) = NULL; EG(active_op_array) = &fbc->op_array; if (RETURN_VALUE_USED(opline)) { @@ -2698,40 +2704,50 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) Z_VAR_FLAGS_P(return_value) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; } - if (UNEXPECTED((EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { if (RETURN_VALUE_USED(opline)) { - zend_generator_create_zval(EG(active_op_array), EX_VAR(opline->result.var) TSRMLS_CC); + zend_generator_create_zval(&fbc->op_array, EX_VAR(opline->result.var) TSRMLS_CC); } - } else if (EXPECTED(zend_execute_ex == execute_ex)) { - if (EXPECTED(EG(exception) == NULL)) { - i_create_execute_data_from_op_array(EG(active_op_array), return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + } else { + call->prev_execute_data = EG(current_execute_data); + i_init_execute_data(call, &fbc->op_array, return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); + + if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); + } else { + execute_ex(call TSRMLS_CC); } - } else { - zend_execute(EG(active_op_array), return_value TSRMLS_CC); } EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; if (UNEXPECTED(EG(active_symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC); } EG(active_symbol_table) = EX(symbol_table); } else { /* ZEND_OVERLOADED_FUNCTION */ - Z_OBJ(EG(This)) = object; + Z_OBJ(EG(This)) = call->object; //??? EG(scope) = NULL; EG(scope) = fbc->common.scope; - EG(called_scope) = EX(call)->called_scope; + EG(called_scope) = call->called_scope; ZVAL_NULL(EX_VAR(opline->result.var)); /* Not sure what should be done here if it's a static method */ - if (EXPECTED(object != NULL)) { - object->handlers->call_method(fbc->common.function_name, object, num_args, EX_VAR(opline->result.var) TSRMLS_CC); + if (EXPECTED(call->object != NULL)) { + call->object->handlers->call_method(fbc->common.function_name, call->object, call->num_args, EX_VAR(opline->result.var) TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } + zend_vm_stack_free_args(call TSRMLS_CC); + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { STR_RELEASE(fbc->common.function_name); } @@ -2748,8 +2764,8 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) ZEND_VM_C_LABEL(fcall_end_change_scope): if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && (EX(call)->flags & ZEND_CALL_CTOR)) { - if (EX(call)->flags & ZEND_CALL_CTOR_RESULT_USED) { + if (UNEXPECTED(EG(exception) != NULL) && (call_flags & ZEND_CALL_CTOR)) { + if (call_flags & ZEND_CALL_CTOR_RESULT_USED) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -2757,7 +2773,6 @@ ZEND_VM_C_LABEL(fcall_end_change_scope): } } if (!Z_DELREF(EG(This))) { - EX(call)->flags &= ~ZEND_CALL_DONE; _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); @@ -2768,10 +2783,6 @@ ZEND_VM_C_LABEL(fcall_end_change_scope): EG(called_scope) = EX(called_scope); ZEND_VM_C_LABEL(fcall_end): - call = EX(call); - EX(call) = EX(call)->prev; - zend_vm_stack_free_call_frame(call, 1 TSRMLS_CC); - if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { @@ -2923,7 +2934,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV) /* Check whether an exception has been thrown, if not, jump over code */ zend_exception_restore(TSRMLS_C); if (EG(exception) == NULL) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->extended_value]); ZEND_VM_CONTINUE(); /* CHECK_ME */ } if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { @@ -2947,7 +2958,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV) zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION(); } - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->extended_value]); ZEND_VM_CONTINUE(); /* CHECK_ME */ } } @@ -2969,7 +2980,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV) ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY) { USE_OPLINE - zval *value, *top; + zval *value, *arg; zend_free_op free_op1; SAVE_OPLINE(); @@ -2980,11 +2991,11 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY) } value = GET_OP1_ZVAL_PTR(BP_VAR_R); - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY_VALUE(top, value); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + ZVAL_COPY_VALUE(arg, value); if (OP1_TYPE == IS_CONST) { - if (UNEXPECTED(Z_OPT_COPYABLE_P(top))) { - zval_copy_ctor_func(top); + if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { + zval_copy_ctor_func(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -2993,18 +3004,18 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY) ZEND_VM_HELPER(zend_send_by_var_helper, VAR|CV, ANY) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; zend_free_op free_op1; varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); FREE_OP1(); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (OP1_TYPE == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -3014,7 +3025,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ @@ -3039,15 +3050,16 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) if (OP1_TYPE == IS_CV) { Z_ADDREF_P(varptr); } - zend_vm_stack_push(varptr TSRMLS_CC); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + ZVAL_COPY_VALUE(arg, varptr); } else { if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : !ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY(top, varptr); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + ZVAL_COPY(arg, varptr); FREE_OP1_IF_VAR(); } CHECK_EXCEPTION(); @@ -3058,7 +3070,7 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); varptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); @@ -3067,23 +3079,23 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY) zend_error_noreturn(E_ERROR, "Only variables can be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); if (OP1_TYPE == IS_VAR && UNEXPECTED(varptr == &EG(error_zval))) { - ZVAL_NEW_REF(top, &EG(uninitialized_zval)); + ZVAL_NEW_REF(arg, &EG(uninitialized_zval)); ZEND_VM_NEXT_OPCODE(); } if (Z_ISREF_P(varptr)) { Z_ADDREF_P(varptr); - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); } else if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { - ZVAL_COPY_VALUE(top, varptr); - ZVAL_MAKE_REF(top); + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_MAKE_REF(arg); } else { ZVAL_MAKE_REF(varptr); Z_ADDREF_P(varptr); - ZVAL_REF(top, Z_REF_P(varptr)); + ZVAL_REF(arg, Z_REF_P(varptr)); } FREE_OP1_VAR_PTR(); @@ -3093,7 +3105,7 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY) ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; zend_free_op free_op1; if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { @@ -3103,14 +3115,14 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY) } varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); FREE_OP1(); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (OP1_TYPE == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -3134,7 +3146,7 @@ ZEND_VM_C_LABEL(send_again): zval *arg, *top; zend_string *name; - ZEND_VM_STACK_GROW_IF_NEEDED(zend_hash_num_elements(ht)); + zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht) TSRMLS_DC); if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_IMMUTABLE_P(args)) { int i; @@ -3161,7 +3173,7 @@ ZEND_VM_C_LABEL(send_again): ZEND_VM_NEXT_OPCODE(); } - top = zend_vm_stack_top_inc(TSRMLS_C); + top = ZEND_CALL_ARG(EX(call), arg_num); if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (!Z_IMMUTABLE_P(args)) { ZVAL_MAKE_REF(arg); @@ -3171,6 +3183,7 @@ ZEND_VM_C_LABEL(send_again): ZVAL_DUP(top, arg); } } else if (Z_ISREF_P(arg)) { +//TODO: change into ZVAL_COPY()??? ZVAL_DUP(top, Z_REFVAL_P(arg)); } else { ZVAL_COPY(top, arg); @@ -3210,7 +3223,7 @@ ZEND_VM_C_LABEL(send_again): } for (; iter->funcs->valid(iter TSRMLS_CC) == SUCCESS; ++arg_num) { - zval *arg; + zval *arg, *top; if (UNEXPECTED(EG(exception) != NULL)) { ZEND_VM_C_GOTO(unpack_iter_dtor); @@ -3254,8 +3267,9 @@ ZEND_VM_C_LABEL(send_again): if (Z_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } - ZEND_VM_STACK_GROW_IF_NEEDED(1); - zend_vm_stack_push(arg TSRMLS_CC); + zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1 TSRMLS_DC); + top = ZEND_CALL_ARG(EX(call), arg_num); + ZVAL_COPY_VALUE(top, arg); EX(call)->num_args++; iter->funcs->move_forward(iter TSRMLS_CC); @@ -3285,24 +3299,18 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zend_uint arg_count = EX(prev_execute_data)->call->num_args; SAVE_OPLINE(); - if (UNEXPECTED(arg_num > arg_count)) { + if (UNEXPECTED(arg_num > EX(num_args))) { zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC); - } else { - zval *var_ptr; - zval *param = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); + CHECK_EXCEPTION(); + } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, param, opline->extended_value TSRMLS_CC); - } - var_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(var_ptr))) Z_DELREF_P(var_ptr); - ZVAL_COPY(var_ptr, param); + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + CHECK_EXCEPTION(); } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -3310,29 +3318,24 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zend_uint arg_count = EX(prev_execute_data)->call->num_args; - zval *var_ptr; + zval *param; SAVE_OPLINE(); - var_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(var_ptr))) Z_DELREF_P(var_ptr); - if (arg_num > arg_count) { - ZVAL_COPY_VALUE(var_ptr, opline->op2.zv); - if (Z_OPT_CONSTANT_P(var_ptr)) { - zval_update_constant(var_ptr, 0 TSRMLS_CC); + param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); + if (arg_num > EX(num_args)) { + ZVAL_COPY_VALUE(param, opline->op2.zv); + if (Z_OPT_CONSTANT_P(param)) { + zval_update_constant(param, 0 TSRMLS_CC); } else { /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */ - if (UNEXPECTED(Z_OPT_COPYABLE_P(var_ptr))) { - zval_copy_ctor_func(var_ptr); + if (UNEXPECTED(Z_OPT_COPYABLE_P(param))) { + zval_copy_ctor_func(param); } } - } else { - zval *param = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); - ZVAL_COPY(var_ptr, param); } - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, var_ptr, opline->extended_value TSRMLS_CC); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); } CHECK_EXCEPTION(); @@ -3343,30 +3346,39 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zend_uint arg_count = EX(prev_execute_data)->call->num_args; + zend_uint arg_count = EX(num_args); zval *params; SAVE_OPLINE(); params = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(params))) Z_DELREF_P(params); if (arg_num <= arg_count) { - zval *param = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); + zval *param, tmp; + + ZVAL_COPY_VALUE(&tmp, params); array_init_size(params, arg_count - arg_num + 1); - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - do { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, param, opline->extended_value TSRMLS_CC); - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); - if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); - param++; - } while (++arg_num <= arg_count); + param = EX(extra_args); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + zend_verify_arg_type(EX(func), arg_num, &tmp, opline->extended_value TSRMLS_CC); + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), &tmp); + if (param) { + while (++arg_num <= arg_count) { + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } + } } else { - do { - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); - if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); - param++; - } while (++arg_num <= arg_count); + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), &tmp); + if (param) { + while (++arg_num <= arg_count) { + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } + } } } else { array_init(params); @@ -3398,8 +3410,8 @@ ZEND_VM_HANDLER(50, ZEND_BRK, ANY, CONST) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, - EX(op_array), execute_data TSRMLS_CC); - ZEND_VM_JMP(EX(op_array)->opcodes + el->brk); + &EX(func)->op_array, execute_data TSRMLS_CC); + ZEND_VM_JMP(EX(func)->op_array.opcodes + el->brk); } ZEND_VM_HANDLER(51, ZEND_CONT, ANY, CONST) @@ -3409,8 +3421,8 @@ ZEND_VM_HANDLER(51, ZEND_CONT, ANY, CONST) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, - EX(op_array), execute_data TSRMLS_CC); - ZEND_VM_JMP(EX(op_array)->opcodes + el->cont); + &EX(func)->op_array, execute_data TSRMLS_CC); + ZEND_VM_JMP(EX(func)->op_array.opcodes + el->cont); } ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST) @@ -3421,9 +3433,9 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->extended_value, - EX(op_array), execute_data TSRMLS_CC); + &EX(func)->op_array, execute_data TSRMLS_CC); - brk_opline = EX(op_array)->opcodes + el->brk; + brk_opline = EX(func)->op_array.opcodes + el->brk; if (brk_opline->opcode == ZEND_SWITCH_FREE) { if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { @@ -3492,7 +3504,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) } else { /* We are not handling overloaded classes right now */ EX(call) = zend_vm_stack_push_call_frame( - constructor, 0, + constructor, opline->extended_value, RETURN_VALUE_USED(opline) ? (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_USED) : ZEND_CALL_CTOR, Z_CE_P(EX_VAR(opline->op1.var)), @@ -3981,7 +3993,6 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) HANDLE_EXCEPTION(); } else if (EXPECTED(new_op_array != NULL)) { zval *return_value = NULL; - zend_call_frame *call; EG(active_op_array) = new_op_array; if (RETURN_VALUE_USED(opline)) { @@ -3989,24 +4000,22 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) } EX(call) = zend_vm_stack_push_call_frame( - (zend_function*)new_op_array, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } + EX(call)->prev_execute_data = EG(current_execute_data); + i_init_execute_data(EX(call), new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - i_create_execute_data_from_op_array(new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); ZEND_VM_ENTER(); } else { - zend_execute(new_op_array, return_value TSRMLS_CC); + execute_ex(EG(current_execute_data) TSRMLS_CC); } EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); - call = EX(call); - EX(call) = EX(call)->prev; - zend_vm_stack_free((zval*)call TSRMLS_CC); + EG(active_op_array) = &EX(func)->op_array; destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -4837,7 +4846,7 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY) ZEND_VM_HANDLER(142, ZEND_RAISE_ABSTRACT_ERROR, ANY, ANY) { SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name->val, EX(op_array)->function_name->val); + zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name->val, EX(func)->op_array.function_name->val); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } @@ -4963,7 +4972,7 @@ ZEND_VM_HANDLER(101, ZEND_EXT_STMT, ANY, ANY) { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_statement_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_statement_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -4973,7 +4982,7 @@ ZEND_VM_HANDLER(102, ZEND_EXT_FCALL_BEGIN, ANY, ANY) { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_begin_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_begin_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -4983,7 +4992,7 @@ ZEND_VM_HANDLER(103, ZEND_EXT_FCALL_END, ANY, ANY) { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -4994,7 +5003,7 @@ ZEND_VM_HANDLER(139, ZEND_DECLARE_CLASS, ANY, ANY) USE_OPLINE SAVE_OPLINE(); - Z_CE_P(EX_VAR(opline->result.var)) = do_bind_class(EX(op_array), opline, EG(class_table), 0 TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = do_bind_class(&EX(func)->op_array, opline, EG(class_table), 0 TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -5004,7 +5013,7 @@ ZEND_VM_HANDLER(140, ZEND_DECLARE_INHERITED_CLASS, ANY, ANY) USE_OPLINE SAVE_OPLINE(); - Z_CE_P(EX_VAR(opline->result.var)) = do_bind_inherited_class(EX(op_array), opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -5018,7 +5027,7 @@ ZEND_VM_HANDLER(145, ZEND_DECLARE_INHERITED_CLASS_DELAYED, ANY, ANY) if ((zce = zend_hash_find(EG(class_table), Z_STR_P(opline->op2.zv))) == NULL || ((orig_zce = zend_hash_find(EG(class_table), Z_STR_P(opline->op1.zv))) != NULL && Z_CE_P(zce) != Z_CE_P(orig_zce))) { - do_bind_inherited_class(EX(op_array), opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); + do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -5029,7 +5038,7 @@ ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY) USE_OPLINE SAVE_OPLINE(); - do_bind_function(EX(op_array), opline, EG(function_table), 0); + do_bind_function(&EX(func)->op_array, opline, EG(function_table), 0); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -5159,28 +5168,24 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) break; } 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; + catch_op_num = EX(func)->op_array.try_catch_array[i].catch_op; } - 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; + 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; } - if (op_num >= EG(active_op_array)->try_catch_array[i].finally_op && - op_num < EG(active_op_array)->try_catch_array[i].finally_end) { - finally_op_end = EG(active_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) { + finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end; } } if (EX(call)) { - zend_call_frame *call = EX(call); + zend_execute_data *call = EX(call); do { - zval *args = ZEND_CALL_ARG(call, 1); - /* If the exception was thrown during a function call there might be * arguments pushed to the stack that have to be dtor'ed. */ - while (zend_vm_stack_top(TSRMLS_C) != args) { - zval *stack_zval_p = zend_vm_stack_pop(TSRMLS_C); - zval_ptr_dtor(stack_zval_p); - } + zend_vm_stack_free_args(EX(call) TSRMLS_CC); + if (call->object) { if (call->flags & ZEND_CALL_CTOR) { if (call->flags & ZEND_CALL_CTOR_RESULT_USED) { @@ -5192,22 +5197,22 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } OBJ_RELEASE(call->object); } - EG(argument_stack)->top = (zval*)call; - call = call->prev; + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + call = EX(call); } while (call); - EX(call) = NULL; } - for (i=0; ilast_brk_cont; i++) { - if (EX(op_array)->brk_cont_array[i].start < 0) { + for (i = 0; i < EX(func)->op_array.last_brk_cont; i++) { + if (EX(func)->op_array.brk_cont_array[i].start < 0) { continue; - } else if (EX(op_array)->brk_cont_array[i].start > op_num) { + } else if (EX(func)->op_array.brk_cont_array[i].start > op_num) { /* further blocks will not be relevant... */ break; - } else if (op_num < EX(op_array)->brk_cont_array[i].brk) { + } else if (op_num < EX(func)->op_array.brk_cont_array[i].brk) { 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]; + catch_op_num >= EX(func)->op_array.brk_cont_array[i].brk) { + zend_op *brk_opline = &EX(func)->op_array.opcodes[EX(func)->op_array.brk_cont_array[i].brk]; if (brk_opline->opcode == ZEND_SWITCH_FREE) { if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { @@ -5243,7 +5248,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) EX(delayed_exception) = EG(exception); EG(exception) = NULL; EX(fast_ret) = NULL; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); + 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) { @@ -5253,14 +5258,14 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) EX(delayed_exception) = NULL; } } - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); + 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 (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN); } else { ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); @@ -5291,7 +5296,7 @@ ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY) case ZEND_USER_OPCODE_CONTINUE: ZEND_VM_CONTINUE(); case ZEND_USER_OPCODE_RETURN: - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN); } else { ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); @@ -5405,7 +5410,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE if (OP1_TYPE != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) { @@ -5533,7 +5538,7 @@ ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY) 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_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); } EX(fast_ret) = opline + 1; @@ -5552,15 +5557,15 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY) 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_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); } else { EG(exception) = EX(delayed_exception); EX(delayed_exception) = NULL; if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); - } else if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN); } else { ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index f341e19fdb..0534cfd8b1 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -375,16 +375,28 @@ ZEND_API void execute_ex(zend_execute_data *execute_data TSRMLS_DC) ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value TSRMLS_DC) { + zend_execute_data *execute_data; + if (EG(exception) != NULL) { return; - } - zend_execute_ex(i_create_execute_data_from_op_array(op_array, return_value, EG(active_symbol_table) ? VM_FRAME_TOP_CODE : VM_FRAME_TOP_FUNCTION TSRMLS_CC) TSRMLS_CC); + } + + if (EG(current_execute_data) && EG(current_execute_data)->call) { + execute_data = EG(current_execute_data)->call; + } else { + execute_data = zend_vm_stack_push_call_frame( + (zend_function*)op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), NULL TSRMLS_CC); + } + EX(prev_execute_data) = EG(current_execute_data); + i_init_execute_data(execute_data, op_array, return_value, EG(active_symbol_table) ? VM_FRAME_TOP_CODE : VM_FRAME_TOP_FUNCTION TSRMLS_CC); + zend_execute_ex(execute_data TSRMLS_CC); } static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) { vm_frame_kind frame_kind = EX(frame_kind); - zend_call_frame *call; + zend_execute_data *prev_nested_call; + zend_uint call_flags; EG(current_execute_data) = EX(prev_execute_data); @@ -393,19 +405,23 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table) TSRMLS_CC); } - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(op_array)->prototype) { - zval_ptr_dtor((zval*)EX(op_array)->prototype); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(func)->op_array.prototype) { + zval_ptr_dtor((zval*)EX(func)->op_array.prototype); } - zend_vm_stack_free((char*)execute_data TSRMLS_CC); + call_flags = EX(flags); + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); execute_data = EG(current_execute_data); + EX(call) = prev_nested_call; EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; EG(active_symbol_table) = EX(symbol_table); if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && (EX(call)->flags & ZEND_CALL_CTOR)) { - if (EX(call)->flags & ZEND_CALL_CTOR_RESULT_USED) { + if (UNEXPECTED(EG(exception) != NULL) && (call_flags & ZEND_CALL_CTOR)) { + if (call_flags & ZEND_CALL_CTOR_RESULT_USED) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -422,10 +438,6 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EG(scope) = EX(scope); EG(called_scope) = EX(called_scope); - call = EX(call); - EX(call) = EX(call)->prev; - zend_vm_stack_free_call_frame(call, 1 TSRMLS_CC); - if (UNEXPECTED(EG(exception) != NULL)) { zend_op *opline = EX(opline); zend_throw_exception_internal(NULL TSRMLS_CC); @@ -440,17 +452,16 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_LEAVE(); } else if (frame_kind == VM_FRAME_NESTED_CODE) { zend_detach_symbol_table(execute_data); - destroy_op_array(EX(op_array) TSRMLS_CC); - efree(EX(op_array)); - zend_vm_stack_free((char*)execute_data TSRMLS_CC); + destroy_op_array(&EX(func)->op_array TSRMLS_CC); + efree(EX(func)); + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); execute_data = EG(current_execute_data); + EX(call) = prev_nested_call; zend_attach_symbol_table(execute_data); EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); - call = EX(call); - EX(call) = EX(call)->prev; - zend_vm_stack_free((zval*)call TSRMLS_CC); + EG(active_op_array) = &EX(func)->op_array; if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION_LEAVE(); @@ -462,6 +473,7 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) } else { if (frame_kind == VM_FRAME_TOP_FUNCTION) { i_free_compiled_variables(execute_data TSRMLS_CC); + zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); } else /* if (frame_kind == VM_FRAME_TOP_CODE) */ { zend_array *symbol_table = EX(symbol_table); zend_execute_data *old_execute_data; @@ -469,7 +481,7 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) zend_detach_symbol_table(execute_data); old_execute_data = EX(prev_execute_data); while (old_execute_data) { - if (old_execute_data->op_array) { + if (old_execute_data->func && (old_execute_data->func->op_array.type == ZEND_USER_FUNCTION || old_execute_data->func->op_array.type == ZEND_EVAL_CODE)) { if (old_execute_data->symbol_table == symbol_table) { zend_attach_symbol_table(old_execute_data); } @@ -478,10 +490,15 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) old_execute_data = old_execute_data->prev_execute_data; } } - if ((EX(op_array)->fn_flags & ZEND_ACC_CLOSURE) && EX(op_array)->prototype) { - zval_ptr_dtor((zval*)EX(op_array)->prototype); + if ((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) && EX(func)->op_array.prototype) { + zval_ptr_dtor((zval*)EX(func)->op_array.prototype); + } + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); + + if (EG(current_execute_data)) { + EG(current_execute_data)->call = prev_nested_call; } - zend_vm_stack_free((char*)execute_data TSRMLS_CC); EG(opline_ptr) = NULL; ZEND_VM_RETURN(); } @@ -509,14 +526,12 @@ static int ZEND_FASTCALL ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_function *fbc = EX(call)->func; - zend_object *object; - zend_uint num_args; - zend_call_frame *call; + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; + zend_uint call_flags = call->flags; SAVE_OPLINE(); - EX(call)->flags |= ZEND_CALL_DONE; - object = EX(call)->object; + call->flags |= ZEND_CALL_DONE; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name->val, fbc->common.function_name->val); @@ -533,7 +548,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (fbc->common.scope && !(fbc->common.fn_flags & ZEND_ACC_STATIC) && - !object) { + !call->object) { if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { /* FIXME: output identifiers properly */ @@ -548,37 +563,33 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } - if (EXPECTED(EX(call)->num_args == 0)) { - EX(call)->num_args = num_args = opline->extended_value; - } else { - EX(call)->num_args += opline->extended_value; - num_args = EX(call)->num_args; - zend_vm_stack_adjust_call_frame(&EX(call) TSRMLS_CC); - } +//??? + call->num_args += opline->extended_value; + LOAD_OPLINE(); - if (fbc->type == ZEND_INTERNAL_FUNCTION) { + if (UNEXPECTED(fbc->type == ZEND_INTERNAL_FUNCTION)) { int should_change_scope = 0; zval *ret; if (fbc->common.scope) { should_change_scope = 1; - Z_OBJ(EG(This)) = object; + Z_OBJ(EG(This)) = call->object; /* TODO: we don't set scope if we call an object method ??? */ /* See: ext/pdo_sqlite/tests/pdo_fetch_func_001.phpt */ #if 1 - EG(scope) = (object) ? NULL : fbc->common.scope; + EG(scope) = (call->object) ? NULL : fbc->common.scope; #else EG(scope) = fbc->common.scope; #endif - EG(called_scope) = EX(call)->called_scope; + EG(called_scope) = call->called_scope; } if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { zend_uint i; - zval *p = ZEND_CALL_ARG(EX(call), 1); + zval *p = ZEND_CALL_ARG(call, 1); - for (i = 0; i < num_args; ++i) { + for (i = 0; i < call->num_args; ++i) { zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); p++; } @@ -600,11 +611,16 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (!zend_execute_internal) { /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(num_args, ret TSRMLS_CC); + fbc->internal_function.handler(call->num_args, ret TSRMLS_CC); } else { zend_execute_internal(execute_data, NULL TSRMLS_CC); } + zend_vm_stack_free_args(call TSRMLS_CC); + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + if (!RETURN_VALUE_USED(opline)) { zval_ptr_dtor(ret); } @@ -614,12 +630,12 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { goto fcall_end; } - } else if (fbc->type == ZEND_USER_FUNCTION) { + } else if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { zval *return_value = NULL; - Z_OBJ(EG(This)) = object; + Z_OBJ(EG(This)) = call->object; EG(scope) = fbc->common.scope; - EG(called_scope) = EX(call)->called_scope; + EG(called_scope) = call->called_scope; EG(active_symbol_table) = NULL; EG(active_op_array) = &fbc->op_array; if (RETURN_VALUE_USED(opline)) { @@ -629,40 +645,50 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) Z_VAR_FLAGS_P(return_value) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; } - if (UNEXPECTED((EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { if (RETURN_VALUE_USED(opline)) { - zend_generator_create_zval(EG(active_op_array), EX_VAR(opline->result.var) TSRMLS_CC); + zend_generator_create_zval(&fbc->op_array, EX_VAR(opline->result.var) TSRMLS_CC); } - } else if (EXPECTED(zend_execute_ex == execute_ex)) { - if (EXPECTED(EG(exception) == NULL)) { - i_create_execute_data_from_op_array(EG(active_op_array), return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + } else { + call->prev_execute_data = EG(current_execute_data); + i_init_execute_data(call, &fbc->op_array, return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); + + if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); + } else { + execute_ex(call TSRMLS_CC); } - } else { - zend_execute(EG(active_op_array), return_value TSRMLS_CC); } EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; if (UNEXPECTED(EG(active_symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC); } EG(active_symbol_table) = EX(symbol_table); } else { /* ZEND_OVERLOADED_FUNCTION */ - Z_OBJ(EG(This)) = object; + Z_OBJ(EG(This)) = call->object; //??? EG(scope) = NULL; EG(scope) = fbc->common.scope; - EG(called_scope) = EX(call)->called_scope; + EG(called_scope) = call->called_scope; ZVAL_NULL(EX_VAR(opline->result.var)); /* Not sure what should be done here if it's a static method */ - if (EXPECTED(object != NULL)) { - object->handlers->call_method(fbc->common.function_name, object, num_args, EX_VAR(opline->result.var) TSRMLS_CC); + if (EXPECTED(call->object != NULL)) { + call->object->handlers->call_method(fbc->common.function_name, call->object, call->num_args, EX_VAR(opline->result.var) TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } + zend_vm_stack_free_args(call TSRMLS_CC); + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { STR_RELEASE(fbc->common.function_name); } @@ -679,8 +705,8 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) fcall_end_change_scope: if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && (EX(call)->flags & ZEND_CALL_CTOR)) { - if (EX(call)->flags & ZEND_CALL_CTOR_RESULT_USED) { + if (UNEXPECTED(EG(exception) != NULL) && (call_flags & ZEND_CALL_CTOR)) { + if (call_flags & ZEND_CALL_CTOR_RESULT_USED) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -688,7 +714,6 @@ fcall_end_change_scope: } } if (!Z_DELREF(EG(This))) { - EX(call)->flags &= ~ZEND_CALL_DONE; _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); @@ -699,10 +724,6 @@ fcall_end_change_scope: EG(called_scope) = EX(called_scope); fcall_end: - call = EX(call); - EX(call) = EX(call)->prev; - zend_vm_stack_free_call_frame(call, 1 TSRMLS_CC); - if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { @@ -744,7 +765,7 @@ send_again: zval *arg, *top; zend_string *name; - ZEND_VM_STACK_GROW_IF_NEEDED(zend_hash_num_elements(ht)); + zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht) TSRMLS_DC); if (opline->op1_type != IS_CONST && opline->op1_type != IS_TMP_VAR && Z_IMMUTABLE_P(args)) { int i; @@ -771,7 +792,7 @@ send_again: ZEND_VM_NEXT_OPCODE(); } - top = zend_vm_stack_top_inc(TSRMLS_C); + top = ZEND_CALL_ARG(EX(call), arg_num); if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (!Z_IMMUTABLE_P(args)) { ZVAL_MAKE_REF(arg); @@ -781,6 +802,7 @@ send_again: ZVAL_DUP(top, arg); } } else if (Z_ISREF_P(arg)) { +//TODO: change into ZVAL_COPY()??? ZVAL_DUP(top, Z_REFVAL_P(arg)); } else { ZVAL_COPY(top, arg); @@ -820,7 +842,7 @@ send_again: } for (; iter->funcs->valid(iter TSRMLS_CC) == SUCCESS; ++arg_num) { - zval *arg; + zval *arg, *top; if (UNEXPECTED(EG(exception) != NULL)) { goto unpack_iter_dtor; @@ -864,8 +886,9 @@ send_again: if (Z_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } - ZEND_VM_STACK_GROW_IF_NEEDED(1); - zend_vm_stack_push(arg TSRMLS_CC); + zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1 TSRMLS_DC); + top = ZEND_CALL_ARG(EX(call), arg_num); + ZVAL_COPY_VALUE(top, arg); EX(call)->num_args++; iter->funcs->move_forward(iter TSRMLS_CC); @@ -895,24 +918,18 @@ static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zend_uint arg_count = EX(prev_execute_data)->call->num_args; SAVE_OPLINE(); - if (UNEXPECTED(arg_num > arg_count)) { + if (UNEXPECTED(arg_num > EX(num_args))) { zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC); - } else { - zval *var_ptr; - zval *param = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); + CHECK_EXCEPTION(); + } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, param, opline->extended_value TSRMLS_CC); - } - var_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(var_ptr))) Z_DELREF_P(var_ptr); - ZVAL_COPY(var_ptr, param); + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + CHECK_EXCEPTION(); } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -920,30 +937,39 @@ static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR { USE_OPLINE zend_uint arg_num = opline->op1.num; - zend_uint arg_count = EX(prev_execute_data)->call->num_args; + zend_uint arg_count = EX(num_args); zval *params; SAVE_OPLINE(); params = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(params))) Z_DELREF_P(params); if (arg_num <= arg_count) { - zval *param = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); + zval *param, tmp; + + ZVAL_COPY_VALUE(&tmp, params); array_init_size(params, arg_count - arg_num + 1); - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - do { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, param, opline->extended_value TSRMLS_CC); - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); - if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); - param++; - } while (++arg_num <= arg_count); + param = EX(extra_args); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + zend_verify_arg_type(EX(func), arg_num, &tmp, opline->extended_value TSRMLS_CC); + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), &tmp); + if (param) { + while (++arg_num <= arg_count) { + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } + } } else { - do { - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); - if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); - param++; - } while (++arg_num <= arg_count); + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), &tmp); + if (param) { + while (++arg_num <= arg_count) { + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } + } } } else { array_init(params); @@ -982,7 +1008,7 @@ static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { /* We are not handling overloaded classes right now */ EX(call) = zend_vm_stack_push_call_frame( - constructor, 0, + constructor, opline->extended_value, RETURN_VALUE_USED(opline) ? (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_USED) : ZEND_CALL_CTOR, Z_CE_P(EX_VAR(opline->op1.var)), @@ -1044,7 +1070,7 @@ static int ZEND_FASTCALL ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR static int ZEND_FASTCALL ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name->val, EX(op_array)->function_name->val); + zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name->val, EX(func)->op_array.function_name->val); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } @@ -1052,7 +1078,7 @@ static int ZEND_FASTCALL ZEND_EXT_STMT_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_statement_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_statement_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1062,7 +1088,7 @@ static int ZEND_FASTCALL ZEND_EXT_FCALL_BEGIN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_begin_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_begin_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1072,7 +1098,7 @@ static int ZEND_FASTCALL ZEND_EXT_FCALL_END_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1083,7 +1109,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_CLASS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR USE_OPLINE SAVE_OPLINE(); - Z_CE_P(EX_VAR(opline->result.var)) = do_bind_class(EX(op_array), opline, EG(class_table), 0 TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = do_bind_class(&EX(func)->op_array, opline, EG(class_table), 0 TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -1093,7 +1119,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_INHERITED_CLASS_SPEC_HANDLER(ZEND_OPCODE_ USE_OPLINE SAVE_OPLINE(); - Z_CE_P(EX_VAR(opline->result.var)) = do_bind_inherited_class(EX(op_array), opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -1107,7 +1133,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_INHERITED_CLASS_DELAYED_SPEC_HANDLER(ZEND if ((zce = zend_hash_find(EG(class_table), Z_STR_P(opline->op2.zv))) == NULL || ((orig_zce = zend_hash_find(EG(class_table), Z_STR_P(opline->op1.zv))) != NULL && Z_CE_P(zce) != Z_CE_P(orig_zce))) { - do_bind_inherited_class(EX(op_array), opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); + do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1118,7 +1144,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_FUNCTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER USE_OPLINE SAVE_OPLINE(); - do_bind_function(EX(op_array), opline, EG(function_table), 0); + do_bind_function(&EX(func)->op_array, opline, EG(function_table), 0); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -1200,28 +1226,24 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER break; } 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; + catch_op_num = EX(func)->op_array.try_catch_array[i].catch_op; } - 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; + 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; } - if (op_num >= EG(active_op_array)->try_catch_array[i].finally_op && - op_num < EG(active_op_array)->try_catch_array[i].finally_end) { - finally_op_end = EG(active_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) { + finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end; } } if (EX(call)) { - zend_call_frame *call = EX(call); + zend_execute_data *call = EX(call); do { - zval *args = ZEND_CALL_ARG(call, 1); - /* If the exception was thrown during a function call there might be * arguments pushed to the stack that have to be dtor'ed. */ - while (zend_vm_stack_top(TSRMLS_C) != args) { - zval *stack_zval_p = zend_vm_stack_pop(TSRMLS_C); - zval_ptr_dtor(stack_zval_p); - } + zend_vm_stack_free_args(EX(call) TSRMLS_CC); + if (call->object) { if (call->flags & ZEND_CALL_CTOR) { if (call->flags & ZEND_CALL_CTOR_RESULT_USED) { @@ -1233,22 +1255,22 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER } OBJ_RELEASE(call->object); } - EG(argument_stack)->top = (zval*)call; - call = call->prev; + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + call = EX(call); } while (call); - EX(call) = NULL; } - for (i=0; ilast_brk_cont; i++) { - if (EX(op_array)->brk_cont_array[i].start < 0) { + for (i = 0; i < EX(func)->op_array.last_brk_cont; i++) { + if (EX(func)->op_array.brk_cont_array[i].start < 0) { continue; - } else if (EX(op_array)->brk_cont_array[i].start > op_num) { + } else if (EX(func)->op_array.brk_cont_array[i].start > op_num) { /* further blocks will not be relevant... */ break; - } else if (op_num < EX(op_array)->brk_cont_array[i].brk) { + } else if (op_num < EX(func)->op_array.brk_cont_array[i].brk) { 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]; + catch_op_num >= EX(func)->op_array.brk_cont_array[i].brk) { + zend_op *brk_opline = &EX(func)->op_array.opcodes[EX(func)->op_array.brk_cont_array[i].brk]; if (brk_opline->opcode == ZEND_SWITCH_FREE) { if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { @@ -1284,7 +1306,7 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER EX(delayed_exception) = EG(exception); EG(exception) = NULL; EX(fast_ret) = NULL; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); + 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) { @@ -1294,14 +1316,14 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER EX(delayed_exception) = NULL; } } - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); + 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 (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } else { return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -1332,7 +1354,7 @@ static int ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS case ZEND_USER_OPCODE_CONTINUE: ZEND_VM_CONTINUE(); case ZEND_USER_OPCODE_RETURN: - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } else { return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -1366,7 +1388,7 @@ static int ZEND_FASTCALL ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) 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_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); } EX(fast_ret) = opline + 1; @@ -1385,15 +1407,15 @@ static int ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) 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_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); } else { EG(exception) = EX(delayed_exception); EX(delayed_exception) = NULL; if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); - } else if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } else { return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -1462,7 +1484,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); @@ -1488,7 +1510,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE STR_FREE(lcname); EX(call) = zend_vm_stack_push_call_frame( - Z_FUNC_P(func), 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + Z_FUNC_P(func), opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1508,7 +1530,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1566,7 +1588,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1606,7 +1628,7 @@ static int ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); } @@ -1630,7 +1652,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); } @@ -1639,29 +1661,24 @@ static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ { USE_OPLINE zend_uint arg_num = opline->op1.num; - zend_uint arg_count = EX(prev_execute_data)->call->num_args; - zval *var_ptr; + zval *param; SAVE_OPLINE(); - var_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(var_ptr))) Z_DELREF_P(var_ptr); - if (arg_num > arg_count) { - ZVAL_COPY_VALUE(var_ptr, opline->op2.zv); - if (Z_OPT_CONSTANT_P(var_ptr)) { - zval_update_constant(var_ptr, 0 TSRMLS_CC); + param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); + if (arg_num > EX(num_args)) { + ZVAL_COPY_VALUE(param, opline->op2.zv); + if (Z_OPT_CONSTANT_P(param)) { + zval_update_constant(param, 0 TSRMLS_CC); } else { /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */ - if (UNEXPECTED(Z_OPT_COPYABLE_P(var_ptr))) { - zval_copy_ctor_func(var_ptr); + if (UNEXPECTED(Z_OPT_COPYABLE_P(param))) { + zval_copy_ctor_func(param); } } - } else { - zval *param = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); - ZVAL_COPY(var_ptr, param); } - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, var_ptr, opline->extended_value TSRMLS_CC); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); } CHECK_EXCEPTION(); @@ -1675,8 +1692,8 @@ static int ZEND_FASTCALL ZEND_BRK_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, - EX(op_array), execute_data TSRMLS_CC); - ZEND_VM_JMP(EX(op_array)->opcodes + el->brk); + &EX(func)->op_array, execute_data TSRMLS_CC); + ZEND_VM_JMP(EX(func)->op_array.opcodes + el->brk); } static int ZEND_FASTCALL ZEND_CONT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -1686,8 +1703,8 @@ static int ZEND_FASTCALL ZEND_CONT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, - EX(op_array), execute_data TSRMLS_CC); - ZEND_VM_JMP(EX(op_array)->opcodes + el->cont); + &EX(func)->op_array, execute_data TSRMLS_CC); + ZEND_VM_JMP(EX(func)->op_array.opcodes + el->cont); } static int ZEND_FASTCALL ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -1698,9 +1715,9 @@ static int ZEND_FASTCALL ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->extended_value, - EX(op_array), execute_data TSRMLS_CC); + &EX(func)->op_array, execute_data TSRMLS_CC); - brk_opline = EX(op_array)->opcodes + el->brk; + brk_opline = EX(func)->op_array.opcodes + el->brk; if (brk_opline->opcode == ZEND_SWITCH_FREE) { if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { @@ -1802,7 +1819,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); @@ -1829,7 +1846,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H zval_dtor(free_op2.var); EX(call) = zend_vm_stack_push_call_frame( - Z_FUNC_P(func), 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + Z_FUNC_P(func), opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1849,7 +1866,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1907,7 +1924,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); CHECK_EXCEPTION(); @@ -1984,7 +2001,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); @@ -2011,7 +2028,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H zval_ptr_dtor_nogc(free_op2.var); EX(call) = zend_vm_stack_push_call_frame( - Z_FUNC_P(func), 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + Z_FUNC_P(func), opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2031,7 +2048,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2089,7 +2106,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); CHECK_EXCEPTION(); @@ -2204,7 +2221,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); @@ -2230,7 +2247,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA STR_FREE(lcname); EX(call) = zend_vm_stack_push_call_frame( - Z_FUNC_P(func), 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + Z_FUNC_P(func), opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2250,7 +2267,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2308,7 +2325,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2654,7 +2671,7 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *value, *top; + zval *value, *arg; SAVE_OPLINE(); @@ -2665,11 +2682,11 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A } value = opline->op1.zv; - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY_VALUE(top, value); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + ZVAL_COPY_VALUE(arg, value); if (IS_CONST == IS_CONST) { - if (UNEXPECTED(Z_OPT_COPYABLE_P(top))) { - zval_copy_ctor_func(top); + if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { + zval_copy_ctor_func(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -2942,7 +2959,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA HANDLE_EXCEPTION(); } else if (EXPECTED(new_op_array != NULL)) { zval *return_value = NULL; - zend_call_frame *call; EG(active_op_array) = new_op_array; if (RETURN_VALUE_USED(opline)) { @@ -2950,24 +2966,22 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA } EX(call) = zend_vm_stack_push_call_frame( - (zend_function*)new_op_array, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } + EX(call)->prev_execute_data = EG(current_execute_data); + i_init_execute_data(EX(call), new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - i_create_execute_data_from_op_array(new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); ZEND_VM_ENTER(); } else { - zend_execute(new_op_array, return_value TSRMLS_CC); + execute_ex(EG(current_execute_data) TSRMLS_CC); } EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); - call = EX(call); - EX(call) = EX(call)->prev; - zend_vm_stack_free((zval*)call TSRMLS_CC); + EG(active_op_array) = &EX(func)->op_array; destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -3751,7 +3765,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -3837,13 +3851,14 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( } if (IS_CONST != IS_CONST) { - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { ce = EG(called_scope); } } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -4287,7 +4302,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE if (IS_CONST != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { @@ -4718,7 +4733,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -4804,13 +4819,14 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE } if (IS_CONST != IS_CONST) { - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { ce = EG(called_scope); } } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -4972,7 +4988,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_CONST != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { @@ -5553,7 +5569,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -5639,13 +5655,14 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE } if (IS_CONST != IS_CONST) { - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { ce = EG(called_scope); } } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -5958,7 +5975,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_CONST != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { @@ -6247,7 +6264,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -6333,13 +6350,14 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER } if (IS_CONST != IS_CONST) { - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { ce = EG(called_scope); } } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -6661,7 +6679,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL if (IS_CONST != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { @@ -7077,7 +7095,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -7163,13 +7181,14 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN } if (IS_CONST != IS_CONST) { - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { ce = EG(called_scope); } } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -7185,7 +7204,7 @@ static int ZEND_FASTCALL ZEND_CATCH_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A /* Check whether an exception has been thrown, if not, jump over code */ zend_exception_restore(TSRMLS_C); if (EG(exception) == NULL) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->extended_value]); ZEND_VM_CONTINUE(); /* CHECK_ME */ } if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { @@ -7209,7 +7228,7 @@ static int ZEND_FASTCALL ZEND_CATCH_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION(); } - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->extended_value]); ZEND_VM_CONTINUE(); /* CHECK_ME */ } } @@ -7383,7 +7402,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A if (IS_CONST != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { @@ -7853,7 +7872,7 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *value, *top; + zval *value, *arg; zend_free_op free_op1; SAVE_OPLINE(); @@ -7864,11 +7883,11 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG } value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY_VALUE(top, value); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + ZVAL_COPY_VALUE(arg, value); if (IS_TMP_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_COPYABLE_P(top))) { - zval_copy_ctor_func(top); + if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { + zval_copy_ctor_func(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -8143,7 +8162,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HAND HANDLE_EXCEPTION(); } else if (EXPECTED(new_op_array != NULL)) { zval *return_value = NULL; - zend_call_frame *call; EG(active_op_array) = new_op_array; if (RETURN_VALUE_USED(opline)) { @@ -8151,24 +8169,22 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HAND } EX(call) = zend_vm_stack_push_call_frame( - (zend_function*)new_op_array, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } + EX(call)->prev_execute_data = EG(current_execute_data); + i_init_execute_data(EX(call), new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - i_create_execute_data_from_op_array(new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); ZEND_VM_ENTER(); } else { - zend_execute(new_op_array, return_value TSRMLS_CC); + execute_ex(EG(current_execute_data) TSRMLS_CC); } EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); - call = EX(call); - EX(call) = EX(call)->prev; - zend_vm_stack_free((zval*)call TSRMLS_CC); + EG(active_op_array) = &EX(func)->op_array; destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -9087,7 +9103,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -9400,7 +9416,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { @@ -9923,7 +9939,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -10087,7 +10103,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { @@ -10760,7 +10776,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -11075,7 +11091,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { @@ -11640,7 +11656,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { @@ -12147,7 +12163,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_ } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -12309,7 +12325,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { @@ -12998,18 +13014,18 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) static int ZEND_FASTCALL zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; zend_free_op free_op1; varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); zval_ptr_dtor_nogc(free_op1.var); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (IS_VAR == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -13019,7 +13035,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND { USE_OPLINE zend_free_op free_op1; - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ @@ -13044,15 +13060,16 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND if (IS_VAR == IS_CV) { Z_ADDREF_P(varptr); } - zend_vm_stack_push(varptr TSRMLS_CC); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + ZVAL_COPY_VALUE(arg, varptr); } else { if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : !ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY(top, varptr); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + ZVAL_COPY(arg, varptr); zval_ptr_dtor_nogc(free_op1.var); } CHECK_EXCEPTION(); @@ -13063,7 +13080,7 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG { USE_OPLINE zend_free_op free_op1; - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); varptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -13072,23 +13089,23 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_error_noreturn(E_ERROR, "Only variables can be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); if (IS_VAR == IS_VAR && UNEXPECTED(varptr == &EG(error_zval))) { - ZVAL_NEW_REF(top, &EG(uninitialized_zval)); + ZVAL_NEW_REF(arg, &EG(uninitialized_zval)); ZEND_VM_NEXT_OPCODE(); } if (Z_ISREF_P(varptr)) { Z_ADDREF_P(varptr); - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); } else if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { - ZVAL_COPY_VALUE(top, varptr); - ZVAL_MAKE_REF(top); + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_MAKE_REF(arg); } else { ZVAL_MAKE_REF(varptr); Z_ADDREF_P(varptr); - ZVAL_REF(top, Z_REF_P(varptr)); + ZVAL_REF(arg, Z_REF_P(varptr)); } if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; @@ -13098,7 +13115,7 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; zend_free_op free_op1; if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { @@ -13108,14 +13125,14 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG } varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); zval_ptr_dtor_nogc(free_op1.var); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (IS_VAR == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -13401,7 +13418,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND HANDLE_EXCEPTION(); } else if (EXPECTED(new_op_array != NULL)) { zval *return_value = NULL; - zend_call_frame *call; EG(active_op_array) = new_op_array; if (RETURN_VALUE_USED(opline)) { @@ -13409,24 +13425,22 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND } EX(call) = zend_vm_stack_push_call_frame( - (zend_function*)new_op_array, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } + EX(call)->prev_execute_data = EG(current_execute_data); + i_init_execute_data(EX(call), new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - i_create_execute_data_from_op_array(new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); ZEND_VM_ENTER(); } else { - zend_execute(new_op_array, return_value TSRMLS_CC); + execute_ex(EG(current_execute_data) TSRMLS_CC); } EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); - call = EX(call); - EX(call) = EX(call)->prev; - zend_vm_stack_free((zval*)call TSRMLS_CC); + EG(active_op_array) = &EX(func)->op_array; destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -15349,7 +15363,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op1.var); @@ -15372,7 +15386,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -15458,13 +15472,14 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE } if (IS_VAR != IS_CONST) { - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { ce = EG(called_scope); } } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -16144,7 +16159,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { @@ -17577,7 +17592,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); zval_ptr_dtor_nogc(free_op1.var); @@ -17601,7 +17616,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -17687,13 +17702,14 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND } if (IS_VAR != IS_CONST) { - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { ce = EG(called_scope); } } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -18126,7 +18142,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR if (IS_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { @@ -19773,7 +19789,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); zval_ptr_dtor_nogc(free_op1.var); @@ -19797,7 +19813,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -19883,13 +19899,14 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND } if (IS_VAR != IS_CONST) { - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { ce = EG(called_scope); } } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -20473,7 +20490,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR if (IS_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { @@ -21262,7 +21279,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -21348,13 +21365,14 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z } if (IS_VAR != IS_CONST) { - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { ce = EG(called_scope); } } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -21669,7 +21687,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER if (IS_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { @@ -23143,7 +23161,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_ } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op1.var); @@ -23166,7 +23184,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -23252,13 +23270,14 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ } if (IS_VAR != IS_CONST) { - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { ce = EG(called_scope); } } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -23688,7 +23707,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG if (IS_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { @@ -24720,7 +24739,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -25147,7 +25166,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL if (IS_UNUSED != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { @@ -26094,7 +26113,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -26425,7 +26444,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER if (IS_UNUSED != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { @@ -27372,7 +27391,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -27703,7 +27722,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER if (IS_UNUSED != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { @@ -28219,7 +28238,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND if (IS_UNUSED != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { @@ -29160,7 +29179,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -29488,7 +29507,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_UNUSED != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { @@ -30147,18 +30166,18 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) static int ZEND_FASTCALL zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (IS_CV == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -30168,7 +30187,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ @@ -30193,15 +30212,16 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL if (IS_CV == IS_CV) { Z_ADDREF_P(varptr); } - zend_vm_stack_push(varptr TSRMLS_CC); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + ZVAL_COPY_VALUE(arg, varptr); } else { if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : !ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY(top, varptr); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + ZVAL_COPY(arg, varptr); } CHECK_EXCEPTION(); @@ -30212,7 +30232,7 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); varptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); @@ -30221,23 +30241,23 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS zend_error_noreturn(E_ERROR, "Only variables can be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); if (IS_CV == IS_VAR && UNEXPECTED(varptr == &EG(error_zval))) { - ZVAL_NEW_REF(top, &EG(uninitialized_zval)); + ZVAL_NEW_REF(arg, &EG(uninitialized_zval)); ZEND_VM_NEXT_OPCODE(); } if (Z_ISREF_P(varptr)) { Z_ADDREF_P(varptr); - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); } else if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { - ZVAL_COPY_VALUE(top, varptr); - ZVAL_MAKE_REF(top); + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_MAKE_REF(arg); } else { ZVAL_MAKE_REF(varptr); Z_ADDREF_P(varptr); - ZVAL_REF(top, Z_REF_P(varptr)); + ZVAL_REF(arg, Z_REF_P(varptr)); } ZEND_VM_NEXT_OPCODE(); @@ -30246,7 +30266,7 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { @@ -30256,14 +30276,14 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS } varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (IS_CV == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -30536,7 +30556,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL HANDLE_EXCEPTION(); } else if (EXPECTED(new_op_array != NULL)) { zval *return_value = NULL; - zend_call_frame *call; EG(active_op_array) = new_op_array; if (RETURN_VALUE_USED(opline)) { @@ -30544,24 +30563,22 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL } EX(call) = zend_vm_stack_push_call_frame( - (zend_function*)new_op_array, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } + EX(call)->prev_execute_data = EG(current_execute_data); + i_init_execute_data(EX(call), new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - i_create_execute_data_from_op_array(new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); ZEND_VM_ENTER(); } else { - zend_execute(new_op_array, return_value TSRMLS_CC); + execute_ex(EG(current_execute_data) TSRMLS_CC); } EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); - call = EX(call); - EX(call) = EX(call)->prev; - zend_vm_stack_free((zval*)call TSRMLS_CC); + EG(active_op_array) = &EX(func)->op_array; destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -32333,7 +32350,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -32915,7 +32932,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A if (IS_CV != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { @@ -34376,7 +34393,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -34811,7 +34828,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG if (IS_CV != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { @@ -36455,7 +36472,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -37041,7 +37058,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG if (IS_CV != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { @@ -38104,7 +38121,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_CV != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { @@ -39575,7 +39592,7 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H } EX(call) = zend_vm_stack_push_call_frame( - fbc, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -40006,7 +40023,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS if (IS_CV != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index fa976cb678..41a834de95 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -33,10 +33,21 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *execute_data TSRMLS_DC) ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array, zval *return_value TSRMLS_DC) { + zend_execute_data *execute_data; + if (EG(exception) != NULL) { return; - } - zend_{%EXECUTOR_NAME%}_ex(i_create_execute_data_from_op_array(op_array, return_value, EG(active_symbol_table) ? VM_FRAME_TOP_CODE : VM_FRAME_TOP_FUNCTION TSRMLS_CC) TSRMLS_CC); + } + + if (EG(current_execute_data) && EG(current_execute_data)->call) { + execute_data = EG(current_execute_data)->call; + } else { + execute_data = zend_vm_stack_push_call_frame( + (zend_function*)op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), NULL TSRMLS_CC); + } + EX(prev_execute_data) = EG(current_execute_data); + i_init_execute_data(execute_data, op_array, return_value, EG(active_symbol_table) ? VM_FRAME_TOP_CODE : VM_FRAME_TOP_FUNCTION TSRMLS_CC); + zend_{%EXECUTOR_NAME%}_ex(execute_data TSRMLS_CC); } {%EXTERNAL_EXECUTOR%} diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index b5f2c95efe..048362d3ec 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -286,6 +286,10 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char EG(active_op_array) = new_op_array; zend_try { + if (EG(current_execute_data)) { + EG(current_execute_data)->call = zend_vm_stack_push_call_frame( + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EG(current_execute_data)->call TSRMLS_CC); + } zend_execute(new_op_array, &result TSRMLS_CC); if (PHAR_G(cwd)) { efree(PHAR_G(cwd)); diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 22e2a0c671..5ec20cd563 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -292,6 +292,10 @@ static int spl_autoload(zend_string *class_name, zend_string *lc_name, const cha } ZVAL_UNDEF(&result); + if (EG(current_execute_data)) { + EG(current_execute_data)->call = zend_vm_stack_push_call_frame( + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EG(current_execute_data)->call TSRMLS_CC); + } zend_execute(new_op_array, &result TSRMLS_CC); destroy_op_array(new_op_array TSRMLS_CC); diff --git a/sapi/fpm/fpm/fpm_php_trace.c b/sapi/fpm/fpm/fpm_php_trace.c index 22ccb8f2bb..d5b4242fc3 100644 --- a/sapi/fpm/fpm/fpm_php_trace.c +++ b/sapi/fpm/fpm/fpm_php_trace.c @@ -42,6 +42,8 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC) /* {{{ */ { +// TODO: fpm_php_trace_dump() has to be reimplemented ??? +#if 0 int callers_limit = 20; pid_t pid = child->pid; struct timeval tv; @@ -74,10 +76,9 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC fprintf(slowlog, "[0x%" PTR_FMT "lx] ", execute_data); - // TODO: fpm_php_trace_dump() has be reimplemented ??? -//??? if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, function_state.function), &l)) { -//??? return -1; -//??? } + if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, function_state.function), &l)) { + return -1; + } function = l; @@ -132,6 +133,7 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC break; } } +#endif return 0; } /* }}} */ -- 2.40.0