From: Dmitry Stogov Date: Mon, 30 Jun 2014 11:43:45 +0000 (+0400) Subject: Refactored parameter passing mechanism. X-Git-Tag: POST_PHPNG_MERGE~98^2~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b7715c7e8a6166f84d9c4d6e35bffef853cabc5c;p=php Refactored parameter passing mechanism. In PHP-5.6 and below each argument passed to user function was copies on VM stack twice. Now we always have ZEND_INIT_FCALL (or simular) opcode that pushes "call frame" on top of VM stack. "Call frame" is actually the same zend_execute_data structure. All the following ZEND_SEND instructions push arguments on top of the stack in a way that they directly comes into corresponding CV variables of the called frame. Extra arguments are copied at the end of stack frame (after all CV and TMP variables) on function enterance. There are two minor incompatibilities: 1) It's not allowed to decalre functions redefining arguments e.g. "function foo($a,$a) {}". 2) func_get_arg() and func_get args() return the current value of argument and not the original value that was sent. --- diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 1568374f4e..6b469c2b0a 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -44,14 +44,13 @@ static zend_class_entry **class_cleanup_handlers; /* this function doesn't check for too many parameters */ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ { - zval *p; int arg_count; va_list ptr; zval **param, *param_ptr; TSRMLS_FETCH(); - p = zend_vm_stack_top(TSRMLS_C) - 1; - arg_count = Z_LVAL_P(p); + param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); + arg_count = EG(current_execute_data)->call->num_args; if (param_count>arg_count) { return FAILURE; @@ -61,7 +60,6 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ while (param_count-->0) { param = va_arg(ptr, zval **); - param_ptr = (p-arg_count); if (!Z_ISREF_P(param_ptr) && Z_REFCOUNT_P(param_ptr) > 1) { zval new_tmp; @@ -70,7 +68,7 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ ZVAL_COPY_VALUE(param_ptr, &new_tmp); } *param = param_ptr; - arg_count--; + param_ptr++; } va_end(ptr); @@ -82,14 +80,13 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ /* this function doesn't check for too many parameters */ ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */ { - zval *p; int arg_count; va_list ptr; - zval **param; + zval **param, *param_ptr; TSRMLS_FETCH(); - p = zend_vm_stack_top(TSRMLS_C) - 1; - arg_count = Z_LVAL_P(p); + param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); + arg_count = EG(current_execute_data)->call->num_args; if (param_count>arg_count) { return FAILURE; @@ -98,7 +95,8 @@ ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */ va_start(ptr, param_count); while (param_count-->0) { param = va_arg(ptr, zval **); - *param = p-(arg_count--); + *param = param_ptr; + param_ptr++; } va_end(ptr); @@ -108,22 +106,20 @@ ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */ ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array TSRMLS_DC) /* {{{ */ { - zval *p; + zval *param_ptr; int arg_count; - p = zend_vm_stack_top(TSRMLS_C) - 1; - arg_count = Z_LVAL_P(p); + param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); + arg_count = EG(current_execute_data)->call->num_args; if (param_count>arg_count) { return FAILURE; } while (param_count-->0) { - zval *value = (p-arg_count); - - ZVAL_COPY_VALUE(argument_array, value); + ZVAL_COPY_VALUE(argument_array, param_ptr); argument_array++; - arg_count--; + param_ptr++; } return SUCCESS; @@ -132,22 +128,22 @@ ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array TSRMLS_DC) /* {{{ */ { - zval *p; + zval *param_ptr; int arg_count; - p = zend_vm_stack_top(TSRMLS_C) - 1; - arg_count = Z_LVAL_P(p); + param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); + arg_count = EG(current_execute_data)->call->num_args; if (param_count>arg_count) { return FAILURE; } while (param_count-->0) { - zval *param = p-(arg_count--); - if (Z_REFCOUNTED_P(param)) { - Z_ADDREF_P(param); + if (Z_REFCOUNTED_P(param_ptr)) { + Z_ADDREF_P(param_ptr); } - add_next_index_zval(argument_array, param); + zend_hash_next_index_insert_new(Z_ARRVAL_P(argument_array), param_ptr); + param_ptr++; } return SUCCESS; @@ -807,7 +803,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, case '+': if (have_varargs) { if (!quiet) { - zend_function *active_function = EG(current_execute_data)->function_state.function; + zend_function *active_function = EG(current_execute_data)->call->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; zend_error(E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted", class_name, @@ -827,7 +823,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, default: if (!quiet) { - zend_function *active_function = EG(current_execute_data)->function_state.function; + zend_function *active_function = EG(current_execute_data)->call->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; zend_error(E_WARNING, "%s%s%s(): bad type specifier while parsing parameters", class_name, @@ -850,7 +846,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, if (num_args < min_num_args || (num_args > max_num_args && max_num_args > 0)) { if (!quiet) { - zend_function *active_function = EG(current_execute_data)->function_state.function; + zend_function *active_function = EG(current_execute_data)->call->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given", class_name, @@ -864,7 +860,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, return FAILURE; } - arg_count = Z_LVAL_P(zend_vm_stack_top(TSRMLS_C) - 1); + arg_count = EG(current_execute_data)->call->num_args; if (num_args > arg_count) { zend_error(E_WARNING, "%s(): could not obtain parameters for parsing", @@ -888,7 +884,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, if (num_varargs > 0) { *n_varargs = num_varargs; - *varargs = (zend_vm_stack_top(TSRMLS_C) - 1 - (arg_count - i)); + *varargs = ZEND_CALL_ARG(EG(current_execute_data)->call, i + 1); /* adjust how many args we have left and restart loop */ num_args += 1 - num_varargs; i += num_varargs; @@ -899,7 +895,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, } } - arg = zend_vm_stack_top(TSRMLS_C) - 1 - (arg_count-i); + arg = ZEND_CALL_ARG(EG(current_execute_data)->call, i + 1); if (zend_parse_arg(i+1, arg, va, &type_spec, quiet TSRMLS_CC) == FAILURE) { /* clean up varargs array if it was used */ @@ -970,7 +966,7 @@ ZEND_API int zend_parse_method_parameters(int num_args TSRMLS_DC, zval *this_ptr * Z_OBJ(EG(This)) to NULL when calling an internal function with common.scope == NULL. * In that case EG(This) would still be the $this from the calling code and we'd take the * wrong branch here. */ - zend_bool is_method = EG(current_execute_data)->function_state.function->common.scope != NULL; + zend_bool is_method = EG(current_execute_data)->call->func->common.scope != NULL; if (!is_method || !this_ptr || Z_TYPE_P(this_ptr) != IS_OBJECT) { RETURN_IF_ZERO_ARGS(num_args, p, 0); diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index cb2205b82c..df81c5d666 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->function_state.arguments) { - RETURN_LONG(Z_LVAL_P(ex->function_state.arguments)); + 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); @@ -409,11 +409,10 @@ ZEND_FUNCTION(func_num_args) Get the $arg_num'th argument that was passed to the function */ ZEND_FUNCTION(func_get_arg) { - zval *p; - int arg_count; + int arg_count, first_extra_arg; 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; @@ -424,20 +423,28 @@ ZEND_FUNCTION(func_get_arg) RETURN_FALSE; } - if (!ex || !ex->function_state.arguments) { + 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; } - p = ex->function_state.arguments; - arg_count = Z_LVAL_P(p); /* this is the amount of arguments passed to func_get_arg(); */ + 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 = p-(arg_count-requested_offset); + first_extra_arg = ex->func->op_array.num_args; + if (ex->func->op_array.fn_flags & ZEND_ACC_VARIADIC) { + first_extra_arg--; + } + if (requested_offset >= first_extra_arg && (ex->num_args > first_extra_arg)) { + arg = EX_VAR_NUM_2(ex, ex->func->op_array.last_var + ex->func->op_array.T) + (requested_offset - first_extra_arg); + } else { + arg = ZEND_CALL_ARG(ex, requested_offset + 1); + } RETURN_ZVAL_FAST(arg); } /* }}} */ @@ -447,26 +454,45 @@ ZEND_FUNCTION(func_get_arg) ZEND_FUNCTION(func_get_args) { zval *p; - int arg_count; + int arg_count, first_extra_arg; int i; - zend_execute_data *ex = EG(current_execute_data)->prev_execute_data; + zend_execute_data *ex = EG(current_execute_data); - if (!ex || !ex->function_state.arguments) { + 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; } - p = ex->function_state.arguments; - arg_count = Z_LVAL_P(p); /* this is the amount of arguments passed to func_get_args(); */ + arg_count = ex->num_args; array_init_size(return_value, arg_count); if (arg_count) { Bucket *q; - p -= arg_count; + first_extra_arg = ex->func->op_array.num_args; + if (ex->func->op_array.fn_flags & ZEND_ACC_VARIADIC) { + first_extra_arg--; + } zend_hash_real_init(Z_ARRVAL_P(return_value), 1); + i = 0; q = Z_ARRVAL_P(return_value)->arData; - for (i=0; inum_args > first_extra_arg) { + while (i < first_extra_arg) { + 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_VAR_NUM_2(ex, ex->func->op_array.last_var + ex->func->op_array.T); + } + while (i < arg_count) { q->h = i; q->key = NULL; if (!Z_ISREF_P(p)) { @@ -476,6 +502,7 @@ ZEND_FUNCTION(func_get_args) } p++; q++; + i++; } Z_ARRVAL_P(return_value)->nNumUsed = i; Z_ARRVAL_P(return_value)->nNumOfElements = i; @@ -1957,22 +1984,37 @@ ZEND_FUNCTION(get_defined_constants) /* }}} */ -static void debug_backtrace_get_args(zval *curpos, zval *arg_array TSRMLS_DC) +static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array TSRMLS_DC) { - zval *p = curpos; - zval *arg; - int arg_count = Z_LVAL_P(p); + int num_args = call->num_args; - array_init_size(arg_array, arg_count); - p -= arg_count; + 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->func->type == ZEND_USER_FUNCTION) { + int first_extra_arg = call->func->op_array.num_args; + + if (call->func->op_array.fn_flags & ZEND_ACC_VARIADIC) { + first_extra_arg--; + } + if (call->num_args > first_extra_arg) { + while (i < first_extra_arg) { + if (Z_REFCOUNTED_P(p)) Z_ADDREF_P(p); + zend_hash_next_index_insert_new(Z_ARRVAL_P(arg_array), p); + p++; + i++; + } + p = EX_VAR_NUM_2(call, call->func->op_array.last_var + call->func->op_array.T); + } + } + + 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++; } } } @@ -1996,6 +2038,7 @@ ZEND_FUNCTION(debug_print_backtrace) zend_execute_data *ptr, *skip; zend_object *object; int lineno, frameno = 0; + zend_function *func; const char *function_name; const char *filename; zend_string *class_name = NULL; @@ -2025,17 +2068,16 @@ ZEND_FUNCTION(debug_print_backtrace) skip = ptr; /* skip internal handler */ - if (!skip->op_array && + if ((!skip->func || !ZEND_USER_CODE(skip->func->common.type)) && skip->prev_execute_data && skip->prev_execute_data->opline && skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL && - skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME && skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) { skip = skip->prev_execute_data; } - if (skip->op_array) { - filename = skip->op_array->filename->val; + if (skip->func && ZEND_USER_CODE(skip->func->common.type)) { + filename = skip->func->op_array.filename->val; lineno = skip->opline->lineno; } else { filename = NULL; @@ -2044,41 +2086,47 @@ ZEND_FUNCTION(debug_print_backtrace) /* $this may be passed into regular internal functions */ if (object && - ptr->function_state.function->type == ZEND_INTERNAL_FUNCTION && - !ptr->function_state.function->common.scope) { + ptr->call && + ptr->call->func->type == ZEND_INTERNAL_FUNCTION && + !ptr->call->func->common.scope) { object = NULL; } - function_name = (ptr->function_state.function->common.scope && - ptr->function_state.function->common.scope->trait_aliases) ? + if (ptr->call && ptr->call->func && (ptr->call->flags & ZEND_CALL_DONE)) { + func = ptr->call->func; + function_name = (func->common.scope && + func->common.scope->trait_aliases) ? zend_resolve_method_name( - object ? + (object ? zend_get_class_entry(object TSRMLS_CC) : - ptr->function_state.function->common.scope, - ptr->function_state.function)->val : - (ptr->function_state.function->common.function_name ? - ptr->function_state.function->common.function_name->val : - NULL); + func->common.scope), func)->val : + (func->common.function_name ? + func->common.function_name->val : NULL); + } else { + func = ptr->func; + function_name = func && func->common.function_name ? + func->common.function_name->val : NULL; + } if (function_name) { if (object) { - if (ptr->function_state.function->common.scope) { - class_name = ptr->function_state.function->common.scope->name; + if (func->common.scope) { + class_name = func->common.scope->name; } else { class_name = zend_get_object_classname(object TSRMLS_CC); } call_type = "->"; - } else if (ptr->function_state.function->common.scope) { - class_name = ptr->function_state.function->common.scope->name; + } else if (func->common.scope) { + class_name = func->common.scope->name; call_type = "::"; } else { class_name = NULL; call_type = NULL; } - if ((! ptr->opline) || ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL))) { - if (ptr->function_state.arguments && (options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0) { - debug_backtrace_get_args(ptr->function_state.arguments, &arg_array TSRMLS_CC); + if (func->type != ZEND_EVAL_CODE) { + if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0) { + debug_backtrace_get_args(ptr->call, &arg_array TSRMLS_CC); } } } else { @@ -2137,13 +2185,14 @@ ZEND_FUNCTION(debug_print_backtrace) zend_execute_data *prev = skip->prev_execute_data; while (prev) { - if (prev->function_state.function && - prev->function_state.function->common.type != ZEND_USER_FUNCTION) { + if (prev->call && + prev->call->func && + !ZEND_USER_CODE(prev->call->func->common.type)) { 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 && ZEND_USER_CODE(prev->func->common.type)) { + zend_printf(") called at [%s:%d]\n", prev->func->op_array.filename->val, prev->opline->lineno); break; } prev = prev->prev_execute_data; @@ -2166,6 +2215,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int zend_execute_data *ptr, *skip; zend_object *object = Z_OBJ(EG(This)); int lineno, frameno = 0; + zend_function *func; const char *function_name; const char *filename; zend_string *class_name; @@ -2194,17 +2244,16 @@ 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 || !ZEND_USER_CODE(skip->func->common.type)) && skip->prev_execute_data && skip->prev_execute_data->opline && skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL && - skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME && skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) { skip = skip->prev_execute_data; } - if (skip->op_array) { - filename = skip->op_array->filename->val; + if (skip->func && ZEND_USER_CODE(skip->func->common.type)) { + 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); @@ -2216,15 +2265,16 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int zend_execute_data *prev = skip->prev_execute_data; while (prev) { - if (prev->function_state.function && - prev->function_state.function->common.type != ZEND_USER_FUNCTION && - !(prev->function_state.function->common.type == ZEND_INTERNAL_FUNCTION && - (prev->function_state.function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER))) { + if (prev->call && + prev->call->func && + !ZEND_USER_CODE(prev->call->func->common.type) && + !(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 && ZEND_USER_CODE(prev->func->common.type)) { // 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; } @@ -2235,28 +2285,34 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int /* $this may be passed into regular internal functions */ if (object && - ptr->function_state.function->type == ZEND_INTERNAL_FUNCTION && - !ptr->function_state.function->common.scope) { + ptr->call && + ptr->call->func->type == ZEND_INTERNAL_FUNCTION && + !ptr->call->func->common.scope) { object = NULL; } - function_name = (ptr->function_state.function->common.scope && - ptr->function_state.function->common.scope->trait_aliases) ? + if (ptr->call && ptr->call->func && (ptr->call->flags & ZEND_CALL_DONE)) { + func = ptr->call->func; + function_name = (func->common.scope && + func->common.scope->trait_aliases) ? zend_resolve_method_name( - object ? + (object ? zend_get_class_entry(object TSRMLS_CC) : - ptr->function_state.function->common.scope, - ptr->function_state.function)->val : - (ptr->function_state.function->common.function_name ? - ptr->function_state.function->common.function_name->val : - NULL); + func->common.scope), func)->val : + (func->common.function_name ? + func->common.function_name->val : NULL); + } else { + func = ptr->func; + function_name = func && func->common.function_name ? + func->common.function_name->val : NULL; + } if (function_name) { add_assoc_string_ex(&stack_frame, "function", sizeof("function")-1, (char*)function_name); if (object) { - if (ptr->function_state.function->common.scope) { - add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(ptr->function_state.function->common.scope->name)); + if (func->common.scope) { + add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(func->common.scope->name)); } else { class_name = zend_get_object_classname(object TSRMLS_CC); add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(class_name)); @@ -2270,16 +2326,16 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int } add_assoc_string_ex(&stack_frame, "type", sizeof("type")-1, "->"); - } else if (ptr->function_state.function->common.scope) { - add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(ptr->function_state.function->common.scope->name)); + } else if (func->common.scope) { + add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(func->common.scope->name)); add_assoc_string_ex(&stack_frame, "type", sizeof("type")-1, "::"); } if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0 && - ((! ptr->opline) || ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL)))) { - if (ptr->function_state.arguments) { + func->type != ZEND_EVAL_CODE) { + if (ptr->call) { zval args; - debug_backtrace_get_args(ptr->function_state.arguments, &args TSRMLS_CC); + debug_backtrace_get_args(ptr->call, &args TSRMLS_CC); add_assoc_zval_ex(&stack_frame, "args", sizeof("args")-1, &args); } } @@ -2333,7 +2389,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 3c2921f53c..053a5eb199 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -47,7 +47,7 @@ static zend_object_handlers closure_handlers; ZEND_METHOD(Closure, __invoke) /* {{{ */ { - zend_function *func = EG(current_execute_data)->function_state.function; + zend_function *func = EG(current_execute_data)->call->func; zval *arguments; arguments = emalloc(sizeof(zval) * ZEND_NUM_ARGS()); @@ -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 c6116693b7..647fab48be 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,8 +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).nested_calls = 0; - CG(context).used_stack = 0; CG(context).in_finally = 0; CG(context).labels = NULL; } @@ -1463,6 +1461,11 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */ && opline->result.var == op1->u.op.var) { if (opline->opcode == ZEND_NEW) { opline->result_type |= EXT_TYPE_UNUSED; + opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1]; + while (opline->opcode != ZEND_DO_FCALL || opline->op1.num != ZEND_CALL_CTOR) { + opline--; + } + opline->op1.num |= ZEND_CALL_CTOR_RESULT_UNUSED; } break; } @@ -1841,7 +1844,9 @@ void zend_do_receive_param(zend_uchar op, znode *varname, znode *initialization, var.u.op.var = lookup_cv(CG(active_op_array), Z_STR(varname->u.constant) TSRMLS_CC); Z_STR(varname->u.constant) = CG(active_op_array)->vars[EX_VAR_TO_NUM(var.u.op.var)]; var.EA = 0; - if (Z_STRHASH(varname->u.constant) == THIS_HASHVAL && + if (EX_VAR_TO_NUM(var.u.op.var) != CG(active_op_array)->num_args) { + zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter %s", Z_STRVAL(varname->u.constant)); + } else if (Z_STRHASH(varname->u.constant) == THIS_HASHVAL && Z_STRLEN(varname->u.constant) == sizeof("this")-1 && !memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")-1)) { if (CG(active_op_array)->scope && @@ -1949,6 +1954,8 @@ 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,10 +1984,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; - zend_push_function_call_entry(function TSRMLS_CC); - if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls + 1; - } + 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, op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); return 0; } @@ -2017,12 +2028,10 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ } last_op->opcode = ZEND_INIT_METHOD_CALL; last_op->result_type = IS_UNUSED; - last_op->result.num = CG(context).nested_calls; Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME; } else { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_FCALL_BY_NAME; - opline->result.num = CG(context).nested_calls; SET_UNUSED(opline->op1); if (left_bracket->op_type == IS_CONST) { opline->op2_type = IS_CONST; @@ -2033,10 +2042,7 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ } } - zend_push_function_call_entry(NULL TSRMLS_CC); - if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls; - } + zend_push_function_call_entry(NULL, last_op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); } /* }}} */ @@ -2056,21 +2062,21 @@ 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 internal function with short name */ opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME; - opline->result.num = CG(context).nested_calls; SET_UNUSED(opline->op1); opline->op2_type = IS_CONST; opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC); GET_CACHE_SLOT(opline->op2.constant); } else { opline->opcode = ZEND_INIT_FCALL_BY_NAME; - opline->result.num = CG(context).nested_calls; SET_UNUSED(opline->op1); if (function_name->op_type == IS_CONST) { opline->op2_type = IS_CONST; @@ -2081,10 +2087,7 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML } } - zend_push_function_call_entry(NULL TSRMLS_CC); - if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls; - } + zend_push_function_call_entry(NULL, op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); } /* }}} */ @@ -2481,6 +2484,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) { @@ -2501,14 +2505,14 @@ 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; - opline->result.num = CG(context).nested_calls; if (class_node.op_type == IS_CONST) { opline->op1_type = IS_CONST; opline->op1.constant = @@ -2529,10 +2533,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); - if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls; - } + zend_push_function_call_entry(NULL, op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); return 1; /* Dynamic */ } @@ -2550,26 +2551,20 @@ 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 = get_next_op(CG(active_op_array) TSRMLS_CC); - if (fcall->fbc) { - opline->opcode = ZEND_DO_FCALL; - SET_NODE(opline->op1, function_name); - SET_UNUSED(opline->op2); - opline->op2.num = CG(context).nested_calls; - GET_CACHE_SLOT(opline->op1.constant); - } else { - opline->opcode = ZEND_DO_FCALL_BY_NAME; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); - opline->op2.num = --CG(context).nested_calls; + zend_uint call_flags = 0; - /* This would normally be a ZEND_DO_FCALL, but was forced to use - * ZEND_DO_FCALL_BY_NAME due to a ... argument. In this case we need to - * free the function_name */ - if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) { - zval_dtor(&function_name->u.constant); - } + opline = &CG(active_op_array)->opcodes[fcall->op_number]; + opline->extended_value = fcall->arg_num; + + if (opline->opcode == ZEND_NEW) { + call_flags = ZEND_CALL_CTOR; } + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_DO_FCALL; + SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); + opline->op1.num = call_flags; } opline->result.var = get_temporary_variable(CG(active_op_array)); @@ -2577,10 +2572,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 + 1 > CG(active_op_array)->used_stack) { - CG(active_op_array)->used_stack = CG(context).used_stack + 1; - } - CG(context).used_stack -= fcall->arg_num; zend_stack_del_top(&CG(function_call_stack)); } /* }}} */ @@ -2682,19 +2673,13 @@ void zend_do_pass_param(znode *param, zend_uchar op TSRMLS_DC) /* {{{ */ } } else { if (function_ptr) { - opline->extended_value = ZEND_DO_FCALL; - } else { - opline->extended_value = ZEND_DO_FCALL_BY_NAME; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; } } opline->opcode = op; SET_NODE(opline->op1, param); opline->op2.opline_num = fcall->arg_num; SET_UNUSED(opline->op2); - - if (++CG(context).used_stack > CG(active_op_array)->used_stack) { - CG(active_op_array)->used_stack = CG(context).used_stack; - } } /* }}} */ @@ -2705,25 +2690,6 @@ void zend_do_unpack_params(znode *params TSRMLS_DC) /* {{{ */ fcall->uses_argument_unpacking = 1; - if (fcall->fbc) { - /* If argument unpacking is used argument numbers and sending modes can no longer be - * computed at compile time, thus we need access to EX(call). In order to have it we - * retroactively emit a ZEND_INIT_FCALL_BY_NAME opcode. */ - zval func_name; - ZVAL_STR(&func_name, STR_COPY(fcall->fbc->common.function_name)); - - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_INIT_FCALL_BY_NAME; - opline->result.num = CG(context).nested_calls; - SET_UNUSED(opline->op1); - opline->op2_type = IS_CONST; - opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &func_name TSRMLS_CC); - GET_CACHE_SLOT(opline->op2.constant); - - ++CG(context).nested_calls; - fcall->fbc = NULL; - } - opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_SEND_UNPACK; SET_NODE(opline->op1, params); @@ -5619,16 +5585,12 @@ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /* new_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_NEW; - opline->extended_value = CG(context).nested_calls; opline->result_type = IS_VAR; opline->result.var = get_temporary_variable(CG(active_op_array)); SET_NODE(opline->op1, class_type); SET_UNUSED(opline->op2); - zend_push_function_call_entry(NULL TSRMLS_CC); - if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls; - } + zend_push_function_call_entry(NULL, new_token->u.op.opline_num TSRMLS_CC); } /* }}} */ @@ -5819,6 +5781,14 @@ 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)); + GET_CACHE_SLOT(opline->op2.constant); + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); switch (cmd->op_type) { case IS_CONST: case IS_TMP_VAR: @@ -5830,28 +5800,18 @@ void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC) /* {{{ */ } SET_NODE(opline->op1, cmd); opline->op2.opline_num = 1; - opline->extended_value = ZEND_DO_FCALL; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; SET_UNUSED(opline->op2); /* FIXME: exception support not added to this op2 */ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_DO_FCALL; + opline->extended_value = 1; opline->result.var = get_temporary_variable(CG(active_op_array)); opline->result_type = IS_VAR; - LITERAL_STR(opline->op1, STR_INIT("shell_exec", sizeof("shell_exec")-1, 0)); - opline->op1_type = IS_CONST; - GET_CACHE_SLOT(opline->op1.constant); - opline->extended_value = 1; + SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); - opline->op2.num = CG(context).nested_calls; GET_NODE(result, opline->result); - - if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls + 1; - } - if (CG(context).used_stack + 2 > CG(active_op_array)->used_stack) { - CG(active_op_array)->used_stack = CG(context).used_stack + 2; - } } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 5b5397844f..b053ee9820 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -59,8 +59,6 @@ typedef struct _zend_compiler_context { int literals_size; int current_brk_cont; int backpatch_count; - int nested_calls; - int used_stack; int in_finally; HashTable *labels; } zend_compiler_context; @@ -266,9 +264,6 @@ struct _zend_op_array { zend_uint T; - zend_uint nested_calls; - zend_uint used_stack; - zend_brk_cont_element *brk_cont_array; int last_brk_cont; @@ -336,14 +331,9 @@ union _zend_function { zend_internal_function internal_function; }; - -typedef struct _zend_function_state { - zend_function *function; - zval *arguments; -} zend_function_state; - 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; @@ -361,15 +351,6 @@ typedef struct _list_llist_element { znode value; } list_llist_element; -typedef struct _call_slot { - zend_function *fbc; - zend_class_entry *called_scope; - zend_object *object; - zend_uint num_additional_args; - zend_bool is_ctor_call; - zend_bool is_ctor_result_used; -} call_slot; - 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 */ @@ -379,28 +360,38 @@ typedef enum _vm_frame_kind { struct _zend_execute_data { struct _zend_op *opline; /* executed opline */ - zend_op_array *op_array; /* executed op_array */ - zend_function_state function_state; /* called function and arguments */ - zend_object *object; /* current $this */ - zend_class_entry *scope; /* function scope (self) */ - zend_class_entry *called_scope; /* function called scope (static) */ - zend_array *symbol_table; + zend_execute_data *call; /* current call */ void **run_time_cache; + zend_function *func; /* executed op_array */ + zend_uint num_args; + zend_uchar flags; + zend_uchar frame_kind; + zend_class_entry *called_scope; + zend_object *object; + zend_execute_data *prev_nested_call; zend_execute_data *prev_execute_data; zval *return_value; - 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; - call_slot *call_slots; - call_slot *call; + zend_class_entry *scope; /* function scope (self) */ + zend_array *symbol_table; + struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */ + zend_object *delayed_exception; + zval old_error_reporting; }; +#define ZEND_CALL_CTOR (1 << 0) +#define ZEND_CALL_CTOR_RESULT_UNUSED (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) @@ -730,8 +721,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 @@ -750,7 +741,6 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC); #define ZEND_PARSED_NEW (1<<6) #define ZEND_PARSED_LIST_EXPR (1<<7) - /* unset types */ #define ZEND_UNSET_REG 0 @@ -770,6 +760,9 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC); #define ZEND_EVAL_CODE 4 #define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5 +/* A quick check (type == ZEND_USER_FUNCTION || type == ZEND_EVAL_CODE) */ +#define ZEND_USER_CODE(type) ((type & 1) == 0) + #define ZEND_INTERNAL_CLASS 1 #define ZEND_USER_CLASS 2 @@ -877,7 +870,7 @@ END_EXTERN_C() /* call op_array handler of extendions */ #define ZEND_COMPILE_HANDLE_OP_ARRAY (1<<1) -/* generate ZEND_DO_FCALL_BY_NAME for internal functions instead of ZEND_DO_FCALL */ +/* generate ZEND_INIT_FCALL_BY_NAME for internal functions instead of ZEND_INIT_FCALL */ #define ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS (1<<2) /* don't perform early binding for classes inherited form internal ones; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index a6f6d65d72..5318bbe2d3 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 && ZEND_USER_CODE(ptr->func->common.type)) { + 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 && ZEND_USER_CODE(ptr->func->common.type)) { + 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); } @@ -1468,13 +1478,13 @@ ZEND_API opcode_handler_t *zend_opcode_handlers; ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, zend_fcall_info *fci TSRMLS_DC) { if (fci != NULL) { - execute_data_ptr->function_state.function->internal_function.handler( + execute_data_ptr->call->func->internal_function.handler( fci->param_count, fci->retval TSRMLS_CC ); } else { zval *return_value = EX_VAR_2(execute_data_ptr, execute_data_ptr->opline->result.var); - execute_data_ptr->function_state.function->internal_function.handler( - execute_data_ptr->opline->extended_value + execute_data_ptr->call->num_additional_args, return_value TSRMLS_CC + execute_data_ptr->call->func->internal_function.handler( + execute_data_ptr->call->num_args, return_value TSRMLS_CC ); } } @@ -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,132 +1527,65 @@ 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->num_args-1] = ARG[N] | * | ... | * | VAR[op_array->last_var-1] | - * | VAR[op_array->last_var] | + * | VAR[op_array->last_var] = TMP[0] | * | ... | * | VAR[op_array->last_var+op_array->T-1] | - * +----------------------------------------+ - * EX(call_slots) -> | CALL_SLOT[0] | + * | ARG[N+1] (extra_args) | * | ... | - * | CALL_SLOT[op_array->nested_calls-1] | - * +----------------------------------------+ - * zend_vm_stack_frame_base -> | 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 call_slots_size = ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * op_array->nested_calls; - size_t stack_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval)) * op_array->used_stack; - size_t total_size = execute_data_size + vars_size + call_slots_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)) * (args_count + 1); - - 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)->function_state.function = (zend_function*)op_array; - EX(prev_execute_data)->function_state.arguments = (zval*)(((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + execute_data_size + args_size - sizeof(zval))); - - /* copy arguments */ - ZVAL_LONG(EX(prev_execute_data)->function_state.arguments, args_count); - 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; ZVAL_UNDEF(&EX(old_error_reporting)); EX(delayed_exception) = NULL; - EX(call_slots) = (call_slot*)((char *)execute_data + execute_data_size + vars_size); EX(call) = NULL; 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(function_state).function = (zend_function *) op_array; - EX(function_state).arguments = NULL; - EX(op_array) = op_array; - EX(object) = Z_OBJ(EG(This)); 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 { + zend_uint first_extra_arg = op_array->num_args; + + if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_VARIADIC) != 0)) { + first_extra_arg--; + } + if (UNEXPECTED(EX(num_args) > first_extra_arg)) { + /* move extra args into separate array after all CV and TMP vars */ + zval *extra_args = EX_VAR_NUM(op_array->last_var + op_array->T); + + memmove(extra_args, EX_VAR_NUM(first_extra_arg), sizeof(zval) * (EX(num_args) - first_extra_arg)); + } + 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)); - while (var != end) { - ZVAL_UNDEF(var); - var++; + if (EXPECTED(num_args < op_array->last_var)) { + zval *var = EX_VAR_NUM(num_args); + zval *end = EX_VAR_NUM(op_array->last_var); + + do { + ZVAL_UNDEF(var); + var++; + } while (var != end); } } while (0); @@ -1661,62 +1604,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, call_slot *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->fbc, arg_num); + return ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num); } /* }}} */ -static zval *zend_vm_stack_push_args_with_copy(int count TSRMLS_DC) /* {{{ */ -{ - zend_vm_stack p = EG(argument_stack); - - zend_vm_stack_extend(count + 1 TSRMLS_CC); +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_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); + } - EG(argument_stack)->top += count; - ZVAL_LONG(EG(argument_stack)->top, count); - while (count-- > 0) { - zval *data = --p->top; - ZVAL_COPY_VALUE(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + count, data); + /* delete old call_frame from previous stack segment */ + EG(argument_stack)->prev->top = (zval*)call; - if (UNEXPECTED(p->top == ZEND_VM_STACK_ELEMETS(p))) { - zend_vm_stack r = p; + /* 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 = p->prev; - p = p->prev; - efree(r); - } + EG(argument_stack)->prev = r->prev; + efree(r); } - return EG(argument_stack)->top++; + + return new_call; } /* }}} */ -static zend_always_inline zval *zend_vm_stack_push_args(int count 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)) < count) - || UNEXPECTED(EG(argument_stack)->top == EG(argument_stack)->end)) { - return zend_vm_stack_push_args_with_copy(count 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); } - ZVAL_LONG(EG(argument_stack)->top, count); - return EG(argument_stack)->top++; } /* }}} */ - #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 b80d2adff8..40f42ae2dd 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,22 +158,26 @@ 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)))) - -#define ZEND_VM_STACK_GROW_IF_NEEDED(count) \ - do { \ - if (UNEXPECTED((count) > \ - EG(argument_stack)->end - EG(argument_stack)->top)) { \ - zend_vm_stack_extend((count) TSRMLS_CC); \ - } \ + (((zval*)(stack)) + ZEND_VM_STACK_HEADER_SLOT) + +#define ZEND_VM_STACK_GROW_IF_NEEDED(count) \ + do { \ + if (UNEXPECTED(((count) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) > \ + ((char*)EG(argument_stack)->end) - \ + ((char*)EG(argument_stack)->top))) { \ + zend_vm_stack_extend((count) TSRMLS_CC); \ + } \ } 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 +185,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,95 +201,90 @@ 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); + int size = count * ZEND_MM_ALIGNED_SIZE(sizeof(zval)); + zend_vm_stack p = zend_vm_stack_new_page( + (size >= (ZEND_VM_STACK_PAGE_SIZE - ZEND_VM_STACK_HEADER_SLOT) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) ? + (size + ((ZEND_VM_STACK_HEADER_SLOT + ZEND_VM_STACK_PAGE_SIZE) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) - 1) & + ~((ZEND_VM_STACK_PAGE_SIZE * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) - 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) +static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_function *func, zend_uint num_args, zend_uchar flags, zend_class_entry *called_scope, zend_object *object, zend_execute_data *prev TSRMLS_DC) { - return EG(argument_stack)->top++; + int used_stack = ZEND_CALL_FRAME_SLOT + num_args; + zend_execute_data *call; + + if (ZEND_USER_CODE(func->type)) { + used_stack += func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args); + } + ZEND_VM_STACK_GROW_IF_NEEDED(used_stack); + call = (zend_execute_data*)EG(argument_stack)->top; + EG(argument_stack)->top += used_stack; + call->func = func; + call->num_args = 0; + call->flags = flags; + call->called_scope = called_scope; + call->object = object; + call->prev_nested_call = prev; + return call; } -static zend_always_inline void zend_vm_stack_push(zval *ptr TSRMLS_DC) +static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call TSRMLS_DC) { - ZVAL_COPY_VALUE(EG(argument_stack)->top, ptr); - EG(argument_stack)->top++; -} + zend_uint first_extra_arg = call->func->op_array.num_args - ((call->func->common.fn_flags & ZEND_ACC_VARIADIC) != 0); -static zend_always_inline zval *zend_vm_stack_pop(TSRMLS_D) -{ - return --EG(argument_stack)->top; + if (UNEXPECTED(call->num_args > first_extra_arg)) { + zval *end = EX_VAR_NUM_2(call, call->func->op_array.last_var + call->func->op_array.T); + zval *p = end + (call->num_args - first_extra_arg); + do { + p--; + i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC); + } while (p != end); + } } -static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC) +static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call TSRMLS_DC) { - zval *ret; - int count = (size + (sizeof(zval) - 1)) / sizeof(zval); + zend_uint num_args = call->num_args; - ZEND_VM_STACK_GROW_IF_NEEDED(count); - ret = EG(argument_stack)->top; - EG(argument_stack)->top += count; - return ret; -} + if (num_args > 0) { + zval *p = ZEND_CALL_ARG(call, num_args + 1); + zval *end = p - num_args;; -static zend_always_inline zval* zend_vm_stack_frame_base(zend_execute_data *ex) -{ - return (zval*)((char*)ex->call_slots + - ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * ex->op_array->nested_calls); + do { + p--; + i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC); + } while (p != end); + } } -static zend_always_inline void zend_vm_stack_free(void *ptr TSRMLS_DC) +static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call TSRMLS_DC) { - if (UNEXPECTED((void*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == ptr)) { + 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 { - EG(argument_stack)->top = (zval*)ptr; - } -} - -static zend_always_inline void zend_vm_stack_clear_multiple(int nested TSRMLS_DC) -{ - zval *p = EG(argument_stack)->top - 1; - - if (EXPECTED(Z_LVAL_P(p) > 0)) { - zval *end = p - Z_LVAL_P(p); - - do { - p--; - i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC); - } while (p != end); - } - if (nested) { - EG(argument_stack)->top = p; - } else { - zend_vm_stack_free(p TSRMLS_CC); + EG(argument_stack)->top = (zval*)call; } } static zend_always_inline int zend_vm_stack_get_args_count_ex(zend_execute_data *ex) { - zval *p = ex->function_state.arguments; - return Z_LVAL_P(p); + return ex->call->num_args; } static zend_always_inline zval* zend_vm_stack_get_arg_ex(zend_execute_data *ex, int requested_arg) { - zval *p = ex->function_state.arguments; - int arg_count = Z_LVAL_P(p); + int arg_count = ex->call->num_args; if (UNEXPECTED(requested_arg > arg_count)) { return NULL; } - return p - arg_count + requested_arg - 1; + return ZEND_CALL_ARG(ex->call, requested_arg); } static zend_always_inline int zend_vm_stack_get_args_count(TSRMLS_D) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index ebb995a262..2ba582942a 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; @@ -393,17 +392,25 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ /* return class name and "::" or "". */ ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{ */ { + zend_function *func; + if (!zend_is_executing(TSRMLS_C)) { if (space) { *space = ""; } return ""; } - switch (EG(current_execute_data)->function_state.function->type) { + + if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) { + func = EG(current_execute_data)->call->func; + } else { + func = EG(current_execute_data)->func; + } + switch (func->type) { case ZEND_USER_FUNCTION: case ZEND_INTERNAL_FUNCTION: { - zend_class_entry *ce = EG(current_execute_data)->function_state.function->common.scope; + zend_class_entry *ce = func->common.scope; if (space) { *space = ce ? "::" : ""; @@ -421,12 +428,19 @@ ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{ ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */ { + zend_function *func; + if (!zend_is_executing(TSRMLS_C)) { return NULL; } - switch (EG(current_execute_data)->function_state.function->type) { + if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) { + func = EG(current_execute_data)->call->func; + } else { + func = EG(current_execute_data)->func; + } + switch (func->type) { case ZEND_USER_FUNCTION: { - zend_string *function_name = ((zend_op_array *) EG(current_execute_data)->function_state.function)->function_name; + zend_string *function_name = func->common.function_name; if (function_name) { return function_name->val; @@ -436,7 +450,7 @@ ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */ } break; case ZEND_INTERNAL_FUNCTION: - return ((zend_internal_function *) EG(current_execute_data)->function_state.function)->function_name->val; + return func->common.function_name->val; break; default: return NULL; @@ -655,6 +669,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zend_class_entry *called_scope = NULL; zend_execute_data execute_data; zend_fcall_info_cache fci_cache_local; + zend_function *func; zval tmp; ZVAL_UNDEF(fci->retval); @@ -681,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 @@ -719,7 +734,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS STR_RELEASE(callable_name); } - EX(function_state).function = fci_cache->function_handler; + 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; called_scope = fci_cache->called_scope; fci->object = fci_cache->object; @@ -729,24 +745,22 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS return FAILURE; } - if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) { - if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(function_state).function->common.scope->name->val, EX(function_state).function->common.function_name->val); + if (func->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) { + if (func->common.fn_flags & ZEND_ACC_ABSTRACT) { + zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", func->common.scope->name->val, func->common.function_name->val); } - if (EX(function_state).function->common.fn_flags & ZEND_ACC_DEPRECATED) { + if (func->common.fn_flags & ZEND_ACC_DEPRECATED) { zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name->val : "", - EX(function_state).function->common.scope ? "::" : "", - EX(function_state).function->common.function_name->val); + func->common.scope ? func->common.scope->name->val : "", + func->common.scope ? "::" : "", + func->common.function_name->val); } } - ZEND_VM_STACK_GROW_IF_NEEDED(fci->param_count + 1); - for (i=0; iparam_count; i++) { zval *param; - if (ARG_SHOULD_BE_SENT_BY_REF(EX(function_state).function, i + 1)) { + if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) { // TODO: Scalar values don't have reference counters anymore. // They are assumed to be 1, and they may be easily passed by // reference now. However, previously scalars with refcount==1 @@ -766,19 +780,19 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS (!Z_ISREF(fci->params[i]) && Z_REFCOUNT(fci->params[i]) > 1)) { if (fci->no_separation && - !ARG_MAY_BE_SENT_BY_REF(EX(function_state).function, i + 1)) { - if (i || UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (EG(argument_stack)->top))) { + !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { + if (i) { /* hack to clean up the stack */ - ZVAL_LONG(&tmp, i); - zend_vm_stack_push(&tmp TSRMLS_CC); - zend_vm_stack_clear_multiple(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, - EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name->val : "", - EX(function_state).function->common.scope ? "::" : "", - EX(function_state).function->common.function_name->val); + func->common.scope ? func->common.scope->name->val : "", + func->common.scope ? "::" : "", + func->common.function_name->val); return FAILURE; } @@ -794,27 +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 */ - (EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) { + (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(function_state).arguments = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_LONG(EX(function_state).arguments, fci->param_count); + EX(call)->num_args = fci->param_count; EG(scope) = calling_scope; EG(called_scope) = called_scope; if (!fci->object || - (EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) { - Z_OBJ(EG(This)) = NULL; + (func->common.fn_flags & ZEND_ACC_STATIC)) { + Z_OBJ(EG(This)) = EX(call)->object = NULL; } else { Z_OBJ(EG(This)) = fci->object; Z_ADDREF(EG(This)); @@ -823,9 +836,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS EX(prev_execute_data) = EG(current_execute_data); EG(current_execute_data) = &execute_data; - if (EX(function_state).function->type == ZEND_USER_FUNCTION) { + if (func->type == ZEND_USER_FUNCTION) { calling_symbol_table = EG(active_symbol_table); - EG(scope) = EX(function_state).function->common.scope; + EG(scope) = func->common.scope; if (fci->symbol_table) { EG(active_symbol_table) = fci->symbol_table; } else { @@ -833,7 +846,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } original_op_array = EG(active_op_array); - EG(active_op_array) = (zend_op_array *) EX(function_state).function; + EG(active_op_array) = (zend_op_array *) func; original_opline_ptr = EG(opline_ptr); if (EXPECTED((EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) == 0)) { @@ -848,18 +861,21 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC); } EG(active_symbol_table) = calling_symbol_table; - } else if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { - int call_via_handler = (EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0; + } else if (func->type == ZEND_INTERNAL_FUNCTION) { + int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0; ZVAL_NULL(fci->retval); - if (EX(function_state).function->common.scope) { - EG(scope) = EX(function_state).function->common.scope; + if (func->common.scope) { + EG(scope) = func->common.scope; } if (EXPECTED(zend_execute_internal == NULL)) { /* saves one function call if zend_execute_internal is not used */ - EX(function_state).function->internal_function.handler(fci->param_count, fci->retval TSRMLS_CC); + func->internal_function.handler(fci->param_count, fci->retval TSRMLS_CC); } 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) @@ -880,22 +896,21 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS /* Not sure what should be done here if it's a static method */ if (fci->object) { - fci->object->handlers->call_method(EX(function_state).function->common.function_name, fci->object, fci->param_count, fci->retval TSRMLS_CC); + fci->object->handlers->call_method(func->common.function_name, fci->object, fci->param_count, fci->retval TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } - if (EX(function_state).function->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { - STR_RELEASE(EX(function_state).function->common.function_name); + if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { + STR_RELEASE(func->common.function_name); } - efree(EX(function_state).function); + efree(func); if (EG(exception)) { zval_ptr_dtor(fci->retval); ZVAL_UNDEF(fci->retval); } } - zend_vm_stack_clear_multiple(0 TSRMLS_CC); if (Z_OBJ(EG(This))) { zval_ptr_dtor(&EG(This)); @@ -1080,6 +1095,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); @@ -1583,33 +1602,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 || !ZEND_USER_CODE(ex->func->common.type))) { 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); } } } @@ -1618,7 +1638,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 @@ -1649,7 +1669,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 */ @@ -1669,7 +1689,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) { @@ -1702,7 +1722,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 c80e909565..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 >= execute_data->call_slots) { + while (execute_data->call) { if (execute_data->call->object) { OBJ_RELEASE(execute_data->call->object); } - execute_data->call--; + 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,23 +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; - zval *arguments = prev_execute_data->function_state.arguments; - - if (arguments) { - int arguments_count = Z_LVAL_P(arguments); - zval *arguments_start = arguments - arguments_count; - 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). */ @@ -158,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; } @@ -171,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; @@ -196,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); @@ -288,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; @@ -300,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; @@ -343,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; @@ -358,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; @@ -670,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_object_handlers.c b/Zend/zend_object_handlers.c index ac4599282e..e38fbfc640 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -905,7 +905,7 @@ static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{ ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ { - zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function; + zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->call->func; zval method_name, method_args; zval method_result; zend_class_entry *ce = Z_OBJCE_P(getThis()); @@ -1123,7 +1123,7 @@ static union _zend_function *zend_std_get_method(zend_object **obj_ptr, zend_str ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ { - zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function; + zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->call->func; zval method_name, method_args; zval method_result; zend_class_entry *ce = EG(scope); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 7ecccdaf32..cad1dd2e9c 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -70,9 +70,6 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->T = 0; - op_array->nested_calls = 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; @@ -631,7 +628,7 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC) { zend_op *opline, *end; - if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) { + if (!ZEND_USER_CODE(op_array->type)) { return 0; } if (op_array->has_finally_block) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 38377d3cce..f0da4eeded 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1772,6 +1772,7 @@ 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_execute_data *prev_nested_call; EG(current_execute_data) = EX(prev_execute_data); @@ -1780,22 +1781,22 @@ 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); + 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); - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { - if (EX(call)->is_ctor_result_used) { + if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) { + if (!(EX(opline)->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -1812,10 +1813,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) EG(scope) = EX(scope); EG(called_scope) = EX(called_scope); - EX(call)--; - - zend_vm_stack_clear_multiple(1 TSRMLS_CC); - if (UNEXPECTED(EG(exception) != NULL)) { zend_op *opline = EX(opline); zend_throw_exception_internal(NULL TSRMLS_CC); @@ -1830,16 +1827,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); - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION_LEAVE(); @@ -1851,6 +1848,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; @@ -1858,7 +1856,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 && ZEND_USER_CODE(old_execute_data->func->op_array.type)) { if (old_execute_data->symbol_table == symbol_table) { zend_attach_symbol_table(old_execute_data); } @@ -1867,224 +1865,20 @@ 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(); } } -ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) -{ - USE_OPLINE - zend_function *fbc = EX(function_state).function; - zend_object *object; - zend_uint num_args; - - SAVE_OPLINE(); - object = EX(call)->object; - 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); - } - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - fbc->common.scope ? fbc->common.scope->name->val : "", - fbc->common.scope ? "::" : "", - fbc->common.function_name->val); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); - } - } - } - if (fbc->common.scope && - !(fbc->common.fn_flags & ZEND_ACC_STATIC) && - !object) { - - if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - /* FIXME: output identifiers properly */ - zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", fbc->common.scope->name->val, fbc->common.function_name->val); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); - } - } else { - /* FIXME: output identifiers properly */ - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", fbc->common.scope->name->val, fbc->common.function_name->val); - } - } - - if (EXPECTED(EX(call)->num_additional_args == 0)) { - num_args = opline->extended_value; - EX(function_state).arguments = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_LONG(EX(function_state).arguments, num_args); - } else { - num_args = opline->extended_value + EX(call)->num_additional_args; - EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC); - } - LOAD_OPLINE(); - - if (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; - /* 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; -#else - EG(scope) = fbc->common.scope; -#endif - EG(called_scope) = EX(call)->called_scope; - } - - if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { - zend_uint i; - zval *p = EX(function_state).arguments - num_args; - - for (i = 0; i < num_args; ++i, ++p) { - zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); - } - if (UNEXPECTED(EG(exception) != NULL)) { - if (RETURN_VALUE_USED(opline)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); - } - if (UNEXPECTED(should_change_scope)) { - ZEND_VM_C_GOTO(fcall_end_change_scope); - } else { - ZEND_VM_C_GOTO(fcall_end); - } - } - } - - ret = EX_VAR(opline->result.var); - ZVAL_NULL(ret); - Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; - - if (!zend_execute_internal) { - /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(num_args, ret TSRMLS_CC); - } else { - zend_execute_internal(execute_data, NULL TSRMLS_CC); - } - - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(ret); - } - - if (UNEXPECTED(should_change_scope)) { - ZEND_VM_C_GOTO(fcall_end_change_scope); - } else { - ZEND_VM_C_GOTO(fcall_end); - } - } else if (fbc->type == ZEND_USER_FUNCTION) { - zval *return_value = NULL; - - Z_OBJ(EG(This)) = object; - EG(scope) = fbc->common.scope; - EG(called_scope) = EX(call)->called_scope; - EG(active_symbol_table) = NULL; - EG(active_op_array) = &fbc->op_array; - if (RETURN_VALUE_USED(opline)) { - return_value = EX_VAR(opline->result.var); - - ZVAL_NULL(return_value); - 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 (RETURN_VALUE_USED(opline)) { - zend_generator_create_zval(EG(active_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); - ZEND_VM_ENTER(); - } - } else { - zend_execute(EG(active_op_array), return_value TSRMLS_CC); - } - - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(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; -//??? EG(scope) = NULL; - EG(scope) = fbc->common.scope; - EG(called_scope) = EX(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); - } else { - zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); - } - - if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { - STR_RELEASE(fbc->common.function_name); - } - efree(fbc); - - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(EX_VAR(opline->result.var)); - } else { -//??? Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr); -//??? Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1); - Z_VAR_FLAGS_P(EX_VAR(opline->result.var)) = 0; - } - } - -ZEND_VM_C_LABEL(fcall_end_change_scope): - if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { - if (EX(call)->is_ctor_result_used) { - Z_DELREF(EG(This)); - } - if (Z_REFCOUNT(EG(This)) == 1) { - zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); - } - } - if (!Z_DELREF(EG(This))) { - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - _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); - } - } - Z_OBJ(EG(This)) = EX(object); - EG(scope) = EX(scope); - EG(called_scope) = EX(called_scope); - -ZEND_VM_C_LABEL(fcall_end): - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - EX(call)--; - - zend_vm_stack_clear_multiple(1 TSRMLS_CC); - - if (UNEXPECTED(EG(exception) != NULL)) { - zend_throw_exception_internal(NULL TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(EX_VAR(opline->result.var)); - } - HANDLE_EXCEPTION(); - } - - ZEND_VM_NEXT_OPCODE(); -} - ZEND_VM_HANDLER(42, ZEND_JMP, ANY, ANY) { USE_OPLINE @@ -2407,8 +2201,10 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) USE_OPLINE zval *function_name; zend_free_op free_op1, free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -2423,32 +2219,8 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) } object = GET_OP1_OBJ_ZVAL_PTR_DEREF(BP_VAR_R); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (OP2_TYPE != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((OP2_TYPE == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (OP2_TYPE == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { FREE_OP2(); HANDLE_EXCEPTION(); @@ -2456,15 +2228,38 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (OP2_TYPE != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((OP2_TYPE == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (OP2_TYPE == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); FREE_OP2(); FREE_OP1_IF_VAR(); @@ -2478,7 +2273,8 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -2487,7 +2283,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(); } @@ -2496,24 +2292,17 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (OP1_TYPE != IS_CONST && OP2_TYPE == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (OP2_TYPE != IS_UNUSED) { zend_free_op free_op2; @@ -2529,20 +2318,20 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((OP2_TYPE == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((OP2_TYPE == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (OP2_TYPE == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (OP1_TYPE == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (OP2_TYPE != IS_CONST) { @@ -2555,33 +2344,37 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (OP1_TYPE != IS_CONST) { + /* 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); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2590,32 +2383,32 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) { USE_OPLINE - zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; + zval *function_name, *func; if (OP2_TYPE == IS_CONST) { - function_name_ptr = function_name = (zval*)(opline->op2.zv+1); + function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { zend_string *lcname; zend_free_op free_op2; + zend_class_entry *called_scope; + zend_object *object; + zval *function_name_ptr; SAVE_OPLINE(); function_name_ptr = function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); @@ -2634,37 +2427,23 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } STR_FREE(lcname); FREE_OP2(); - - call->fbc = Z_FUNC_P(func); - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; } else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { - if (call->object) { - GC_REFCOUNT(call->object)++; + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object TSRMLS_CC) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; } if (OP2_TYPE == IS_VAR && OP2_FREE && Z_REFCOUNT_P(function_name) == 1 && - call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { + fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - call->fbc->common.prototype = (zend_function*)function_name_ptr; + fbc->common.prototype = (zend_function*)function_name_ptr; } else { FREE_OP2(); } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else if (OP2_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { @@ -2687,51 +2466,49 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } if (Z_TYPE_P(obj) == IS_STRING) { - call->object = NULL; - call->called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); - if (UNEXPECTED(call->called_scope == NULL)) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); + if (UNEXPECTED(called_scope == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - if (call->called_scope->get_static_method) { - call->fbc = call->called_scope->get_static_method(call->called_scope, Z_STR_P(method) TSRMLS_CC); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(call->called_scope, Z_STR_P(method), NULL TSRMLS_CC); + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", call->called_scope->name->val, Z_STRVAL_P(method)); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); } } else { - call->called_scope = Z_OBJCE_P(obj); - call->object = Z_OBJ_P(obj); + called_scope = Z_OBJCE_P(obj); + object = Z_OBJ_P(obj); - call->fbc = Z_OBJ_HT_P(obj)->get_method(&call->object, Z_STR_P(method), NULL TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(method)); + fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(object), Z_STRVAL_P(method)); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(object)++; /* For $this pointer */ } } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - FREE_OP2(); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else { if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ + ZEND_VM_CONTINUE(); /* Never reached */ } + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } } @@ -2741,68 +2518,263 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) USE_OPLINE zval *func_name; zval *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; func_name = opline->op2.zv + 1; if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if ((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL) { func_name++; if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(61, ZEND_DO_FCALL_BY_NAME, ANY, ANY) -{ - EX(function_state).function = EX(call)->fbc; - ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_common_helper); -} - -ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) +ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, ANY, CONST) { USE_OPLINE - zend_free_op free_op1; - zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R); + zend_free_op free_op2; + zval *fname = GET_OP2_ZVAL_PTR(BP_VAR_R); zval *func; - call_slot *call = EX(call_slots) + opline->op2.num; + zend_function *fbc; if (CACHED_PTR(Z_CACHE_SLOT_P(fname))) { - EX(function_state).function = CACHED_PTR(Z_CACHE_SLOT_P(fname)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(fname)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(fname))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(fname)); } else { - EX(function_state).function = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(fname), EX(function_state).function); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(fname), fbc); } - call->fbc = EX(function_state).function; - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); - FREE_OP1(); + FREE_OP2(); + + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; + + SAVE_OPLINE(); + 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); + } + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { + zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", + fbc->common.scope ? fbc->common.scope->name->val : "", + fbc->common.scope ? "::" : "", + fbc->common.function_name->val); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + } + } + if (fbc->common.scope && + !(fbc->common.fn_flags & ZEND_ACC_STATIC) && + !call->object) { + + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + /* FIXME: output identifiers properly */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", fbc->common.scope->name->val, fbc->common.function_name->val); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + } else { + /* FIXME: output identifiers properly */ + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", fbc->common.scope->name->val, fbc->common.function_name->val); + } + } + + LOAD_OPLINE(); + + 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)) = 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) = (call->object) ? NULL : fbc->common.scope; +#else + EG(scope) = fbc->common.scope; +#endif + EG(called_scope) = call->called_scope; + } + + if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { + zend_uint i; + zval *p = ZEND_CALL_ARG(call, 1); + + for (i = 0; i < call->num_args; ++i) { + zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); + p++; + } + if (UNEXPECTED(EG(exception) != NULL)) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } + if (UNEXPECTED(should_change_scope)) { + ZEND_VM_C_GOTO(fcall_end_change_scope); + } else { + ZEND_VM_C_GOTO(fcall_end); + } + } + } + + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + + if (!zend_execute_internal) { + /* saves one function call if zend_execute_internal is not used */ + 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); + } - ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_common_helper); + if (UNEXPECTED(should_change_scope)) { + ZEND_VM_C_GOTO(fcall_end_change_scope); + } else { + ZEND_VM_C_GOTO(fcall_end); + } + } else if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { + zval *return_value = NULL; + + Z_OBJ(EG(This)) = call->object; + EG(scope) = fbc->common.scope; + EG(called_scope) = call->called_scope; + EG(active_symbol_table) = NULL; + EG(active_op_array) = &fbc->op_array; + if (RETURN_VALUE_USED(opline)) { + return_value = EX_VAR(opline->result.var); + + ZVAL_NULL(return_value); + Z_VAR_FLAGS_P(return_value) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + } + + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (RETURN_VALUE_USED(opline)) { + zend_generator_create_zval(&fbc->op_array, EX_VAR(opline->result.var) 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); + } + } + + EG(opline_ptr) = &EX(opline); + 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)) = call->object; +//??? EG(scope) = NULL; + EG(scope) = fbc->common.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(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); + } + efree(fbc); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } else { +//??? Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr); +//??? Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1); + Z_VAR_FLAGS_P(EX_VAR(opline->result.var)) = 0; + } + } + +ZEND_VM_C_LABEL(fcall_end_change_scope): + if (Z_OBJ(EG(This))) { + if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) { + if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { + Z_DELREF(EG(This)); + } + if (Z_REFCOUNT(EG(This)) == 1) { + zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); + } + } + if (!Z_DELREF(EG(This))) { + _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); + } + } + Z_OBJ(EG(This)) = EX(object); + EG(scope) = EX(scope); + EG(called_scope) = EX(called_scope); + +ZEND_VM_C_LABEL(fcall_end): + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + HANDLE_EXCEPTION(); + } + + ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) @@ -2945,7 +2917,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))) { @@ -2969,7 +2941,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 */ } } @@ -2991,22 +2963,23 @@ 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(); - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num); } } 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); + EX(call)->num_args = 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(); @@ -3015,18 +2988,19 @@ 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); + EX(call)->num_args = 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(); @@ -3036,7 +3010,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 */ @@ -3044,7 +3018,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } } else { - if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } } @@ -3061,15 +3035,18 @@ 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); + EX(call)->num_args = 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)->fbc, opline->op2.num)) { + !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); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY(arg, varptr); FREE_OP1_IF_VAR(); } CHECK_EXCEPTION(); @@ -3080,7 +3057,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); @@ -3089,23 +3066,24 @@ 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); + EX(call)->num_args = 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(); @@ -3115,24 +3093,25 @@ 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_DO_FCALL_BY_NAME) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); } } 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); + EX(call)->num_args = 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(); @@ -3147,7 +3126,7 @@ ZEND_VM_HANDLER(165, ZEND_SEND_UNPACK, ANY, ANY) SAVE_OPLINE(); args = GET_OP1_ZVAL_PTR(BP_VAR_R); - arg_num = opline->op2.num + EX(call)->num_additional_args + 1; + arg_num = EX(call)->num_args + 1; ZEND_VM_C_LABEL(send_again): switch (Z_TYPE_P(args)) { @@ -3156,7 +3135,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; @@ -3164,7 +3143,7 @@ ZEND_VM_C_LABEL(send_again): /* check if any of arguments are going to be passed by reference */ for (i = 0; i < zend_hash_num_elements(ht); i++) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num + i)) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num + i)) { separate = 1; break; } @@ -3183,8 +3162,8 @@ ZEND_VM_C_LABEL(send_again): ZEND_VM_NEXT_OPCODE(); } - top = zend_vm_stack_top_inc(TSRMLS_C); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + 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); Z_ADDREF_P(arg); @@ -3193,12 +3172,13 @@ 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); } - EX(call)->num_additional_args++; + EX(call)->num_args++; arg_num++; } ZEND_HASH_FOREACH_END(); @@ -3232,7 +3212,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); @@ -3260,13 +3240,13 @@ ZEND_VM_C_LABEL(send_again): zval_dtor(&key); } - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" " by unpacking a Traversable, passing by-value instead", arg_num, - EX(call)->fbc->common.scope ? EX(call)->fbc->common.scope->name->val : "", - EX(call)->fbc->common.scope ? "::" : "", - EX(call)->fbc->common.function_name->val + EX(call)->func->common.scope ? EX(call)->func->common.scope->name->val : "", + EX(call)->func->common.scope ? "::" : "", + EX(call)->func->common.function_name->val ); } @@ -3276,9 +3256,10 @@ 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); - EX(call)->num_additional_args++; + 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); if (UNEXPECTED(EG(exception) != NULL)) { @@ -3307,25 +3288,18 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); 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 = arguments - arg_count + arg_num - 1; + 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(); } @@ -3333,30 +3307,24 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); - 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 = arguments - arg_count + arg_num - 1; - 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(); @@ -3367,21 +3335,21 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); + 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 = arguments - arg_count + arg_num - 1; + zval *param; + 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); + param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + do { + 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++; @@ -3423,8 +3391,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) @@ -3434,8 +3402,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) @@ -3446,9 +3414,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)) { @@ -3515,21 +3483,19 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) } ZEND_VM_JMP(opline->op2.jmp_addr); } else { - call_slot *call = EX(call_slots) + opline->extended_value; + /* We are not handling overloaded classes right now */ + EX(call) = zend_vm_stack_push_call_frame( + constructor, opline->extended_value, + RETURN_VALUE_USED(opline) ? + ZEND_CALL_CTOR : (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_UNUSED), + Z_CE_P(EX_VAR(opline->op1.var)), + Z_OBJ(object_zval), + EX(call) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); } - /* We are not handling overloaded classes right now */ - call->fbc = constructor; - call->object = Z_OBJ(object_zval); - call->called_scope = Z_CE_P(EX_VAR(opline->op1.var)); - call->num_additional_args = 0; - call->is_ctor_call = 1; - call->is_ctor_result_used = RETURN_VALUE_USED(opline); - EX(call) = call; - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -4014,23 +3980,23 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) return_value = EX_VAR(opline->result.var); } - EX(function_state).function = (zend_function *) new_op_array; + EX(call) = zend_vm_stack_push_call_frame( + (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); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + 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)) { @@ -4861,7 +4827,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 */ } @@ -4987,7 +4953,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(); @@ -4997,7 +4963,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(); @@ -5007,7 +4973,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(); @@ -5018,7 +4984,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(); } @@ -5028,7 +4994,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(); } @@ -5042,7 +5008,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(); @@ -5053,7 +5019,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(); } @@ -5173,45 +5139,37 @@ ZEND_VM_HANDLER(155, ZEND_BIND_TRAITS, ANY, ANY) ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) { - zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes; + zend_uint op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes; int i; zend_uint catch_op_num = 0, finally_op_num = 0, finally_op_end = 0; - zval *stack_frame; - - /* Figure out where the next stack frame (which maybe contains pushed - * arguments that have to be dtor'ed) starts */ - stack_frame = zend_vm_stack_frame_base(execute_data); - /* 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) != stack_frame) { - zval *stack_zval_p = zend_vm_stack_pop(TSRMLS_C); - zval_ptr_dtor(stack_zval_p); - } - - for (i=0; ilast_try_catch; i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { + for (i = 0; i < EX(func)->op_array.last_try_catch; i++) { + if (EX(func)->op_array.try_catch_array[i].try_op > op_num) { /* further blocks will not be relevant... */ 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; + if (op_num < EX(func)->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) >= EX(call_slots)) { - call_slot *call = EX(call); + if (EX(call)) { + zend_execute_data *call = EX(call); do { + /* If the exception was thrown during a function call there might be + * arguments pushed to the stack that have to be dtor'ed. */ + zend_vm_stack_free_args(EX(call) TSRMLS_CC); + if (call->object) { - if (call->is_ctor_call) { - if (call->is_ctor_result_used) { + if (call->flags & ZEND_CALL_CTOR) { + if (!(call->flags & ZEND_CALL_CTOR_RESULT_UNUSED)) { GC_REFCOUNT(call->object)--; } if (GC_REFCOUNT(call->object) == 1) { @@ -5220,21 +5178,22 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } OBJ_RELEASE(call->object); } - call--; - } while (call >= EX(call_slots)); - EX(call) = NULL; + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + call = EX(call); + } while (call); } - 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)) { @@ -5270,7 +5229,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) { @@ -5280,14 +5239,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); @@ -5318,7 +5277,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); @@ -5382,7 +5341,7 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED) } closure_is_static = Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC; - closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->function_state.function->common.fn_flags & ZEND_ACC_STATIC; + closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->call->func->common.fn_flags & ZEND_ACC_STATIC; if (closure_is_static || closure_is_being_defined_inside_static_context) { zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc), EG(called_scope), NULL TSRMLS_CC); } else { @@ -5432,7 +5391,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) { @@ -5560,7 +5519,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; @@ -5579,15 +5538,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); @@ -5646,4 +5605,4 @@ ZEND_VM_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper) +ZEND_VM_EXPORT_HANDLER(zend_do_fcall, ZEND_DO_FCALL) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index b69dcbf711..3f373a1a98 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -375,15 +375,27 @@ 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_execute_data *prev_nested_call; EG(current_execute_data) = EX(prev_execute_data); @@ -392,22 +404,22 @@ 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); + 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); - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { - if (EX(call)->is_ctor_result_used) { + if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) { + if (!(EX(opline)->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -424,10 +436,6 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EG(scope) = EX(scope); EG(called_scope) = EX(called_scope); - EX(call)--; - - zend_vm_stack_clear_multiple(1 TSRMLS_CC); - if (UNEXPECTED(EG(exception) != NULL)) { zend_op *opline = EX(opline); zend_throw_exception_internal(NULL TSRMLS_CC); @@ -442,16 +450,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); - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION_LEAVE(); @@ -463,6 +471,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; @@ -470,7 +479,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 && ZEND_USER_CODE(old_execute_data->func->op_array.type)) { if (old_execute_data->symbol_table == symbol_table) { zend_attach_symbol_table(old_execute_data); } @@ -479,24 +488,47 @@ 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(); } } -static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_function *fbc = EX(function_state).function; - zend_object *object; - zend_uint num_args; + + ZEND_VM_SET_OPCODE(opline->op1.jmp_addr); + ZEND_VM_CONTINUE(); +} + +static int ZEND_FASTCALL ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *tmp = EX_VAR(opline->result.var); SAVE_OPLINE(); - object = EX(call)->object; + ZVAL_EMPTY_STRING(tmp); + /*CHECK_EXCEPTION();*/ + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; + + SAVE_OPLINE(); + 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); @@ -513,7 +545,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR } 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 */ @@ -528,39 +560,32 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR } } - if (EXPECTED(EX(call)->num_additional_args == 0)) { - num_args = opline->extended_value; - EX(function_state).arguments = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_LONG(EX(function_state).arguments, num_args); - } else { - num_args = opline->extended_value + EX(call)->num_additional_args; - EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC); - } 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 = EX(function_state).arguments - num_args; + zval *p = ZEND_CALL_ARG(call, 1); - for (i = 0; i < num_args; ++i, ++p) { + for (i = 0; i < call->num_args; ++i) { zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); + p++; } if (UNEXPECTED(EG(exception) != NULL)) { if (RETURN_VALUE_USED(opline)) { @@ -580,11 +605,16 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR 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); } @@ -594,12 +624,12 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR } 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)) { @@ -609,40 +639,50 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR 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); } @@ -659,8 +699,8 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR fcall_end_change_scope: if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { - if (EX(call)->is_ctor_result_used) { + if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) { + if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -668,8 +708,6 @@ fcall_end_change_scope: } } if (!Z_DELREF(EG(This))) { - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; _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); @@ -680,12 +718,6 @@ fcall_end_change_scope: EG(called_scope) = EX(called_scope); fcall_end: - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - EX(call)--; - - zend_vm_stack_clear_multiple(1 TSRMLS_CC); - if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { @@ -697,31 +729,6 @@ fcall_end: ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - - ZEND_VM_SET_OPCODE(opline->op1.jmp_addr); - ZEND_VM_CONTINUE(); -} - -static int ZEND_FASTCALL ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *tmp = EX_VAR(opline->result.var); - - SAVE_OPLINE(); - ZVAL_EMPTY_STRING(tmp); - /*CHECK_EXCEPTION();*/ - ZEND_VM_NEXT_OPCODE(); -} - -static int ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - EX(function_state).function = EX(call)->fbc; - return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); -} - static int ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { /* The generator object is stored in EX(return_value) */ @@ -743,7 +750,7 @@ static int ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS SAVE_OPLINE(); args = get_zval_ptr(opline->op1_type, &opline->op1, execute_data, &free_op1, BP_VAR_R); - arg_num = opline->op2.num + EX(call)->num_additional_args + 1; + arg_num = EX(call)->num_args + 1; send_again: switch (Z_TYPE_P(args)) { @@ -752,7 +759,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; @@ -760,7 +767,7 @@ send_again: /* check if any of arguments are going to be passed by reference */ for (i = 0; i < zend_hash_num_elements(ht); i++) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num + i)) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num + i)) { separate = 1; break; } @@ -779,8 +786,8 @@ send_again: ZEND_VM_NEXT_OPCODE(); } - top = zend_vm_stack_top_inc(TSRMLS_C); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + 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); Z_ADDREF_P(arg); @@ -789,12 +796,13 @@ 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); } - EX(call)->num_additional_args++; + EX(call)->num_args++; arg_num++; } ZEND_HASH_FOREACH_END(); @@ -828,7 +836,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; @@ -856,13 +864,13 @@ send_again: zval_dtor(&key); } - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" " by unpacking a Traversable, passing by-value instead", arg_num, - EX(call)->fbc->common.scope ? EX(call)->fbc->common.scope->name->val : "", - EX(call)->fbc->common.scope ? "::" : "", - EX(call)->fbc->common.function_name->val + EX(call)->func->common.scope ? EX(call)->func->common.scope->name->val : "", + EX(call)->func->common.scope ? "::" : "", + EX(call)->func->common.function_name->val ); } @@ -872,9 +880,10 @@ 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); - EX(call)->num_additional_args++; + 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); if (UNEXPECTED(EG(exception) != NULL)) { @@ -903,25 +912,18 @@ static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); 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 = arguments - arg_count + arg_num - 1; + 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(); } @@ -929,21 +931,21 @@ static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); + 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 = arguments - arg_count + arg_num - 1; + zval *param; + array_init_size(params, arg_count - arg_num + 1); - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); + if (UNEXPECTED((EX(func)->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_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++; @@ -990,21 +992,19 @@ static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } ZEND_VM_JMP(opline->op2.jmp_addr); } else { - call_slot *call = EX(call_slots) + opline->extended_value; + /* We are not handling overloaded classes right now */ + EX(call) = zend_vm_stack_push_call_frame( + constructor, opline->extended_value, + RETURN_VALUE_USED(opline) ? + ZEND_CALL_CTOR : (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_UNUSED), + Z_CE_P(EX_VAR(opline->op1.var)), + Z_OBJ(object_zval), + EX(call) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); } - /* We are not handling overloaded classes right now */ - call->fbc = constructor; - call->object = Z_OBJ(object_zval); - call->called_scope = Z_CE_P(EX_VAR(opline->op1.var)); - call->num_additional_args = 0; - call->is_ctor_call = 1; - call->is_ctor_result_used = RETURN_VALUE_USED(opline); - EX(call) = call; - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -1056,7 +1056,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 */ } @@ -1064,7 +1064,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(); @@ -1074,7 +1074,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(); @@ -1084,7 +1084,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(); @@ -1095,7 +1095,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(); } @@ -1105,7 +1105,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(); } @@ -1119,7 +1119,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(); @@ -1130,7 +1130,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(); } @@ -1202,45 +1202,37 @@ static int ZEND_FASTCALL ZEND_BIND_TRAITS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes; + zend_uint op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes; int i; zend_uint catch_op_num = 0, finally_op_num = 0, finally_op_end = 0; - zval *stack_frame; - /* Figure out where the next stack frame (which maybe contains pushed - * arguments that have to be dtor'ed) starts */ - stack_frame = zend_vm_stack_frame_base(execute_data); - - /* 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) != stack_frame) { - zval *stack_zval_p = zend_vm_stack_pop(TSRMLS_C); - zval_ptr_dtor(stack_zval_p); - } - - for (i=0; ilast_try_catch; i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { + for (i = 0; i < EX(func)->op_array.last_try_catch; i++) { + if (EX(func)->op_array.try_catch_array[i].try_op > op_num) { /* further blocks will not be relevant... */ 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; + if (op_num < EX(func)->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) >= EX(call_slots)) { - call_slot *call = EX(call); + if (EX(call)) { + zend_execute_data *call = EX(call); do { + /* If the exception was thrown during a function call there might be + * arguments pushed to the stack that have to be dtor'ed. */ + zend_vm_stack_free_args(EX(call) TSRMLS_CC); + if (call->object) { - if (call->is_ctor_call) { - if (call->is_ctor_result_used) { + if (call->flags & ZEND_CALL_CTOR) { + if (!(call->flags & ZEND_CALL_CTOR_RESULT_UNUSED)) { GC_REFCOUNT(call->object)--; } if (GC_REFCOUNT(call->object) == 1) { @@ -1249,21 +1241,22 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER } OBJ_RELEASE(call->object); } - call--; - } while (call >= EX(call_slots)); - EX(call) = NULL; + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + call = EX(call); + } while (call); } - 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)) { @@ -1299,7 +1292,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) { @@ -1309,14 +1302,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); @@ -1347,7 +1340,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); @@ -1381,7 +1374,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; @@ -1400,15 +1393,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); @@ -1459,32 +1452,32 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; + zval *function_name, *func; if (IS_CONST == IS_CONST) { - function_name_ptr = function_name = (zval*)(opline->op2.zv+1); + function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { zend_string *lcname; + zend_class_entry *called_scope; + zend_object *object; + zval *function_name_ptr; SAVE_OPLINE(); function_name_ptr = function_name = opline->op2.zv; @@ -1503,36 +1496,23 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } STR_FREE(lcname); - call->fbc = Z_FUNC_P(func); - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; } else if (IS_CONST != IS_CONST && IS_CONST != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { - if (call->object) { - GC_REFCOUNT(call->object)++; + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object TSRMLS_CC) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; } if (IS_CONST == IS_VAR && 0 && Z_REFCOUNT_P(function_name) == 1 && - call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { + fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - call->fbc->common.prototype = (zend_function*)function_name_ptr; + fbc->common.prototype = (zend_function*)function_name_ptr; } else { } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { @@ -1555,50 +1535,49 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } if (Z_TYPE_P(obj) == IS_STRING) { - call->object = NULL; - call->called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); - if (UNEXPECTED(call->called_scope == NULL)) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); + if (UNEXPECTED(called_scope == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - if (call->called_scope->get_static_method) { - call->fbc = call->called_scope->get_static_method(call->called_scope, Z_STR_P(method) TSRMLS_CC); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(call->called_scope, Z_STR_P(method), NULL TSRMLS_CC); + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", call->called_scope->name->val, Z_STRVAL_P(method)); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); } } else { - call->called_scope = Z_OBJCE_P(obj); - call->object = Z_OBJ_P(obj); + called_scope = Z_OBJCE_P(obj); + object = Z_OBJ_P(obj); - call->fbc = Z_OBJ_HT_P(obj)->get_method(&call->object, Z_STR_P(method), NULL TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(method)); + fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(object), Z_STRVAL_P(method)); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(object)++; /* For $this pointer */ } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else { if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ + ZEND_VM_CONTINUE(); /* Never reached */ } + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } } @@ -1608,30 +1587,51 @@ static int ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC USE_OPLINE zval *func_name; zval *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; func_name = opline->op2.zv + 1; if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if ((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL) { func_name++; if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); + } + + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); + + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_INIT_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *fname = opline->op2.zv; + zval *func; + zend_function *fbc; + + if (CACHED_PTR(Z_CACHE_SLOT_P(fname))) { + fbc = CACHED_PTR(Z_CACHE_SLOT_P(fname)); + } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(fname))) == NULL)) { + SAVE_OPLINE(); + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(fname)); + } else { + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(fname), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); } @@ -1640,30 +1640,24 @@ static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); - 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 = arguments - arg_count + arg_num - 1; - 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(); @@ -1677,8 +1671,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) @@ -1688,8 +1682,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) @@ -1700,9 +1694,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)) { @@ -1786,32 +1780,32 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; + zval *function_name, *func; if (IS_TMP_VAR == IS_CONST) { - function_name_ptr = function_name = (zval*)(opline->op2.zv+1); + function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { zend_string *lcname; zend_free_op free_op2; + zend_class_entry *called_scope; + zend_object *object; + zval *function_name_ptr; SAVE_OPLINE(); function_name_ptr = function_name = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); @@ -1830,37 +1824,23 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } STR_FREE(lcname); zval_dtor(free_op2.var); - - call->fbc = Z_FUNC_P(func); - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; } else if (IS_TMP_VAR != IS_CONST && IS_TMP_VAR != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { - if (call->object) { - GC_REFCOUNT(call->object)++; + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object TSRMLS_CC) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; } if (IS_TMP_VAR == IS_VAR && 1 && Z_REFCOUNT_P(function_name) == 1 && - call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { + fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - call->fbc->common.prototype = (zend_function*)function_name_ptr; + fbc->common.prototype = (zend_function*)function_name_ptr; } else { zval_dtor(free_op2.var); } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else if (IS_TMP_VAR != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { @@ -1883,51 +1863,49 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } if (Z_TYPE_P(obj) == IS_STRING) { - call->object = NULL; - call->called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); - if (UNEXPECTED(call->called_scope == NULL)) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); + if (UNEXPECTED(called_scope == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - if (call->called_scope->get_static_method) { - call->fbc = call->called_scope->get_static_method(call->called_scope, Z_STR_P(method) TSRMLS_CC); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(call->called_scope, Z_STR_P(method), NULL TSRMLS_CC); + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", call->called_scope->name->val, Z_STRVAL_P(method)); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); } } else { - call->called_scope = Z_OBJCE_P(obj); - call->object = Z_OBJ_P(obj); + called_scope = Z_OBJCE_P(obj); + object = Z_OBJ_P(obj); - call->fbc = Z_OBJ_HT_P(obj)->get_method(&call->object, Z_STR_P(method), NULL TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(method)); + fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(object), Z_STRVAL_P(method)); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(object)++; /* For $this pointer */ } } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - zval_dtor(free_op2.var); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else { if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ + ZEND_VM_CONTINUE(); /* Never reached */ } + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } } @@ -1975,32 +1953,32 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; + zval *function_name, *func; if (IS_VAR == IS_CONST) { - function_name_ptr = function_name = (zval*)(opline->op2.zv+1); + function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { zend_string *lcname; zend_free_op free_op2; + zend_class_entry *called_scope; + zend_object *object; + zval *function_name_ptr; SAVE_OPLINE(); function_name_ptr = function_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); @@ -2019,37 +1997,23 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } STR_FREE(lcname); zval_ptr_dtor_nogc(free_op2.var); - - call->fbc = Z_FUNC_P(func); - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; } else if (IS_VAR != IS_CONST && IS_VAR != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { - if (call->object) { - GC_REFCOUNT(call->object)++; + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object TSRMLS_CC) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; } if (IS_VAR == IS_VAR && (free_op2.var != NULL) && Z_REFCOUNT_P(function_name) == 1 && - call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { + fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - call->fbc->common.prototype = (zend_function*)function_name_ptr; + fbc->common.prototype = (zend_function*)function_name_ptr; } else { zval_ptr_dtor_nogc(free_op2.var); } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else if (IS_VAR != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { @@ -2072,51 +2036,49 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } if (Z_TYPE_P(obj) == IS_STRING) { - call->object = NULL; - call->called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); - if (UNEXPECTED(call->called_scope == NULL)) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); + if (UNEXPECTED(called_scope == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - if (call->called_scope->get_static_method) { - call->fbc = call->called_scope->get_static_method(call->called_scope, Z_STR_P(method) TSRMLS_CC); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(call->called_scope, Z_STR_P(method), NULL TSRMLS_CC); + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", call->called_scope->name->val, Z_STRVAL_P(method)); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); } } else { - call->called_scope = Z_OBJCE_P(obj); - call->object = Z_OBJ_P(obj); + called_scope = Z_OBJCE_P(obj); + object = Z_OBJ_P(obj); - call->fbc = Z_OBJ_HT_P(obj)->get_method(&call->object, Z_STR_P(method), NULL TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(method)); + fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(object), Z_STRVAL_P(method)); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(object)++; /* For $this pointer */ } } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - zval_ptr_dtor_nogc(free_op2.var); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else { if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ + ZEND_VM_CONTINUE(); /* Never reached */ } + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } } @@ -2202,32 +2164,32 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; + zval *function_name, *func; if (IS_CV == IS_CONST) { - function_name_ptr = function_name = (zval*)(opline->op2.zv+1); + function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { zend_string *lcname; + zend_class_entry *called_scope; + zend_object *object; + zval *function_name_ptr; SAVE_OPLINE(); function_name_ptr = function_name = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); @@ -2246,36 +2208,23 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } STR_FREE(lcname); - call->fbc = Z_FUNC_P(func); - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; } else if (IS_CV != IS_CONST && IS_CV != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { - if (call->object) { - GC_REFCOUNT(call->object)++; + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object TSRMLS_CC) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; } if (IS_CV == IS_VAR && 0 && Z_REFCOUNT_P(function_name) == 1 && - call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { + fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - call->fbc->common.prototype = (zend_function*)function_name_ptr; + fbc->common.prototype = (zend_function*)function_name_ptr; } else { } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { @@ -2298,50 +2247,49 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } if (Z_TYPE_P(obj) == IS_STRING) { - call->object = NULL; - call->called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); - if (UNEXPECTED(call->called_scope == NULL)) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); + if (UNEXPECTED(called_scope == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - if (call->called_scope->get_static_method) { - call->fbc = call->called_scope->get_static_method(call->called_scope, Z_STR_P(method) TSRMLS_CC); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(call->called_scope, Z_STR_P(method), NULL TSRMLS_CC); + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", call->called_scope->name->val, Z_STRVAL_P(method)); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); } } else { - call->called_scope = Z_OBJCE_P(obj); - call->object = Z_OBJ_P(obj); + called_scope = Z_OBJCE_P(obj); + object = Z_OBJ_P(obj); - call->fbc = Z_OBJ_HT_P(obj)->get_method(&call->object, Z_STR_P(method), NULL TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(method)); + fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(object), Z_STRVAL_P(method)); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(object)++; /* For $this pointer */ } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else { if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ + ZEND_VM_CONTINUE(); /* Never reached */ } + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } } @@ -2557,34 +2505,6 @@ static int ZEND_FASTCALL ZEND_JMPNZ_EX_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A ZEND_VM_JMP(opline); } -static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - - zval *fname = opline->op1.zv; - zval *func; - call_slot *call = EX(call_slots) + opline->op2.num; - - if (CACHED_PTR(Z_CACHE_SLOT_P(fname))) { - EX(function_state).function = CACHED_PTR(Z_CACHE_SLOT_P(fname)); - } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(fname))) == NULL)) { - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(fname)); - } else { - EX(function_state).function = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(fname), EX(function_state).function); - } - - call->fbc = EX(function_state).function; - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); -} - static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -2705,22 +2625,23 @@ 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(); - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num); } } 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); + EX(call)->num_args = 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(); @@ -2999,23 +2920,23 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA return_value = EX_VAR(opline->result.var); } - EX(function_state).function = (zend_function *) new_op_array; + EX(call) = zend_vm_stack_push_call_frame( + (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); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + 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)) { @@ -3789,7 +3710,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -3798,7 +3720,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(); } @@ -3807,24 +3729,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_CONST == IS_CONST && IS_CONST == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_CONST != IS_CONST && IS_CONST == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_CONST != IS_UNUSED) { @@ -3840,20 +3755,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_CONST != IS_CONST) { @@ -3866,33 +3781,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_CONST != IS_CONST) { + /* 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); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -4336,7 +4255,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) { @@ -4757,7 +4676,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -4766,7 +4686,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(); } @@ -4775,24 +4695,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_CONST == IS_CONST && IS_TMP_VAR == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_CONST != IS_CONST && IS_TMP_VAR == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op2; @@ -4808,20 +4721,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_TMP_VAR != IS_CONST) { @@ -4834,33 +4747,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_CONST != IS_CONST) { + /* 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); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -5022,7 +4939,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) { @@ -5593,7 +5510,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -5602,7 +5520,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(); } @@ -5611,24 +5529,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_CONST == IS_CONST && IS_VAR == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_CONST != IS_CONST && IS_VAR == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_VAR != IS_UNUSED) { zend_free_op free_op2; @@ -5644,20 +5555,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_VAR != IS_CONST) { @@ -5670,33 +5581,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_CONST != IS_CONST) { + /* 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); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -6009,7 +5924,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) { @@ -6288,7 +6203,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -6297,7 +6213,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(); } @@ -6306,24 +6222,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_CONST == IS_CONST && IS_UNUSED == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_CONST != IS_CONST && IS_UNUSED == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_UNUSED != IS_UNUSED) { @@ -6339,20 +6248,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_UNUSED == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_UNUSED == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_UNUSED == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_UNUSED != IS_CONST) { @@ -6365,33 +6274,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_CONST != IS_CONST) { + /* 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); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -6681,7 +6594,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER } closure_is_static = Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC; - closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->function_state.function->common.fn_flags & ZEND_ACC_STATIC; + closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->call->func->common.fn_flags & ZEND_ACC_STATIC; if (closure_is_static || closure_is_being_defined_inside_static_context) { zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc), EG(called_scope), NULL TSRMLS_CC); } else { @@ -6713,7 +6626,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) { @@ -7119,7 +7032,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -7128,7 +7042,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(); } @@ -7137,24 +7051,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_CONST == IS_CONST && IS_CV == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_CONST != IS_CONST && IS_CV == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_CV != IS_UNUSED) { @@ -7170,20 +7077,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_CV != IS_CONST) { @@ -7196,33 +7103,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_CONST != IS_CONST) { + /* 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); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -7238,7 +7149,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))) { @@ -7262,7 +7173,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 */ } } @@ -7436,7 +7347,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) { @@ -7906,22 +7817,23 @@ 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(); - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num); } } 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); + EX(call)->num_args = 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(); @@ -8202,23 +8114,23 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HAND return_value = EX_VAR(opline->result.var); } - EX(function_state).function = (zend_function *) new_op_array; + EX(call) = zend_vm_stack_push_call_frame( + (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); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + 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)) { @@ -9079,8 +8991,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO USE_OPLINE zval *function_name; zend_free_op free_op1; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -9095,48 +9009,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO } object = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CONST != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CONST != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CONST == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -9449,7 +9362,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) { @@ -9914,8 +9827,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE USE_OPLINE zval *function_name; zend_free_op free_op1, free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -9930,32 +9845,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE } object = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (IS_TMP_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_dtor(free_op2.var); HANDLE_EXCEPTION(); @@ -9963,15 +9854,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_TMP_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_TMP_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -10135,7 +10049,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) { @@ -10750,8 +10664,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE USE_OPLINE zval *function_name; zend_free_op free_op1, free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -10766,32 +10682,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE } object = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (IS_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2.var); HANDLE_EXCEPTION(); @@ -10799,15 +10691,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -11122,7 +11037,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) { @@ -11687,7 +11602,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) { @@ -12136,8 +12051,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_ USE_OPLINE zval *function_name; zend_free_op free_op1; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -12152,48 +12069,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_ } object = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CV != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CV != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CV == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -12355,7 +12271,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) { @@ -13044,18 +12960,19 @@ 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); + EX(call)->num_args = 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(); @@ -13065,7 +12982,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 */ @@ -13073,7 +12990,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } else { - if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } @@ -13090,15 +13007,18 @@ 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); + EX(call)->num_args = 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)->fbc, opline->op2.num)) { + !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); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY(arg, varptr); zval_ptr_dtor_nogc(free_op1.var); } CHECK_EXCEPTION(); @@ -13109,7 +13029,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); @@ -13118,23 +13038,24 @@ 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); + EX(call)->num_args = 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);}; @@ -13144,24 +13065,25 @@ 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_DO_FCALL_BY_NAME) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { return ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } 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); + EX(call)->num_args = 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(); @@ -13453,23 +13375,23 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND return_value = EX_VAR(opline->result.var); } - EX(function_state).function = (zend_function *) new_op_array; + EX(call) = zend_vm_stack_push_call_frame( + (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); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + 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)) { @@ -15334,8 +15256,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO USE_OPLINE zval *function_name; zend_free_op free_op1; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -15350,48 +15274,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO } object = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CONST != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CONST != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CONST == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op1.var); @@ -15404,7 +15327,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -15413,7 +15337,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(); } @@ -15422,24 +15346,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_VAR == IS_CONST && IS_CONST == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_VAR != IS_CONST && IS_CONST == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_CONST != IS_UNUSED) { @@ -15455,20 +15372,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_CONST != IS_CONST) { @@ -15481,33 +15398,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_VAR != IS_CONST) { + /* 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); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -16187,7 +16108,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) { @@ -17562,8 +17483,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE USE_OPLINE zval *function_name; zend_free_op free_op1, free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -17578,32 +17501,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE } object = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (IS_TMP_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_dtor(free_op2.var); HANDLE_EXCEPTION(); @@ -17611,15 +17510,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_TMP_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_TMP_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); zval_ptr_dtor_nogc(free_op1.var); @@ -17633,7 +17555,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -17642,7 +17565,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(); } @@ -17651,24 +17574,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_VAR == IS_CONST && IS_TMP_VAR == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_VAR != IS_CONST && IS_TMP_VAR == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op2; @@ -17684,20 +17600,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_TMP_VAR != IS_CONST) { @@ -17710,33 +17626,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_VAR != IS_CONST) { + /* 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); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -18169,7 +18089,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) { @@ -19758,8 +19678,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE USE_OPLINE zval *function_name; zend_free_op free_op1, free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -19774,32 +19696,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE } object = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - if (IS_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2.var); HANDLE_EXCEPTION(); @@ -19807,15 +19705,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + 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); @@ -19829,7 +19750,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -19838,7 +19760,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(); } @@ -19847,24 +19769,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_VAR == IS_CONST && IS_VAR == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_VAR != IS_CONST && IS_VAR == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_VAR != IS_UNUSED) { zend_free_op free_op2; @@ -19880,20 +19795,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_VAR != IS_CONST) { @@ -19906,33 +19821,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_VAR != IS_CONST) { + /* 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); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -20516,7 +20435,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) { @@ -21295,7 +21214,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -21304,7 +21224,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(); } @@ -21313,24 +21233,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_VAR == IS_CONST && IS_UNUSED == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_VAR != IS_CONST && IS_UNUSED == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_UNUSED != IS_UNUSED) { @@ -21346,20 +21259,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_UNUSED == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_UNUSED == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_UNUSED == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_UNUSED != IS_CONST) { @@ -21372,33 +21285,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_VAR != IS_CONST) { + /* 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); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -21713,7 +21630,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) { @@ -23129,8 +23046,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_ USE_OPLINE zval *function_name; zend_free_op free_op1; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -23145,48 +23064,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_ } object = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CV != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CV != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CV == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op1.var); @@ -23199,7 +23117,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -23208,7 +23127,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(); } @@ -23217,24 +23136,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_VAR == IS_CONST && IS_CV == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_VAR != IS_CONST && IS_CV == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_CV != IS_UNUSED) { @@ -23250,20 +23162,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_CV != IS_CONST) { @@ -23276,33 +23188,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_VAR != IS_CONST) { + /* 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); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -23732,7 +23648,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) { @@ -24706,8 +24622,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O USE_OPLINE zval *function_name; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -24722,48 +24640,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O } object = _get_obj_zval_ptr_unused(TSRMLS_C); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CONST != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CONST != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CONST == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -25190,7 +25107,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) { @@ -26079,8 +25996,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC USE_OPLINE zval *function_name; zend_free_op free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -26095,32 +26014,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC } object = _get_obj_zval_ptr_unused(TSRMLS_C); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (IS_TMP_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_dtor(free_op2.var); HANDLE_EXCEPTION(); @@ -26128,15 +26023,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_TMP_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_TMP_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -26467,7 +26385,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) { @@ -27356,8 +27274,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC USE_OPLINE zval *function_name; zend_free_op free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -27372,32 +27292,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC } object = _get_obj_zval_ptr_unused(TSRMLS_C); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (IS_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2.var); HANDLE_EXCEPTION(); @@ -27405,15 +27301,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -27744,7 +27663,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) { @@ -28260,7 +28179,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) { @@ -29143,8 +29062,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO USE_OPLINE zval *function_name; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -29159,48 +29080,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO } object = _get_obj_zval_ptr_unused(TSRMLS_C); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CV != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CV != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CV == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -29528,7 +29448,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) { @@ -30187,18 +30107,19 @@ 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); + EX(call)->num_args = 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(); @@ -30208,7 +30129,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 */ @@ -30216,7 +30137,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } else { - if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } @@ -30233,15 +30154,18 @@ 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); + EX(call)->num_args = 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)->fbc, opline->op2.num)) { + !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); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY(arg, varptr); } CHECK_EXCEPTION(); @@ -30252,7 +30176,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); @@ -30261,23 +30185,24 @@ 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); + EX(call)->num_args = 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(); @@ -30286,24 +30211,25 @@ 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_DO_FCALL_BY_NAME) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { return ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } 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); + EX(call)->num_args = 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(); @@ -30582,23 +30508,23 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL return_value = EX_VAR(opline->result.var); } - EX(function_state).function = (zend_function *) new_op_array; + EX(call) = zend_vm_stack_push_call_frame( + (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); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + 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)) { @@ -32312,8 +32238,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD USE_OPLINE zval *function_name; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -32328,48 +32256,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD } object = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { + + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (IS_CONST != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + if (IS_CONST != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CONST == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -32951,7 +32878,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) { @@ -34354,8 +34281,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ USE_OPLINE zval *function_name; zend_free_op free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -34370,32 +34299,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ } object = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - if (IS_TMP_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_dtor(free_op2.var); HANDLE_EXCEPTION(); @@ -34403,15 +34308,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_TMP_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_TMP_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -34846,7 +34774,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) { @@ -36432,8 +36360,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ USE_OPLINE zval *function_name; zend_free_op free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -36448,32 +36378,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ } object = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - if (IS_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2.var); HANDLE_EXCEPTION(); @@ -36481,15 +36387,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -37075,7 +37004,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) { @@ -38138,7 +38067,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) { @@ -39551,8 +39480,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H USE_OPLINE zval *function_name; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -39567,48 +39498,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H } object = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CV != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CV != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CV == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -40039,7 +39969,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) { @@ -41678,56 +41608,56 @@ void zend_init_opcodes_handlers(void) ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER, - ZEND_DO_FCALL_SPEC_CONST_HANDLER, - ZEND_DO_FCALL_SPEC_CONST_HANDLER, - ZEND_DO_FCALL_SPEC_CONST_HANDLER, - ZEND_DO_FCALL_SPEC_CONST_HANDLER, - ZEND_DO_FCALL_SPEC_CONST_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_INIT_FCALL_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_FCALL_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_FCALL_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_FCALL_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_FCALL_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, ZEND_RETURN_SPEC_CONST_HANDLER, ZEND_RETURN_SPEC_CONST_HANDLER, ZEND_RETURN_SPEC_CONST_HANDLER, @@ -44438,6 +44368,6 @@ ZEND_API void zend_vm_set_opcode_handler(zend_op* op) ZEND_API int zend_do_fcall(ZEND_OPCODE_HANDLER_ARGS) { - return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } 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/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index df127039c6..8859228aad 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -83,7 +83,7 @@ const char *zend_vm_opcodes_map[169] = { "ZEND_END_SILENCE", "ZEND_INIT_FCALL_BY_NAME", "ZEND_DO_FCALL", - "ZEND_DO_FCALL_BY_NAME", + "ZEND_INIT_FCALL", "ZEND_RETURN", "ZEND_RECV", "ZEND_RECV_INIT", diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index df499f946b..7d74a807b5 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -84,7 +84,7 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode); #define ZEND_END_SILENCE 58 #define ZEND_INIT_FCALL_BY_NAME 59 #define ZEND_DO_FCALL 60 -#define ZEND_DO_FCALL_BY_NAME 61 +#define ZEND_INIT_FCALL 61 #define ZEND_RETURN 62 #define ZEND_RECV 63 #define ZEND_RECV_INIT 64 diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 7baebd36d8..a3b6d08578 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -1958,7 +1958,6 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char * case ZEND_ASSIGN: case ZEND_ASSIGN_REF: case ZEND_DO_FCALL: - case ZEND_DO_FCALL_BY_NAME: if (ZEND_RESULT_TYPE(opline) == IS_VAR) { #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO ZEND_RESULT_TYPE(opline) |= EXT_TYPE_UNUSED; diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c index 26af07a189..480e4f92fe 100644 --- a/ext/opcache/Optimizer/compact_literals.c +++ b/ext/opcache/Optimizer/compact_literals.c @@ -108,8 +108,8 @@ static void optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_c end = opline + op_array->last; while (opline < end) { switch (opline->opcode) { - case ZEND_DO_FCALL: - LITERAL_INFO(opline->op1.constant, LITERAL_FUNC, 1, 1, 1); + case ZEND_INIT_FCALL: + LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 1); break; case ZEND_INIT_FCALL_BY_NAME: if (ZEND_OP2_TYPE(opline) == IS_CONST) { diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c index cd27704de5..3f755bed18 100644 --- a/ext/opcache/Optimizer/optimize_func_calls.c +++ b/ext/opcache/Optimizer/optimize_func_calls.c @@ -12,9 +12,15 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx zend_op *opline = op_array->opcodes; zend_op *end = opline + op_array->last; int call = 0; - void *checkpoint = zend_arena_checkpoint(ctx->arena); - optimizer_call_info *call_stack = zend_arena_calloc(&ctx->arena, op_array->nested_calls + 1, sizeof(optimizer_call_info)); + void *checkpoint; + optimizer_call_info *call_stack; + if (op_array->last < 2) { + return; + } + + checkpoint = zend_arena_checkpoint(ctx->arena); + call_stack = zend_arena_calloc(&ctx->arena, op_array->last / 2, sizeof(optimizer_call_info)); while (opline < end) { switch (opline->opcode) { case ZEND_INIT_FCALL_BY_NAME: @@ -31,23 +37,27 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx case ZEND_NEW: case ZEND_INIT_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL: + case ZEND_INIT_FCALL: call_stack[call].opline = opline; call++; break; - case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_FCALL: call--; if (call_stack[call].func && call_stack[call].opline) { zend_op *fcall = call_stack[call].opline; - opline->opcode = ZEND_DO_FCALL; - ZEND_OP1_TYPE(opline) = IS_CONST; - opline->op1.constant = fcall->op2.constant + 1; - Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]); - literal_dtor(&ZEND_OP2_LITERAL(fcall)); - if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { + if (fcall->opcode == ZEND_INIT_FCALL_BY_NAME) { + fcall->opcode = ZEND_INIT_FCALL; + literal_dtor(&ZEND_OP2_LITERAL(fcall)); + fcall->op2.constant = fcall->op2.constant + 1; + } else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { + fcall->opcode = ZEND_INIT_FCALL; + literal_dtor(&op_array->literals[fcall->op2.constant]); literal_dtor(&op_array->literals[fcall->op2.constant + 2]); + fcall->op2.constant = fcall->op2.constant + 1; + } else { + ZEND_ASSERT(0); } - MAKE_NOP(fcall); } else if (opline->extended_value == 0 && call_stack[call].opline && call_stack[call].opline->opcode == ZEND_INIT_FCALL_BY_NAME && @@ -55,12 +65,9 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx zend_op *fcall = call_stack[call].opline; - opline->opcode = ZEND_DO_FCALL; - ZEND_OP1_TYPE(opline) = IS_CONST; - opline->op1.constant = fcall->op2.constant + 1; - Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]); + fcall->opcode = ZEND_INIT_FCALL; literal_dtor(&ZEND_OP2_LITERAL(fcall)); - MAKE_NOP(fcall); + fcall->op2.constant = fcall->op2.constant + 1; } call_stack[call].func = NULL; call_stack[call].opline = NULL; @@ -79,21 +86,21 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx } break; case ZEND_SEND_VAL: - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) { + if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) && call_stack[call - 1].func) { if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) { /* We won't convert it into_DO_FCALL to emit error at run-time */ call_stack[call - 1].opline = NULL; } else { - opline->extended_value = ZEND_DO_FCALL; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; } } break; case ZEND_SEND_VAR: - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) { + if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) && call_stack[call - 1].func) { if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) { opline->opcode = ZEND_SEND_REF; } - opline->extended_value = ZEND_DO_FCALL; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; } break; case ZEND_SEND_VAR_NO_REF: @@ -104,12 +111,12 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND; } else { opline->opcode = ZEND_SEND_VAR; - opline->extended_value = ZEND_DO_FCALL; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; } } break; case ZEND_SEND_REF: - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND && call_stack[call - 1].func) { /* We won't handle run-time pass by reference */ call_stack[call - 1].opline = NULL; } diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c index 73fa0d02f9..de97f64db8 100644 --- a/ext/opcache/Optimizer/pass1_5.c +++ b/ext/opcache/Optimizer/pass1_5.c @@ -320,22 +320,25 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { #endif break; - case ZEND_DO_FCALL: + case ZEND_INIT_FCALL: /* define("name", scalar); */ if (collect_constants && - opline->extended_value == 2 && - ZEND_OP1_TYPE(opline) == IS_CONST && - Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && - Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("define")-1 && - zend_binary_strcasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), "define", sizeof("define")-1) == 0 && - (opline-1)->opcode == ZEND_SEND_VAL && - ZEND_OP1_TYPE(opline-1) == IS_CONST && - Z_TYPE(ZEND_OP1_LITERAL(opline-1)) <= IS_STRING && - (opline-2)->opcode == ZEND_SEND_VAL && - ZEND_OP1_TYPE(opline-2) == IS_CONST && - Z_TYPE(ZEND_OP1_LITERAL(opline-2)) == IS_STRING) { - zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline-2), &ZEND_OP1_LITERAL(opline-1)); - break; + ZEND_OP2_TYPE(opline) == IS_CONST && + Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING && + Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("define")-1 && + zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), "define", sizeof("define")-1) == 0) { + + if ((opline+1)->opcode == ZEND_SEND_VAL && + ZEND_OP1_TYPE(opline+1) == IS_CONST && + Z_TYPE(ZEND_OP1_LITERAL(opline+1)) == IS_STRING && + (opline+2)->opcode == ZEND_SEND_VAL && + ZEND_OP1_TYPE(opline+2) == IS_CONST && + Z_TYPE(ZEND_OP1_LITERAL(opline+2)) <= IS_STRING && + (opline+3)->opcode == ZEND_DO_FCALL) { + + zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline+1), &ZEND_OP1_LITERAL(opline+2)); + break; + } } else { /* don't colllect constants after any other function call */ collect_constants = 0; @@ -348,40 +351,42 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { is_callable(x) extension_loaded(x) */ - if (opline->extended_value == 1 && (opline - 1)->opcode == ZEND_SEND_VAL && - ZEND_OP1_TYPE(opline - 1) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline - 1)) == IS_STRING && - ZEND_OP1_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) { - if ((Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("function_exists")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + if ((opline + 1)->opcode == ZEND_SEND_VAL && + (opline + 2)->opcode == ZEND_DO_FCALL && + ZEND_OP1_TYPE(opline + 1) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline + 1)) == IS_STRING && + ZEND_OP2_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) { + if ((Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("function_exists")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "function_exists", sizeof("function_exists")-1)) || - (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("is_callable")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("is_callable")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "is_callable", sizeof("is_callable")))) { zend_internal_function *func; char *lc_name = zend_str_tolower_dup( - Z_STRVAL(ZEND_OP1_LITERAL(opline - 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline - 1))); + Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1))); - if ((func = zend_hash_str_find_ptr(EG(function_table), lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline - 1)))) != NULL && + if ((func = zend_hash_str_find_ptr(EG(function_table), lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)))) != NULL && func->type == ZEND_INTERNAL_FUNCTION && func->module->type == MODULE_PERSISTENT) { zval t; ZVAL_BOOL(&t, 1); - if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) { - literal_dtor(&ZEND_OP1_LITERAL(opline - 1)); - MAKE_NOP((opline - 1)); - literal_dtor(&ZEND_OP1_LITERAL(opline)); + if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) { + literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); + literal_dtor(&ZEND_OP1_LITERAL(opline + 1)); + MAKE_NOP(opline + 1); + MAKE_NOP(opline + 2); } } efree(lc_name); - } else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("extension_loaded")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + } else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("extension_loaded")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "extension_loaded", sizeof("extension_loaded")-1)) { zval t; char *lc_name = zend_str_tolower_dup( - Z_STRVAL(ZEND_OP1_LITERAL(opline - 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline - 1))); + Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1))); zend_module_entry *m = zend_hash_str_find_ptr(&module_registry, - lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline - 1))); + lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1))); efree(lc_name); if (!m) { @@ -398,51 +403,55 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { } } - if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) { - literal_dtor(&ZEND_OP1_LITERAL(opline - 1)); - MAKE_NOP((opline - 1)); - literal_dtor(&ZEND_OP1_LITERAL(opline)); + if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) { + literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); + literal_dtor(&ZEND_OP1_LITERAL(opline + 1)); + MAKE_NOP(opline + 1); + MAKE_NOP(opline + 2); } - } else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("defined")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + } else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("defined")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "defined", sizeof("defined")-1)) { zval t; - if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline - 1)), &t, 0 TSRMLS_CC)) { + if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline + 1)), &t, 0 TSRMLS_CC)) { ZVAL_BOOL(&t, 1); - if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) { - literal_dtor(&ZEND_OP1_LITERAL(opline - 1)); - MAKE_NOP((opline - 1)); - literal_dtor(&ZEND_OP1_LITERAL(opline)); + if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) { + literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); + literal_dtor(&ZEND_OP1_LITERAL(opline + 1)); + MAKE_NOP(opline + 1); + MAKE_NOP(opline + 2); } } - } else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("constant")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + } else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("constant")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "constant", sizeof("constant")-1)) { zval t; - if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline - 1)), &t, 1 TSRMLS_CC)) { - if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) { - literal_dtor(&ZEND_OP1_LITERAL(opline - 1)); - MAKE_NOP((opline - 1)); - literal_dtor(&ZEND_OP1_LITERAL(opline)); + if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline + 1)), &t, 1 TSRMLS_CC)) { + if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) { + literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); + literal_dtor(&ZEND_OP1_LITERAL(opline + 1)); + MAKE_NOP(opline + 1); + MAKE_NOP(opline + 2); } } - } else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("strlen")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + } else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("strlen")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "strlen", sizeof("strlen")-1)) { zval t; - ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline - 1))); - if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) { - literal_dtor(&ZEND_OP1_LITERAL(opline - 1)); - MAKE_NOP((opline - 1)); - literal_dtor(&ZEND_OP1_LITERAL(opline)); + ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1))); + if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) { + literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); + literal_dtor(&ZEND_OP1_LITERAL(opline + 1)); + MAKE_NOP(opline + 1); + MAKE_NOP(opline + 2); } } } @@ -485,7 +494,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { case ZEND_FE_RESET: case ZEND_FE_FETCH: case ZEND_NEW: - case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_FCALL: #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO case ZEND_JMP_SET: #endif diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 2ea6544e23..681a54a74e 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -178,12 +178,6 @@ static void update_op1_const(zend_op_array *op_array, zend_optimizer_add_literal(op_array, val TSRMLS_CC); STR_HASH_VAL(Z_STR(op_array->literals[opline->op1.constant+1])); break; - case ZEND_DO_FCALL: - zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); - opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC); - STR_HASH_VAL(Z_STR(ZEND_OP1_LITERAL(opline))); - Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->last_cache_slot++; - break; default: opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC); STR_HASH_VAL(Z_STR(ZEND_OP1_LITERAL(opline))); @@ -204,6 +198,13 @@ static void update_op2_const(zend_op_array *op_array, { ZEND_OP2_TYPE(opline) = IS_CONST; #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO + if (opline->opcode == ZEND_INIT_FCALL) { + zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); + opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC); + STR_HASH_VAL(Z_STR(ZEND_OP2_LITERAL(opline))); + Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->last_cache_slot++; + return; + } opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC); if (Z_TYPE_P(val) == IS_STRING) { STR_HASH_VAL(Z_STR(ZEND_OP2_LITERAL(opline))); @@ -340,9 +341,9 @@ static int replace_var_by_const(zend_op_array *op_array, if (opline->extended_value & ZEND_ARG_SEND_BY_REF) { return 0; } - opline->extended_value = ZEND_DO_FCALL; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; } else { - opline->extended_value = ZEND_DO_FCALL_BY_NAME; + opline->extended_value = 0; } opline->opcode = ZEND_SEND_VAL; break; diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 0ae3feb2ee..361d1207f8 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -44,7 +44,7 @@ #define INV_EX_COND_EX(op) ((op) == ZEND_JMPZ_EX ? ZEND_JMPNZ_EX : ZEND_JMPZ_EX) #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO -# define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(opline->result)); memset(&opline->op1,0,sizeof(opline->op1)); memset(&opline->op2,0,sizeof(opline->op2)); opline->result_type=opline->op1_type=opline->op2_type=IS_UNUSED; opline->handler = zend_opcode_handlers[ZEND_NOP]; } +# define MAKE_NOP(opline) { (opline)->opcode = ZEND_NOP; memset(&(opline)->result, 0, sizeof((opline)->result)); memset(&(opline)->op1, 0, sizeof((opline)->op1)); memset(&(opline)->op2, 0, sizeof((opline)->op2));(opline)->result_type=(opline)->op1_type=(opline)->op2_type=IS_UNUSED; (opline)->handler = zend_opcode_handlers[ZEND_NOP]; } # define RESULT_USED(op) (((op->result_type & IS_VAR) && !(op->result_type & EXT_TYPE_UNUSED)) || op->result_type == IS_TMP_VAR) # define RESULT_UNUSED(op) ((op->result_type & EXT_TYPE_UNUSED) != 0) # define SAME_VAR(op1, op2) ((((op1 ## _type & IS_VAR) && (op2 ## _type & IS_VAR)) || (op1 ## _type == IS_TMP_VAR && op2 ## _type == IS_TMP_VAR)) && op1.var == op2.var) 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/cli/php_cli.c b/sapi/cli/php_cli.c index d353b00a06..ec76f37715 100644 --- a/sapi/cli/php_cli.c +++ b/sapi/cli/php_cli.c @@ -1102,7 +1102,6 @@ static int do_cli(int argc, char **argv TSRMLS_DC) /* {{{ */ memset(&execute_data, 0, sizeof(zend_execute_data)); EG(current_execute_data) = &execute_data; - EX(function_state).function = pce->constructor; zend_call_method_with_1_params(&ref, pce, &pce->constructor, "__construct", NULL, &arg); if (EG(exception)) { diff --git a/sapi/fpm/fpm/fpm_php_trace.c b/sapi/fpm/fpm/fpm_php_trace.c index 925f2de64e..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; @@ -131,6 +133,7 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC break; } } +#endif return 0; } /* }}} */