From: Dmitry Stogov Date: Mon, 23 Jun 2014 22:17:16 +0000 (+0400) Subject: Refactoring: use call_frames instead of call_slots X-Git-Tag: POST_PHPNG_MERGE~90^2~23 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=43477bc7a2da3077abf290b13571f532979db57a;p=php Refactoring: use call_frames instead of call_slots --- diff --git a/Zend/zend_API.c b/Zend/zend_API.c index ea333632be..ab38bc2c45 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); @@ -80,19 +78,17 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ ZEND_API int _zend_get_parameters_array(int ht, int param_count, zval *argument_array TSRMLS_DC) /* {{{ */ { - zval *p; int arg_count; zval *param_ptr; - 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) { - param_ptr = (p-arg_count); if (Z_REFCOUNTED_P(param_ptr) && !Z_ISREF_P(param_ptr) && Z_REFCOUNT_P(param_ptr) > 1) { @@ -105,7 +101,7 @@ ZEND_API int _zend_get_parameters_array(int ht, int param_count, zval *argument_ ZVAL_COPY_VALUE(argument_array, param_ptr); } argument_array++; - arg_count--; + param_ptr++; } return SUCCESS; @@ -116,14 +112,13 @@ ZEND_API int _zend_get_parameters_array(int ht, int param_count, zval *argument_ /* 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; @@ -132,7 +127,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); @@ -142,22 +138,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; @@ -166,22 +160,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); + add_next_index_zval(argument_array, param_ptr); + param_ptr++; } return SUCCESS; @@ -841,7 +835,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, @@ -861,7 +855,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, @@ -884,7 +878,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, @@ -898,7 +892,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", @@ -922,7 +916,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; @@ -933,7 +927,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 */ @@ -1004,7 +998,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..f0ed68b703 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -396,8 +396,8 @@ ZEND_FUNCTION(func_num_args) { zend_execute_data *ex = EG(current_execute_data)->prev_execute_data; - if (ex && ex->function_state.arguments) { - RETURN_LONG(Z_LVAL_P(ex->function_state.arguments)); + if (ex && ex->call) { + RETURN_LONG(ex->call->num_args); } else { zend_error(E_WARNING, "func_num_args(): Called from the global scope - no function context"); RETURN_LONG(-1); @@ -409,7 +409,6 @@ 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; zval *arg; long requested_offset; @@ -424,20 +423,19 @@ ZEND_FUNCTION(func_get_arg) RETURN_FALSE; } - if (!ex || !ex->function_state.arguments) { + if (!ex || !ex->call) { 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->call->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); + arg = ZEND_CALL_ARG(ex->call, requested_offset + 1); RETURN_ZVAL_FAST(arg); } /* }}} */ @@ -451,19 +449,18 @@ ZEND_FUNCTION(func_get_args) int i; zend_execute_data *ex = EG(current_execute_data)->prev_execute_data; - if (!ex || !ex->function_state.arguments) { + if (!ex || !ex->call) { 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->call->num_args; array_init_size(return_value, arg_count); if (arg_count) { Bucket *q; - p -= arg_count; + p = ZEND_CALL_ARG(ex->call, 1); zend_hash_real_init(Z_ARRVAL_P(return_value), 1); q = Z_ARRVAL_P(return_value)->arData; for (i=0; inum_args; array_init_size(arg_array, arg_count); - p -= arg_count; - - 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 (arg_count > 0) { + 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); + } } } } @@ -1996,6 +1995,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; @@ -2029,7 +2029,6 @@ ZEND_FUNCTION(debug_print_backtrace) 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; } @@ -2044,41 +2043,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 = (zend_function*)(ptr->op_array); + 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 (!ptr->opline || ptr->opline->opcode == ZEND_DO_FCALL) { + if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0) { + debug_backtrace_get_args(ptr->call, &arg_array TSRMLS_CC); } } } else { @@ -2137,8 +2142,9 @@ 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 && + prev->call->func->common.type != ZEND_USER_FUNCTION) { prev = NULL; break; } @@ -2166,6 +2172,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; @@ -2198,7 +2205,6 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int 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; } @@ -2216,10 +2222,11 @@ 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 && + prev->call->func->common.type != ZEND_USER_FUNCTION && + !(prev->call->func->common.type == ZEND_INTERNAL_FUNCTION && + (prev->call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER))) { break; } if (prev->op_array) { @@ -2235,28 +2242,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 = (zend_function*)(ptr->op_array); + 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 +2283,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) { + (!ptr->opline || ptr->opline->opcode == ZEND_DO_FCALL)) { + 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); } } diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 3c2921f53c..85056d3cd5 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()); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c6116693b7..690020a67d 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -182,7 +182,6 @@ void zend_init_compiler_context(TSRMLS_D) /* {{{ */ CG(context).literals_size = 0; CG(context).current_brk_cont = -1; CG(context).backpatch_count = 0; - CG(context).nested_calls = 0; CG(context).used_stack = 0; CG(context).in_finally = 0; CG(context).labels = NULL; @@ -1949,6 +1948,7 @@ void zend_do_receive_param(zend_uchar op, znode *varname, znode *initialization, int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ { + zend_op *opline; zend_function *function; zend_string *lcname; char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant)); @@ -1977,10 +1977,14 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace STR_RELEASE(Z_STR(function_name->u.constant)); Z_STR(function_name->u.constant) = lcname; + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_INIT_FCALL; + SET_UNUSED(opline->op1); + SET_NODE(opline->op2, function_name); + GET_CACHE_SLOT(opline->op2.constant); + zend_push_function_call_entry(function TSRMLS_CC); - if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls + 1; - } + CG(context).used_stack += ZEND_CALL_FRAME_SLOT; zend_do_extended_fcall_begin(TSRMLS_C); return 0; } @@ -2017,12 +2021,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; @@ -2034,9 +2036,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; - } + CG(context).used_stack += ZEND_CALL_FRAME_SLOT; zend_do_extended_fcall_begin(TSRMLS_C); } /* }}} */ @@ -2063,14 +2063,12 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML /* 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; @@ -2082,9 +2080,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; - } + CG(context).used_stack += ZEND_CALL_FRAME_SLOT; zend_do_extended_fcall_begin(TSRMLS_C); } /* }}} */ @@ -2508,7 +2504,6 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na 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 = @@ -2530,9 +2525,7 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na } 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; - } + CG(context).used_stack += ZEND_CALL_FRAME_SLOT; zend_do_extended_fcall_begin(TSRMLS_C); return 1; /* Dynamic */ } @@ -2551,25 +2544,9 @@ void zend_do_end_function_call(znode *function_name, znode *result, int is_metho opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)]; } else { opline = 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; - - /* 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->opcode = ZEND_DO_FCALL; + SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); } opline->result.var = get_temporary_variable(CG(active_op_array)); @@ -2577,10 +2554,10 @@ 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; + if (CG(context).used_stack > CG(active_op_array)->used_stack) { + CG(active_op_array)->used_stack = CG(context).used_stack; } - CG(context).used_stack -= fcall->arg_num; + CG(context).used_stack -= ZEND_CALL_FRAME_SLOT + fcall->arg_num; zend_stack_del_top(&CG(function_call_stack)); } /* }}} */ @@ -2682,9 +2659,7 @@ 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; @@ -2692,9 +2667,7 @@ void zend_do_pass_param(znode *param, zend_uchar op TSRMLS_DC) /* {{{ */ 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; - } + CG(context).used_stack++; } /* }}} */ @@ -2705,25 +2678,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 +5573,13 @@ 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; - } + CG(context).used_stack += ZEND_CALL_FRAME_SLOT; } /* }}} */ @@ -5819,6 +5770,13 @@ 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; + 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,27 +5788,21 @@ 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; + if (CG(context).used_stack + ZEND_CALL_FRAME_SLOT + 1 > CG(active_op_array)->used_stack) { + CG(active_op_array)->used_stack = CG(context).used_stack + ZEND_CALL_FRAME_SLOT + 1; } } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 5b5397844f..35be52f2f7 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -59,7 +59,6 @@ typedef struct _zend_compiler_context { int literals_size; int current_brk_cont; int backpatch_count; - int nested_calls; int used_stack; int in_finally; HashTable *labels; @@ -266,7 +265,6 @@ struct _zend_op_array { zend_uint T; - zend_uint nested_calls; zend_uint used_stack; zend_brk_cont_element *brk_cont_array; @@ -336,12 +334,6 @@ 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 arg_num; @@ -361,14 +353,26 @@ 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 struct _zend_call_frame zend_call_frame; + +struct _zend_call_frame { + zend_function *func; + zend_uint num_args; + zend_uint flags; + zend_class_entry *called_scope; + zend_object *object; + zend_call_frame *prev; +}; + +#define ZEND_CALL_CTOR (1 << 0) +#define ZEND_CALL_CTOR_RESULT_USED (1 << 1) +#define ZEND_CALL_DONE (1 << 2) + +#define ZEND_CALL_FRAME_SLOT \ + ((ZEND_MM_ALIGNED_SIZE(sizeof(zend_call_frame)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))) + +#define ZEND_CALL_ARG(call, n) \ + (((zval*)(call)) + ((n) + (ZEND_CALL_FRAME_SLOT - 1))) typedef enum _vm_frame_kind { VM_FRAME_NESTED_FUNCTION, /* stackless VM call to function */ @@ -380,7 +384,7 @@ 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_call_frame *call; /* current call */ zend_object *object; /* current $this */ zend_class_entry *scope; /* function scope (self) */ zend_class_entry *called_scope; /* function called scope (static) */ @@ -393,8 +397,6 @@ struct _zend_execute_data { 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; }; #define EX(element) execute_data.element @@ -877,7 +879,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..4e5b811d7e 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1468,13 +1468,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 ); } } @@ -1536,12 +1536,10 @@ void zend_free_compiled_variables(zend_execute_data *execute_data TSRMLS_DC) /* * | VAR[op_array->last_var] | * | ... | * | VAR[op_array->last_var+op_array->T-1] | + * zend_vm_stack_frame_base -> +----------------------------------------+ + * EX(call_slot) -> | CALL_SLOT | * +----------------------------------------+ - * EX(call_slots) -> | CALL_SLOT[0] | - * | ... | - * | CALL_SLOT[op_array->nested_calls-1] | - * +----------------------------------------+ - * zend_vm_stack_frame_base -> | ARGUMENTS STACK [0] | + * | ARGUMENTS STACK [0] | * | ... | * zend_vm_stack_top --------> | ... | * | ... | @@ -1566,9 +1564,8 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array */ 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; + size_t total_size = execute_data_size + vars_size + stack_size; /* * Normally the execute_data is allocated on the VM stack (because it does @@ -1585,7 +1582,7 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array * 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); + size_t args_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval)) * (ZEND_CALL_FRAME_SLOT + args_count); total_size += args_size + execute_data_size; @@ -1596,11 +1593,15 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array /* 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))); + EX(prev_execute_data)->call = (zend_call_frame*)(((char*)EX(prev_execute_data)) + sizeof(zend_execute_data)); + EX(prev_execute_data)->call->func = (zend_function*)op_array; + EX(prev_execute_data)->call->num_args = args_count; + EX(prev_execute_data)->call->flags = ZEND_CALL_DONE; + EX(prev_execute_data)->call->called_scope = NULL; + EX(prev_execute_data)->call->object = NULL; + EX(prev_execute_data)->call->prev = NULL; /* copy arguments */ - 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); @@ -1619,13 +1620,10 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array 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); @@ -1674,24 +1672,28 @@ ZEND_API zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array } /* }}} */ -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_call_frame *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) /* {{{ */ +static zend_call_frame *zend_vm_stack_copy_call_frame(zend_call_frame *call TSRMLS_DC) /* {{{ */ { + zend_uint count; + zend_call_frame *new_call; zend_vm_stack p = EG(argument_stack); - zend_vm_stack_extend(count + 1 TSRMLS_CC); + zend_vm_stack_extend(ZEND_CALL_FRAME_SLOT + call->num_args TSRMLS_CC); - EG(argument_stack)->top += count; - ZVAL_LONG(EG(argument_stack)->top, count); + new_call = (zend_call_frame*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)); + *new_call = *call; + EG(argument_stack)->top += ZEND_CALL_FRAME_SLOT + call->num_args; + count = call->num_args; while (count-- > 0) { zval *data = --p->top; - ZVAL_COPY_VALUE(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + count, data); + ZVAL_COPY_VALUE(ZEND_CALL_ARG(new_call, count), data); if (UNEXPECTED(p->top == ZEND_VM_STACK_ELEMETS(p))) { zend_vm_stack r = p; @@ -1701,18 +1703,16 @@ static zval *zend_vm_stack_push_args_with_copy(int count TSRMLS_DC) /* {{{ */ 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_adjust_call_frame(zend_call_frame **call TSRMLS_DC) /* {{{ */ { - if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < count) + if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < ZEND_CALL_FRAME_SLOT + (*call)->num_args) || UNEXPECTED(EG(argument_stack)->top == EG(argument_stack)->end)) { - return zend_vm_stack_push_args_with_copy(count TSRMLS_CC); + *call = zend_vm_stack_copy_call_frame(*call TSRMLS_CC); } - ZVAL_LONG(EG(argument_stack)->top, count); - return EG(argument_stack)->top++; } /* }}} */ diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 1b74564dfd..49d9275bfa 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -221,6 +221,19 @@ static zend_always_inline zval *zend_vm_stack_pop(TSRMLS_D) return --EG(argument_stack)->top; } +static zend_always_inline zend_call_frame *zend_vm_stack_push_call_frame(zend_function *func, zend_uint num_args, zend_uint flags, zend_class_entry *called_scope, zend_object *object, zend_call_frame *prev TSRMLS_DC) +{ + zend_call_frame * call = (zend_call_frame*)EG(argument_stack)->top; + call->func = func; + call->num_args = num_args; + call->flags = flags; + call->called_scope = called_scope; + call->object = object; + call->prev = prev; + EG(argument_stack)->top += ZEND_CALL_FRAME_SLOT; + return call; +} + static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC) { zval *ret; @@ -234,8 +247,7 @@ static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC) 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); + return EX_VAR_NUM_2(ex, ex->op_array->last_var + ex->op_array->T); } static zend_always_inline void zend_vm_stack_free(void *ptr TSRMLS_DC) @@ -250,12 +262,13 @@ static zend_always_inline void zend_vm_stack_free(void *ptr TSRMLS_DC) } } -static zend_always_inline void zend_vm_stack_clear_multiple(int nested TSRMLS_DC) +static zend_always_inline void zend_vm_stack_free_call_frame(zend_call_frame *call, int nested TSRMLS_DC) { - zval *p = EG(argument_stack)->top - 1; + zend_uint num_args = call->num_args; - if (EXPECTED(Z_LVAL_P(p) > 0)) { - zval *end = p - Z_LVAL_P(p); + if (num_args > 0) { + zval *p = ZEND_CALL_ARG(call, num_args + 1); + zval *end = p - num_args; do { p--; @@ -263,27 +276,25 @@ static zend_always_inline void zend_vm_stack_clear_multiple(int nested TSRMLS_DC } while (p != end); } if (nested) { - EG(argument_stack)->top = p; + EG(argument_stack)->top = (zval*)call; } else { - zend_vm_stack_free(p TSRMLS_CC); + zend_vm_stack_free((zval*)call TSRMLS_CC); } } 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..d326037b15 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -393,17 +393,24 @@ 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 = (zend_function*)EG(current_execute_data)->op_array; + } + 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 = (zend_function*)EG(current_execute_data)->op_array; + } + 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); @@ -719,7 +734,10 @@ 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; + ZEND_VM_STACK_GROW_IF_NEEDED(ZEND_CALL_FRAME_SLOT + fci->param_count); + + func = fci_cache->function_handler; + EX(call) = zend_vm_stack_push_call_frame(func, fci->param_count, ZEND_CALL_DONE, fci_cache->called_scope, fci_cache->object, NULL TSRMLS_CC); calling_scope = fci_cache->calling_scope; called_scope = fci_cache->called_scope; fci->object = fci_cache->object; @@ -729,24 +747,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 +782,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)) { + !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { if (i || UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (EG(argument_stack)->top))) { /* 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); + zend_vm_stack_free_call_frame(EX(call), 0 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; } @@ -797,7 +813,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS 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; ZVAL_DUP(param, Z_REFVAL(fci->params[i])); } else { @@ -807,13 +823,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS 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); - EG(scope) = calling_scope; EG(called_scope) = called_scope; if (!fci->object || - (EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) { + (func->common.fn_flags & ZEND_ACC_STATIC)) { Z_OBJ(EG(This)) = NULL; } else { Z_OBJ(EG(This)) = fci->object; @@ -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,15 +861,15 @@ 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); } @@ -880,22 +893,22 @@ 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); + zend_vm_stack_free_call_frame(EX(call), 0 TSRMLS_CC); if (Z_OBJ(EG(This))) { zval_ptr_dtor(&EG(This)); diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index c80e909565..2f82922b7a 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -87,11 +87,11 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato /* 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; } } /* }}} */ @@ -133,11 +133,10 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished * 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; + if (prev_execute_data->call) { + int arguments_count = prev_execute_data->call->num_args; + zval *arguments_start = ZEND_CALL_ARG(prev_execute_data->call, 1); int i; for (i = 0; i < arguments_count; ++i) { 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..7fb1d9d878 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -70,7 +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; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 38377d3cce..f6153d80ec 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_call_frame *call; EG(current_execute_data) = EX(prev_execute_data); @@ -1790,12 +1791,9 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) EG(active_op_array) = EX(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(call)->flags & ZEND_CALL_CTOR)) { + if (EX(call)->flags & ZEND_CALL_CTOR_RESULT_USED) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -1812,9 +1810,9 @@ 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); + call = EX(call); + EX(call) = EX(call)->prev; + zend_vm_stack_free_call_frame(call, 1 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { zend_op *opline = EX(opline); @@ -1836,10 +1834,11 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) execute_data = EG(current_execute_data); 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); + call = EX(call); + EX(call) = EX(call)->prev; + zend_vm_stack_free((zval*)call TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION_LEAVE(); @@ -1876,215 +1875,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } } -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 +2197,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,29 +2215,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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)); + 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(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); + 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); } } } else { @@ -2456,15 +2248,14 @@ 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; + 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); FREE_OP2(); FREE_OP1_IF_VAR(); @@ -2478,7 +2269,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(); @@ -2496,24 +2288,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 +2314,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 +2340,38 @@ 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; + if (fbc->common.fn_flags & ZEND_ACC_STATIC) { + 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); + 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", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + 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); } } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + object = Z_OBJ(EG(This)); + if (object) { + GC_REFCOUNT(object)++; + } + } + + if (OP1_TYPE != IS_CONST) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->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, 0, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2590,26 +2380,25 @@ 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 + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *object; zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; if (OP2_TYPE == IS_CONST) { function_name_ptr = 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, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); @@ -2635,33 +2424,28 @@ 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; + EX(call) = zend_vm_stack_push_call_frame( + Z_FUNC_P(func), 0, 0, NULL, NULL, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } 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; + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2687,40 +2471,39 @@ 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; + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); FREE_OP2(); CHECK_EXCEPTION(); @@ -2741,68 +2524,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, 0, 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, 0, 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_function *fbc = EX(call)->func; + zend_object *object; + zend_uint num_args; + zend_call_frame *call; + + SAVE_OPLINE(); + EX(call)->flags |= ZEND_CALL_DONE; + 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_args == 0)) { + EX(call)->num_args = num_args = opline->extended_value; + } else { + EX(call)->num_args += opline->extended_value; + num_args = EX(call)->num_args; + zend_vm_stack_adjust_call_frame(&EX(call) TSRMLS_CC); + } + 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 = ZEND_CALL_ARG(EX(call), 1); + + for (i = 0; i < 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(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; - ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_common_helper); + 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)->flags & ZEND_CALL_CTOR)) { + if (EX(call)->flags & ZEND_CALL_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(call)->flags &= ~ZEND_CALL_DONE; + _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); + } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { + gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); + } + } + Z_OBJ(EG(This)) = EX(object); + EG(scope) = EX(scope); + EG(called_scope) = EX(called_scope); + +ZEND_VM_C_LABEL(fcall_end): + call = EX(call); + EX(call) = EX(call)->prev; + zend_vm_stack_free_call_frame(call, 1 TSRMLS_CC); + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + 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) @@ -2995,8 +2973,8 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY) 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); } } @@ -3044,7 +3022,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); } } @@ -3065,7 +3043,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) } 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); @@ -3118,8 +3096,8 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY) zval *varptr, *top; 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); } } @@ -3147,7 +3125,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 = opline->op2.num + EX(call)->num_args + 1; ZEND_VM_C_LABEL(send_again): switch (Z_TYPE_P(args)) { @@ -3164,7 +3142,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; } @@ -3184,7 +3162,7 @@ ZEND_VM_C_LABEL(send_again): } top = zend_vm_stack_top_inc(TSRMLS_C); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, 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); @@ -3198,7 +3176,7 @@ ZEND_VM_C_LABEL(send_again): ZVAL_COPY(top, arg); } - EX(call)->num_additional_args++; + EX(call)->num_args++; arg_num++; } ZEND_HASH_FOREACH_END(); @@ -3260,13 +3238,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 ); } @@ -3278,7 +3256,7 @@ ZEND_VM_C_LABEL(send_again): ZEND_VM_STACK_GROW_IF_NEEDED(1); zend_vm_stack_push(arg TSRMLS_CC); - EX(call)->num_additional_args++; + EX(call)->num_args++; iter->funcs->move_forward(iter TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { @@ -3307,15 +3285,14 @@ 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); + zend_uint arg_count = EX(prev_execute_data)->call->num_args; SAVE_OPLINE(); if (UNEXPECTED(arg_num > arg_count)) { zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC); } else { zval *var_ptr; - zval *param = arguments - arg_count + arg_num - 1; + zval *param = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); 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); @@ -3333,8 +3310,7 @@ 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); + zend_uint arg_count = EX(prev_execute_data)->call->num_args; zval *var_ptr; SAVE_OPLINE(); @@ -3351,7 +3327,7 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) } } } else { - zval *param = arguments - arg_count + arg_num - 1; + zval *param = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); ZVAL_COPY(var_ptr, param); } @@ -3367,8 +3343,7 @@ 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(prev_execute_data)->call->num_args; zval *params; SAVE_OPLINE(); @@ -3377,7 +3352,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY) 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 = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); array_init_size(params, arg_count - arg_num + 1); if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { do { @@ -3515,21 +3490,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, 0, + RETURN_VALUE_USED(opline) ? + (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_USED) : ZEND_CALL_CTOR, + 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(); } @@ -4008,13 +3981,15 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) HANDLE_EXCEPTION(); } else if (EXPECTED(new_op_array != NULL)) { zval *return_value = NULL; + zend_call_frame *call; EG(active_op_array) = new_op_array; if (RETURN_VALUE_USED(opline)) { 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, NULL, NULL, EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); @@ -4027,10 +4002,11 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) zend_execute(new_op_array, return_value TSRMLS_CC); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); + call = EX(call); + EX(call) = EX(call)->prev; + zend_vm_stack_free((zval*)call TSRMLS_CC); destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -5176,18 +5152,6 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) zend_uint op_num = EG(opline_before_exception)-EG(active_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) { @@ -5206,12 +5170,20 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } } - if (EX(call) >= EX(call_slots)) { - call_slot *call = EX(call); + if (EX(call)) { + zend_call_frame *call = EX(call); do { + zval *args = ZEND_CALL_ARG(call, 1); + + /* If the exception was thrown during a function call there might be + * arguments pushed to the stack that have to be dtor'ed. */ + while (zend_vm_stack_top(TSRMLS_C) != args) { + zval *stack_zval_p = zend_vm_stack_pop(TSRMLS_C); + zval_ptr_dtor(stack_zval_p); + } 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_USED) { GC_REFCOUNT(call->object)--; } if (GC_REFCOUNT(call->object) == 1) { @@ -5220,8 +5192,9 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } OBJ_RELEASE(call->object); } - call--; - } while (call >= EX(call_slots)); + EG(argument_stack)->top = (zval*)call; + call = call->prev; + } while (call); EX(call) = NULL; } @@ -5382,7 +5355,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 { @@ -5646,4 +5619,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..f341e19fdb 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -384,6 +384,7 @@ ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value TSRMLS_DC static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) { vm_frame_kind frame_kind = EX(frame_kind); + zend_call_frame *call; EG(current_execute_data) = EX(prev_execute_data); @@ -402,12 +403,9 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EG(active_op_array) = EX(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(call)->flags & ZEND_CALL_CTOR)) { + if (EX(call)->flags & ZEND_CALL_CTOR_RESULT_USED) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -424,9 +422,9 @@ 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); + call = EX(call); + EX(call) = EX(call)->prev; + zend_vm_stack_free_call_frame(call, 1 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { zend_op *opline = EX(opline); @@ -448,10 +446,11 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) execute_data = EG(current_execute_data); 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); + call = EX(call); + EX(call) = EX(call)->prev; + zend_vm_stack_free((zval*)call TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION_LEAVE(); @@ -488,14 +487,35 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) } } -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_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_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_function *fbc = EX(call)->func; zend_object *object; zend_uint num_args; + zend_call_frame *call; SAVE_OPLINE(); + EX(call)->flags |= ZEND_CALL_DONE; 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)) { @@ -528,13 +548,12 @@ 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); + if (EXPECTED(EX(call)->num_args == 0)) { + EX(call)->num_args = num_args = opline->extended_value; } else { - num_args = opline->extended_value + EX(call)->num_additional_args; - EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC); + EX(call)->num_args += opline->extended_value; + num_args = EX(call)->num_args; + zend_vm_stack_adjust_call_frame(&EX(call) TSRMLS_CC); } LOAD_OPLINE(); @@ -557,10 +576,11 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR 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(EX(call), 1); - for (i = 0; i < num_args; ++i, ++p) { + for (i = 0; i < 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)) { @@ -659,8 +679,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) && (EX(call)->flags & ZEND_CALL_CTOR)) { + if (EX(call)->flags & ZEND_CALL_CTOR_RESULT_USED) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -668,8 +688,7 @@ fcall_end_change_scope: } } if (!Z_DELREF(EG(This))) { - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; + EX(call)->flags &= ~ZEND_CALL_DONE; _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); @@ -680,11 +699,9 @@ 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); + call = EX(call); + EX(call) = EX(call)->prev; + zend_vm_stack_free_call_frame(call, 1 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); @@ -697,31 +714,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 +735,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 = opline->op2.num + EX(call)->num_args + 1; send_again: switch (Z_TYPE_P(args)) { @@ -760,7 +752,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; } @@ -780,7 +772,7 @@ send_again: } top = zend_vm_stack_top_inc(TSRMLS_C); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, 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); @@ -794,7 +786,7 @@ send_again: ZVAL_COPY(top, arg); } - EX(call)->num_additional_args++; + EX(call)->num_args++; arg_num++; } ZEND_HASH_FOREACH_END(); @@ -856,13 +848,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 ); } @@ -874,7 +866,7 @@ send_again: ZEND_VM_STACK_GROW_IF_NEEDED(1); zend_vm_stack_push(arg TSRMLS_CC); - EX(call)->num_additional_args++; + EX(call)->num_args++; iter->funcs->move_forward(iter TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { @@ -903,15 +895,14 @@ 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); + zend_uint arg_count = EX(prev_execute_data)->call->num_args; SAVE_OPLINE(); if (UNEXPECTED(arg_num > arg_count)) { zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC); } else { zval *var_ptr; - zval *param = arguments - arg_count + arg_num - 1; + zval *param = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); 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); @@ -929,8 +920,7 @@ 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(prev_execute_data)->call->num_args; zval *params; SAVE_OPLINE(); @@ -939,7 +929,7 @@ static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR 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 = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); array_init_size(params, arg_count - arg_num + 1); if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { do { @@ -990,21 +980,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, 0, + RETURN_VALUE_USED(opline) ? + (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_USED) : ZEND_CALL_CTOR, + 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(); } @@ -1205,18 +1193,6 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER zend_uint op_num = EG(opline_before_exception)-EG(active_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) { @@ -1235,12 +1211,20 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER } } - if (EX(call) >= EX(call_slots)) { - call_slot *call = EX(call); + if (EX(call)) { + zend_call_frame *call = EX(call); do { + zval *args = ZEND_CALL_ARG(call, 1); + + /* If the exception was thrown during a function call there might be + * arguments pushed to the stack that have to be dtor'ed. */ + while (zend_vm_stack_top(TSRMLS_C) != args) { + zval *stack_zval_p = zend_vm_stack_pop(TSRMLS_C); + zval_ptr_dtor(stack_zval_p); + } 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_USED) { GC_REFCOUNT(call->object)--; } if (GC_REFCOUNT(call->object) == 1) { @@ -1249,8 +1233,9 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER } OBJ_RELEASE(call->object); } - call--; - } while (call >= EX(call_slots)); + EG(argument_stack)->top = (zval*)call; + call = call->prev; + } while (call); EX(call) = NULL; } @@ -1459,26 +1444,25 @@ 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 + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *object; zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; if (IS_CONST == IS_CONST) { function_name_ptr = 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, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); @@ -1503,33 +1487,28 @@ 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; + EX(call) = zend_vm_stack_push_call_frame( + Z_FUNC_P(func), 0, 0, NULL, NULL, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } 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; + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1555,40 +1534,39 @@ 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; + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1608,30 +1586,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); } - 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, 0, 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); + } + + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); } @@ -1640,8 +1639,7 @@ 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); + zend_uint arg_count = EX(prev_execute_data)->call->num_args; zval *var_ptr; SAVE_OPLINE(); @@ -1658,7 +1656,7 @@ static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ } } } else { - zval *param = arguments - arg_count + arg_num - 1; + zval *param = ZEND_CALL_ARG(EX(prev_execute_data)->call, arg_num); ZVAL_COPY(var_ptr, param); } @@ -1786,26 +1784,25 @@ 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 + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *object; zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; if (IS_TMP_VAR == IS_CONST) { function_name_ptr = 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, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); @@ -1831,33 +1828,28 @@ 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; + EX(call) = zend_vm_stack_push_call_frame( + Z_FUNC_P(func), 0, 0, NULL, NULL, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } 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; + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1883,40 +1875,39 @@ 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; + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); CHECK_EXCEPTION(); @@ -1975,26 +1966,25 @@ 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 + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *object; zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; if (IS_VAR == IS_CONST) { function_name_ptr = 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, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); @@ -2020,33 +2010,28 @@ 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; + EX(call) = zend_vm_stack_push_call_frame( + Z_FUNC_P(func), 0, 0, NULL, NULL, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } 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; + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2072,40 +2057,39 @@ 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; + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); CHECK_EXCEPTION(); @@ -2202,26 +2186,25 @@ 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 + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *object; zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; if (IS_CV == IS_CONST) { function_name_ptr = 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, 0, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); @@ -2246,33 +2229,28 @@ 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; + EX(call) = zend_vm_stack_push_call_frame( + Z_FUNC_P(func), 0, 0, NULL, NULL, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } 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; + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2298,40 +2276,39 @@ 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; + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, called_scope, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2557,34 +2534,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 @@ -2709,8 +2658,8 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A 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); } } @@ -2993,13 +2942,15 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA HANDLE_EXCEPTION(); } else if (EXPECTED(new_op_array != NULL)) { zval *return_value = NULL; + zend_call_frame *call; EG(active_op_array) = new_op_array; if (RETURN_VALUE_USED(opline)) { 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, NULL, NULL, EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); @@ -3012,10 +2963,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA zend_execute(new_op_array, return_value TSRMLS_CC); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); + call = EX(call); + EX(call) = EX(call)->prev; + zend_vm_stack_free((zval*)call TSRMLS_CC); destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -3789,7 +3741,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(); @@ -3807,24 +3760,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 +3786,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 +3812,38 @@ 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; + if (fbc->common.fn_flags & ZEND_ACC_STATIC) { + 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); + 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", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + 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); } } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + object = Z_OBJ(EG(This)); + if (object) { + GC_REFCOUNT(object)++; } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + if (IS_CONST != IS_CONST) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); + } + } + + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -4757,7 +4708,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(); @@ -4775,24 +4727,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 +4753,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 +4779,38 @@ 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; + if (fbc->common.fn_flags & ZEND_ACC_STATIC) { + 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); + 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", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + 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); } } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + object = Z_OBJ(EG(This)); + if (object) { + GC_REFCOUNT(object)++; } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + if (IS_CONST != IS_CONST) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); + } + } + + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -5593,7 +5543,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(); @@ -5611,24 +5562,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 +5588,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 +5614,38 @@ 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; + if (fbc->common.fn_flags & ZEND_ACC_STATIC) { + 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); + 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", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + 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); } } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + object = Z_OBJ(EG(This)); + if (object) { + GC_REFCOUNT(object)++; } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + if (IS_CONST != IS_CONST) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); + } + } + + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -6288,7 +6237,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(); @@ -6306,24 +6256,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 +6282,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 +6308,38 @@ 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; + if (fbc->common.fn_flags & ZEND_ACC_STATIC) { + 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); + 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", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + 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); } } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + object = Z_OBJ(EG(This)); + if (object) { + GC_REFCOUNT(object)++; + } + } + + if (IS_CONST != IS_CONST) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->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, 0, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -6681,7 +6629,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 { @@ -7119,7 +7067,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(); @@ -7137,24 +7086,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 +7112,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 +7138,38 @@ 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; + if (fbc->common.fn_flags & ZEND_ACC_STATIC) { + 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); + 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", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + 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); } } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + object = Z_OBJ(EG(This)); + if (object) { + GC_REFCOUNT(object)++; + } + } + + if (IS_CONST != IS_CONST) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->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, 0, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -7910,8 +7857,8 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_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); } } @@ -8196,13 +8143,15 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HAND HANDLE_EXCEPTION(); } else if (EXPECTED(new_op_array != NULL)) { zval *return_value = NULL; + zend_call_frame *call; EG(active_op_array) = new_op_array; if (RETURN_VALUE_USED(opline)) { 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, NULL, NULL, EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); @@ -8215,10 +8164,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HAND zend_execute(new_op_array, return_value TSRMLS_CC); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); + call = EX(call); + EX(call) = EX(call)->prev; + zend_vm_stack_free((zval*)call TSRMLS_CC); destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -9079,8 +9029,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,29 +9047,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj TSRMLS_CC); 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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_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)); + 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(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); + 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); } } } else { @@ -9128,15 +9080,14 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -9914,8 +9865,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,29 +9883,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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)); + 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(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); + 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); } } } else { @@ -9963,15 +9916,14 @@ 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; + 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -10750,8 +10702,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,29 +10720,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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)); + 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(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); + 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); } } } else { @@ -10799,15 +10753,14 @@ 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; + 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -12136,8 +12089,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,29 +12107,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj TSRMLS_CC); 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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_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)); + 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(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); + 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); } } } else { @@ -12185,15 +12140,14 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_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; + 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -13073,7 +13027,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); } } @@ -13094,7 +13048,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND } 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); @@ -13147,8 +13101,8 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG zval *varptr, *top; 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); } } @@ -13447,13 +13401,15 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND HANDLE_EXCEPTION(); } else if (EXPECTED(new_op_array != NULL)) { zval *return_value = NULL; + zend_call_frame *call; EG(active_op_array) = new_op_array; if (RETURN_VALUE_USED(opline)) { 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, NULL, NULL, EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); @@ -13466,10 +13422,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND zend_execute(new_op_array, return_value TSRMLS_CC); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); + call = EX(call); + EX(call) = EX(call)->prev; + zend_vm_stack_free((zval*)call TSRMLS_CC); destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -15334,8 +15291,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,29 +15309,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj TSRMLS_CC); 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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_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)); + 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(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); + 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); } } } else { @@ -15383,15 +15342,14 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op1.var); @@ -15404,7 +15362,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(); @@ -15422,24 +15381,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 +15407,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 +15433,38 @@ 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; + if (fbc->common.fn_flags & ZEND_ACC_STATIC) { + 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); + 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", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + 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); } } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + object = Z_OBJ(EG(This)); + if (object) { + GC_REFCOUNT(object)++; + } + } + + if (IS_VAR != IS_CONST) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->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, 0, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -17562,8 +17519,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,29 +17537,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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)); + 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(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); + 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); } } } else { @@ -17611,15 +17570,14 @@ 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; + 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); zval_ptr_dtor_nogc(free_op1.var); @@ -17633,7 +17591,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(); @@ -17651,24 +17610,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 +17636,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 +17662,38 @@ 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; + if (fbc->common.fn_flags & ZEND_ACC_STATIC) { + 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); + 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", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + 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); } } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + object = Z_OBJ(EG(This)); + if (object) { + GC_REFCOUNT(object)++; } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + if (IS_VAR != IS_CONST) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); + } + } + + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -19758,8 +19715,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,29 +19733,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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)); + 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(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); + 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); } } } else { @@ -19807,15 +19766,14 @@ 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; + 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); zval_ptr_dtor_nogc(free_op1.var); @@ -19829,7 +19787,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(); @@ -19847,24 +19806,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 +19832,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 +19858,38 @@ 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; + if (fbc->common.fn_flags & ZEND_ACC_STATIC) { + 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); + 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", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + 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); } } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + object = Z_OBJ(EG(This)); + if (object) { + GC_REFCOUNT(object)++; + } + } + + if (IS_VAR != IS_CONST) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->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, 0, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -21295,7 +21252,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(); @@ -21313,24 +21271,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 +21297,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 +21323,38 @@ 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; + if (fbc->common.fn_flags & ZEND_ACC_STATIC) { + 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); + 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", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + 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); } } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + object = Z_OBJ(EG(This)); + if (object) { + GC_REFCOUNT(object)++; + } + } + + if (IS_VAR != IS_CONST) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->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, 0, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -23129,8 +23085,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,29 +23103,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj TSRMLS_CC); 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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_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)); + 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(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); + 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); } } } else { @@ -23178,15 +23136,14 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_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; + 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op1.var); @@ -23199,7 +23156,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(); @@ -23217,24 +23175,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 +23201,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 +23227,38 @@ 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; + if (fbc->common.fn_flags & ZEND_ACC_STATIC) { + 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); + 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", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + 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); } } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + object = Z_OBJ(EG(This)); + if (object) { + GC_REFCOUNT(object)++; } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + if (IS_VAR != IS_CONST) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); + } + } + + EX(call) = zend_vm_stack_push_call_frame( + fbc, 0, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -24706,8 +24662,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,29 +24680,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj TSRMLS_CC); 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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_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)); + 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(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); + 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); } } } else { @@ -24755,15 +24713,14 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -26079,8 +26036,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,29 +26054,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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)); + 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(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); + 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); } } } else { @@ -26128,15 +26087,14 @@ 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; + 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -27356,8 +27314,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,29 +27332,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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)); + 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(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); + 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); } } } else { @@ -27405,15 +27365,14 @@ 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; + 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -29143,8 +29102,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,29 +29120,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj TSRMLS_CC); 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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_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)); + 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(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); + 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); } } } else { @@ -29192,15 +29153,14 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -30216,7 +30176,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); } } @@ -30237,7 +30197,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL } 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); @@ -30289,8 +30249,8 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS zval *varptr, *top; - 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); } } @@ -30576,13 +30536,15 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL HANDLE_EXCEPTION(); } else if (EXPECTED(new_op_array != NULL)) { zval *return_value = NULL; + zend_call_frame *call; EG(active_op_array) = new_op_array; if (RETURN_VALUE_USED(opline)) { 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, NULL, NULL, EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); @@ -30595,10 +30557,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL zend_execute(new_op_array, return_value TSRMLS_CC); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); + call = EX(call); + EX(call) = EX(call)->prev; + zend_vm_stack_free((zval*)call TSRMLS_CC); destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -32312,8 +32275,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,29 +32293,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj TSRMLS_CC); 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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_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)); + 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(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); + 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); } } } else { @@ -32361,15 +32326,14 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -34354,8 +34318,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,29 +34336,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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)); + 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(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); + 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); } } } else { @@ -34403,15 +34369,14 @@ 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; + 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -36432,8 +36397,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,29 +36415,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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)); + 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(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); + 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); } } } else { @@ -36481,15 +36448,14 @@ 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; + 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -39551,8 +39517,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,29 +39535,29 @@ 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; + obj = 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 (EXPECTED(obj != NULL)) { + called_scope = zend_get_class_entry(obj TSRMLS_CC); 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; + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - if (UNEXPECTED(object->handlers->get_method == NULL)) { + if (UNEXPECTED(obj->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_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)); + 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(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); + 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); } } } else { @@ -39600,15 +39568,14 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H 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, 0, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -41678,56 +41645,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 +44405,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_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/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..22ccb8f2bb 100644 --- a/sapi/fpm/fpm/fpm_php_trace.c +++ b/sapi/fpm/fpm/fpm_php_trace.c @@ -74,9 +74,10 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC fprintf(slowlog, "[0x%" PTR_FMT "lx] ", execute_data); - if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, function_state.function), &l)) { - return -1; - } + // TODO: fpm_php_trace_dump() has be reimplemented ??? +//??? if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, function_state.function), &l)) { +//??? return -1; +//??? } function = l;