diff options
author | Xinchen Hui <laruence@php.net> | 2014-07-01 10:29:11 +0800 |
---|---|---|
committer | Xinchen Hui <laruence@php.net> | 2014-07-01 10:29:11 +0800 |
commit | 42bfa2382ce4461c34c1b1c169ae0ac7c68a5170 (patch) | |
tree | c4d0c5d809f1df36e77cdc653a192bcd0df018ed | |
parent | d660d7f5997347942452ab639345fee7711254a2 (diff) | |
parent | fd62771fe5f209790c292c8917e8ee0b6053c283 (diff) | |
download | php-git-42bfa2382ce4461c34c1b1c169ae0ac7c68a5170.tar.gz |
Merge branch 'phpng' of https://git.php.net/repository/php-src into phpng
59 files changed, 3564 insertions, 3322 deletions
diff --git a/Zend/tests/67468.phpt b/Zend/tests/67468.phpt new file mode 100644 index 0000000000..767217644a --- /dev/null +++ b/Zend/tests/67468.phpt @@ -0,0 +1,11 @@ +--TEST-- +Bug #67468 (Segfault in highlight_file()/highlight_string()) +--SKIPIF-- +<?php if(!function_exists("leak")) print "skip only for debug builds"; ?> +--FILE-- +<?php +highlight_string("<?php __CLASS__;", true); +echo "done"; +?> +--EXPECT-- +done diff --git a/Zend/tests/bug67368.phpt b/Zend/tests/bug67368.phpt new file mode 100644 index 0000000000..c92e994b94 --- /dev/null +++ b/Zend/tests/bug67368.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #67368 (Memory leak with immediately dereferenced array in class constant) +--INI-- +report_memleaks=1 +--FILE-- +<?php +class FooBar { + const bar = ["bar" => 3]["bar"]; +} +echo "okey"; +--EXPECTF-- +okey diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 1568374f4e..6b469c2b0a 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -44,14 +44,13 @@ static zend_class_entry **class_cleanup_handlers; /* this function doesn't check for too many parameters */ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ { - zval *p; int arg_count; va_list ptr; zval **param, *param_ptr; TSRMLS_FETCH(); - p = zend_vm_stack_top(TSRMLS_C) - 1; - arg_count = Z_LVAL_P(p); + param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); + arg_count = EG(current_execute_data)->call->num_args; if (param_count>arg_count) { return FAILURE; @@ -61,7 +60,6 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ while (param_count-->0) { param = va_arg(ptr, zval **); - param_ptr = (p-arg_count); if (!Z_ISREF_P(param_ptr) && Z_REFCOUNT_P(param_ptr) > 1) { zval new_tmp; @@ -70,7 +68,7 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ ZVAL_COPY_VALUE(param_ptr, &new_tmp); } *param = param_ptr; - arg_count--; + param_ptr++; } va_end(ptr); @@ -82,14 +80,13 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ /* this function doesn't check for too many parameters */ ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */ { - zval *p; int arg_count; va_list ptr; - zval **param; + zval **param, *param_ptr; TSRMLS_FETCH(); - p = zend_vm_stack_top(TSRMLS_C) - 1; - arg_count = Z_LVAL_P(p); + param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); + arg_count = EG(current_execute_data)->call->num_args; if (param_count>arg_count) { return FAILURE; @@ -98,7 +95,8 @@ ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */ va_start(ptr, param_count); while (param_count-->0) { param = va_arg(ptr, zval **); - *param = p-(arg_count--); + *param = param_ptr; + param_ptr++; } va_end(ptr); @@ -108,22 +106,20 @@ ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */ ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array TSRMLS_DC) /* {{{ */ { - zval *p; + zval *param_ptr; int arg_count; - p = zend_vm_stack_top(TSRMLS_C) - 1; - arg_count = Z_LVAL_P(p); + param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); + arg_count = EG(current_execute_data)->call->num_args; if (param_count>arg_count) { return FAILURE; } while (param_count-->0) { - zval *value = (p-arg_count); - - ZVAL_COPY_VALUE(argument_array, value); + ZVAL_COPY_VALUE(argument_array, param_ptr); argument_array++; - arg_count--; + param_ptr++; } return SUCCESS; @@ -132,22 +128,22 @@ ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array TSRMLS_DC) /* {{{ */ { - zval *p; + zval *param_ptr; int arg_count; - p = zend_vm_stack_top(TSRMLS_C) - 1; - arg_count = Z_LVAL_P(p); + param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); + arg_count = EG(current_execute_data)->call->num_args; if (param_count>arg_count) { return FAILURE; } while (param_count-->0) { - zval *param = p-(arg_count--); - if (Z_REFCOUNTED_P(param)) { - Z_ADDREF_P(param); + if (Z_REFCOUNTED_P(param_ptr)) { + Z_ADDREF_P(param_ptr); } - add_next_index_zval(argument_array, param); + zend_hash_next_index_insert_new(Z_ARRVAL_P(argument_array), param_ptr); + param_ptr++; } return SUCCESS; @@ -807,7 +803,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, case '+': if (have_varargs) { if (!quiet) { - zend_function *active_function = EG(current_execute_data)->function_state.function; + zend_function *active_function = EG(current_execute_data)->call->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; zend_error(E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted", class_name, @@ -827,7 +823,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, default: if (!quiet) { - zend_function *active_function = EG(current_execute_data)->function_state.function; + zend_function *active_function = EG(current_execute_data)->call->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; zend_error(E_WARNING, "%s%s%s(): bad type specifier while parsing parameters", class_name, @@ -850,7 +846,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, if (num_args < min_num_args || (num_args > max_num_args && max_num_args > 0)) { if (!quiet) { - zend_function *active_function = EG(current_execute_data)->function_state.function; + zend_function *active_function = EG(current_execute_data)->call->func; const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : ""; zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given", class_name, @@ -864,7 +860,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, return FAILURE; } - arg_count = Z_LVAL_P(zend_vm_stack_top(TSRMLS_C) - 1); + arg_count = EG(current_execute_data)->call->num_args; if (num_args > arg_count) { zend_error(E_WARNING, "%s(): could not obtain parameters for parsing", @@ -888,7 +884,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, if (num_varargs > 0) { *n_varargs = num_varargs; - *varargs = (zend_vm_stack_top(TSRMLS_C) - 1 - (arg_count - i)); + *varargs = ZEND_CALL_ARG(EG(current_execute_data)->call, i + 1); /* adjust how many args we have left and restart loop */ num_args += 1 - num_varargs; i += num_varargs; @@ -899,7 +895,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, } } - arg = zend_vm_stack_top(TSRMLS_C) - 1 - (arg_count-i); + arg = ZEND_CALL_ARG(EG(current_execute_data)->call, i + 1); if (zend_parse_arg(i+1, arg, va, &type_spec, quiet TSRMLS_CC) == FAILURE) { /* clean up varargs array if it was used */ @@ -970,7 +966,7 @@ ZEND_API int zend_parse_method_parameters(int num_args TSRMLS_DC, zval *this_ptr * Z_OBJ(EG(This)) to NULL when calling an internal function with common.scope == NULL. * In that case EG(This) would still be the $this from the calling code and we'd take the * wrong branch here. */ - zend_bool is_method = EG(current_execute_data)->function_state.function->common.scope != NULL; + zend_bool is_method = EG(current_execute_data)->call->func->common.scope != NULL; if (!is_method || !this_ptr || Z_TYPE_P(this_ptr) != IS_OBJECT) { RETURN_IF_ZERO_ARGS(num_args, p, 0); diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 7a9547b475..e173afd2f9 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -350,6 +350,20 @@ ZEND_API void zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *s } } break; +//??? +#if 0 + case ZEND_FETCH_DIM_R: + zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC); + zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC); + { + zval *tmp; + zend_fetch_dimension_by_zval(&tmp, &op1, &op2 TSRMLS_CC); + ZVAL_ZVAL(result, tmp, 1, 1); + } + zval_dtor(&op1); + zval_dtor(&op2); + break; +#endif default: zend_error(E_ERROR, "Unsupported constant expression"); } diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index cb2205b82c..df81c5d666 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -394,10 +394,10 @@ ZEND_FUNCTION(gc_disable) Get the number of arguments that were passed to the function */ ZEND_FUNCTION(func_num_args) { - zend_execute_data *ex = EG(current_execute_data)->prev_execute_data; + zend_execute_data *ex = EG(current_execute_data); - if (ex && ex->function_state.arguments) { - RETURN_LONG(Z_LVAL_P(ex->function_state.arguments)); + if (ex->frame_kind == VM_FRAME_NESTED_FUNCTION || ex->frame_kind == VM_FRAME_TOP_FUNCTION) { + RETURN_LONG(ex->num_args); } else { zend_error(E_WARNING, "func_num_args(): Called from the global scope - no function context"); RETURN_LONG(-1); @@ -409,11 +409,10 @@ ZEND_FUNCTION(func_num_args) Get the $arg_num'th argument that was passed to the function */ ZEND_FUNCTION(func_get_arg) { - zval *p; - int arg_count; + int arg_count, first_extra_arg; zval *arg; long requested_offset; - zend_execute_data *ex = EG(current_execute_data)->prev_execute_data; + zend_execute_data *ex; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &requested_offset) == FAILURE) { return; @@ -424,20 +423,28 @@ ZEND_FUNCTION(func_get_arg) RETURN_FALSE; } - if (!ex || !ex->function_state.arguments) { + ex = EG(current_execute_data); + if (ex->frame_kind != VM_FRAME_NESTED_FUNCTION && ex->frame_kind != VM_FRAME_TOP_FUNCTION) { zend_error(E_WARNING, "func_get_arg(): Called from the global scope - no function context"); RETURN_FALSE; } - p = ex->function_state.arguments; - arg_count = Z_LVAL_P(p); /* this is the amount of arguments passed to func_get_arg(); */ + arg_count = ex->num_args; if (requested_offset >= arg_count) { zend_error(E_WARNING, "func_get_arg(): Argument %ld not passed to function", requested_offset); RETURN_FALSE; } - arg = p-(arg_count-requested_offset); + first_extra_arg = ex->func->op_array.num_args; + if (ex->func->op_array.fn_flags & ZEND_ACC_VARIADIC) { + first_extra_arg--; + } + if (requested_offset >= first_extra_arg && (ex->num_args > first_extra_arg)) { + arg = EX_VAR_NUM_2(ex, ex->func->op_array.last_var + ex->func->op_array.T) + (requested_offset - first_extra_arg); + } else { + arg = ZEND_CALL_ARG(ex, requested_offset + 1); + } RETURN_ZVAL_FAST(arg); } /* }}} */ @@ -447,26 +454,45 @@ ZEND_FUNCTION(func_get_arg) ZEND_FUNCTION(func_get_args) { zval *p; - int arg_count; + int arg_count, first_extra_arg; int i; - zend_execute_data *ex = EG(current_execute_data)->prev_execute_data; + zend_execute_data *ex = EG(current_execute_data); - if (!ex || !ex->function_state.arguments) { + if (ex->frame_kind != VM_FRAME_NESTED_FUNCTION && ex->frame_kind != VM_FRAME_TOP_FUNCTION) { zend_error(E_WARNING, "func_get_args(): Called from the global scope - no function context"); RETURN_FALSE; } - p = ex->function_state.arguments; - arg_count = Z_LVAL_P(p); /* this is the amount of arguments passed to func_get_args(); */ + arg_count = ex->num_args; array_init_size(return_value, arg_count); if (arg_count) { Bucket *q; - p -= arg_count; + first_extra_arg = ex->func->op_array.num_args; + if (ex->func->op_array.fn_flags & ZEND_ACC_VARIADIC) { + first_extra_arg--; + } zend_hash_real_init(Z_ARRVAL_P(return_value), 1); + i = 0; q = Z_ARRVAL_P(return_value)->arData; - for (i=0; i<arg_count; i++) { + p = ZEND_CALL_ARG(ex, 1); + if (ex->num_args > first_extra_arg) { + while (i < first_extra_arg) { + q->h = i; + q->key = NULL; + if (!Z_ISREF_P(p)) { + ZVAL_COPY(&q->val, p); + } else { + ZVAL_DUP(&q->val, Z_REFVAL_P(p)); + } + p++; + q++; + i++; + } + p = EX_VAR_NUM_2(ex, ex->func->op_array.last_var + ex->func->op_array.T); + } + while (i < arg_count) { q->h = i; q->key = NULL; if (!Z_ISREF_P(p)) { @@ -476,6 +502,7 @@ ZEND_FUNCTION(func_get_args) } p++; q++; + i++; } Z_ARRVAL_P(return_value)->nNumUsed = i; Z_ARRVAL_P(return_value)->nNumOfElements = i; @@ -1957,22 +1984,37 @@ ZEND_FUNCTION(get_defined_constants) /* }}} */ -static void debug_backtrace_get_args(zval *curpos, zval *arg_array TSRMLS_DC) +static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array TSRMLS_DC) { - zval *p = curpos; - zval *arg; - int arg_count = Z_LVAL_P(p); + int num_args = call->num_args; - array_init_size(arg_array, arg_count); - p -= arg_count; + array_init_size(arg_array, num_args); + if (num_args) { + int i = 0; + zval *p = ZEND_CALL_ARG(call, 1); - while (--arg_count >= 0) { - arg = p++; - if (arg) { - if (Z_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); - add_next_index_zval(arg_array, arg); - } else { - add_next_index_null(arg_array); + if (call->func->type == ZEND_USER_FUNCTION) { + int first_extra_arg = call->func->op_array.num_args; + + if (call->func->op_array.fn_flags & ZEND_ACC_VARIADIC) { + first_extra_arg--; + } + if (call->num_args > first_extra_arg) { + while (i < first_extra_arg) { + if (Z_REFCOUNTED_P(p)) Z_ADDREF_P(p); + zend_hash_next_index_insert_new(Z_ARRVAL_P(arg_array), p); + p++; + i++; + } + p = EX_VAR_NUM_2(call, call->func->op_array.last_var + call->func->op_array.T); + } + } + + while (i < num_args) { + if (Z_REFCOUNTED_P(p)) Z_ADDREF_P(p); + zend_hash_next_index_insert_new(Z_ARRVAL_P(arg_array), p); + p++; + i++; } } } @@ -1996,6 +2038,7 @@ ZEND_FUNCTION(debug_print_backtrace) zend_execute_data *ptr, *skip; zend_object *object; int lineno, frameno = 0; + zend_function *func; const char *function_name; const char *filename; zend_string *class_name = NULL; @@ -2025,17 +2068,16 @@ ZEND_FUNCTION(debug_print_backtrace) skip = ptr; /* skip internal handler */ - if (!skip->op_array && + if ((!skip->func || !ZEND_USER_CODE(skip->func->common.type)) && skip->prev_execute_data && skip->prev_execute_data->opline && skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL && - skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME && skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) { skip = skip->prev_execute_data; } - if (skip->op_array) { - filename = skip->op_array->filename->val; + if (skip->func && ZEND_USER_CODE(skip->func->common.type)) { + filename = skip->func->op_array.filename->val; lineno = skip->opline->lineno; } else { filename = NULL; @@ -2044,41 +2086,47 @@ ZEND_FUNCTION(debug_print_backtrace) /* $this may be passed into regular internal functions */ if (object && - ptr->function_state.function->type == ZEND_INTERNAL_FUNCTION && - !ptr->function_state.function->common.scope) { + ptr->call && + ptr->call->func->type == ZEND_INTERNAL_FUNCTION && + !ptr->call->func->common.scope) { object = NULL; } - function_name = (ptr->function_state.function->common.scope && - ptr->function_state.function->common.scope->trait_aliases) ? + if (ptr->call && ptr->call->func && (ptr->call->flags & ZEND_CALL_DONE)) { + func = ptr->call->func; + function_name = (func->common.scope && + func->common.scope->trait_aliases) ? zend_resolve_method_name( - object ? + (object ? zend_get_class_entry(object TSRMLS_CC) : - ptr->function_state.function->common.scope, - ptr->function_state.function)->val : - (ptr->function_state.function->common.function_name ? - ptr->function_state.function->common.function_name->val : - NULL); + func->common.scope), func)->val : + (func->common.function_name ? + func->common.function_name->val : NULL); + } else { + func = ptr->func; + function_name = func && func->common.function_name ? + func->common.function_name->val : NULL; + } if (function_name) { if (object) { - if (ptr->function_state.function->common.scope) { - class_name = ptr->function_state.function->common.scope->name; + if (func->common.scope) { + class_name = func->common.scope->name; } else { class_name = zend_get_object_classname(object TSRMLS_CC); } call_type = "->"; - } else if (ptr->function_state.function->common.scope) { - class_name = ptr->function_state.function->common.scope->name; + } else if (func->common.scope) { + class_name = func->common.scope->name; call_type = "::"; } else { class_name = NULL; call_type = NULL; } - if ((! ptr->opline) || ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL))) { - if (ptr->function_state.arguments && (options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0) { - debug_backtrace_get_args(ptr->function_state.arguments, &arg_array TSRMLS_CC); + if (func->type != ZEND_EVAL_CODE) { + if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0) { + debug_backtrace_get_args(ptr->call, &arg_array TSRMLS_CC); } } } else { @@ -2137,13 +2185,14 @@ ZEND_FUNCTION(debug_print_backtrace) zend_execute_data *prev = skip->prev_execute_data; while (prev) { - if (prev->function_state.function && - prev->function_state.function->common.type != ZEND_USER_FUNCTION) { + if (prev->call && + prev->call->func && + !ZEND_USER_CODE(prev->call->func->common.type)) { prev = NULL; break; } - if (prev->op_array) { - zend_printf(") called at [%s:%d]\n", prev->op_array->filename->val, prev->opline->lineno); + if (prev->func && ZEND_USER_CODE(prev->func->common.type)) { + zend_printf(") called at [%s:%d]\n", prev->func->op_array.filename->val, prev->opline->lineno); break; } prev = prev->prev_execute_data; @@ -2166,6 +2215,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int zend_execute_data *ptr, *skip; zend_object *object = Z_OBJ(EG(This)); int lineno, frameno = 0; + zend_function *func; const char *function_name; const char *filename; zend_string *class_name; @@ -2194,17 +2244,16 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int skip = ptr; /* skip internal handler */ - if (!skip->op_array && + if ((!skip->func || !ZEND_USER_CODE(skip->func->common.type)) && skip->prev_execute_data && skip->prev_execute_data->opline && skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL && - skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME && skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) { skip = skip->prev_execute_data; } - if (skip->op_array) { - filename = skip->op_array->filename->val; + if (skip->func && ZEND_USER_CODE(skip->func->common.type)) { + filename = skip->func->op_array.filename->val; lineno = skip->opline->lineno; add_assoc_string_ex(&stack_frame, "file", sizeof("file")-1, (char*)filename); add_assoc_long_ex(&stack_frame, "line", sizeof("line")-1, lineno); @@ -2216,15 +2265,16 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int zend_execute_data *prev = skip->prev_execute_data; while (prev) { - if (prev->function_state.function && - prev->function_state.function->common.type != ZEND_USER_FUNCTION && - !(prev->function_state.function->common.type == ZEND_INTERNAL_FUNCTION && - (prev->function_state.function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER))) { + if (prev->call && + prev->call->func && + !ZEND_USER_CODE(prev->call->func->common.type) && + !(prev->call->func->common.type == ZEND_INTERNAL_FUNCTION && + (prev->call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER))) { break; } - if (prev->op_array) { + if (prev->func && ZEND_USER_CODE(prev->func->common.type)) { // TODO: we have to duplicate it, becaise it may be stored in opcache SHM ??? - add_assoc_str_ex(&stack_frame, "file", sizeof("file")-1, STR_DUP(prev->op_array->filename, 0)); + add_assoc_str_ex(&stack_frame, "file", sizeof("file")-1, STR_DUP(prev->func->op_array.filename, 0)); add_assoc_long_ex(&stack_frame, "line", sizeof("line")-1, prev->opline->lineno); break; } @@ -2235,28 +2285,34 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int /* $this may be passed into regular internal functions */ if (object && - ptr->function_state.function->type == ZEND_INTERNAL_FUNCTION && - !ptr->function_state.function->common.scope) { + ptr->call && + ptr->call->func->type == ZEND_INTERNAL_FUNCTION && + !ptr->call->func->common.scope) { object = NULL; } - function_name = (ptr->function_state.function->common.scope && - ptr->function_state.function->common.scope->trait_aliases) ? + if (ptr->call && ptr->call->func && (ptr->call->flags & ZEND_CALL_DONE)) { + func = ptr->call->func; + function_name = (func->common.scope && + func->common.scope->trait_aliases) ? zend_resolve_method_name( - object ? + (object ? zend_get_class_entry(object TSRMLS_CC) : - ptr->function_state.function->common.scope, - ptr->function_state.function)->val : - (ptr->function_state.function->common.function_name ? - ptr->function_state.function->common.function_name->val : - NULL); + func->common.scope), func)->val : + (func->common.function_name ? + func->common.function_name->val : NULL); + } else { + func = ptr->func; + function_name = func && func->common.function_name ? + func->common.function_name->val : NULL; + } if (function_name) { add_assoc_string_ex(&stack_frame, "function", sizeof("function")-1, (char*)function_name); if (object) { - if (ptr->function_state.function->common.scope) { - add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(ptr->function_state.function->common.scope->name)); + if (func->common.scope) { + add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(func->common.scope->name)); } else { class_name = zend_get_object_classname(object TSRMLS_CC); add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(class_name)); @@ -2270,16 +2326,16 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int } add_assoc_string_ex(&stack_frame, "type", sizeof("type")-1, "->"); - } else if (ptr->function_state.function->common.scope) { - add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(ptr->function_state.function->common.scope->name)); + } else if (func->common.scope) { + add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(func->common.scope->name)); add_assoc_string_ex(&stack_frame, "type", sizeof("type")-1, "::"); } if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0 && - ((! ptr->opline) || ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL)))) { - if (ptr->function_state.arguments) { + func->type != ZEND_EVAL_CODE) { + if (ptr->call) { zval args; - debug_backtrace_get_args(ptr->function_state.arguments, &args TSRMLS_CC); + debug_backtrace_get_args(ptr->call, &args TSRMLS_CC); add_assoc_zval_ex(&stack_frame, "args", sizeof("args")-1, &args); } } @@ -2333,7 +2389,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int add_assoc_string_ex(&stack_frame, "function", sizeof("function")-1, (char*)function_name); } - add_next_index_zval(return_value, &stack_frame); + zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &stack_frame); include_filename = filename; diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 3c2921f53c..053a5eb199 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -47,7 +47,7 @@ static zend_object_handlers closure_handlers; ZEND_METHOD(Closure, __invoke) /* {{{ */ { - zend_function *func = EG(current_execute_data)->function_state.function; + zend_function *func = EG(current_execute_data)->call->func; zval *arguments; arguments = emalloc(sizeof(zval) * ZEND_NUM_ARGS()); @@ -213,7 +213,7 @@ static void zend_closure_free_storage(zend_object *object TSRMLS_DC) /* {{{ */ if (closure->func.type == ZEND_USER_FUNCTION) { zend_execute_data *ex = EG(current_execute_data); while (ex) { - if (ex->op_array == &closure->func.op_array) { + if (ex->func == &closure->func) { zend_error(E_ERROR, "Cannot destroy active lambda function"); } ex = ex->prev_execute_data; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c6116693b7..647fab48be 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -97,9 +97,9 @@ ZEND_API zend_compiler_globals compiler_globals; ZEND_API zend_executor_globals executor_globals; #endif -static void zend_push_function_call_entry(zend_function *fbc TSRMLS_DC) /* {{{ */ +static void zend_push_function_call_entry(zend_function *fbc, zend_uint opline_num TSRMLS_DC) /* {{{ */ { - zend_function_call_entry fcall = { fbc }; + zend_function_call_entry fcall = { fbc, opline_num }; zend_stack_push(&CG(function_call_stack), &fcall); } /* }}} */ @@ -182,8 +182,6 @@ void zend_init_compiler_context(TSRMLS_D) /* {{{ */ CG(context).literals_size = 0; CG(context).current_brk_cont = -1; CG(context).backpatch_count = 0; - CG(context).nested_calls = 0; - CG(context).used_stack = 0; CG(context).in_finally = 0; CG(context).labels = NULL; } @@ -1463,6 +1461,11 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */ && opline->result.var == op1->u.op.var) { if (opline->opcode == ZEND_NEW) { opline->result_type |= EXT_TYPE_UNUSED; + opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1]; + while (opline->opcode != ZEND_DO_FCALL || opline->op1.num != ZEND_CALL_CTOR) { + opline--; + } + opline->op1.num |= ZEND_CALL_CTOR_RESULT_UNUSED; } break; } @@ -1841,7 +1844,9 @@ void zend_do_receive_param(zend_uchar op, znode *varname, znode *initialization, var.u.op.var = lookup_cv(CG(active_op_array), Z_STR(varname->u.constant) TSRMLS_CC); Z_STR(varname->u.constant) = CG(active_op_array)->vars[EX_VAR_TO_NUM(var.u.op.var)]; var.EA = 0; - if (Z_STRHASH(varname->u.constant) == THIS_HASHVAL && + if (EX_VAR_TO_NUM(var.u.op.var) != CG(active_op_array)->num_args) { + zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter %s", Z_STRVAL(varname->u.constant)); + } else if (Z_STRHASH(varname->u.constant) == THIS_HASHVAL && Z_STRLEN(varname->u.constant) == sizeof("this")-1 && !memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")-1)) { if (CG(active_op_array)->scope && @@ -1949,6 +1954,8 @@ void zend_do_receive_param(zend_uchar op, znode *varname, znode *initialization, int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */ { + zend_op *opline; + zend_uint op_number; zend_function *function; zend_string *lcname; char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant)); @@ -1977,10 +1984,14 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace STR_RELEASE(Z_STR(function_name->u.constant)); Z_STR(function_name->u.constant) = lcname; - zend_push_function_call_entry(function TSRMLS_CC); - if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls + 1; - } + op_number = get_next_op_number(CG(active_op_array)); + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_INIT_FCALL; + SET_UNUSED(opline->op1); + SET_NODE(opline->op2, function_name); + GET_CACHE_SLOT(opline->op2.constant); + + zend_push_function_call_entry(function, op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); return 0; } @@ -2017,12 +2028,10 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ } last_op->opcode = ZEND_INIT_METHOD_CALL; last_op->result_type = IS_UNUSED; - last_op->result.num = CG(context).nested_calls; Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME; } else { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_FCALL_BY_NAME; - opline->result.num = CG(context).nested_calls; SET_UNUSED(opline->op1); if (left_bracket->op_type == IS_CONST) { opline->op2_type = IS_CONST; @@ -2033,10 +2042,7 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ } } - zend_push_function_call_entry(NULL TSRMLS_CC); - if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls; - } + zend_push_function_call_entry(NULL, last_op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); } /* }}} */ @@ -2056,21 +2062,21 @@ void zend_do_clone(znode *result, znode *expr TSRMLS_DC) /* {{{ */ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRMLS_DC) /* {{{ */ { + zend_uint op_number; zend_op *opline; + op_number = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); if (ns_call) { /* In run-time PHP will check for function with full name and internal function with short name */ opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME; - opline->result.num = CG(context).nested_calls; SET_UNUSED(opline->op1); opline->op2_type = IS_CONST; opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC); GET_CACHE_SLOT(opline->op2.constant); } else { opline->opcode = ZEND_INIT_FCALL_BY_NAME; - opline->result.num = CG(context).nested_calls; SET_UNUSED(opline->op1); if (function_name->op_type == IS_CONST) { opline->op2_type = IS_CONST; @@ -2081,10 +2087,7 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML } } - zend_push_function_call_entry(NULL TSRMLS_CC); - if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls; - } + zend_push_function_call_entry(NULL, op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); } /* }}} */ @@ -2481,6 +2484,7 @@ void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_c int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */ { znode class_node; + zend_uint op_number; zend_op *opline; if (method_name->op_type == IS_CONST) { @@ -2501,14 +2505,14 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) { zend_resolve_class_name(class_name TSRMLS_CC); class_node = *class_name; + op_number = get_next_op_number(CG(active_op_array) TSRMLS_CC); opline = get_next_op(CG(active_op_array) TSRMLS_CC); } else { zend_do_fetch_class(&class_node, class_name TSRMLS_CC); + op_number = get_next_op_number(CG(active_op_array) TSRMLS_CC); opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->extended_value = class_node.EA ; } opline->opcode = ZEND_INIT_STATIC_METHOD_CALL; - opline->result.num = CG(context).nested_calls; if (class_node.op_type == IS_CONST) { opline->op1_type = IS_CONST; opline->op1.constant = @@ -2529,10 +2533,7 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na SET_NODE(opline->op2, method_name); } - zend_push_function_call_entry(NULL TSRMLS_CC); - if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls; - } + zend_push_function_call_entry(NULL, op_number TSRMLS_CC); zend_do_extended_fcall_begin(TSRMLS_C); return 1; /* Dynamic */ } @@ -2550,26 +2551,20 @@ void zend_do_end_function_call(znode *function_name, znode *result, int is_metho } opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)]; } else { - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - if (fcall->fbc) { - opline->opcode = ZEND_DO_FCALL; - SET_NODE(opline->op1, function_name); - SET_UNUSED(opline->op2); - opline->op2.num = CG(context).nested_calls; - GET_CACHE_SLOT(opline->op1.constant); - } else { - opline->opcode = ZEND_DO_FCALL_BY_NAME; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); - opline->op2.num = --CG(context).nested_calls; + zend_uint call_flags = 0; - /* This would normally be a ZEND_DO_FCALL, but was forced to use - * ZEND_DO_FCALL_BY_NAME due to a ... argument. In this case we need to - * free the function_name */ - if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) { - zval_dtor(&function_name->u.constant); - } + opline = &CG(active_op_array)->opcodes[fcall->op_number]; + opline->extended_value = fcall->arg_num; + + if (opline->opcode == ZEND_NEW) { + call_flags = ZEND_CALL_CTOR; } + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_DO_FCALL; + SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); + opline->op1.num = call_flags; } opline->result.var = get_temporary_variable(CG(active_op_array)); @@ -2577,10 +2572,6 @@ void zend_do_end_function_call(znode *function_name, znode *result, int is_metho GET_NODE(result, opline->result); opline->extended_value = fcall->arg_num; - if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) { - CG(active_op_array)->used_stack = CG(context).used_stack + 1; - } - CG(context).used_stack -= fcall->arg_num; zend_stack_del_top(&CG(function_call_stack)); } /* }}} */ @@ -2682,19 +2673,13 @@ void zend_do_pass_param(znode *param, zend_uchar op TSRMLS_DC) /* {{{ */ } } else { if (function_ptr) { - opline->extended_value = ZEND_DO_FCALL; - } else { - opline->extended_value = ZEND_DO_FCALL_BY_NAME; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; } } opline->opcode = op; SET_NODE(opline->op1, param); opline->op2.opline_num = fcall->arg_num; SET_UNUSED(opline->op2); - - if (++CG(context).used_stack > CG(active_op_array)->used_stack) { - CG(active_op_array)->used_stack = CG(context).used_stack; - } } /* }}} */ @@ -2705,25 +2690,6 @@ void zend_do_unpack_params(znode *params TSRMLS_DC) /* {{{ */ fcall->uses_argument_unpacking = 1; - if (fcall->fbc) { - /* If argument unpacking is used argument numbers and sending modes can no longer be - * computed at compile time, thus we need access to EX(call). In order to have it we - * retroactively emit a ZEND_INIT_FCALL_BY_NAME opcode. */ - zval func_name; - ZVAL_STR(&func_name, STR_COPY(fcall->fbc->common.function_name)); - - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_INIT_FCALL_BY_NAME; - opline->result.num = CG(context).nested_calls; - SET_UNUSED(opline->op1); - opline->op2_type = IS_CONST; - opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &func_name TSRMLS_CC); - GET_CACHE_SLOT(opline->op2.constant); - - ++CG(context).nested_calls; - fcall->fbc = NULL; - } - opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_SEND_UNPACK; SET_NODE(opline->op1, params); @@ -5619,16 +5585,12 @@ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /* new_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_NEW; - opline->extended_value = CG(context).nested_calls; opline->result_type = IS_VAR; opline->result.var = get_temporary_variable(CG(active_op_array)); SET_NODE(opline->op1, class_type); SET_UNUSED(opline->op2); - zend_push_function_call_entry(NULL TSRMLS_CC); - if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls; - } + zend_push_function_call_entry(NULL, new_token->u.op.opline_num TSRMLS_CC); } /* }}} */ @@ -5819,6 +5781,14 @@ void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC) /* {{{ */ { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->opcode = ZEND_INIT_FCALL; + opline->extended_value = 1; + SET_UNUSED(opline->op1); + opline->op2_type = IS_CONST; + LITERAL_STR(opline->op2, STR_INIT("shell_exec", sizeof("shell_exec")-1, 0)); + GET_CACHE_SLOT(opline->op2.constant); + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); switch (cmd->op_type) { case IS_CONST: case IS_TMP_VAR: @@ -5830,28 +5800,18 @@ void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC) /* {{{ */ } SET_NODE(opline->op1, cmd); opline->op2.opline_num = 1; - opline->extended_value = ZEND_DO_FCALL; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; SET_UNUSED(opline->op2); /* FIXME: exception support not added to this op2 */ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_DO_FCALL; + opline->extended_value = 1; opline->result.var = get_temporary_variable(CG(active_op_array)); opline->result_type = IS_VAR; - LITERAL_STR(opline->op1, STR_INIT("shell_exec", sizeof("shell_exec")-1, 0)); - opline->op1_type = IS_CONST; - GET_CACHE_SLOT(opline->op1.constant); - opline->extended_value = 1; + SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); - opline->op2.num = CG(context).nested_calls; GET_NODE(result, opline->result); - - if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) { - CG(active_op_array)->nested_calls = CG(context).nested_calls + 1; - } - if (CG(context).used_stack + 2 > CG(active_op_array)->used_stack) { - CG(active_op_array)->used_stack = CG(context).used_stack + 2; - } } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 5b5397844f..b053ee9820 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -59,8 +59,6 @@ typedef struct _zend_compiler_context { int literals_size; int current_brk_cont; int backpatch_count; - int nested_calls; - int used_stack; int in_finally; HashTable *labels; } zend_compiler_context; @@ -266,9 +264,6 @@ struct _zend_op_array { zend_uint T; - zend_uint nested_calls; - zend_uint used_stack; - zend_brk_cont_element *brk_cont_array; int last_brk_cont; @@ -336,14 +331,9 @@ union _zend_function { zend_internal_function internal_function; }; - -typedef struct _zend_function_state { - zend_function *function; - zval *arguments; -} zend_function_state; - typedef struct _zend_function_call_entry { zend_function *fbc; + zend_uint op_number; zend_uint arg_num; zend_bool uses_argument_unpacking; } zend_function_call_entry; @@ -361,15 +351,6 @@ typedef struct _list_llist_element { znode value; } list_llist_element; -typedef struct _call_slot { - zend_function *fbc; - zend_class_entry *called_scope; - zend_object *object; - zend_uint num_additional_args; - zend_bool is_ctor_call; - zend_bool is_ctor_result_used; -} call_slot; - typedef enum _vm_frame_kind { VM_FRAME_NESTED_FUNCTION, /* stackless VM call to function */ VM_FRAME_NESTED_CODE, /* stackless VM call to include/require/eval */ @@ -379,28 +360,38 @@ typedef enum _vm_frame_kind { struct _zend_execute_data { struct _zend_op *opline; /* executed opline */ - zend_op_array *op_array; /* executed op_array */ - zend_function_state function_state; /* called function and arguments */ - zend_object *object; /* current $this */ - zend_class_entry *scope; /* function scope (self) */ - zend_class_entry *called_scope; /* function called scope (static) */ - zend_array *symbol_table; + zend_execute_data *call; /* current call */ void **run_time_cache; + zend_function *func; /* executed op_array */ + zend_uint num_args; + zend_uchar flags; + zend_uchar frame_kind; + zend_class_entry *called_scope; + zend_object *object; + zend_execute_data *prev_nested_call; zend_execute_data *prev_execute_data; zval *return_value; - vm_frame_kind frame_kind; - // TODO: simplify call sequence and remove call_* ??? - zval old_error_reporting; - struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */ - zend_object *delayed_exception; - call_slot *call_slots; - call_slot *call; + zend_class_entry *scope; /* function scope (self) */ + zend_array *symbol_table; + struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */ + zend_object *delayed_exception; + zval old_error_reporting; }; +#define ZEND_CALL_CTOR (1 << 0) +#define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 1) +#define ZEND_CALL_DONE (1 << 2) + +#define ZEND_CALL_FRAME_SLOT \ + ((ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))) + +#define ZEND_CALL_ARG(call, n) \ + (((zval*)(call)) + ((n) + (ZEND_CALL_FRAME_SLOT - 1))) + #define EX(element) execute_data.element #define EX_VAR_2(ex, n) ((zval*)(((char*)(ex)) + ((int)(n)))) -#define EX_VAR_NUM_2(ex, n) (((zval*)(((char*)(ex))+ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data))))+(n)) +#define EX_VAR_NUM_2(ex, n) (((zval*)(ex)) + (ZEND_CALL_FRAME_SLOT + ((int)(n)))) #define EX_VAR(n) EX_VAR_2(execute_data, n) #define EX_VAR_NUM(n) EX_VAR_NUM_2(execute_data, n) @@ -730,8 +721,8 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC); #define ZEND_FETCH_CLASS_DEFAULT 0 #define ZEND_FETCH_CLASS_SELF 1 #define ZEND_FETCH_CLASS_PARENT 2 -#define ZEND_FETCH_CLASS_MAIN 3 /* unused */ -#define ZEND_FETCH_CLASS_GLOBAL 4 /* unused */ +#define ZEND_FETCH_CLASS_MAIN 3 /* unused ??? */ +#define ZEND_FETCH_CLASS_GLOBAL 4 /* unused ??? */ #define ZEND_FETCH_CLASS_AUTO 5 #define ZEND_FETCH_CLASS_INTERFACE 6 #define ZEND_FETCH_CLASS_STATIC 7 @@ -750,7 +741,6 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC); #define ZEND_PARSED_NEW (1<<6) #define ZEND_PARSED_LIST_EXPR (1<<7) - /* unset types */ #define ZEND_UNSET_REG 0 @@ -770,6 +760,9 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC); #define ZEND_EVAL_CODE 4 #define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5 +/* A quick check (type == ZEND_USER_FUNCTION || type == ZEND_EVAL_CODE) */ +#define ZEND_USER_CODE(type) ((type & 1) == 0) + #define ZEND_INTERNAL_CLASS 1 #define ZEND_USER_CLASS 2 @@ -877,7 +870,7 @@ END_EXTERN_C() /* call op_array handler of extendions */ #define ZEND_COMPILE_HANDLE_OP_ARRAY (1<<1) -/* generate ZEND_DO_FCALL_BY_NAME for internal functions instead of ZEND_DO_FCALL */ +/* generate ZEND_INIT_FCALL_BY_NAME for internal functions instead of ZEND_INIT_FCALL */ #define ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS (1<<2) /* don't perform early binding for classes inherited form internal ones; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index a6f6d65d72..5318bbe2d3 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -525,12 +525,13 @@ ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ul } } -ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind TSRMLS_DC) +ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC) { zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data; const char *fname = zf->common.function_name->val; const char *fsep; const char *fclass; + zval old_arg; if (zf->common.scope) { fsep = "::"; @@ -540,11 +541,20 @@ ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zen fclass = ""; } - if (ptr && ptr->op_array) { - zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind, ptr->op_array->filename->val, ptr->opline->lineno); + if (arg && zf->common.type == ZEND_USER_FUNCTION) { + ZVAL_COPY_VALUE(&old_arg, arg); + ZVAL_UNDEF(arg); + } + + if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { + zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind, ptr->func->op_array.filename->val, ptr->opline->lineno); } else { zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind); } + + if (arg && zf->common.type == ZEND_USER_FUNCTION) { + ZVAL_COPY_VALUE(arg, &old_arg); + } } static void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type TSRMLS_DC) @@ -572,21 +582,21 @@ static void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg if (Z_TYPE_P(arg) == IS_OBJECT) { need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg TSRMLS_CC); } } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) { need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg TSRMLS_CC); } } else if (cur_arg_info->type_hint) { if (cur_arg_info->type_hint == IS_ARRAY) { ZVAL_DEREF(arg); if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg TSRMLS_CC); } } else if (cur_arg_info->type_hint == IS_CALLABLE) { if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg TSRMLS_CC); } #if ZEND_DEBUG } else { @@ -618,12 +628,12 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, zend_uint arg_ char *class_name; need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "", NULL TSRMLS_CC); } else if (cur_arg_info->type_hint) { if (cur_arg_info->type_hint == IS_ARRAY) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "", NULL TSRMLS_CC); } else if (cur_arg_info->type_hint == IS_CALLABLE) { - zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "" TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "", NULL TSRMLS_CC); #if ZEND_DEBUG } else { zend_error(E_ERROR, "Unknown typehint"); @@ -635,15 +645,15 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, zend_uint arg_ static void zend_verify_missing_arg(zend_execute_data *execute_data, zend_uint arg_num TSRMLS_DC) { - if (EXPECTED(!(EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) || - zend_verify_missing_arg_type((zend_function *) EX(op_array), arg_num, EX(opline)->extended_value TSRMLS_CC)) { - const char *class_name = EX(op_array)->scope ? EX(op_array)->scope->name->val : ""; - const char *space = EX(op_array)->scope ? "::" : ""; - const char *func_name = EX(op_array)->function_name ? EX(op_array)->function_name->val : "main"; + if (EXPECTED(!(EX(func)->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) || + zend_verify_missing_arg_type(EX(func), arg_num, EX(opline)->extended_value TSRMLS_CC)) { + const char *class_name = EX(func)->common.scope ? EX(func)->common.scope->name->val : ""; + const char *space = EX(func)->common.scope ? "::" : ""; + const char *func_name = EX(func)->common.function_name ? EX(func)->common.function_name->val : "main"; zend_execute_data *ptr = EX(prev_execute_data); - if(ptr && ptr->op_array) { - zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", arg_num, class_name, space, func_name, ptr->op_array->filename->val, ptr->opline->lineno); + if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { + zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", arg_num, class_name, space, func_name, ptr->func->op_array.filename->val, ptr->opline->lineno); } else { zend_error(E_WARNING, "Missing argument %u for %s%s%s()", arg_num, class_name, space, func_name); } @@ -1468,13 +1478,13 @@ ZEND_API opcode_handler_t *zend_opcode_handlers; ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, zend_fcall_info *fci TSRMLS_DC) { if (fci != NULL) { - execute_data_ptr->function_state.function->internal_function.handler( + execute_data_ptr->call->func->internal_function.handler( fci->param_count, fci->retval TSRMLS_CC ); } else { zval *return_value = EX_VAR_2(execute_data_ptr, execute_data_ptr->opline->result.var); - execute_data_ptr->function_state.function->internal_function.handler( - execute_data_ptr->opline->extended_value + execute_data_ptr->call->num_additional_args, return_value TSRMLS_CC + execute_data_ptr->call->func->internal_function.handler( + execute_data_ptr->call->num_args, return_value TSRMLS_CC ); } } @@ -1495,9 +1505,9 @@ void zend_clean_and_cache_symbol_table(zend_array *symbol_table TSRMLS_DC) /* {{ static zend_always_inline void i_free_compiled_variables(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */ { - if (EXPECTED(EX(op_array)->last_var > 0)) { + if (EXPECTED(EX(func)->op_array.last_var > 0)) { zval *cv = EX_VAR_NUM(0); - zval *end = cv + EX(op_array)->last_var; + zval *end = cv + EX(func)->op_array.last_var; do { zval_ptr_dtor(cv); cv++; @@ -1517,132 +1527,65 @@ void zend_free_compiled_variables(zend_execute_data *execute_data TSRMLS_DC) /* * ================== * * +========================================+ - * | zend_execute_data |<---+ - * | EX(function_state).arguments |--+ | - * | ... | | | - * | ARGUMENT [1] | | | - * | ... | | | - * | ARGUMENT [ARGS_NUMBER] | | | - * | ARGS_NUMBER |<-+ | - * +========================================+ | - * | - * +========================================+ | - * EG(current_execute_data) -> | zend_execute_data | | - * | EX(prev_execute_data) |----+ + * EG(current_execute_data) -> | zend_execute_data | * +----------------------------------------+ - * EX_CV_NUM(0) ---------> | VAR[0] | + * EX_CV_NUM(0) ---------> | VAR[0] = ARG[1] | + * | ... | + * | VAR[op_array->num_args-1] = ARG[N] | * | ... | * | VAR[op_array->last_var-1] | - * | VAR[op_array->last_var] | + * | VAR[op_array->last_var] = TMP[0] | * | ... | * | VAR[op_array->last_var+op_array->T-1] | - * +----------------------------------------+ - * EX(call_slots) -> | CALL_SLOT[0] | + * | ARG[N+1] (extra_args) | * | ... | - * | CALL_SLOT[op_array->nested_calls-1] | - * +----------------------------------------+ - * zend_vm_stack_frame_base -> | ARGUMENTS STACK [0] | - * | ... | - * zend_vm_stack_top --------> | ... | - * | ... | - * | ARGUMENTS STACK [op_array->used_stack] | * +----------------------------------------+ */ -static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */ +static zend_always_inline void i_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */ { - zend_execute_data *execute_data; - - /* - * When allocating the execute_data, memory for compiled variables and - * temporary variables is also allocated before and after the actual - * zend_execute_data struct. In addition we also allocate space to store - * information about syntactically nested called functions and actual - * parameters. op_array->last_var specifies the number of compiled - * variables and op_array->T is the number of temporary variables. If there - * is no symbol table, then twice as much memory is allocated for compiled - * variables. In that case the first half contains zval**s and the second - * half the actual zval*s (which would otherwise be in the symbol table). - */ - size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)); - size_t vars_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval)) * (op_array->last_var + op_array->T); - size_t call_slots_size = ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * op_array->nested_calls; - size_t stack_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval)) * op_array->used_stack; - size_t total_size = execute_data_size + vars_size + call_slots_size + stack_size; - - /* - * Normally the execute_data is allocated on the VM stack (because it does - * not actually do any allocation and thus is faster). For generators - * though this behavior would be suboptimal, because the (rather large) - * structure would have to be copied back and forth every time execution is - * suspended or resumed. That's why for generators the execution context - * is allocated using a separate VM stack, thus allowing to save and - * restore it simply by replacing a pointer. The same segment also keeps - * a copy of previous execute_data and passed parameters. - */ - if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_GENERATOR) != 0)) { - /* Prepend the regular stack frame with a copy of prev_execute_data - * and the passed arguments - */ - int args_count = zend_vm_stack_get_args_count_ex(EG(current_execute_data)); - size_t args_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval)) * (args_count + 1); - - total_size += args_size + execute_data_size; - - EG(argument_stack) = zend_vm_stack_new_page((total_size + (sizeof(zval) - 1)) / sizeof(zval)); - EG(argument_stack)->prev = NULL; - execute_data = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + execute_data_size + args_size); - - /* copy prev_execute_data */ - EX(prev_execute_data) = (zend_execute_data*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)); - memset(EX(prev_execute_data), 0, sizeof(zend_execute_data)); - EX(prev_execute_data)->function_state.function = (zend_function*)op_array; - EX(prev_execute_data)->function_state.arguments = (zval*)(((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + execute_data_size + args_size - sizeof(zval))); - - /* copy arguments */ - ZVAL_LONG(EX(prev_execute_data)->function_state.arguments, args_count); - if (args_count > 0) { - zval *arg_src = zend_vm_stack_get_arg_ex(EG(current_execute_data), 1); - zval *arg_dst = zend_vm_stack_get_arg_ex(EX(prev_execute_data), 1); - int i; - - for (i = 0; i < args_count; i++) { - ZVAL_COPY(arg_dst + i, arg_src + i); - } - } - } else { - execute_data = zend_vm_stack_alloc(total_size TSRMLS_CC); - EX(prev_execute_data) = EG(current_execute_data); - } + ZEND_ASSERT(EX(func) == (zend_function*)op_array); + ZEND_ASSERT(EX(object) == Z_OBJ(EG(This))); + ZEND_ASSERT(EX(called_scope) == EG(called_scope)); EX(return_value) = return_value; EX(frame_kind) = frame_kind; ZVAL_UNDEF(&EX(old_error_reporting)); EX(delayed_exception) = NULL; - EX(call_slots) = (call_slot*)((char *)execute_data + execute_data_size + vars_size); EX(call) = NULL; EG(opline_ptr) = &EX(opline); EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes; - EX(function_state).function = (zend_function *) op_array; - EX(function_state).arguments = NULL; - EX(op_array) = op_array; - EX(object) = Z_OBJ(EG(This)); EX(scope) = EG(scope); - EX(called_scope) = EG(called_scope); EX(symbol_table) = EG(active_symbol_table); - if (EX(symbol_table)) { + if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_attach_symbol_table(execute_data); } else { + zend_uint first_extra_arg = op_array->num_args; + + if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_VARIADIC) != 0)) { + first_extra_arg--; + } + if (UNEXPECTED(EX(num_args) > first_extra_arg)) { + /* move extra args into separate array after all CV and TMP vars */ + zval *extra_args = EX_VAR_NUM(op_array->last_var + op_array->T); + + memmove(extra_args, EX_VAR_NUM(first_extra_arg), sizeof(zval) * (EX(num_args) - first_extra_arg)); + } + do { - /* Initialize CV variables */ - zval *var = EX_VAR_NUM(0); - zval *end = var + op_array->last_var; + /* Initialize CV variables (skip arguments) */ + int num_args = MIN(op_array->num_args, EX(num_args)); - while (var != end) { - ZVAL_UNDEF(var); - var++; + if (EXPECTED(num_args < op_array->last_var)) { + zval *var = EX_VAR_NUM(num_args); + zval *end = EX_VAR_NUM(op_array->last_var); + + do { + ZVAL_UNDEF(var); + var++; + } while (var != end); } } while (0); @@ -1661,62 +1604,120 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array } EX(run_time_cache) = op_array->run_time_cache; - EG(argument_stack)->top = (zval*)zend_vm_stack_frame_base(execute_data); EG(current_execute_data) = execute_data; +} +/* }}} */ + +ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_op_array *op_array, zval *return_value TSRMLS_DC) /* {{{ */ +{ + /* + * Normally the execute_data is allocated on the VM stack (because it does + * not actually do any allocation and thus is faster). For generators + * though this behavior would be suboptimal, because the (rather large) + * structure would have to be copied back and forth every time execution is + * suspended or resumed. That's why for generators the execution context + * is allocated using a separate VM stack, thus allowing to save and + * restore it simply by replacing a pointer. + */ + zend_execute_data *execute_data; + zend_uint num_args = EG(current_execute_data)->call->num_args; + + EG(argument_stack) = zend_vm_stack_new_page( + MAX(ZEND_VM_STACK_PAGE_SIZE, + ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args))); + EG(argument_stack)->prev = NULL; + + execute_data = zend_vm_stack_push_call_frame( + (zend_function*)op_array, + num_args, + EG(current_execute_data)->call->flags, + EG(current_execute_data)->call->called_scope, + EG(current_execute_data)->call->object, + NULL TSRMLS_CC); + execute_data->num_args = num_args; + + /* copy arguments */ + if (num_args > 0) { + zval *arg_src = ZEND_CALL_ARG(EG(current_execute_data)->call, 1); + zval *arg_dst = ZEND_CALL_ARG(execute_data, 1); + int i; + + for (i = 0; i < num_args; i++) { + ZVAL_COPY_VALUE(arg_dst + i, arg_src + i); + } + } + + i_init_execute_data(execute_data, op_array, return_value, VM_FRAME_TOP_FUNCTION TSRMLS_CC); return execute_data; } /* }}} */ -ZEND_API zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */ +ZEND_API zend_execute_data *zend_create_execute_data(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */ { - return i_create_execute_data_from_op_array(op_array, return_value, frame_kind TSRMLS_CC); + zend_execute_data *execute_data; + + execute_data = EG(current_execute_data)->call; + EX(prev_execute_data) = EG(current_execute_data); + i_init_execute_data(execute_data, op_array, return_value, frame_kind TSRMLS_CC); + + return execute_data; } /* }}} */ -static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(zend_op *opline, call_slot *call TSRMLS_DC) /* {{{ */ +static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(zend_op *opline, zend_execute_data *call TSRMLS_DC) /* {{{ */ { zend_uint arg_num = opline->extended_value & ZEND_FETCH_ARG_MASK; - return ARG_SHOULD_BE_SENT_BY_REF(call->fbc, arg_num); + return ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num); } /* }}} */ -static zval *zend_vm_stack_push_args_with_copy(int count TSRMLS_DC) /* {{{ */ -{ - zend_vm_stack p = EG(argument_stack); - - zend_vm_stack_extend(count + 1 TSRMLS_CC); +static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, zend_uint passed_args, zend_uint additional_args TSRMLS_DC) /* {{{ */ +{ + zend_execute_data *new_call; + int used_stack = (EG(argument_stack)->top - (zval*)call) + additional_args; + + /* copy call frame into new stack segment */ + zend_vm_stack_extend(used_stack TSRMLS_CC); + new_call = (zend_execute_data*)EG(argument_stack)->top; + EG(argument_stack)->top += used_stack; + *new_call = *call; + if (passed_args) { + zval *src = ZEND_CALL_ARG(call, 1); + zval *dst = ZEND_CALL_ARG(new_call, 1); + do { + ZVAL_COPY_VALUE(dst, src); + passed_args--; + src++; + dst++; + } while (passed_args); + } - EG(argument_stack)->top += count; - ZVAL_LONG(EG(argument_stack)->top, count); - while (count-- > 0) { - zval *data = --p->top; - ZVAL_COPY_VALUE(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + count, data); + /* delete old call_frame from previous stack segment */ + EG(argument_stack)->prev->top = (zval*)call; - if (UNEXPECTED(p->top == ZEND_VM_STACK_ELEMETS(p))) { - zend_vm_stack r = p; + /* delete previous stack segment if it becames empty */ + if (UNEXPECTED(EG(argument_stack)->prev->top == ZEND_VM_STACK_ELEMETS(EG(argument_stack)->prev))) { + zend_vm_stack r = EG(argument_stack)->prev; - EG(argument_stack)->prev = p->prev; - p = p->prev; - efree(r); - } + EG(argument_stack)->prev = r->prev; + efree(r); } - return EG(argument_stack)->top++; + + return new_call; } /* }}} */ -static zend_always_inline zval *zend_vm_stack_push_args(int count TSRMLS_DC) /* {{{ */ +static zend_always_inline void zend_vm_stack_extend_call_frame(zend_execute_data **call, zend_uint passed_args, zend_uint additional_args TSRMLS_DC) /* {{{ */ { - if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < count) - || UNEXPECTED(EG(argument_stack)->top == EG(argument_stack)->end)) { - return zend_vm_stack_push_args_with_copy(count TSRMLS_CC); + if (EXPECTED(EG(argument_stack)->end - EG(argument_stack)->top > additional_args)) { + EG(argument_stack)->top += additional_args; + } else { + *call = zend_vm_stack_copy_call_frame(*call, passed_args, additional_args TSRMLS_CC); } - ZVAL_LONG(EG(argument_stack)->top, count); - return EG(argument_stack)->top++; } /* }}} */ - #define ZEND_VM_NEXT_OPCODE() \ CHECK_SYMBOL_TABLES() \ ZEND_VM_INC_OPCODE(); \ diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index b80d2adff8..40f42ae2dd 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -35,7 +35,8 @@ ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data_pt void init_executor(TSRMLS_D); void shutdown_executor(TSRMLS_D); void shutdown_destructors(TSRMLS_D); -ZEND_API zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC); +ZEND_API zend_execute_data *zend_create_execute_data(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC); +ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_op_array *op_array, zval *return_value TSRMLS_DC); ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value TSRMLS_DC); ZEND_API void execute_ex(zend_execute_data *execute_data TSRMLS_DC); ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, struct _zend_fcall_info *fci TSRMLS_DC); @@ -48,7 +49,7 @@ ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, ZEND_API int zend_eval_stringl_ex(char *str, int str_len, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ulong fetch_type, char **class_name, zend_class_entry **pce TSRMLS_DC); -ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind TSRMLS_DC); +ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC); static zend_always_inline void i_zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC TSRMLS_DC) { @@ -149,7 +150,7 @@ ZEND_API int zval_update_constant_no_inline_change(zval *pp, zend_class_entry *s ZEND_API int zval_update_constant_ex(zval *pp, zend_bool inline_change, zend_class_entry *scope TSRMLS_DC); /* dedicated Zend executor functions - do not use! */ -#define ZEND_VM_STACK_PAGE_SIZE ((16 * 1024) - 16) +#define ZEND_VM_STACK_PAGE_SIZE (16 * 1024) /* should be a power of 2 */ struct _zend_vm_stack { zval *top; @@ -157,22 +158,26 @@ struct _zend_vm_stack { zend_vm_stack prev; }; +#define ZEND_VM_STACK_HEADER_SLOT \ + ((ZEND_MM_ALIGNED_SIZE(sizeof(struct _zend_vm_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))) + #define ZEND_VM_STACK_ELEMETS(stack) \ - ((zval*)(((char*)(stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(struct _zend_vm_stack)))) - -#define ZEND_VM_STACK_GROW_IF_NEEDED(count) \ - do { \ - if (UNEXPECTED((count) > \ - EG(argument_stack)->end - EG(argument_stack)->top)) { \ - zend_vm_stack_extend((count) TSRMLS_CC); \ - } \ + (((zval*)(stack)) + ZEND_VM_STACK_HEADER_SLOT) + +#define ZEND_VM_STACK_GROW_IF_NEEDED(count) \ + do { \ + if (UNEXPECTED(((count) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) > \ + ((char*)EG(argument_stack)->end) - \ + ((char*)EG(argument_stack)->top))) { \ + zend_vm_stack_extend((count) TSRMLS_CC); \ + } \ } while (0) static zend_always_inline zend_vm_stack zend_vm_stack_new_page(int count) { - zend_vm_stack page = (zend_vm_stack)emalloc(ZEND_MM_ALIGNED_SIZE(sizeof(*page)) + sizeof(zval) * count); + zend_vm_stack page = (zend_vm_stack)emalloc(count * ZEND_MM_ALIGNED_SIZE(sizeof(zval))); page->top = ZEND_VM_STACK_ELEMETS(page); - page->end = page->top + count; + page->end = (zval*)page + count; page->prev = NULL; return page; } @@ -180,6 +185,7 @@ static zend_always_inline zend_vm_stack zend_vm_stack_new_page(int count) { static zend_always_inline void zend_vm_stack_init(TSRMLS_D) { EG(argument_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE); + EG(argument_stack)->top++; } static zend_always_inline void zend_vm_stack_destroy(TSRMLS_D) @@ -195,95 +201,90 @@ static zend_always_inline void zend_vm_stack_destroy(TSRMLS_D) static zend_always_inline void zend_vm_stack_extend(int count TSRMLS_DC) { - zend_vm_stack p = zend_vm_stack_new_page(count >= ZEND_VM_STACK_PAGE_SIZE ? count : ZEND_VM_STACK_PAGE_SIZE); + int size = count * ZEND_MM_ALIGNED_SIZE(sizeof(zval)); + zend_vm_stack p = zend_vm_stack_new_page( + (size >= (ZEND_VM_STACK_PAGE_SIZE - ZEND_VM_STACK_HEADER_SLOT) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) ? + (size + ((ZEND_VM_STACK_HEADER_SLOT + ZEND_VM_STACK_PAGE_SIZE) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) - 1) & + ~((ZEND_VM_STACK_PAGE_SIZE * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) - 1) : + ZEND_VM_STACK_PAGE_SIZE); p->prev = EG(argument_stack); EG(argument_stack) = p; } -static zend_always_inline zval *zend_vm_stack_top(TSRMLS_D) -{ - return EG(argument_stack)->top; -} - -static zend_always_inline zval *zend_vm_stack_top_inc(TSRMLS_D) +static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_function *func, zend_uint num_args, zend_uchar flags, zend_class_entry *called_scope, zend_object *object, zend_execute_data *prev TSRMLS_DC) { - return EG(argument_stack)->top++; + int used_stack = ZEND_CALL_FRAME_SLOT + num_args; + zend_execute_data *call; + + if (ZEND_USER_CODE(func->type)) { + used_stack += func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args); + } + ZEND_VM_STACK_GROW_IF_NEEDED(used_stack); + call = (zend_execute_data*)EG(argument_stack)->top; + EG(argument_stack)->top += used_stack; + call->func = func; + call->num_args = 0; + call->flags = flags; + call->called_scope = called_scope; + call->object = object; + call->prev_nested_call = prev; + return call; } -static zend_always_inline void zend_vm_stack_push(zval *ptr TSRMLS_DC) +static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call TSRMLS_DC) { - ZVAL_COPY_VALUE(EG(argument_stack)->top, ptr); - EG(argument_stack)->top++; -} + zend_uint first_extra_arg = call->func->op_array.num_args - ((call->func->common.fn_flags & ZEND_ACC_VARIADIC) != 0); -static zend_always_inline zval *zend_vm_stack_pop(TSRMLS_D) -{ - return --EG(argument_stack)->top; + if (UNEXPECTED(call->num_args > first_extra_arg)) { + zval *end = EX_VAR_NUM_2(call, call->func->op_array.last_var + call->func->op_array.T); + zval *p = end + (call->num_args - first_extra_arg); + do { + p--; + i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC); + } while (p != end); + } } -static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC) +static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call TSRMLS_DC) { - zval *ret; - int count = (size + (sizeof(zval) - 1)) / sizeof(zval); + zend_uint num_args = call->num_args; - ZEND_VM_STACK_GROW_IF_NEEDED(count); - ret = EG(argument_stack)->top; - EG(argument_stack)->top += count; - return ret; -} + if (num_args > 0) { + zval *p = ZEND_CALL_ARG(call, num_args + 1); + zval *end = p - num_args;; -static zend_always_inline zval* zend_vm_stack_frame_base(zend_execute_data *ex) -{ - return (zval*)((char*)ex->call_slots + - ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * ex->op_array->nested_calls); + do { + p--; + i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC); + } while (p != end); + } } -static zend_always_inline void zend_vm_stack_free(void *ptr TSRMLS_DC) +static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call TSRMLS_DC) { - if (UNEXPECTED((void*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == ptr)) { + if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (zval*)call)) { zend_vm_stack p = EG(argument_stack); EG(argument_stack) = p->prev; efree(p); } else { - EG(argument_stack)->top = (zval*)ptr; - } -} - -static zend_always_inline void zend_vm_stack_clear_multiple(int nested TSRMLS_DC) -{ - zval *p = EG(argument_stack)->top - 1; - - if (EXPECTED(Z_LVAL_P(p) > 0)) { - zval *end = p - Z_LVAL_P(p); - - do { - p--; - i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC); - } while (p != end); - } - if (nested) { - EG(argument_stack)->top = p; - } else { - zend_vm_stack_free(p TSRMLS_CC); + EG(argument_stack)->top = (zval*)call; } } static zend_always_inline int zend_vm_stack_get_args_count_ex(zend_execute_data *ex) { - zval *p = ex->function_state.arguments; - return Z_LVAL_P(p); + return ex->call->num_args; } static zend_always_inline zval* zend_vm_stack_get_arg_ex(zend_execute_data *ex, int requested_arg) { - zval *p = ex->function_state.arguments; - int arg_count = Z_LVAL_P(p); + int arg_count = ex->call->num_args; if (UNEXPECTED(requested_arg > arg_count)) { return NULL; } - return p - arg_count + requested_arg - 1; + return ZEND_CALL_ARG(ex->call, requested_arg); } static zend_always_inline int zend_vm_stack_get_args_count(TSRMLS_D) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index ebb995a262..2ba582942a 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -156,7 +156,6 @@ void init_executor(TSRMLS_D) /* {{{ */ EG(error_handling) = EH_NORMAL; zend_vm_stack_init(TSRMLS_C); - ZVAL_LONG(zend_vm_stack_top_inc(TSRMLS_C), 0); zend_hash_init(&EG(symbol_table).ht, 64, NULL, ZVAL_PTR_DTOR, 0); GC_REFCOUNT(&EG(symbol_table)) = 1; @@ -393,17 +392,25 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ /* return class name and "::" or "". */ ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{ */ { + zend_function *func; + if (!zend_is_executing(TSRMLS_C)) { if (space) { *space = ""; } return ""; } - switch (EG(current_execute_data)->function_state.function->type) { + + if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) { + func = EG(current_execute_data)->call->func; + } else { + func = EG(current_execute_data)->func; + } + switch (func->type) { case ZEND_USER_FUNCTION: case ZEND_INTERNAL_FUNCTION: { - zend_class_entry *ce = EG(current_execute_data)->function_state.function->common.scope; + zend_class_entry *ce = func->common.scope; if (space) { *space = ce ? "::" : ""; @@ -421,12 +428,19 @@ ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{ ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */ { + zend_function *func; + if (!zend_is_executing(TSRMLS_C)) { return NULL; } - switch (EG(current_execute_data)->function_state.function->type) { + if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) { + func = EG(current_execute_data)->call->func; + } else { + func = EG(current_execute_data)->func; + } + switch (func->type) { case ZEND_USER_FUNCTION: { - zend_string *function_name = ((zend_op_array *) EG(current_execute_data)->function_state.function)->function_name; + zend_string *function_name = func->common.function_name; if (function_name) { return function_name->val; @@ -436,7 +450,7 @@ ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */ } break; case ZEND_INTERNAL_FUNCTION: - return ((zend_internal_function *) EG(current_execute_data)->function_state.function)->function_name->val; + return func->common.function_name->val; break; default: return NULL; @@ -655,6 +669,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zend_class_entry *called_scope = NULL; zend_execute_data execute_data; zend_fcall_info_cache fci_cache_local; + zend_function *func; zval tmp; ZVAL_UNDEF(fci->retval); @@ -681,7 +696,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS EX(object) = Z_OBJ(EG(This)); EX(scope) = EG(scope); EX(called_scope) = EG(called_scope); - EX(op_array) = NULL; + EX(func) = NULL; EX(opline) = NULL; } else { /* This only happens when we're called outside any execute()'s @@ -719,7 +734,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS STR_RELEASE(callable_name); } - EX(function_state).function = fci_cache->function_handler; + func = fci_cache->function_handler; + EX(call) = zend_vm_stack_push_call_frame(func, fci->param_count, ZEND_CALL_DONE, fci_cache->called_scope, fci_cache->object, NULL TSRMLS_CC); calling_scope = fci_cache->calling_scope; called_scope = fci_cache->called_scope; fci->object = fci_cache->object; @@ -729,24 +745,22 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS return FAILURE; } - if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) { - if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(function_state).function->common.scope->name->val, EX(function_state).function->common.function_name->val); + if (func->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) { + if (func->common.fn_flags & ZEND_ACC_ABSTRACT) { + zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", func->common.scope->name->val, func->common.function_name->val); } - if (EX(function_state).function->common.fn_flags & ZEND_ACC_DEPRECATED) { + if (func->common.fn_flags & ZEND_ACC_DEPRECATED) { zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name->val : "", - EX(function_state).function->common.scope ? "::" : "", - EX(function_state).function->common.function_name->val); + func->common.scope ? func->common.scope->name->val : "", + func->common.scope ? "::" : "", + func->common.function_name->val); } } - ZEND_VM_STACK_GROW_IF_NEEDED(fci->param_count + 1); - for (i=0; i<fci->param_count; i++) { zval *param; - if (ARG_SHOULD_BE_SENT_BY_REF(EX(function_state).function, i + 1)) { + if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) { // TODO: Scalar values don't have reference counters anymore. // They are assumed to be 1, and they may be easily passed by // reference now. However, previously scalars with refcount==1 @@ -766,19 +780,19 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS (!Z_ISREF(fci->params[i]) && Z_REFCOUNT(fci->params[i]) > 1)) { if (fci->no_separation && - !ARG_MAY_BE_SENT_BY_REF(EX(function_state).function, i + 1)) { - if (i || UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (EG(argument_stack)->top))) { + !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { + if (i) { /* hack to clean up the stack */ - ZVAL_LONG(&tmp, i); - zend_vm_stack_push(&tmp TSRMLS_CC); - zend_vm_stack_clear_multiple(0 TSRMLS_CC); + EX(call)->num_args = i; + zend_vm_stack_free_args(EX(call) TSRMLS_CC); } + zend_vm_stack_free_call_frame(EX(call) TSRMLS_CC); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", i+1, - EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name->val : "", - EX(function_state).function->common.scope ? "::" : "", - EX(function_state).function->common.function_name->val); + func->common.scope ? func->common.scope->name->val : "", + func->common.scope ? "::" : "", + func->common.function_name->val); return FAILURE; } @@ -794,27 +808,26 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } else if (Z_REFCOUNTED(fci->params[i])) { Z_ADDREF(fci->params[i]); } - param = &fci->params[i]; + param = ZEND_CALL_ARG(EX(call), i+1); + ZVAL_COPY_VALUE(param, &fci->params[i]); } else if (Z_ISREF(fci->params[i]) && /* don't separate references for __call */ - (EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) { + (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) { param = &tmp; + param = ZEND_CALL_ARG(EX(call), i+1); ZVAL_DUP(param, Z_REFVAL(fci->params[i])); } else { - param = &tmp; + param = ZEND_CALL_ARG(EX(call), i+1); ZVAL_COPY(param, &fci->params[i]); } - zend_vm_stack_push(param TSRMLS_CC); } - - EX(function_state).arguments = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_LONG(EX(function_state).arguments, fci->param_count); + EX(call)->num_args = fci->param_count; EG(scope) = calling_scope; EG(called_scope) = called_scope; if (!fci->object || - (EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) { - Z_OBJ(EG(This)) = NULL; + (func->common.fn_flags & ZEND_ACC_STATIC)) { + Z_OBJ(EG(This)) = EX(call)->object = NULL; } else { Z_OBJ(EG(This)) = fci->object; Z_ADDREF(EG(This)); @@ -823,9 +836,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS EX(prev_execute_data) = EG(current_execute_data); EG(current_execute_data) = &execute_data; - if (EX(function_state).function->type == ZEND_USER_FUNCTION) { + if (func->type == ZEND_USER_FUNCTION) { calling_symbol_table = EG(active_symbol_table); - EG(scope) = EX(function_state).function->common.scope; + EG(scope) = func->common.scope; if (fci->symbol_table) { EG(active_symbol_table) = fci->symbol_table; } else { @@ -833,7 +846,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } original_op_array = EG(active_op_array); - EG(active_op_array) = (zend_op_array *) EX(function_state).function; + EG(active_op_array) = (zend_op_array *) func; original_opline_ptr = EG(opline_ptr); if (EXPECTED((EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) == 0)) { @@ -848,18 +861,21 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC); } EG(active_symbol_table) = calling_symbol_table; - } else if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { - int call_via_handler = (EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0; + } else if (func->type == ZEND_INTERNAL_FUNCTION) { + int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0; ZVAL_NULL(fci->retval); - if (EX(function_state).function->common.scope) { - EG(scope) = EX(function_state).function->common.scope; + if (func->common.scope) { + EG(scope) = func->common.scope; } if (EXPECTED(zend_execute_internal == NULL)) { /* saves one function call if zend_execute_internal is not used */ - EX(function_state).function->internal_function.handler(fci->param_count, fci->retval TSRMLS_CC); + func->internal_function.handler(fci->param_count, fci->retval TSRMLS_CC); } else { zend_execute_internal(&execute_data, fci TSRMLS_CC); } + zend_vm_stack_free_args(EX(call) TSRMLS_CC); + zend_vm_stack_free_call_frame(EX(call) TSRMLS_CC); + /* We shouldn't fix bad extensions here, because it can break proper ones (Bug #34045) if (!EX(function_state).function->common.return_reference) @@ -880,22 +896,21 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS /* Not sure what should be done here if it's a static method */ if (fci->object) { - fci->object->handlers->call_method(EX(function_state).function->common.function_name, fci->object, fci->param_count, fci->retval TSRMLS_CC); + fci->object->handlers->call_method(func->common.function_name, fci->object, fci->param_count, fci->retval TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } - if (EX(function_state).function->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { - STR_RELEASE(EX(function_state).function->common.function_name); + if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { + STR_RELEASE(func->common.function_name); } - efree(EX(function_state).function); + efree(func); if (EG(exception)) { zval_ptr_dtor(fci->retval); ZVAL_UNDEF(fci->retval); } } - zend_vm_stack_clear_multiple(0 TSRMLS_CC); if (Z_OBJ(EG(This))) { zval_ptr_dtor(&EG(This)); @@ -1080,6 +1095,10 @@ ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *s zend_try { ZVAL_UNDEF(&local_retval); + if (EG(current_execute_data)) { + EG(current_execute_data)->call = zend_vm_stack_push_call_frame( + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EG(current_execute_data)->call TSRMLS_CC); + } zend_execute(new_op_array, &local_retval TSRMLS_CC); } zend_catch { destroy_op_array(new_op_array TSRMLS_CC); @@ -1583,33 +1602,34 @@ ZEND_API void zend_rebuild_symbol_table(TSRMLS_D) /* {{{ */ /* Search for last called user function */ ex = EG(current_execute_data); - while (ex && !ex->op_array) { + while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->common.type))) { ex = ex->prev_execute_data; } - if (ex && ex->symbol_table) { + if (!ex) { + return; + } + if (ex->symbol_table) { EG(active_symbol_table) = ex->symbol_table; return; } - if (ex && ex->op_array) { - if (EG(symtable_cache_ptr)>=EG(symtable_cache)) { - /*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/ - EG(active_symbol_table) = *(EG(symtable_cache_ptr)--); - } else { - EG(active_symbol_table) = emalloc(sizeof(zend_array)); - GC_REFCOUNT(EG(active_symbol_table)) = 0; - GC_TYPE_INFO(EG(active_symbol_table)) = IS_ARRAY; - zend_hash_init(&EG(active_symbol_table)->ht, ex->op_array->last_var, NULL, ZVAL_PTR_DTOR, 0); - /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/ - } - ex->symbol_table = EG(active_symbol_table); - for (i = 0; i < ex->op_array->last_var; i++) { - zval zv; - - ZVAL_INDIRECT(&zv, EX_VAR_NUM_2(ex, i)); - zend_hash_add_new(&EG(active_symbol_table)->ht, - ex->op_array->vars[i], &zv); - } + if (EG(symtable_cache_ptr)>=EG(symtable_cache)) { + /*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/ + EG(active_symbol_table) = *(EG(symtable_cache_ptr)--); + } else { + EG(active_symbol_table) = emalloc(sizeof(zend_array)); + GC_REFCOUNT(EG(active_symbol_table)) = 0; + GC_TYPE_INFO(EG(active_symbol_table)) = IS_ARRAY; + zend_hash_init(&EG(active_symbol_table)->ht, ex->func->op_array.last_var, NULL, ZVAL_PTR_DTOR, 0); + /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/ + } + ex->symbol_table = EG(active_symbol_table); + for (i = 0; i < ex->func->op_array.last_var; i++) { + zval zv; + + ZVAL_INDIRECT(&zv, EX_VAR_NUM_2(ex, i)); + zend_hash_add_new(&EG(active_symbol_table)->ht, + ex->func->op_array.vars[i], &zv); } } } @@ -1618,7 +1638,7 @@ ZEND_API void zend_rebuild_symbol_table(TSRMLS_D) /* {{{ */ ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ */ { int i; - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; HashTable *ht = &execute_data->symbol_table->ht; /* copy real values from symbol table into CV slots and create @@ -1649,7 +1669,7 @@ ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ * ZEND_API void zend_detach_symbol_table(zend_execute_data *execute_data) /* {{{ */ { int i; - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; HashTable *ht = &execute_data->symbol_table->ht; /* copy real values from CV slots into symbol table */ @@ -1669,7 +1689,7 @@ ZEND_API int zend_set_local_var(zend_string *name, zval *value, int force TSRMLS if (!EG(active_symbol_table)) { int i; zend_execute_data *execute_data = EG(current_execute_data); - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; zend_ulong h = STR_HASH_VAL(name); if (op_array) { @@ -1702,7 +1722,7 @@ ZEND_API int zend_set_local_var_str(const char *name, int len, zval *value, int if (!EG(active_symbol_table)) { int i; zend_execute_data *execute_data = EG(current_execute_data); - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; zend_ulong h = zend_hash_func(name, len); if (op_array) { diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index c80e909565..f4847b0839 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -32,7 +32,7 @@ static zend_object *zend_generator_create(zend_class_entry *class_type TSRMLS_DC static void zend_generator_cleanup_unfinished_execution(zend_generator *generator TSRMLS_DC) /* {{{ */ { zend_execute_data *execute_data = generator->execute_data; - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; if (generator->send_target) { if (Z_REFCOUNTED_P(generator->send_target)) Z_DELREF_P(generator->send_target); @@ -75,23 +75,13 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato } } - /* Clear any backed up stack arguments */ - { - zval *ptr = generator->stack->top - 1; - zval *end = zend_vm_stack_frame_base(execute_data); - - for (; ptr >= end; --ptr) { - zval_ptr_dtor((zval*) ptr); - } - } - /* If yield was used as a function argument there may be active * method calls those objects need to be freed */ - while (execute_data->call >= execute_data->call_slots) { + while (execute_data->call) { if (execute_data->call->object) { OBJ_RELEASE(execute_data->call->object); } - execute_data->call--; + execute_data->call = execute_data->call->prev_nested_call; } } /* }}} */ @@ -110,7 +100,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished if (generator->execute_data) { zend_execute_data *execute_data = generator->execute_data; - zend_op_array *op_array = execute_data->op_array; + zend_op_array *op_array = &execute_data->func->op_array; if (!execute_data->symbol_table) { zend_free_compiled_variables(execute_data TSRMLS_CC); @@ -128,23 +118,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished return; } - /* We have added an additional stack frame in prev_execute_data, so we - * have to free it. It also contains the arguments passed to the - * generator (for func_get_args) so those have to be freed too. */ - { - zend_execute_data *prev_execute_data = execute_data->prev_execute_data; - zval *arguments = prev_execute_data->function_state.arguments; - - if (arguments) { - int arguments_count = Z_LVAL_P(arguments); - zval *arguments_start = arguments - arguments_count; - int i; - - for (i = 0; i < arguments_count; ++i) { - zval_ptr_dtor(arguments_start + i); - } - } - } + zend_vm_stack_free_extra_args(generator->execute_data TSRMLS_CC); /* Some cleanups are only necessary if the generator was closued * before it could finish execution (reach a return statement). */ @@ -158,6 +132,10 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished efree(op_array); } + if (generator->execute_data->prev_execute_data) { + generator->execute_data->prev_execute_data->call = generator->execute_data->prev_nested_call; + } + efree(generator->stack); generator->execute_data = NULL; } @@ -171,18 +149,18 @@ static void zend_generator_dtor_storage(zend_object *object TSRMLS_DC) /* {{{ */ zend_uint op_num, finally_op_num; int i; - if (!ex || !ex->op_array->has_finally_block) { + if (!ex || !ex->func->op_array.has_finally_block) { return; } /* -1 required because we want the last run opcode, not the * next to-be-run one. */ - op_num = ex->opline - ex->op_array->opcodes - 1; + op_num = ex->opline - ex->func->op_array.opcodes - 1; /* Find next finally block */ finally_op_num = 0; - for (i = 0; i < ex->op_array->last_try_catch; i++) { - zend_try_catch_element *try_catch = &ex->op_array->try_catch_array[i]; + for (i = 0; i < ex->func->op_array.last_try_catch; i++) { + zend_try_catch_element *try_catch = &ex->func->op_array.try_catch_array[i]; if (op_num < try_catch->try_op) { break; @@ -196,7 +174,7 @@ static void zend_generator_dtor_storage(zend_object *object TSRMLS_DC) /* {{{ */ /* If a finally block was found we jump directly to it and * resume the generator. */ if (finally_op_num) { - ex->opline = &ex->op_array->opcodes[finally_op_num]; + ex->opline = &ex->func->op_array.opcodes[finally_op_num]; ex->fast_ret = NULL; generator->flags |= ZEND_GENERATOR_FORCED_CLOSE; zend_generator_resume(generator TSRMLS_CC); @@ -288,7 +266,7 @@ ZEND_API void zend_generator_create_zval(zend_op_array *op_array, zval *return_v opline_ptr = EG(opline_ptr); current_symbol_table = EG(active_symbol_table); EG(active_symbol_table) = NULL; - execute_data = zend_create_execute_data_from_op_array(op_array, return_value, VM_FRAME_TOP_FUNCTION TSRMLS_CC); + execute_data = zend_create_generator_execute_data(op_array, return_value TSRMLS_CC); EG(active_symbol_table) = current_symbol_table; EG(current_execute_data) = current_execute_data; EG(opline_ptr) = opline_ptr; @@ -300,8 +278,8 @@ ZEND_API void zend_generator_create_zval(zend_op_array *op_array, zval *return_v } /* Save execution context in generator object. */ - execute_data->prev_execute_data->object = Z_OBJ_P(return_value); generator = (zend_generator *) Z_OBJ_P(return_value); + execute_data->prev_execute_data = NULL; generator->execute_data = execute_data; generator->stack = EG(argument_stack); EG(argument_stack) = current_stack; @@ -343,13 +321,14 @@ ZEND_API void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ zend_class_entry *original_scope = EG(scope); zend_class_entry *original_called_scope = EG(called_scope); zend_vm_stack original_stack = EG(argument_stack); + zend_execute_data *prev_execute_data; original_This = Z_OBJ(EG(This)); /* Set executor globals */ EG(current_execute_data) = generator->execute_data; EG(opline_ptr) = &generator->execute_data->opline; - EG(active_op_array) = generator->execute_data->op_array; + EG(active_op_array) = &generator->execute_data->func->op_array; EG(active_symbol_table) = generator->execute_data->symbol_table; Z_OBJ(EG(This)) = generator->execute_data->object; EG(scope) = generator->execute_data->scope; @@ -358,17 +337,32 @@ ZEND_API void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ /* We want the backtrace to look as if the generator function was * called from whatever method we are current running (e.g. next()). - * The first prev_execute_data contains an additional stack frame, - * which makes the generator function show up in the backtrace and - * makes the arguments available to func_get_args(). So we have to - * set the prev_execute_data of that prev_execute_data :) */ - generator->execute_data->prev_execute_data->prev_execute_data = original_execute_data; + * So we have to link generator call frame with caller call frames */ + + prev_execute_data = original_execute_data; + if (prev_execute_data && + prev_execute_data->call && + (prev_execute_data->call->flags & ZEND_CALL_DONE)) { + prev_execute_data->call->prev_execute_data = prev_execute_data; + prev_execute_data = prev_execute_data->call; + } + generator->execute_data->prev_execute_data = prev_execute_data; + if (prev_execute_data) { + generator->execute_data->prev_nested_call = prev_execute_data->call; + prev_execute_data->call = generator->execute_data; + } /* Resume execution */ generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING; zend_execute_ex(generator->execute_data TSRMLS_CC); generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING; + /* Unlink generator call_frame from the caller */ + if (generator->execute_data && generator->execute_data->prev_execute_data) { + generator->execute_data->prev_execute_data->call = generator->execute_data->prev_nested_call; + generator->execute_data->prev_execute_data = NULL; + } + /* Restore executor globals */ EG(current_execute_data) = original_execute_data; EG(opline_ptr) = original_opline_ptr; @@ -670,7 +664,7 @@ zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *ob return NULL; } - if (by_ref && !(generator->execute_data->op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) { + if (by_ref && !(generator->execute_data->func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { zend_throw_exception(NULL, "You can only iterate a generator by-reference if it declared that it yields by-reference", 0 TSRMLS_CC); return NULL; } diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index ac4599282e..e38fbfc640 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -905,7 +905,7 @@ static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{ ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ { - zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function; + zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->call->func; zval method_name, method_args; zval method_result; zend_class_entry *ce = Z_OBJCE_P(getThis()); @@ -1123,7 +1123,7 @@ static union _zend_function *zend_std_get_method(zend_object **obj_ptr, zend_str ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ { - zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function; + zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->call->func; zval method_name, method_args; zval method_result; zend_class_entry *ce = EG(scope); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 7ecccdaf32..cad1dd2e9c 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -70,9 +70,6 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->T = 0; - op_array->nested_calls = 0; - op_array->used_stack = 0; - op_array->function_name = NULL; op_array->filename = zend_get_compiled_filename(TSRMLS_C); op_array->doc_comment = NULL; @@ -631,7 +628,7 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC) { zend_op *opline, *end; - if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) { + if (!ZEND_USER_CODE(op_array->type)) { return 0; } if (op_array->has_finally_block) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 38377d3cce..f0da4eeded 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1772,6 +1772,7 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV) ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) { vm_frame_kind frame_kind = EX(frame_kind); + zend_execute_data *prev_nested_call; EG(current_execute_data) = EX(prev_execute_data); @@ -1780,22 +1781,22 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table) TSRMLS_CC); } - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(op_array)->prototype) { - zval_ptr_dtor((zval*)EX(op_array)->prototype); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(func)->op_array.prototype) { + zval_ptr_dtor((zval*)EX(func)->op_array.prototype); } - zend_vm_stack_free((char*)execute_data TSRMLS_CC); + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); execute_data = EG(current_execute_data); + EX(call) = prev_nested_call; EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; EG(active_symbol_table) = EX(symbol_table); - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { - if (EX(call)->is_ctor_result_used) { + if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) { + if (!(EX(opline)->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -1812,10 +1813,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) EG(scope) = EX(scope); EG(called_scope) = EX(called_scope); - EX(call)--; - - zend_vm_stack_clear_multiple(1 TSRMLS_CC); - if (UNEXPECTED(EG(exception) != NULL)) { zend_op *opline = EX(opline); zend_throw_exception_internal(NULL TSRMLS_CC); @@ -1830,16 +1827,16 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) ZEND_VM_LEAVE(); } else if (frame_kind == VM_FRAME_NESTED_CODE) { zend_detach_symbol_table(execute_data); - destroy_op_array(EX(op_array) TSRMLS_CC); - efree(EX(op_array)); - zend_vm_stack_free((char*)execute_data TSRMLS_CC); + destroy_op_array(&EX(func)->op_array TSRMLS_CC); + efree(EX(func)); + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); execute_data = EG(current_execute_data); + EX(call) = prev_nested_call; zend_attach_symbol_table(execute_data); - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION_LEAVE(); @@ -1851,6 +1848,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } else { if (frame_kind == VM_FRAME_TOP_FUNCTION) { i_free_compiled_variables(execute_data TSRMLS_CC); + zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); } else /* if (frame_kind == VM_FRAME_TOP_CODE) */ { zend_array *symbol_table = EX(symbol_table); zend_execute_data *old_execute_data; @@ -1858,7 +1856,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) zend_detach_symbol_table(execute_data); old_execute_data = EX(prev_execute_data); while (old_execute_data) { - if (old_execute_data->op_array) { + if (old_execute_data->func && ZEND_USER_CODE(old_execute_data->func->op_array.type)) { if (old_execute_data->symbol_table == symbol_table) { zend_attach_symbol_table(old_execute_data); } @@ -1867,224 +1865,20 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) old_execute_data = old_execute_data->prev_execute_data; } } - if ((EX(op_array)->fn_flags & ZEND_ACC_CLOSURE) && EX(op_array)->prototype) { - zval_ptr_dtor((zval*)EX(op_array)->prototype); + if ((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) && EX(func)->op_array.prototype) { + zval_ptr_dtor((zval*)EX(func)->op_array.prototype); + } + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); + + if (EG(current_execute_data)) { + EG(current_execute_data)->call = prev_nested_call; } - zend_vm_stack_free((char*)execute_data TSRMLS_CC); EG(opline_ptr) = NULL; ZEND_VM_RETURN(); } } -ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) -{ - USE_OPLINE - zend_function *fbc = EX(function_state).function; - zend_object *object; - zend_uint num_args; - - SAVE_OPLINE(); - object = EX(call)->object; - if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name->val, fbc->common.function_name->val); - } - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - fbc->common.scope ? fbc->common.scope->name->val : "", - fbc->common.scope ? "::" : "", - fbc->common.function_name->val); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); - } - } - } - if (fbc->common.scope && - !(fbc->common.fn_flags & ZEND_ACC_STATIC) && - !object) { - - if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - /* FIXME: output identifiers properly */ - zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", fbc->common.scope->name->val, fbc->common.function_name->val); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); - } - } else { - /* FIXME: output identifiers properly */ - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", fbc->common.scope->name->val, fbc->common.function_name->val); - } - } - - if (EXPECTED(EX(call)->num_additional_args == 0)) { - num_args = opline->extended_value; - EX(function_state).arguments = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_LONG(EX(function_state).arguments, num_args); - } else { - num_args = opline->extended_value + EX(call)->num_additional_args; - EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC); - } - LOAD_OPLINE(); - - if (fbc->type == ZEND_INTERNAL_FUNCTION) { - int should_change_scope = 0; - zval *ret; - - if (fbc->common.scope) { - should_change_scope = 1; - Z_OBJ(EG(This)) = object; - /* TODO: we don't set scope if we call an object method ??? */ - /* See: ext/pdo_sqlite/tests/pdo_fetch_func_001.phpt */ -#if 1 - EG(scope) = (object) ? NULL : fbc->common.scope; -#else - EG(scope) = fbc->common.scope; -#endif - EG(called_scope) = EX(call)->called_scope; - } - - if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { - zend_uint i; - zval *p = EX(function_state).arguments - num_args; - - for (i = 0; i < num_args; ++i, ++p) { - zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); - } - if (UNEXPECTED(EG(exception) != NULL)) { - if (RETURN_VALUE_USED(opline)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); - } - if (UNEXPECTED(should_change_scope)) { - ZEND_VM_C_GOTO(fcall_end_change_scope); - } else { - ZEND_VM_C_GOTO(fcall_end); - } - } - } - - ret = EX_VAR(opline->result.var); - ZVAL_NULL(ret); - Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; - - if (!zend_execute_internal) { - /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(num_args, ret TSRMLS_CC); - } else { - zend_execute_internal(execute_data, NULL TSRMLS_CC); - } - - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(ret); - } - - if (UNEXPECTED(should_change_scope)) { - ZEND_VM_C_GOTO(fcall_end_change_scope); - } else { - ZEND_VM_C_GOTO(fcall_end); - } - } else if (fbc->type == ZEND_USER_FUNCTION) { - zval *return_value = NULL; - - Z_OBJ(EG(This)) = object; - EG(scope) = fbc->common.scope; - EG(called_scope) = EX(call)->called_scope; - EG(active_symbol_table) = NULL; - EG(active_op_array) = &fbc->op_array; - if (RETURN_VALUE_USED(opline)) { - return_value = EX_VAR(opline->result.var); - - ZVAL_NULL(return_value); - Z_VAR_FLAGS_P(return_value) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; - } - - if (UNEXPECTED((EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { - if (RETURN_VALUE_USED(opline)) { - zend_generator_create_zval(EG(active_op_array), EX_VAR(opline->result.var) TSRMLS_CC); - } - } else if (EXPECTED(zend_execute_ex == execute_ex)) { - if (EXPECTED(EG(exception) == NULL)) { - i_create_execute_data_from_op_array(EG(active_op_array), return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); - ZEND_VM_ENTER(); - } - } else { - zend_execute(EG(active_op_array), return_value TSRMLS_CC); - } - - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); - if (UNEXPECTED(EG(active_symbol_table) != NULL)) { - zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC); - } - EG(active_symbol_table) = EX(symbol_table); - } else { /* ZEND_OVERLOADED_FUNCTION */ - Z_OBJ(EG(This)) = object; -//??? EG(scope) = NULL; - EG(scope) = fbc->common.scope; - EG(called_scope) = EX(call)->called_scope; - - ZVAL_NULL(EX_VAR(opline->result.var)); - - /* Not sure what should be done here if it's a static method */ - if (EXPECTED(object != NULL)) { - object->handlers->call_method(fbc->common.function_name, object, num_args, EX_VAR(opline->result.var) TSRMLS_CC); - } else { - zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); - } - - if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { - STR_RELEASE(fbc->common.function_name); - } - efree(fbc); - - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(EX_VAR(opline->result.var)); - } else { -//??? Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr); -//??? Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1); - Z_VAR_FLAGS_P(EX_VAR(opline->result.var)) = 0; - } - } - -ZEND_VM_C_LABEL(fcall_end_change_scope): - if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { - if (EX(call)->is_ctor_result_used) { - Z_DELREF(EG(This)); - } - if (Z_REFCOUNT(EG(This)) == 1) { - zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); - } - } - if (!Z_DELREF(EG(This))) { - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); - } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { - gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); - } - } - Z_OBJ(EG(This)) = EX(object); - EG(scope) = EX(scope); - EG(called_scope) = EX(called_scope); - -ZEND_VM_C_LABEL(fcall_end): - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - EX(call)--; - - zend_vm_stack_clear_multiple(1 TSRMLS_CC); - - if (UNEXPECTED(EG(exception) != NULL)) { - zend_throw_exception_internal(NULL TSRMLS_CC); - if (RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(EX_VAR(opline->result.var)); - } - HANDLE_EXCEPTION(); - } - - ZEND_VM_NEXT_OPCODE(); -} - ZEND_VM_HANDLER(42, ZEND_JMP, ANY, ANY) { USE_OPLINE @@ -2407,8 +2201,10 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) USE_OPLINE zval *function_name; zend_free_op free_op1, free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -2423,32 +2219,8 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) } object = GET_OP1_OBJ_ZVAL_PTR_DEREF(BP_VAR_R); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (OP2_TYPE != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((OP2_TYPE == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (OP2_TYPE == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { FREE_OP2(); HANDLE_EXCEPTION(); @@ -2456,15 +2228,38 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (OP2_TYPE != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((OP2_TYPE == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (OP2_TYPE == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); FREE_OP2(); FREE_OP1_IF_VAR(); @@ -2478,7 +2273,8 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -2487,7 +2283,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -2496,24 +2292,17 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (OP1_TYPE != IS_CONST && OP2_TYPE == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (OP2_TYPE != IS_UNUSED) { zend_free_op free_op2; @@ -2529,20 +2318,20 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((OP2_TYPE == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((OP2_TYPE == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (OP2_TYPE == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (OP1_TYPE == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (OP2_TYPE != IS_CONST) { @@ -2555,33 +2344,37 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (OP1_TYPE != IS_CONST) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2590,32 +2383,32 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) { USE_OPLINE - zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; + zval *function_name, *func; if (OP2_TYPE == IS_CONST) { - function_name_ptr = function_name = (zval*)(opline->op2.zv+1); + function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { zend_string *lcname; zend_free_op free_op2; + zend_class_entry *called_scope; + zend_object *object; + zval *function_name_ptr; SAVE_OPLINE(); function_name_ptr = function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); @@ -2634,37 +2427,23 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } STR_FREE(lcname); FREE_OP2(); - - call->fbc = Z_FUNC_P(func); - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; } else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { - if (call->object) { - GC_REFCOUNT(call->object)++; + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object TSRMLS_CC) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; } if (OP2_TYPE == IS_VAR && OP2_FREE && Z_REFCOUNT_P(function_name) == 1 && - call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { + fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - call->fbc->common.prototype = (zend_function*)function_name_ptr; + fbc->common.prototype = (zend_function*)function_name_ptr; } else { FREE_OP2(); } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else if (OP2_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { @@ -2687,51 +2466,49 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } if (Z_TYPE_P(obj) == IS_STRING) { - call->object = NULL; - call->called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); - if (UNEXPECTED(call->called_scope == NULL)) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); + if (UNEXPECTED(called_scope == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - if (call->called_scope->get_static_method) { - call->fbc = call->called_scope->get_static_method(call->called_scope, Z_STR_P(method) TSRMLS_CC); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(call->called_scope, Z_STR_P(method), NULL TSRMLS_CC); + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", call->called_scope->name->val, Z_STRVAL_P(method)); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); } } else { - call->called_scope = Z_OBJCE_P(obj); - call->object = Z_OBJ_P(obj); + called_scope = Z_OBJCE_P(obj); + object = Z_OBJ_P(obj); - call->fbc = Z_OBJ_HT_P(obj)->get_method(&call->object, Z_STR_P(method), NULL TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(method)); + fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(object), Z_STRVAL_P(method)); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(object)++; /* For $this pointer */ } } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - FREE_OP2(); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else { if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ + ZEND_VM_CONTINUE(); /* Never reached */ } + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } } @@ -2741,68 +2518,263 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) USE_OPLINE zval *func_name; zval *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; func_name = opline->op2.zv + 1; if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if ((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL) { func_name++; if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(61, ZEND_DO_FCALL_BY_NAME, ANY, ANY) -{ - EX(function_state).function = EX(call)->fbc; - ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_common_helper); -} - -ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) +ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, ANY, CONST) { USE_OPLINE - zend_free_op free_op1; - zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R); + zend_free_op free_op2; + zval *fname = GET_OP2_ZVAL_PTR(BP_VAR_R); zval *func; - call_slot *call = EX(call_slots) + opline->op2.num; + zend_function *fbc; if (CACHED_PTR(Z_CACHE_SLOT_P(fname))) { - EX(function_state).function = CACHED_PTR(Z_CACHE_SLOT_P(fname)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(fname)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(fname))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(fname)); } else { - EX(function_state).function = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(fname), EX(function_state).function); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(fname), fbc); } - call->fbc = EX(function_state).function; - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); - FREE_OP1(); + FREE_OP2(); + + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; + + SAVE_OPLINE(); + call->flags = ZEND_CALL_DONE; + if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { + zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name->val, fbc->common.function_name->val); + } + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { + zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", + fbc->common.scope ? fbc->common.scope->name->val : "", + fbc->common.scope ? "::" : "", + fbc->common.function_name->val); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + } + } + if (fbc->common.scope && + !(fbc->common.fn_flags & ZEND_ACC_STATIC) && + !call->object) { + + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + /* FIXME: output identifiers properly */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", fbc->common.scope->name->val, fbc->common.function_name->val); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + } else { + /* FIXME: output identifiers properly */ + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", fbc->common.scope->name->val, fbc->common.function_name->val); + } + } + + LOAD_OPLINE(); + + if (UNEXPECTED(fbc->type == ZEND_INTERNAL_FUNCTION)) { + int should_change_scope = 0; + zval *ret; + + if (fbc->common.scope) { + should_change_scope = 1; + Z_OBJ(EG(This)) = call->object; + /* TODO: we don't set scope if we call an object method ??? */ + /* See: ext/pdo_sqlite/tests/pdo_fetch_func_001.phpt */ +#if 1 + EG(scope) = (call->object) ? NULL : fbc->common.scope; +#else + EG(scope) = fbc->common.scope; +#endif + EG(called_scope) = call->called_scope; + } + + if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { + zend_uint i; + zval *p = ZEND_CALL_ARG(call, 1); + + for (i = 0; i < call->num_args; ++i) { + zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); + p++; + } + if (UNEXPECTED(EG(exception) != NULL)) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } + if (UNEXPECTED(should_change_scope)) { + ZEND_VM_C_GOTO(fcall_end_change_scope); + } else { + ZEND_VM_C_GOTO(fcall_end); + } + } + } + + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + + if (!zend_execute_internal) { + /* saves one function call if zend_execute_internal is not used */ + fbc->internal_function.handler(call->num_args, ret TSRMLS_CC); + } else { + zend_execute_internal(execute_data, NULL TSRMLS_CC); + } + + zend_vm_stack_free_args(call TSRMLS_CC); + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(ret); + } - ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_common_helper); + if (UNEXPECTED(should_change_scope)) { + ZEND_VM_C_GOTO(fcall_end_change_scope); + } else { + ZEND_VM_C_GOTO(fcall_end); + } + } else if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { + zval *return_value = NULL; + + Z_OBJ(EG(This)) = call->object; + EG(scope) = fbc->common.scope; + EG(called_scope) = call->called_scope; + EG(active_symbol_table) = NULL; + EG(active_op_array) = &fbc->op_array; + if (RETURN_VALUE_USED(opline)) { + return_value = EX_VAR(opline->result.var); + + ZVAL_NULL(return_value); + Z_VAR_FLAGS_P(return_value) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + } + + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (RETURN_VALUE_USED(opline)) { + zend_generator_create_zval(&fbc->op_array, EX_VAR(opline->result.var) TSRMLS_CC); + } + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + } else { + call->prev_execute_data = EG(current_execute_data); + i_init_execute_data(call, &fbc->op_array, return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); + + if (EXPECTED(zend_execute_ex == execute_ex)) { + ZEND_VM_ENTER(); + } else { + execute_ex(call TSRMLS_CC); + } + } + + EG(opline_ptr) = &EX(opline); + EG(active_op_array) = &EX(func)->op_array; + if (UNEXPECTED(EG(active_symbol_table) != NULL)) { + zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC); + } + EG(active_symbol_table) = EX(symbol_table); + } else { /* ZEND_OVERLOADED_FUNCTION */ + Z_OBJ(EG(This)) = call->object; +//??? EG(scope) = NULL; + EG(scope) = fbc->common.scope; + EG(called_scope) = call->called_scope; + + ZVAL_NULL(EX_VAR(opline->result.var)); + + /* Not sure what should be done here if it's a static method */ + if (EXPECTED(call->object != NULL)) { + call->object->handlers->call_method(fbc->common.function_name, call->object, call->num_args, EX_VAR(opline->result.var) TSRMLS_CC); + } else { + zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); + } + + zend_vm_stack_free_args(call TSRMLS_CC); + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + + if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { + STR_RELEASE(fbc->common.function_name); + } + efree(fbc); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } else { +//??? Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr); +//??? Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1); + Z_VAR_FLAGS_P(EX_VAR(opline->result.var)) = 0; + } + } + +ZEND_VM_C_LABEL(fcall_end_change_scope): + if (Z_OBJ(EG(This))) { + if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) { + if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { + Z_DELREF(EG(This)); + } + if (Z_REFCOUNT(EG(This)) == 1) { + zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); + } + } + if (!Z_DELREF(EG(This))) { + _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); + } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { + gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); + } + } + Z_OBJ(EG(This)) = EX(object); + EG(scope) = EX(scope); + EG(called_scope) = EX(called_scope); + +ZEND_VM_C_LABEL(fcall_end): + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + HANDLE_EXCEPTION(); + } + + ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) @@ -2945,7 +2917,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV) /* Check whether an exception has been thrown, if not, jump over code */ zend_exception_restore(TSRMLS_C); if (EG(exception) == NULL) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->extended_value]); ZEND_VM_CONTINUE(); /* CHECK_ME */ } if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { @@ -2969,7 +2941,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV) zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION(); } - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->extended_value]); ZEND_VM_CONTINUE(); /* CHECK_ME */ } } @@ -2991,22 +2963,23 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV) ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY) { USE_OPLINE - zval *value, *top; + zval *value, *arg; zend_free_op free_op1; SAVE_OPLINE(); - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num); } } value = GET_OP1_ZVAL_PTR(BP_VAR_R); - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY_VALUE(top, value); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY_VALUE(arg, value); if (OP1_TYPE == IS_CONST) { - if (UNEXPECTED(Z_OPT_COPYABLE_P(top))) { - zval_copy_ctor_func(top); + if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { + zval_copy_ctor_func(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -3015,18 +2988,19 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY) ZEND_VM_HELPER(zend_send_by_var_helper, VAR|CV, ANY) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; zend_free_op free_op1; varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); FREE_OP1(); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (OP1_TYPE == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -3036,7 +3010,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ @@ -3044,7 +3018,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } } else { - if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } } @@ -3061,15 +3035,18 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) if (OP1_TYPE == IS_CV) { Z_ADDREF_P(varptr); } - zend_vm_stack_push(varptr TSRMLS_CC); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY_VALUE(arg, varptr); } else { if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY(top, varptr); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY(arg, varptr); FREE_OP1_IF_VAR(); } CHECK_EXCEPTION(); @@ -3080,7 +3057,7 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); varptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); @@ -3089,23 +3066,24 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY) zend_error_noreturn(E_ERROR, "Only variables can be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; if (OP1_TYPE == IS_VAR && UNEXPECTED(varptr == &EG(error_zval))) { - ZVAL_NEW_REF(top, &EG(uninitialized_zval)); + ZVAL_NEW_REF(arg, &EG(uninitialized_zval)); ZEND_VM_NEXT_OPCODE(); } if (Z_ISREF_P(varptr)) { Z_ADDREF_P(varptr); - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); } else if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { - ZVAL_COPY_VALUE(top, varptr); - ZVAL_MAKE_REF(top); + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_MAKE_REF(arg); } else { ZVAL_MAKE_REF(varptr); Z_ADDREF_P(varptr); - ZVAL_REF(top, Z_REF_P(varptr)); + ZVAL_REF(arg, Z_REF_P(varptr)); } FREE_OP1_VAR_PTR(); @@ -3115,24 +3093,25 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY) ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; zend_free_op free_op1; - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); } } varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); FREE_OP1(); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (OP1_TYPE == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -3147,7 +3126,7 @@ ZEND_VM_HANDLER(165, ZEND_SEND_UNPACK, ANY, ANY) SAVE_OPLINE(); args = GET_OP1_ZVAL_PTR(BP_VAR_R); - arg_num = opline->op2.num + EX(call)->num_additional_args + 1; + arg_num = EX(call)->num_args + 1; ZEND_VM_C_LABEL(send_again): switch (Z_TYPE_P(args)) { @@ -3156,7 +3135,7 @@ ZEND_VM_C_LABEL(send_again): zval *arg, *top; zend_string *name; - ZEND_VM_STACK_GROW_IF_NEEDED(zend_hash_num_elements(ht)); + zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht) TSRMLS_DC); if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_IMMUTABLE_P(args)) { int i; @@ -3164,7 +3143,7 @@ ZEND_VM_C_LABEL(send_again): /* check if any of arguments are going to be passed by reference */ for (i = 0; i < zend_hash_num_elements(ht); i++) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num + i)) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num + i)) { separate = 1; break; } @@ -3183,8 +3162,8 @@ ZEND_VM_C_LABEL(send_again): ZEND_VM_NEXT_OPCODE(); } - top = zend_vm_stack_top_inc(TSRMLS_C); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + top = ZEND_CALL_ARG(EX(call), arg_num); + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (!Z_IMMUTABLE_P(args)) { ZVAL_MAKE_REF(arg); Z_ADDREF_P(arg); @@ -3193,12 +3172,13 @@ ZEND_VM_C_LABEL(send_again): ZVAL_DUP(top, arg); } } else if (Z_ISREF_P(arg)) { +//TODO: change into ZVAL_COPY()??? ZVAL_DUP(top, Z_REFVAL_P(arg)); } else { ZVAL_COPY(top, arg); } - EX(call)->num_additional_args++; + EX(call)->num_args++; arg_num++; } ZEND_HASH_FOREACH_END(); @@ -3232,7 +3212,7 @@ ZEND_VM_C_LABEL(send_again): } for (; iter->funcs->valid(iter TSRMLS_CC) == SUCCESS; ++arg_num) { - zval *arg; + zval *arg, *top; if (UNEXPECTED(EG(exception) != NULL)) { ZEND_VM_C_GOTO(unpack_iter_dtor); @@ -3260,13 +3240,13 @@ ZEND_VM_C_LABEL(send_again): zval_dtor(&key); } - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" " by unpacking a Traversable, passing by-value instead", arg_num, - EX(call)->fbc->common.scope ? EX(call)->fbc->common.scope->name->val : "", - EX(call)->fbc->common.scope ? "::" : "", - EX(call)->fbc->common.function_name->val + EX(call)->func->common.scope ? EX(call)->func->common.scope->name->val : "", + EX(call)->func->common.scope ? "::" : "", + EX(call)->func->common.function_name->val ); } @@ -3276,9 +3256,10 @@ ZEND_VM_C_LABEL(send_again): if (Z_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } - ZEND_VM_STACK_GROW_IF_NEEDED(1); - zend_vm_stack_push(arg TSRMLS_CC); - EX(call)->num_additional_args++; + zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1 TSRMLS_DC); + top = ZEND_CALL_ARG(EX(call), arg_num); + ZVAL_COPY_VALUE(top, arg); + EX(call)->num_args++; iter->funcs->move_forward(iter TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { @@ -3307,25 +3288,18 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); SAVE_OPLINE(); - if (UNEXPECTED(arg_num > arg_count)) { + if (UNEXPECTED(arg_num > EX(num_args))) { zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC); - } else { - zval *var_ptr; - zval *param = arguments - arg_count + arg_num - 1; + CHECK_EXCEPTION(); + } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, param, opline->extended_value TSRMLS_CC); - } - var_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(var_ptr))) Z_DELREF_P(var_ptr); - ZVAL_COPY(var_ptr, param); + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + CHECK_EXCEPTION(); } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -3333,30 +3307,24 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); - zval *var_ptr; + zval *param; SAVE_OPLINE(); - var_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(var_ptr))) Z_DELREF_P(var_ptr); - if (arg_num > arg_count) { - ZVAL_COPY_VALUE(var_ptr, opline->op2.zv); - if (Z_OPT_CONSTANT_P(var_ptr)) { - zval_update_constant(var_ptr, 0 TSRMLS_CC); + param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); + if (arg_num > EX(num_args)) { + ZVAL_COPY_VALUE(param, opline->op2.zv); + if (Z_OPT_CONSTANT_P(param)) { + zval_update_constant(param, 0 TSRMLS_CC); } else { /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */ - if (UNEXPECTED(Z_OPT_COPYABLE_P(var_ptr))) { - zval_copy_ctor_func(var_ptr); + if (UNEXPECTED(Z_OPT_COPYABLE_P(param))) { + zval_copy_ctor_func(param); } } - } else { - zval *param = arguments - arg_count + arg_num - 1; - ZVAL_COPY(var_ptr, param); } - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, var_ptr, opline->extended_value TSRMLS_CC); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); } CHECK_EXCEPTION(); @@ -3367,21 +3335,21 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); + zend_uint arg_count = EX(num_args); zval *params; SAVE_OPLINE(); params = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(params))) Z_DELREF_P(params); if (arg_num <= arg_count) { - zval *param = arguments - arg_count + arg_num - 1; + zval *param; + array_init_size(params, arg_count - arg_num + 1); - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - do { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, param, opline->extended_value TSRMLS_CC); + param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + do { + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); param++; @@ -3423,8 +3391,8 @@ ZEND_VM_HANDLER(50, ZEND_BRK, ANY, CONST) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, - EX(op_array), execute_data TSRMLS_CC); - ZEND_VM_JMP(EX(op_array)->opcodes + el->brk); + &EX(func)->op_array, execute_data TSRMLS_CC); + ZEND_VM_JMP(EX(func)->op_array.opcodes + el->brk); } ZEND_VM_HANDLER(51, ZEND_CONT, ANY, CONST) @@ -3434,8 +3402,8 @@ ZEND_VM_HANDLER(51, ZEND_CONT, ANY, CONST) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, - EX(op_array), execute_data TSRMLS_CC); - ZEND_VM_JMP(EX(op_array)->opcodes + el->cont); + &EX(func)->op_array, execute_data TSRMLS_CC); + ZEND_VM_JMP(EX(func)->op_array.opcodes + el->cont); } ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST) @@ -3446,9 +3414,9 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->extended_value, - EX(op_array), execute_data TSRMLS_CC); + &EX(func)->op_array, execute_data TSRMLS_CC); - brk_opline = EX(op_array)->opcodes + el->brk; + brk_opline = EX(func)->op_array.opcodes + el->brk; if (brk_opline->opcode == ZEND_SWITCH_FREE) { if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { @@ -3515,21 +3483,19 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) } ZEND_VM_JMP(opline->op2.jmp_addr); } else { - call_slot *call = EX(call_slots) + opline->extended_value; + /* We are not handling overloaded classes right now */ + EX(call) = zend_vm_stack_push_call_frame( + constructor, opline->extended_value, + RETURN_VALUE_USED(opline) ? + ZEND_CALL_CTOR : (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_UNUSED), + Z_CE_P(EX_VAR(opline->op1.var)), + Z_OBJ(object_zval), + EX(call) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); } - /* We are not handling overloaded classes right now */ - call->fbc = constructor; - call->object = Z_OBJ(object_zval); - call->called_scope = Z_CE_P(EX_VAR(opline->op1.var)); - call->num_additional_args = 0; - call->is_ctor_call = 1; - call->is_ctor_result_used = RETURN_VALUE_USED(opline); - EX(call) = call; - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -4014,23 +3980,23 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) return_value = EX_VAR(opline->result.var); } - EX(function_state).function = (zend_function *) new_op_array; + EX(call) = zend_vm_stack_push_call_frame( + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } + EX(call)->prev_execute_data = EG(current_execute_data); + i_init_execute_data(EX(call), new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - i_create_execute_data_from_op_array(new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); ZEND_VM_ENTER(); } else { - zend_execute(new_op_array, return_value TSRMLS_CC); + execute_ex(EG(current_execute_data) TSRMLS_CC); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -4861,7 +4827,7 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY) ZEND_VM_HANDLER(142, ZEND_RAISE_ABSTRACT_ERROR, ANY, ANY) { SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name->val, EX(op_array)->function_name->val); + zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name->val, EX(func)->op_array.function_name->val); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } @@ -4987,7 +4953,7 @@ ZEND_VM_HANDLER(101, ZEND_EXT_STMT, ANY, ANY) { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_statement_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_statement_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -4997,7 +4963,7 @@ ZEND_VM_HANDLER(102, ZEND_EXT_FCALL_BEGIN, ANY, ANY) { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_begin_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_begin_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -5007,7 +4973,7 @@ ZEND_VM_HANDLER(103, ZEND_EXT_FCALL_END, ANY, ANY) { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -5018,7 +4984,7 @@ ZEND_VM_HANDLER(139, ZEND_DECLARE_CLASS, ANY, ANY) USE_OPLINE SAVE_OPLINE(); - Z_CE_P(EX_VAR(opline->result.var)) = do_bind_class(EX(op_array), opline, EG(class_table), 0 TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = do_bind_class(&EX(func)->op_array, opline, EG(class_table), 0 TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -5028,7 +4994,7 @@ ZEND_VM_HANDLER(140, ZEND_DECLARE_INHERITED_CLASS, ANY, ANY) USE_OPLINE SAVE_OPLINE(); - Z_CE_P(EX_VAR(opline->result.var)) = do_bind_inherited_class(EX(op_array), opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -5042,7 +5008,7 @@ ZEND_VM_HANDLER(145, ZEND_DECLARE_INHERITED_CLASS_DELAYED, ANY, ANY) if ((zce = zend_hash_find(EG(class_table), Z_STR_P(opline->op2.zv))) == NULL || ((orig_zce = zend_hash_find(EG(class_table), Z_STR_P(opline->op1.zv))) != NULL && Z_CE_P(zce) != Z_CE_P(orig_zce))) { - do_bind_inherited_class(EX(op_array), opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); + do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -5053,7 +5019,7 @@ ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY) USE_OPLINE SAVE_OPLINE(); - do_bind_function(EX(op_array), opline, EG(function_table), 0); + do_bind_function(&EX(func)->op_array, opline, EG(function_table), 0); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -5173,45 +5139,37 @@ ZEND_VM_HANDLER(155, ZEND_BIND_TRAITS, ANY, ANY) ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) { - zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes; + zend_uint op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes; int i; zend_uint catch_op_num = 0, finally_op_num = 0, finally_op_end = 0; - zval *stack_frame; - - /* Figure out where the next stack frame (which maybe contains pushed - * arguments that have to be dtor'ed) starts */ - stack_frame = zend_vm_stack_frame_base(execute_data); - /* If the exception was thrown during a function call there might be - * arguments pushed to the stack that have to be dtor'ed. */ - while (zend_vm_stack_top(TSRMLS_C) != stack_frame) { - zval *stack_zval_p = zend_vm_stack_pop(TSRMLS_C); - zval_ptr_dtor(stack_zval_p); - } - - for (i=0; i<EG(active_op_array)->last_try_catch; i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { + for (i = 0; i < EX(func)->op_array.last_try_catch; i++) { + if (EX(func)->op_array.try_catch_array[i].try_op > op_num) { /* further blocks will not be relevant... */ break; } - if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) { - catch_op_num = EX(op_array)->try_catch_array[i].catch_op; + if (op_num < EX(func)->op_array.try_catch_array[i].catch_op) { + catch_op_num = EX(func)->op_array.try_catch_array[i].catch_op; } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) { - finally_op_num = EX(op_array)->try_catch_array[i].finally_op; + if (op_num < EX(func)->op_array.try_catch_array[i].finally_op) { + finally_op_num = EX(func)->op_array.try_catch_array[i].finally_op; } - if (op_num >= EG(active_op_array)->try_catch_array[i].finally_op && - op_num < EG(active_op_array)->try_catch_array[i].finally_end) { - finally_op_end = EG(active_op_array)->try_catch_array[i].finally_end; + if (op_num >= EX(func)->op_array.try_catch_array[i].finally_op && + op_num < EX(func)->op_array.try_catch_array[i].finally_end) { + finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end; } } - if (EX(call) >= EX(call_slots)) { - call_slot *call = EX(call); + if (EX(call)) { + zend_execute_data *call = EX(call); do { + /* If the exception was thrown during a function call there might be + * arguments pushed to the stack that have to be dtor'ed. */ + zend_vm_stack_free_args(EX(call) TSRMLS_CC); + if (call->object) { - if (call->is_ctor_call) { - if (call->is_ctor_result_used) { + if (call->flags & ZEND_CALL_CTOR) { + if (!(call->flags & ZEND_CALL_CTOR_RESULT_UNUSED)) { GC_REFCOUNT(call->object)--; } if (GC_REFCOUNT(call->object) == 1) { @@ -5220,21 +5178,22 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } OBJ_RELEASE(call->object); } - call--; - } while (call >= EX(call_slots)); - EX(call) = NULL; + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + call = EX(call); + } while (call); } - for (i=0; i<EX(op_array)->last_brk_cont; i++) { - if (EX(op_array)->brk_cont_array[i].start < 0) { + for (i = 0; i < EX(func)->op_array.last_brk_cont; i++) { + if (EX(func)->op_array.brk_cont_array[i].start < 0) { continue; - } else if (EX(op_array)->brk_cont_array[i].start > op_num) { + } else if (EX(func)->op_array.brk_cont_array[i].start > op_num) { /* further blocks will not be relevant... */ break; - } else if (op_num < EX(op_array)->brk_cont_array[i].brk) { + } else if (op_num < EX(func)->op_array.brk_cont_array[i].brk) { if (!catch_op_num || - catch_op_num >= EX(op_array)->brk_cont_array[i].brk) { - zend_op *brk_opline = &EX(op_array)->opcodes[EX(op_array)->brk_cont_array[i].brk]; + catch_op_num >= EX(func)->op_array.brk_cont_array[i].brk) { + zend_op *brk_opline = &EX(func)->op_array.opcodes[EX(func)->op_array.brk_cont_array[i].brk]; if (brk_opline->opcode == ZEND_SWITCH_FREE) { if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { @@ -5270,7 +5229,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) EX(delayed_exception) = EG(exception); EG(exception) = NULL; EX(fast_ret) = NULL; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op_num]); ZEND_VM_CONTINUE(); } else if (catch_op_num) { if (finally_op_end && catch_op_num > finally_op_end) { @@ -5280,14 +5239,14 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) EX(delayed_exception) = NULL; } } - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op_num]); ZEND_VM_CONTINUE(); } else { if (EX(delayed_exception)) { zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC); EX(delayed_exception) = NULL; } - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN); } else { ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); @@ -5318,7 +5277,7 @@ ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY) case ZEND_USER_OPCODE_CONTINUE: ZEND_VM_CONTINUE(); case ZEND_USER_OPCODE_RETURN: - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN); } else { ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); @@ -5382,7 +5341,7 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED) } closure_is_static = Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC; - closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->function_state.function->common.fn_flags & ZEND_ACC_STATIC; + closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->call->func->common.fn_flags & ZEND_ACC_STATIC; if (closure_is_static || closure_is_being_defined_inside_static_context) { zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc), EG(called_scope), NULL TSRMLS_CC); } else { @@ -5432,7 +5391,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE if (OP1_TYPE != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) { @@ -5560,7 +5519,7 @@ ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY) if (opline->extended_value && UNEXPECTED(EG(prev_exception) != NULL)) { /* in case of unhandled exception jump to catch block instead of finally */ - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); } EX(fast_ret) = opline + 1; @@ -5579,15 +5538,15 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY) USE_OPLINE if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); } else { EG(exception) = EX(delayed_exception); EX(delayed_exception) = NULL; if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); - } else if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN); } else { ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); @@ -5646,4 +5605,4 @@ ZEND_VM_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper) +ZEND_VM_EXPORT_HANDLER(zend_do_fcall, ZEND_DO_FCALL) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index b69dcbf711..3f373a1a98 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -375,15 +375,27 @@ ZEND_API void execute_ex(zend_execute_data *execute_data TSRMLS_DC) ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value TSRMLS_DC) { + zend_execute_data *execute_data; + if (EG(exception) != NULL) { return; - } - zend_execute_ex(i_create_execute_data_from_op_array(op_array, return_value, EG(active_symbol_table) ? VM_FRAME_TOP_CODE : VM_FRAME_TOP_FUNCTION TSRMLS_CC) TSRMLS_CC); + } + + if (EG(current_execute_data) && EG(current_execute_data)->call) { + execute_data = EG(current_execute_data)->call; + } else { + execute_data = zend_vm_stack_push_call_frame( + (zend_function*)op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), NULL TSRMLS_CC); + } + EX(prev_execute_data) = EG(current_execute_data); + i_init_execute_data(execute_data, op_array, return_value, EG(active_symbol_table) ? VM_FRAME_TOP_CODE : VM_FRAME_TOP_FUNCTION TSRMLS_CC); + zend_execute_ex(execute_data TSRMLS_CC); } static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) { vm_frame_kind frame_kind = EX(frame_kind); + zend_execute_data *prev_nested_call; EG(current_execute_data) = EX(prev_execute_data); @@ -392,22 +404,22 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table) TSRMLS_CC); } - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(op_array)->prototype) { - zval_ptr_dtor((zval*)EX(op_array)->prototype); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(func)->op_array.prototype) { + zval_ptr_dtor((zval*)EX(func)->op_array.prototype); } - zend_vm_stack_free((char*)execute_data TSRMLS_CC); + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); execute_data = EG(current_execute_data); + EX(call) = prev_nested_call; EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; EG(active_symbol_table) = EX(symbol_table); - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { - if (EX(call)->is_ctor_result_used) { + if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) { + if (!(EX(opline)->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -424,10 +436,6 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EG(scope) = EX(scope); EG(called_scope) = EX(called_scope); - EX(call)--; - - zend_vm_stack_clear_multiple(1 TSRMLS_CC); - if (UNEXPECTED(EG(exception) != NULL)) { zend_op *opline = EX(opline); zend_throw_exception_internal(NULL TSRMLS_CC); @@ -442,16 +450,16 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_LEAVE(); } else if (frame_kind == VM_FRAME_NESTED_CODE) { zend_detach_symbol_table(execute_data); - destroy_op_array(EX(op_array) TSRMLS_CC); - efree(EX(op_array)); - zend_vm_stack_free((char*)execute_data TSRMLS_CC); + destroy_op_array(&EX(func)->op_array TSRMLS_CC); + efree(EX(func)); + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); execute_data = EG(current_execute_data); + EX(call) = prev_nested_call; zend_attach_symbol_table(execute_data); - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION_LEAVE(); @@ -463,6 +471,7 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) } else { if (frame_kind == VM_FRAME_TOP_FUNCTION) { i_free_compiled_variables(execute_data TSRMLS_CC); + zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); } else /* if (frame_kind == VM_FRAME_TOP_CODE) */ { zend_array *symbol_table = EX(symbol_table); zend_execute_data *old_execute_data; @@ -470,7 +479,7 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) zend_detach_symbol_table(execute_data); old_execute_data = EX(prev_execute_data); while (old_execute_data) { - if (old_execute_data->op_array) { + if (old_execute_data->func && ZEND_USER_CODE(old_execute_data->func->op_array.type)) { if (old_execute_data->symbol_table == symbol_table) { zend_attach_symbol_table(old_execute_data); } @@ -479,24 +488,47 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) old_execute_data = old_execute_data->prev_execute_data; } } - if ((EX(op_array)->fn_flags & ZEND_ACC_CLOSURE) && EX(op_array)->prototype) { - zval_ptr_dtor((zval*)EX(op_array)->prototype); + if ((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) && EX(func)->op_array.prototype) { + zval_ptr_dtor((zval*)EX(func)->op_array.prototype); + } + prev_nested_call = EX(prev_nested_call); + zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); + + if (EG(current_execute_data)) { + EG(current_execute_data)->call = prev_nested_call; } - zend_vm_stack_free((char*)execute_data TSRMLS_CC); EG(opline_ptr) = NULL; ZEND_VM_RETURN(); } } -static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_function *fbc = EX(function_state).function; - zend_object *object; - zend_uint num_args; + + ZEND_VM_SET_OPCODE(opline->op1.jmp_addr); + ZEND_VM_CONTINUE(); +} + +static int ZEND_FASTCALL ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *tmp = EX_VAR(opline->result.var); + + SAVE_OPLINE(); + ZVAL_EMPTY_STRING(tmp); + /*CHECK_EXCEPTION();*/ + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_execute_data *call = EX(call); + zend_function *fbc = call->func; SAVE_OPLINE(); - object = EX(call)->object; + call->flags = ZEND_CALL_DONE; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name->val, fbc->common.function_name->val); @@ -513,7 +545,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR } if (fbc->common.scope && !(fbc->common.fn_flags & ZEND_ACC_STATIC) && - !object) { + !call->object) { if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { /* FIXME: output identifiers properly */ @@ -528,39 +560,32 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR } } - if (EXPECTED(EX(call)->num_additional_args == 0)) { - num_args = opline->extended_value; - EX(function_state).arguments = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_LONG(EX(function_state).arguments, num_args); - } else { - num_args = opline->extended_value + EX(call)->num_additional_args; - EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC); - } LOAD_OPLINE(); - if (fbc->type == ZEND_INTERNAL_FUNCTION) { + if (UNEXPECTED(fbc->type == ZEND_INTERNAL_FUNCTION)) { int should_change_scope = 0; zval *ret; if (fbc->common.scope) { should_change_scope = 1; - Z_OBJ(EG(This)) = object; + Z_OBJ(EG(This)) = call->object; /* TODO: we don't set scope if we call an object method ??? */ /* See: ext/pdo_sqlite/tests/pdo_fetch_func_001.phpt */ #if 1 - EG(scope) = (object) ? NULL : fbc->common.scope; + EG(scope) = (call->object) ? NULL : fbc->common.scope; #else EG(scope) = fbc->common.scope; #endif - EG(called_scope) = EX(call)->called_scope; + EG(called_scope) = call->called_scope; } if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { zend_uint i; - zval *p = EX(function_state).arguments - num_args; + zval *p = ZEND_CALL_ARG(call, 1); - for (i = 0; i < num_args; ++i, ++p) { + for (i = 0; i < call->num_args; ++i) { zend_verify_arg_type(fbc, i + 1, p, 0 TSRMLS_CC); + p++; } if (UNEXPECTED(EG(exception) != NULL)) { if (RETURN_VALUE_USED(opline)) { @@ -580,11 +605,16 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR if (!zend_execute_internal) { /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(num_args, ret TSRMLS_CC); + fbc->internal_function.handler(call->num_args, ret TSRMLS_CC); } else { zend_execute_internal(execute_data, NULL TSRMLS_CC); } + zend_vm_stack_free_args(call TSRMLS_CC); + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + if (!RETURN_VALUE_USED(opline)) { zval_ptr_dtor(ret); } @@ -594,12 +624,12 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR } else { goto fcall_end; } - } else if (fbc->type == ZEND_USER_FUNCTION) { + } else if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { zval *return_value = NULL; - Z_OBJ(EG(This)) = object; + Z_OBJ(EG(This)) = call->object; EG(scope) = fbc->common.scope; - EG(called_scope) = EX(call)->called_scope; + EG(called_scope) = call->called_scope; EG(active_symbol_table) = NULL; EG(active_op_array) = &fbc->op_array; if (RETURN_VALUE_USED(opline)) { @@ -609,40 +639,50 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR Z_VAR_FLAGS_P(return_value) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; } - if (UNEXPECTED((EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { if (RETURN_VALUE_USED(opline)) { - zend_generator_create_zval(EG(active_op_array), EX_VAR(opline->result.var) TSRMLS_CC); + zend_generator_create_zval(&fbc->op_array, EX_VAR(opline->result.var) TSRMLS_CC); } - } else if (EXPECTED(zend_execute_ex == execute_ex)) { - if (EXPECTED(EG(exception) == NULL)) { - i_create_execute_data_from_op_array(EG(active_op_array), return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + } else { + call->prev_execute_data = EG(current_execute_data); + i_init_execute_data(call, &fbc->op_array, return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); + + if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); + } else { + execute_ex(call TSRMLS_CC); } - } else { - zend_execute(EG(active_op_array), return_value TSRMLS_CC); } EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; if (UNEXPECTED(EG(active_symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC); } EG(active_symbol_table) = EX(symbol_table); } else { /* ZEND_OVERLOADED_FUNCTION */ - Z_OBJ(EG(This)) = object; + Z_OBJ(EG(This)) = call->object; //??? EG(scope) = NULL; EG(scope) = fbc->common.scope; - EG(called_scope) = EX(call)->called_scope; + EG(called_scope) = call->called_scope; ZVAL_NULL(EX_VAR(opline->result.var)); /* Not sure what should be done here if it's a static method */ - if (EXPECTED(object != NULL)) { - object->handlers->call_method(fbc->common.function_name, object, num_args, EX_VAR(opline->result.var) TSRMLS_CC); + if (EXPECTED(call->object != NULL)) { + call->object->handlers->call_method(fbc->common.function_name, call->object, call->num_args, EX_VAR(opline->result.var) TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } + zend_vm_stack_free_args(call TSRMLS_CC); + + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { STR_RELEASE(fbc->common.function_name); } @@ -659,8 +699,8 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR fcall_end_change_scope: if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { - if (EX(call)->is_ctor_result_used) { + if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) { + if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -668,8 +708,6 @@ fcall_end_change_scope: } } if (!Z_DELREF(EG(This))) { - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); @@ -680,12 +718,6 @@ fcall_end_change_scope: EG(called_scope) = EX(called_scope); fcall_end: - EX(function_state).function = (zend_function *) EX(op_array); - EX(function_state).arguments = NULL; - EX(call)--; - - zend_vm_stack_clear_multiple(1 TSRMLS_CC); - if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { @@ -697,31 +729,6 @@ fcall_end: ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - - ZEND_VM_SET_OPCODE(opline->op1.jmp_addr); - ZEND_VM_CONTINUE(); -} - -static int ZEND_FASTCALL ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *tmp = EX_VAR(opline->result.var); - - SAVE_OPLINE(); - ZVAL_EMPTY_STRING(tmp); - /*CHECK_EXCEPTION();*/ - ZEND_VM_NEXT_OPCODE(); -} - -static int ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - EX(function_state).function = EX(call)->fbc; - return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); -} - static int ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { /* The generator object is stored in EX(return_value) */ @@ -743,7 +750,7 @@ static int ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS SAVE_OPLINE(); args = get_zval_ptr(opline->op1_type, &opline->op1, execute_data, &free_op1, BP_VAR_R); - arg_num = opline->op2.num + EX(call)->num_additional_args + 1; + arg_num = EX(call)->num_args + 1; send_again: switch (Z_TYPE_P(args)) { @@ -752,7 +759,7 @@ send_again: zval *arg, *top; zend_string *name; - ZEND_VM_STACK_GROW_IF_NEEDED(zend_hash_num_elements(ht)); + zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht) TSRMLS_DC); if (opline->op1_type != IS_CONST && opline->op1_type != IS_TMP_VAR && Z_IMMUTABLE_P(args)) { int i; @@ -760,7 +767,7 @@ send_again: /* check if any of arguments are going to be passed by reference */ for (i = 0; i < zend_hash_num_elements(ht); i++) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num + i)) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num + i)) { separate = 1; break; } @@ -779,8 +786,8 @@ send_again: ZEND_VM_NEXT_OPCODE(); } - top = zend_vm_stack_top_inc(TSRMLS_C); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + top = ZEND_CALL_ARG(EX(call), arg_num); + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (!Z_IMMUTABLE_P(args)) { ZVAL_MAKE_REF(arg); Z_ADDREF_P(arg); @@ -789,12 +796,13 @@ send_again: ZVAL_DUP(top, arg); } } else if (Z_ISREF_P(arg)) { +//TODO: change into ZVAL_COPY()??? ZVAL_DUP(top, Z_REFVAL_P(arg)); } else { ZVAL_COPY(top, arg); } - EX(call)->num_additional_args++; + EX(call)->num_args++; arg_num++; } ZEND_HASH_FOREACH_END(); @@ -828,7 +836,7 @@ send_again: } for (; iter->funcs->valid(iter TSRMLS_CC) == SUCCESS; ++arg_num) { - zval *arg; + zval *arg, *top; if (UNEXPECTED(EG(exception) != NULL)) { goto unpack_iter_dtor; @@ -856,13 +864,13 @@ send_again: zval_dtor(&key); } - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, arg_num)) { + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { zend_error( E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" " by unpacking a Traversable, passing by-value instead", arg_num, - EX(call)->fbc->common.scope ? EX(call)->fbc->common.scope->name->val : "", - EX(call)->fbc->common.scope ? "::" : "", - EX(call)->fbc->common.function_name->val + EX(call)->func->common.scope ? EX(call)->func->common.scope->name->val : "", + EX(call)->func->common.scope ? "::" : "", + EX(call)->func->common.function_name->val ); } @@ -872,9 +880,10 @@ send_again: if (Z_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } - ZEND_VM_STACK_GROW_IF_NEEDED(1); - zend_vm_stack_push(arg TSRMLS_CC); - EX(call)->num_additional_args++; + zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1 TSRMLS_DC); + top = ZEND_CALL_ARG(EX(call), arg_num); + ZVAL_COPY_VALUE(top, arg); + EX(call)->num_args++; iter->funcs->move_forward(iter TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { @@ -903,25 +912,18 @@ static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); SAVE_OPLINE(); - if (UNEXPECTED(arg_num > arg_count)) { + if (UNEXPECTED(arg_num > EX(num_args))) { zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC); - } else { - zval *var_ptr; - zval *param = arguments - arg_count + arg_num - 1; + CHECK_EXCEPTION(); + } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, param, opline->extended_value TSRMLS_CC); - } - var_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(var_ptr))) Z_DELREF_P(var_ptr); - ZVAL_COPY(var_ptr, param); + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + CHECK_EXCEPTION(); } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -929,21 +931,21 @@ static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); + zend_uint arg_count = EX(num_args); zval *params; SAVE_OPLINE(); params = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(params))) Z_DELREF_P(params); if (arg_num <= arg_count) { - zval *param = arguments - arg_count + arg_num - 1; + zval *param; + array_init_size(params, arg_count - arg_num + 1); - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { do { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, param, opline->extended_value TSRMLS_CC); + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); param++; @@ -990,21 +992,19 @@ static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } ZEND_VM_JMP(opline->op2.jmp_addr); } else { - call_slot *call = EX(call_slots) + opline->extended_value; + /* We are not handling overloaded classes right now */ + EX(call) = zend_vm_stack_push_call_frame( + constructor, opline->extended_value, + RETURN_VALUE_USED(opline) ? + ZEND_CALL_CTOR : (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_UNUSED), + Z_CE_P(EX_VAR(opline->op1.var)), + Z_OBJ(object_zval), + EX(call) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); } - /* We are not handling overloaded classes right now */ - call->fbc = constructor; - call->object = Z_OBJ(object_zval); - call->called_scope = Z_CE_P(EX_VAR(opline->op1.var)); - call->num_additional_args = 0; - call->is_ctor_call = 1; - call->is_ctor_result_used = RETURN_VALUE_USED(opline); - EX(call) = call; - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -1056,7 +1056,7 @@ static int ZEND_FASTCALL ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR static int ZEND_FASTCALL ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name->val, EX(op_array)->function_name->val); + zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name->val, EX(func)->op_array.function_name->val); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } @@ -1064,7 +1064,7 @@ static int ZEND_FASTCALL ZEND_EXT_STMT_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_statement_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_statement_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1074,7 +1074,7 @@ static int ZEND_FASTCALL ZEND_EXT_FCALL_BEGIN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_begin_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_begin_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1084,7 +1084,7 @@ static int ZEND_FASTCALL ZEND_EXT_FCALL_END_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR { SAVE_OPLINE(); if (!EG(no_extensions)) { - zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, EX(op_array) TSRMLS_CC); + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, EX(func) TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1095,7 +1095,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_CLASS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR USE_OPLINE SAVE_OPLINE(); - Z_CE_P(EX_VAR(opline->result.var)) = do_bind_class(EX(op_array), opline, EG(class_table), 0 TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = do_bind_class(&EX(func)->op_array, opline, EG(class_table), 0 TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -1105,7 +1105,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_INHERITED_CLASS_SPEC_HANDLER(ZEND_OPCODE_ USE_OPLINE SAVE_OPLINE(); - Z_CE_P(EX_VAR(opline->result.var)) = do_bind_inherited_class(EX(op_array), opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); + Z_CE_P(EX_VAR(opline->result.var)) = do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -1119,7 +1119,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_INHERITED_CLASS_DELAYED_SPEC_HANDLER(ZEND if ((zce = zend_hash_find(EG(class_table), Z_STR_P(opline->op2.zv))) == NULL || ((orig_zce = zend_hash_find(EG(class_table), Z_STR_P(opline->op1.zv))) != NULL && Z_CE_P(zce) != Z_CE_P(orig_zce))) { - do_bind_inherited_class(EX(op_array), opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); + do_bind_inherited_class(&EX(func)->op_array, opline, EG(class_table), Z_CE_P(EX_VAR(opline->extended_value)), 0 TSRMLS_CC); } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1130,7 +1130,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_FUNCTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER USE_OPLINE SAVE_OPLINE(); - do_bind_function(EX(op_array), opline, EG(function_table), 0); + do_bind_function(&EX(func)->op_array, opline, EG(function_table), 0); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -1202,45 +1202,37 @@ static int ZEND_FASTCALL ZEND_BIND_TRAITS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes; + zend_uint op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes; int i; zend_uint catch_op_num = 0, finally_op_num = 0, finally_op_end = 0; - zval *stack_frame; - /* Figure out where the next stack frame (which maybe contains pushed - * arguments that have to be dtor'ed) starts */ - stack_frame = zend_vm_stack_frame_base(execute_data); - - /* If the exception was thrown during a function call there might be - * arguments pushed to the stack that have to be dtor'ed. */ - while (zend_vm_stack_top(TSRMLS_C) != stack_frame) { - zval *stack_zval_p = zend_vm_stack_pop(TSRMLS_C); - zval_ptr_dtor(stack_zval_p); - } - - for (i=0; i<EG(active_op_array)->last_try_catch; i++) { - if (EG(active_op_array)->try_catch_array[i].try_op > op_num) { + for (i = 0; i < EX(func)->op_array.last_try_catch; i++) { + if (EX(func)->op_array.try_catch_array[i].try_op > op_num) { /* further blocks will not be relevant... */ break; } - if (op_num < EG(active_op_array)->try_catch_array[i].catch_op) { - catch_op_num = EX(op_array)->try_catch_array[i].catch_op; + if (op_num < EX(func)->op_array.try_catch_array[i].catch_op) { + catch_op_num = EX(func)->op_array.try_catch_array[i].catch_op; } - if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) { - finally_op_num = EX(op_array)->try_catch_array[i].finally_op; + if (op_num < EX(func)->op_array.try_catch_array[i].finally_op) { + finally_op_num = EX(func)->op_array.try_catch_array[i].finally_op; } - if (op_num >= EG(active_op_array)->try_catch_array[i].finally_op && - op_num < EG(active_op_array)->try_catch_array[i].finally_end) { - finally_op_end = EG(active_op_array)->try_catch_array[i].finally_end; + if (op_num >= EX(func)->op_array.try_catch_array[i].finally_op && + op_num < EX(func)->op_array.try_catch_array[i].finally_end) { + finally_op_end = EX(func)->op_array.try_catch_array[i].finally_end; } } - if (EX(call) >= EX(call_slots)) { - call_slot *call = EX(call); + if (EX(call)) { + zend_execute_data *call = EX(call); do { + /* If the exception was thrown during a function call there might be + * arguments pushed to the stack that have to be dtor'ed. */ + zend_vm_stack_free_args(EX(call) TSRMLS_CC); + if (call->object) { - if (call->is_ctor_call) { - if (call->is_ctor_result_used) { + if (call->flags & ZEND_CALL_CTOR) { + if (!(call->flags & ZEND_CALL_CTOR_RESULT_UNUSED)) { GC_REFCOUNT(call->object)--; } if (GC_REFCOUNT(call->object) == 1) { @@ -1249,21 +1241,22 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER } OBJ_RELEASE(call->object); } - call--; - } while (call >= EX(call_slots)); - EX(call) = NULL; + EX(call) = call->prev_nested_call; + zend_vm_stack_free_call_frame(call TSRMLS_CC); + call = EX(call); + } while (call); } - for (i=0; i<EX(op_array)->last_brk_cont; i++) { - if (EX(op_array)->brk_cont_array[i].start < 0) { + for (i = 0; i < EX(func)->op_array.last_brk_cont; i++) { + if (EX(func)->op_array.brk_cont_array[i].start < 0) { continue; - } else if (EX(op_array)->brk_cont_array[i].start > op_num) { + } else if (EX(func)->op_array.brk_cont_array[i].start > op_num) { /* further blocks will not be relevant... */ break; - } else if (op_num < EX(op_array)->brk_cont_array[i].brk) { + } else if (op_num < EX(func)->op_array.brk_cont_array[i].brk) { if (!catch_op_num || - catch_op_num >= EX(op_array)->brk_cont_array[i].brk) { - zend_op *brk_opline = &EX(op_array)->opcodes[EX(op_array)->brk_cont_array[i].brk]; + catch_op_num >= EX(func)->op_array.brk_cont_array[i].brk) { + zend_op *brk_opline = &EX(func)->op_array.opcodes[EX(func)->op_array.brk_cont_array[i].brk]; if (brk_opline->opcode == ZEND_SWITCH_FREE) { if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { @@ -1299,7 +1292,7 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER EX(delayed_exception) = EG(exception); EG(exception) = NULL; EX(fast_ret) = NULL; - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[finally_op_num]); ZEND_VM_CONTINUE(); } else if (catch_op_num) { if (finally_op_end && catch_op_num > finally_op_end) { @@ -1309,14 +1302,14 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER EX(delayed_exception) = NULL; } } - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op_num]); ZEND_VM_CONTINUE(); } else { if (EX(delayed_exception)) { zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC); EX(delayed_exception) = NULL; } - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } else { return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -1347,7 +1340,7 @@ static int ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS case ZEND_USER_OPCODE_CONTINUE: ZEND_VM_CONTINUE(); case ZEND_USER_OPCODE_RETURN: - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } else { return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -1381,7 +1374,7 @@ static int ZEND_FASTCALL ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (opline->extended_value && UNEXPECTED(EG(prev_exception) != NULL)) { /* in case of unhandled exception jump to catch block instead of finally */ - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); } EX(fast_ret) = opline + 1; @@ -1400,15 +1393,15 @@ static int ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) USE_OPLINE if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); } else { EG(exception) = EX(delayed_exception); EX(delayed_exception) = NULL; if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); - } else if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { + } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) { return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } else { return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -1459,32 +1452,32 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; + zval *function_name, *func; if (IS_CONST == IS_CONST) { - function_name_ptr = function_name = (zval*)(opline->op2.zv+1); + function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { zend_string *lcname; + zend_class_entry *called_scope; + zend_object *object; + zval *function_name_ptr; SAVE_OPLINE(); function_name_ptr = function_name = opline->op2.zv; @@ -1503,36 +1496,23 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } STR_FREE(lcname); - call->fbc = Z_FUNC_P(func); - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; } else if (IS_CONST != IS_CONST && IS_CONST != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { - if (call->object) { - GC_REFCOUNT(call->object)++; + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object TSRMLS_CC) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; } if (IS_CONST == IS_VAR && 0 && Z_REFCOUNT_P(function_name) == 1 && - call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { + fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - call->fbc->common.prototype = (zend_function*)function_name_ptr; + fbc->common.prototype = (zend_function*)function_name_ptr; } else { } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { @@ -1555,50 +1535,49 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } if (Z_TYPE_P(obj) == IS_STRING) { - call->object = NULL; - call->called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); - if (UNEXPECTED(call->called_scope == NULL)) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); + if (UNEXPECTED(called_scope == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - if (call->called_scope->get_static_method) { - call->fbc = call->called_scope->get_static_method(call->called_scope, Z_STR_P(method) TSRMLS_CC); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(call->called_scope, Z_STR_P(method), NULL TSRMLS_CC); + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", call->called_scope->name->val, Z_STRVAL_P(method)); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); } } else { - call->called_scope = Z_OBJCE_P(obj); - call->object = Z_OBJ_P(obj); + called_scope = Z_OBJCE_P(obj); + object = Z_OBJ_P(obj); - call->fbc = Z_OBJ_HT_P(obj)->get_method(&call->object, Z_STR_P(method), NULL TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(method)); + fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(object), Z_STRVAL_P(method)); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(object)++; /* For $this pointer */ } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else { if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ + ZEND_VM_CONTINUE(); /* Never reached */ } + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } } @@ -1608,30 +1587,51 @@ static int ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC USE_OPLINE zval *func_name; zval *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; func_name = opline->op2.zv + 1; if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if ((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL) { func_name++; if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(func_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); + + ZEND_VM_NEXT_OPCODE(); +} + +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, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); } @@ -1640,30 +1640,24 @@ static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *arguments = EX(prev_execute_data)->function_state.arguments; - zend_uint arg_count = Z_LVAL_P(arguments); - zval *var_ptr; + zval *param; SAVE_OPLINE(); - var_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (UNEXPECTED(Z_REFCOUNTED_P(var_ptr))) Z_DELREF_P(var_ptr); - if (arg_num > arg_count) { - ZVAL_COPY_VALUE(var_ptr, opline->op2.zv); - if (Z_OPT_CONSTANT_P(var_ptr)) { - zval_update_constant(var_ptr, 0 TSRMLS_CC); + param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); + if (arg_num > EX(num_args)) { + ZVAL_COPY_VALUE(param, opline->op2.zv); + if (Z_OPT_CONSTANT_P(param)) { + zval_update_constant(param, 0 TSRMLS_CC); } else { /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */ - if (UNEXPECTED(Z_OPT_COPYABLE_P(var_ptr))) { - zval_copy_ctor_func(var_ptr); + if (UNEXPECTED(Z_OPT_COPYABLE_P(param))) { + zval_copy_ctor_func(param); } } - } else { - zval *param = arguments - arg_count + arg_num - 1; - ZVAL_COPY(var_ptr, param); } - if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type((zend_function *) EX(op_array), arg_num, var_ptr, opline->extended_value TSRMLS_CC); + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); } CHECK_EXCEPTION(); @@ -1677,8 +1671,8 @@ static int ZEND_FASTCALL ZEND_BRK_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, - EX(op_array), execute_data TSRMLS_CC); - ZEND_VM_JMP(EX(op_array)->opcodes + el->brk); + &EX(func)->op_array, execute_data TSRMLS_CC); + ZEND_VM_JMP(EX(func)->op_array.opcodes + el->brk); } static int ZEND_FASTCALL ZEND_CONT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -1688,8 +1682,8 @@ static int ZEND_FASTCALL ZEND_CONT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->op1.opline_num, - EX(op_array), execute_data TSRMLS_CC); - ZEND_VM_JMP(EX(op_array)->opcodes + el->cont); + &EX(func)->op_array, execute_data TSRMLS_CC); + ZEND_VM_JMP(EX(func)->op_array.opcodes + el->cont); } static int ZEND_FASTCALL ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -1700,9 +1694,9 @@ static int ZEND_FASTCALL ZEND_GOTO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) SAVE_OPLINE(); el = zend_brk_cont(Z_LVAL_P(opline->op2.zv), opline->extended_value, - EX(op_array), execute_data TSRMLS_CC); + &EX(func)->op_array, execute_data TSRMLS_CC); - brk_opline = EX(op_array)->opcodes + el->brk; + brk_opline = EX(func)->op_array.opcodes + el->brk; if (brk_opline->opcode == ZEND_SWITCH_FREE) { if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { @@ -1786,32 +1780,32 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; + zval *function_name, *func; if (IS_TMP_VAR == IS_CONST) { - function_name_ptr = function_name = (zval*)(opline->op2.zv+1); + function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { zend_string *lcname; zend_free_op free_op2; + zend_class_entry *called_scope; + zend_object *object; + zval *function_name_ptr; SAVE_OPLINE(); function_name_ptr = function_name = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); @@ -1830,37 +1824,23 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } STR_FREE(lcname); zval_dtor(free_op2.var); - - call->fbc = Z_FUNC_P(func); - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; } else if (IS_TMP_VAR != IS_CONST && IS_TMP_VAR != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { - if (call->object) { - GC_REFCOUNT(call->object)++; + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object TSRMLS_CC) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; } if (IS_TMP_VAR == IS_VAR && 1 && Z_REFCOUNT_P(function_name) == 1 && - call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { + fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - call->fbc->common.prototype = (zend_function*)function_name_ptr; + fbc->common.prototype = (zend_function*)function_name_ptr; } else { zval_dtor(free_op2.var); } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else if (IS_TMP_VAR != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { @@ -1883,51 +1863,49 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } if (Z_TYPE_P(obj) == IS_STRING) { - call->object = NULL; - call->called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); - if (UNEXPECTED(call->called_scope == NULL)) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); + if (UNEXPECTED(called_scope == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - if (call->called_scope->get_static_method) { - call->fbc = call->called_scope->get_static_method(call->called_scope, Z_STR_P(method) TSRMLS_CC); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(call->called_scope, Z_STR_P(method), NULL TSRMLS_CC); + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", call->called_scope->name->val, Z_STRVAL_P(method)); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); } } else { - call->called_scope = Z_OBJCE_P(obj); - call->object = Z_OBJ_P(obj); + called_scope = Z_OBJCE_P(obj); + object = Z_OBJ_P(obj); - call->fbc = Z_OBJ_HT_P(obj)->get_method(&call->object, Z_STR_P(method), NULL TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(method)); + fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(object), Z_STRVAL_P(method)); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(object)++; /* For $this pointer */ } } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - zval_dtor(free_op2.var); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else { if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ + ZEND_VM_CONTINUE(); /* Never reached */ } + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } } @@ -1975,32 +1953,32 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; + zval *function_name, *func; if (IS_VAR == IS_CONST) { - function_name_ptr = function_name = (zval*)(opline->op2.zv+1); + function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { zend_string *lcname; zend_free_op free_op2; + zend_class_entry *called_scope; + zend_object *object; + zval *function_name_ptr; SAVE_OPLINE(); function_name_ptr = function_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); @@ -2019,37 +1997,23 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } STR_FREE(lcname); zval_ptr_dtor_nogc(free_op2.var); - - call->fbc = Z_FUNC_P(func); - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; } else if (IS_VAR != IS_CONST && IS_VAR != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { - if (call->object) { - GC_REFCOUNT(call->object)++; + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object TSRMLS_CC) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; } if (IS_VAR == IS_VAR && (free_op2.var != NULL) && Z_REFCOUNT_P(function_name) == 1 && - call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { + fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - call->fbc->common.prototype = (zend_function*)function_name_ptr; + fbc->common.prototype = (zend_function*)function_name_ptr; } else { zval_ptr_dtor_nogc(free_op2.var); } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else if (IS_VAR != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { @@ -2072,51 +2036,49 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } if (Z_TYPE_P(obj) == IS_STRING) { - call->object = NULL; - call->called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); - if (UNEXPECTED(call->called_scope == NULL)) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); + if (UNEXPECTED(called_scope == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - if (call->called_scope->get_static_method) { - call->fbc = call->called_scope->get_static_method(call->called_scope, Z_STR_P(method) TSRMLS_CC); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(call->called_scope, Z_STR_P(method), NULL TSRMLS_CC); + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", call->called_scope->name->val, Z_STRVAL_P(method)); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); } } else { - call->called_scope = Z_OBJCE_P(obj); - call->object = Z_OBJ_P(obj); + called_scope = Z_OBJCE_P(obj); + object = Z_OBJ_P(obj); - call->fbc = Z_OBJ_HT_P(obj)->get_method(&call->object, Z_STR_P(method), NULL TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(method)); + fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(object), Z_STRVAL_P(method)); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(object)++; /* For $this pointer */ } } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - zval_ptr_dtor_nogc(free_op2.var); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else { if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ + ZEND_VM_CONTINUE(); /* Never reached */ } + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } } @@ -2202,32 +2164,32 @@ static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *function_name_ptr, *function_name, *func; - call_slot *call = EX(call_slots) + opline->result.num; + zend_function *fbc; + zval *function_name, *func; if (IS_CV == IS_CONST) { - function_name_ptr = function_name = (zval*)(opline->op2.zv+1); + function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(function_name))) == NULL)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - call->fbc = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), call->fbc); + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); } - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, NULL, NULL, EX(call) TSRMLS_CC); /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { zend_string *lcname; + zend_class_entry *called_scope; + zend_object *object; + zval *function_name_ptr; SAVE_OPLINE(); function_name_ptr = function_name = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); @@ -2246,36 +2208,23 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } STR_FREE(lcname); - call->fbc = Z_FUNC_P(func); - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); + fbc = Z_FUNC_P(func); + called_scope = NULL; + object = NULL; } else if (IS_CV != IS_CONST && IS_CV != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { - if (call->object) { - GC_REFCOUNT(call->object)++; + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &called_scope, &fbc, &object TSRMLS_CC) == SUCCESS) { + if (object) { + GC_REFCOUNT(object)++; } if (IS_CV == IS_VAR && 0 && Z_REFCOUNT_P(function_name) == 1 && - call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { + fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - call->fbc->common.prototype = (zend_function*)function_name_ptr; + fbc->common.prototype = (zend_function*)function_name_ptr; } else { } - - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { @@ -2298,50 +2247,49 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } if (Z_TYPE_P(obj) == IS_STRING) { - call->object = NULL; - call->called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); - if (UNEXPECTED(call->called_scope == NULL)) { + object = NULL; + called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, 0 TSRMLS_CC); + if (UNEXPECTED(called_scope == NULL)) { CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - if (call->called_scope->get_static_method) { - call->fbc = call->called_scope->get_static_method(call->called_scope, Z_STR_P(method) TSRMLS_CC); + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(call->called_scope, Z_STR_P(method), NULL TSRMLS_CC); + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", call->called_scope->name->val, Z_STRVAL_P(method)); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); } } else { - call->called_scope = Z_OBJCE_P(obj); - call->object = Z_OBJ_P(obj); + called_scope = Z_OBJCE_P(obj); + object = Z_OBJ_P(obj); - call->fbc = Z_OBJ_HT_P(obj)->get_method(&call->object, Z_STR_P(method), NULL TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(method)); + fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(object), Z_STRVAL_P(method)); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(object)++; /* For $this pointer */ } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); } else { if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ + ZEND_VM_CONTINUE(); /* Never reached */ } + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, object, EX(call) TSRMLS_CC); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } } @@ -2557,34 +2505,6 @@ static int ZEND_FASTCALL ZEND_JMPNZ_EX_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A ZEND_VM_JMP(opline); } -static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - - zval *fname = opline->op1.zv; - zval *func; - call_slot *call = EX(call_slots) + opline->op2.num; - - if (CACHED_PTR(Z_CACHE_SLOT_P(fname))) { - EX(function_state).function = CACHED_PTR(Z_CACHE_SLOT_P(fname)); - } else if (UNEXPECTED((func = zend_hash_find(EG(function_table), Z_STR_P(fname))) == NULL)) { - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(fname)); - } else { - EX(function_state).function = Z_FUNC_P(func); - CACHE_PTR(Z_CACHE_SLOT_P(fname), EX(function_state).function); - } - - call->fbc = EX(function_state).function; - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - - return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); -} - static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -2705,22 +2625,23 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *value, *top; + zval *value, *arg; SAVE_OPLINE(); - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num); } } value = opline->op1.zv; - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY_VALUE(top, value); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY_VALUE(arg, value); if (IS_CONST == IS_CONST) { - if (UNEXPECTED(Z_OPT_COPYABLE_P(top))) { - zval_copy_ctor_func(top); + if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { + zval_copy_ctor_func(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -2999,23 +2920,23 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA return_value = EX_VAR(opline->result.var); } - EX(function_state).function = (zend_function *) new_op_array; + EX(call) = zend_vm_stack_push_call_frame( + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } + EX(call)->prev_execute_data = EG(current_execute_data); + i_init_execute_data(EX(call), new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - i_create_execute_data_from_op_array(new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); ZEND_VM_ENTER(); } else { - zend_execute(new_op_array, return_value TSRMLS_CC); + execute_ex(EG(current_execute_data) TSRMLS_CC); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -3789,7 +3710,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -3798,7 +3720,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -3807,24 +3729,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_CONST == IS_CONST && IS_CONST == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_CONST != IS_CONST && IS_CONST == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_CONST != IS_UNUSED) { @@ -3840,20 +3755,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_CONST != IS_CONST) { @@ -3866,33 +3781,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_CONST != IS_CONST) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -4336,7 +4255,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE if (IS_CONST != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { @@ -4757,7 +4676,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -4766,7 +4686,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -4775,24 +4695,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_CONST == IS_CONST && IS_TMP_VAR == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_CONST != IS_CONST && IS_TMP_VAR == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op2; @@ -4808,20 +4721,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_TMP_VAR != IS_CONST) { @@ -4834,33 +4747,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_CONST != IS_CONST) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -5022,7 +4939,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_CONST != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { @@ -5593,7 +5510,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -5602,7 +5520,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -5611,24 +5529,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_CONST == IS_CONST && IS_VAR == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_CONST != IS_CONST && IS_VAR == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_VAR != IS_UNUSED) { zend_free_op free_op2; @@ -5644,20 +5555,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_VAR != IS_CONST) { @@ -5670,33 +5581,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_CONST != IS_CONST) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -6009,7 +5924,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_CONST != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { @@ -6288,7 +6203,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -6297,7 +6213,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -6306,24 +6222,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_CONST == IS_CONST && IS_UNUSED == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_CONST != IS_CONST && IS_UNUSED == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_UNUSED != IS_UNUSED) { @@ -6339,20 +6248,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_UNUSED == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_UNUSED == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_UNUSED == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_UNUSED != IS_CONST) { @@ -6365,33 +6274,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_CONST != IS_CONST) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -6681,7 +6594,7 @@ static int ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER } closure_is_static = Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC; - closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->function_state.function->common.fn_flags & ZEND_ACC_STATIC; + closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->call->func->common.fn_flags & ZEND_ACC_STATIC; if (closure_is_static || closure_is_being_defined_inside_static_context) { zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc), EG(called_scope), NULL TSRMLS_CC); } else { @@ -6713,7 +6626,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL if (IS_CONST != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { @@ -7119,7 +7032,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -7128,7 +7042,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -7137,24 +7051,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_CONST == IS_CONST && IS_CV == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_CONST != IS_CONST && IS_CV == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_CV != IS_UNUSED) { @@ -7170,20 +7077,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_CV != IS_CONST) { @@ -7196,33 +7103,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_CONST != IS_CONST) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -7238,7 +7149,7 @@ static int ZEND_FASTCALL ZEND_CATCH_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A /* Check whether an exception has been thrown, if not, jump over code */ zend_exception_restore(TSRMLS_C); if (EG(exception) == NULL) { - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->extended_value]); ZEND_VM_CONTINUE(); /* CHECK_ME */ } if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { @@ -7262,7 +7173,7 @@ static int ZEND_FASTCALL ZEND_CATCH_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A zend_throw_exception_internal(NULL TSRMLS_CC); HANDLE_EXCEPTION(); } - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]); + ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->extended_value]); ZEND_VM_CONTINUE(); /* CHECK_ME */ } } @@ -7436,7 +7347,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A if (IS_CONST != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { @@ -7906,22 +7817,23 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *value, *top; + zval *value, *arg; zend_free_op free_op1; SAVE_OPLINE(); - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num); } } value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY_VALUE(top, value); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY_VALUE(arg, value); if (IS_TMP_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_COPYABLE_P(top))) { - zval_copy_ctor_func(top); + if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { + zval_copy_ctor_func(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -8202,23 +8114,23 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HAND return_value = EX_VAR(opline->result.var); } - EX(function_state).function = (zend_function *) new_op_array; + EX(call) = zend_vm_stack_push_call_frame( + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } + EX(call)->prev_execute_data = EG(current_execute_data); + i_init_execute_data(EX(call), new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - i_create_execute_data_from_op_array(new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); ZEND_VM_ENTER(); } else { - zend_execute(new_op_array, return_value TSRMLS_CC); + execute_ex(EG(current_execute_data) TSRMLS_CC); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -9079,8 +8991,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO USE_OPLINE zval *function_name; zend_free_op free_op1; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -9095,48 +9009,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO } object = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CONST != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CONST != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CONST == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -9449,7 +9362,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { @@ -9914,8 +9827,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE USE_OPLINE zval *function_name; zend_free_op free_op1, free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -9930,32 +9845,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE } object = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (IS_TMP_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_dtor(free_op2.var); HANDLE_EXCEPTION(); @@ -9963,15 +9854,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_TMP_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_TMP_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -10135,7 +10049,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { @@ -10750,8 +10664,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE USE_OPLINE zval *function_name; zend_free_op free_op1, free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -10766,32 +10682,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE } object = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (IS_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2.var); HANDLE_EXCEPTION(); @@ -10799,15 +10691,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -11122,7 +11037,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { @@ -11687,7 +11602,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { @@ -12136,8 +12051,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_ USE_OPLINE zval *function_name; zend_free_op free_op1; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -12152,48 +12069,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_ } object = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CV != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CV != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CV == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -12355,7 +12271,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { @@ -13044,18 +12960,19 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) static int ZEND_FASTCALL zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; zend_free_op free_op1; varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); zval_ptr_dtor_nogc(free_op1.var); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (IS_VAR == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -13065,7 +12982,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND { USE_OPLINE zend_free_op free_op1; - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ @@ -13073,7 +12990,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } else { - if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } @@ -13090,15 +13007,18 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND if (IS_VAR == IS_CV) { Z_ADDREF_P(varptr); } - zend_vm_stack_push(varptr TSRMLS_CC); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY_VALUE(arg, varptr); } else { if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY(top, varptr); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY(arg, varptr); zval_ptr_dtor_nogc(free_op1.var); } CHECK_EXCEPTION(); @@ -13109,7 +13029,7 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG { USE_OPLINE zend_free_op free_op1; - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); varptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); @@ -13118,23 +13038,24 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_error_noreturn(E_ERROR, "Only variables can be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; if (IS_VAR == IS_VAR && UNEXPECTED(varptr == &EG(error_zval))) { - ZVAL_NEW_REF(top, &EG(uninitialized_zval)); + ZVAL_NEW_REF(arg, &EG(uninitialized_zval)); ZEND_VM_NEXT_OPCODE(); } if (Z_ISREF_P(varptr)) { Z_ADDREF_P(varptr); - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); } else if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { - ZVAL_COPY_VALUE(top, varptr); - ZVAL_MAKE_REF(top); + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_MAKE_REF(arg); } else { ZVAL_MAKE_REF(varptr); Z_ADDREF_P(varptr); - ZVAL_REF(top, Z_REF_P(varptr)); + ZVAL_REF(arg, Z_REF_P(varptr)); } if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}; @@ -13144,24 +13065,25 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; zend_free_op free_op1; - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { return ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); zval_ptr_dtor_nogc(free_op1.var); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (IS_VAR == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -13453,23 +13375,23 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND return_value = EX_VAR(opline->result.var); } - EX(function_state).function = (zend_function *) new_op_array; + EX(call) = zend_vm_stack_push_call_frame( + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } + EX(call)->prev_execute_data = EG(current_execute_data); + i_init_execute_data(EX(call), new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - i_create_execute_data_from_op_array(new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); ZEND_VM_ENTER(); } else { - zend_execute(new_op_array, return_value TSRMLS_CC); + execute_ex(EG(current_execute_data) TSRMLS_CC); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -15334,8 +15256,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO USE_OPLINE zval *function_name; zend_free_op free_op1; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -15350,48 +15274,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO } object = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CONST != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CONST != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CONST == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op1.var); @@ -15404,7 +15327,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -15413,7 +15337,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -15422,24 +15346,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_VAR == IS_CONST && IS_CONST == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_VAR != IS_CONST && IS_CONST == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_CONST != IS_UNUSED) { @@ -15455,20 +15372,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_CONST != IS_CONST) { @@ -15481,33 +15398,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_VAR != IS_CONST) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -16187,7 +16108,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { @@ -17562,8 +17483,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE USE_OPLINE zval *function_name; zend_free_op free_op1, free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -17578,32 +17501,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE } object = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (IS_TMP_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_dtor(free_op2.var); HANDLE_EXCEPTION(); @@ -17611,15 +17510,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_TMP_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_TMP_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); zval_ptr_dtor_nogc(free_op1.var); @@ -17633,7 +17555,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -17642,7 +17565,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -17651,24 +17574,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_VAR == IS_CONST && IS_TMP_VAR == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_VAR != IS_CONST && IS_TMP_VAR == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_TMP_VAR != IS_UNUSED) { zend_free_op free_op2; @@ -17684,20 +17600,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_TMP_VAR != IS_CONST) { @@ -17710,33 +17626,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_VAR != IS_CONST) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -18169,7 +18089,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR if (IS_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { @@ -19758,8 +19678,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE USE_OPLINE zval *function_name; zend_free_op free_op1, free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -19774,32 +19696,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE } object = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (IS_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2.var); HANDLE_EXCEPTION(); @@ -19807,15 +19705,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); zval_ptr_dtor_nogc(free_op1.var); @@ -19829,7 +19750,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -19838,7 +19760,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -19847,24 +19769,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_VAR == IS_CONST && IS_VAR == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_VAR != IS_CONST && IS_VAR == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_VAR != IS_UNUSED) { zend_free_op free_op2; @@ -19880,20 +19795,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_VAR != IS_CONST) { @@ -19906,33 +19821,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_VAR != IS_CONST) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -20516,7 +20435,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR if (IS_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { @@ -21295,7 +21214,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -21304,7 +21224,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -21313,24 +21233,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_VAR == IS_CONST && IS_UNUSED == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_VAR != IS_CONST && IS_UNUSED == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_UNUSED != IS_UNUSED) { @@ -21346,20 +21259,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_UNUSED == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_UNUSED == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_UNUSED == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_UNUSED != IS_CONST) { @@ -21372,33 +21285,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_VAR != IS_CONST) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -21713,7 +21630,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER if (IS_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { @@ -23129,8 +23046,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_ USE_OPLINE zval *function_name; zend_free_op free_op1; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -23145,48 +23064,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_ } object = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CV != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CV != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CV == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op1.var); @@ -23199,7 +23117,8 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ USE_OPLINE zval *function_name; zend_class_entry *ce; - call_slot *call = EX(call_slots) + opline->result.num; + zend_object *object; + zend_function *fbc; SAVE_OPLINE(); @@ -23208,7 +23127,7 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv))) { ce = CACHED_PTR(Z_CACHE_SLOT_P(opline->op1.zv)); } else { - ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, opline->extended_value TSRMLS_CC); + ce = zend_fetch_class_by_name(Z_STR_P(opline->op1.zv), opline->op1.zv + 1, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } @@ -23217,24 +23136,17 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ } CACHE_PTR(Z_CACHE_SLOT_P(opline->op1.zv), ce); } - call->called_scope = ce; } else { ce = Z_CE_P(EX_VAR(opline->op1.var)); - - if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - call->called_scope = EG(called_scope); - } else { - call->called_scope = ce; - } } if (IS_VAR == IS_CONST && IS_CV == IS_CONST && CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { - call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); + fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); } else if (IS_VAR != IS_CONST && IS_CV == IS_CONST && - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(opline->op2.zv), ce))) { /* do nothing */ } else if (IS_CV != IS_UNUSED) { @@ -23250,20 +23162,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ } if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); + fbc = ce->get_static_method(ce, Z_STR_P(function_name) TSRMLS_CC); } else { - call->fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(call->fbc == NULL)) { + if (UNEXPECTED(fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name->val, Z_STRVAL_P(function_name)); } if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(Z_CACHE_SLOT_P(function_name), call->fbc); + CACHE_PTR(Z_CACHE_SLOT_P(function_name), fbc); } else { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, call->fbc); + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), ce, fbc); } } if (IS_CV != IS_CONST) { @@ -23276,33 +23188,37 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ if (Z_OBJ(EG(This)) && Z_OBJCE(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name->val); } - call->fbc = ce->constructor; + fbc = ce->constructor; } - if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { - call->object = NULL; - } else { - if (Z_OBJ(EG(This)) && - Z_OBJ_HT(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); - } else { - /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name->val, call->fbc->common.function_name->val); + object = NULL; + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (Z_OBJ(EG(This))) { + if (Z_OBJ_HT(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", fbc->common.scope->name->val, fbc->common.function_name->val); + } } + object = Z_OBJ(EG(This)); + GC_REFCOUNT(object)++; } - call->object = Z_OBJ(EG(This)); - if (call->object) { - GC_REFCOUNT(call->object)++; + } + + if (IS_VAR != IS_CONST) { + /* previous opcode is ZEND_FETCH_CLASS */ + if ((opline-1)->extended_value == ZEND_FETCH_CLASS_PARENT || (opline-1)->extended_value == ZEND_FETCH_CLASS_SELF) { + ce = EG(called_scope); } } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, ce, object, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -23732,7 +23648,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG if (IS_VAR != IS_UNUSED) { zend_free_op free_op1; - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { @@ -24706,8 +24622,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O USE_OPLINE zval *function_name; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -24722,48 +24640,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O } object = _get_obj_zval_ptr_unused(TSRMLS_C); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { + + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (IS_CONST != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + if (IS_CONST != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CONST == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -25190,7 +25107,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL if (IS_UNUSED != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { @@ -26079,8 +25996,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC USE_OPLINE zval *function_name; zend_free_op free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -26095,32 +26014,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC } object = _get_obj_zval_ptr_unused(TSRMLS_C); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - if (IS_TMP_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_dtor(free_op2.var); HANDLE_EXCEPTION(); @@ -26128,15 +26023,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_TMP_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_TMP_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -26467,7 +26385,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER if (IS_UNUSED != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { @@ -27356,8 +27274,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC USE_OPLINE zval *function_name; zend_free_op free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -27372,32 +27292,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC } object = _get_obj_zval_ptr_unused(TSRMLS_C); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - if (IS_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2.var); HANDLE_EXCEPTION(); @@ -27405,15 +27301,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -27744,7 +27663,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER if (IS_UNUSED != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { @@ -28260,7 +28179,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND if (IS_UNUSED != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { @@ -29143,8 +29062,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO USE_OPLINE zval *function_name; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -29159,48 +29080,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO } object = _get_obj_zval_ptr_unused(TSRMLS_C); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CV != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CV != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CV == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -29528,7 +29448,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_UNUSED != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { @@ -30187,18 +30107,19 @@ static int ZEND_FASTCALL ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) static int ZEND_FASTCALL zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (IS_CV == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -30208,7 +30129,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ @@ -30216,7 +30137,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } else { - if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } @@ -30233,15 +30154,18 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL if (IS_CV == IS_CV) { Z_ADDREF_P(varptr); } - zend_vm_stack_push(varptr TSRMLS_CC); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY_VALUE(arg, varptr); } else { if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); - ZVAL_COPY(top, varptr); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; + ZVAL_COPY(arg, varptr); } CHECK_EXCEPTION(); @@ -30252,7 +30176,7 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; SAVE_OPLINE(); varptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); @@ -30261,23 +30185,24 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS zend_error_noreturn(E_ERROR, "Only variables can be passed by reference"); } - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; if (IS_CV == IS_VAR && UNEXPECTED(varptr == &EG(error_zval))) { - ZVAL_NEW_REF(top, &EG(uninitialized_zval)); + ZVAL_NEW_REF(arg, &EG(uninitialized_zval)); ZEND_VM_NEXT_OPCODE(); } if (Z_ISREF_P(varptr)) { Z_ADDREF_P(varptr); - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); } else if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { - ZVAL_COPY_VALUE(top, varptr); - ZVAL_MAKE_REF(top); + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_MAKE_REF(arg); } else { ZVAL_MAKE_REF(varptr); Z_ADDREF_P(varptr); - ZVAL_REF(top, Z_REF_P(varptr)); + ZVAL_REF(arg, Z_REF_P(varptr)); } ZEND_VM_NEXT_OPCODE(); @@ -30286,24 +30211,25 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *varptr, *top; + zval *varptr, *arg; - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.num)) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { return ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } } varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - top = zend_vm_stack_top_inc(TSRMLS_C); + arg = ZEND_CALL_ARG(EX(call), opline->op2.num); + EX(call)->num_args = opline->op2.num; if (Z_ISREF_P(varptr)) { - ZVAL_COPY(top, Z_REFVAL_P(varptr)); + ZVAL_COPY(arg, Z_REFVAL_P(varptr)); } else { - ZVAL_COPY_VALUE(top, varptr); + ZVAL_COPY_VALUE(arg, varptr); if (IS_CV == IS_CV) { - if (Z_OPT_REFCOUNTED_P(varptr)) Z_ADDREF_P(varptr); + if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); } } ZEND_VM_NEXT_OPCODE(); @@ -30582,23 +30508,23 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL return_value = EX_VAR(opline->result.var); } - EX(function_state).function = (zend_function *) new_op_array; + EX(call) = zend_vm_stack_push_call_frame( + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EX(call) TSRMLS_CC); if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } + EX(call)->prev_execute_data = EG(current_execute_data); + i_init_execute_data(EX(call), new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { - i_create_execute_data_from_op_array(new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); ZEND_VM_ENTER(); } else { - zend_execute(new_op_array, return_value TSRMLS_CC); + execute_ex(EG(current_execute_data) TSRMLS_CC); } - EX(function_state).function = (zend_function *) EX(op_array); - EG(opline_ptr) = &EX(opline); - EG(active_op_array) = EX(op_array); + EG(active_op_array) = &EX(func)->op_array; destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); if (UNEXPECTED(EG(exception) != NULL)) { @@ -32312,8 +32238,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD USE_OPLINE zval *function_name; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -32328,48 +32256,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD } object = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CONST != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CONST == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CONST != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CONST == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CONST == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -32951,7 +32878,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A if (IS_CV != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { @@ -34354,8 +34281,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ USE_OPLINE zval *function_name; zend_free_op free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -34370,32 +34299,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ } object = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (IS_TMP_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_TMP_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_dtor(free_op2.var); HANDLE_EXCEPTION(); @@ -34403,15 +34308,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_TMP_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_TMP_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_TMP_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_dtor(free_op2.var); @@ -34846,7 +34774,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG if (IS_CV != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { @@ -36432,8 +36360,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ USE_OPLINE zval *function_name; zend_free_op free_op2; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -36448,32 +36378,8 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ } object = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); - - if (IS_VAR != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; - - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_VAR == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } - } - } else { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op2.var); HANDLE_EXCEPTION(); @@ -36481,15 +36387,38 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); + + if (IS_VAR != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_VAR == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_VAR == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); + } + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); zval_ptr_dtor_nogc(free_op2.var); @@ -37075,7 +37004,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG if (IS_CV != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { @@ -38138,7 +38067,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_CV != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { @@ -39551,8 +39480,10 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H USE_OPLINE zval *function_name; - call_slot *call = EX(call_slots) + opline->result.num; zval *object; + zend_function *fbc; + zend_class_entry *called_scope; + zend_object *obj; SAVE_OPLINE(); @@ -39567,48 +39498,47 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H } object = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC); - call->object = Z_TYPE_P(object) == IS_OBJECT ? Z_OBJ_P(object) : NULL; - if (EXPECTED(call->object != NULL)) { - call->called_scope = zend_get_class_entry(call->object TSRMLS_CC); + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { + if (UNEXPECTED(EG(exception) != NULL)) { - if (IS_CV != IS_CONST || - (call->fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope)) == NULL) { - zend_object *object = call->object; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); + } - if (UNEXPECTED(object->handlers->get_method == NULL)) { - zend_error_noreturn(E_ERROR, "Object does not support method calls"); - } + obj = Z_OBJ_P(object); + called_scope = zend_get_class_entry(obj TSRMLS_CC); - /* First, locate the function. */ - call->fbc = object->handlers->get_method(&call->object, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_P(function_name)); - } - if (IS_CV == IS_CONST && - EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && - EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(call->object == object)) { - CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), call->called_scope, call->fbc); - } + if (IS_CV != IS_CONST || + (fbc = CACHED_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope)) == NULL) { + zend_object *orig_obj = obj; + + if (UNEXPECTED(obj->handlers->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); } - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + /* First, locate the function. */ + fbc = obj->handlers->get_method(&obj, Z_STR_P(function_name), ((IS_CV == IS_CONST) ? (opline->op2.zv + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(obj), Z_STRVAL_P(function_name)); + } + if (IS_CV == IS_CONST && + EXPECTED(fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(obj == orig_obj)) { + CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), called_scope, fbc); } - zend_error_noreturn(E_ERROR, "Call to a member function %s() on %s", Z_STRVAL_P(function_name), zend_get_type_by_const(Z_TYPE_P(object))); } - if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + obj = NULL; } else { - GC_REFCOUNT(call->object)++; /* For $this pointer */ + GC_REFCOUNT(obj)++; /* For $this pointer */ } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + EX(call) = zend_vm_stack_push_call_frame( + fbc, opline->extended_value, 0, called_scope, obj, EX(call) TSRMLS_CC); CHECK_EXCEPTION(); @@ -40039,7 +39969,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS if (IS_CV != IS_UNUSED) { - if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { /* Constants and temporary variables aren't yieldable by reference, * but we still allow them with a notice. */ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { @@ -41678,56 +41608,56 @@ void zend_init_opcodes_handlers(void) ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER, - ZEND_DO_FCALL_SPEC_CONST_HANDLER, - ZEND_DO_FCALL_SPEC_CONST_HANDLER, - ZEND_DO_FCALL_SPEC_CONST_HANDLER, - ZEND_DO_FCALL_SPEC_CONST_HANDLER, - ZEND_DO_FCALL_SPEC_CONST_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_INIT_FCALL_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_FCALL_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_FCALL_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_FCALL_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_INIT_FCALL_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, ZEND_RETURN_SPEC_CONST_HANDLER, ZEND_RETURN_SPEC_CONST_HANDLER, ZEND_RETURN_SPEC_CONST_HANDLER, @@ -44438,6 +44368,6 @@ ZEND_API void zend_vm_set_opcode_handler(zend_op* op) ZEND_API int zend_do_fcall(ZEND_OPCODE_HANDLER_ARGS) { - return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index fa976cb678..41a834de95 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -33,10 +33,21 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *execute_data TSRMLS_DC) ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array, zval *return_value TSRMLS_DC) { + zend_execute_data *execute_data; + if (EG(exception) != NULL) { return; - } - zend_{%EXECUTOR_NAME%}_ex(i_create_execute_data_from_op_array(op_array, return_value, EG(active_symbol_table) ? VM_FRAME_TOP_CODE : VM_FRAME_TOP_FUNCTION TSRMLS_CC) TSRMLS_CC); + } + + if (EG(current_execute_data) && EG(current_execute_data)->call) { + execute_data = EG(current_execute_data)->call; + } else { + execute_data = zend_vm_stack_push_call_frame( + (zend_function*)op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), NULL TSRMLS_CC); + } + EX(prev_execute_data) = EG(current_execute_data); + i_init_execute_data(execute_data, op_array, return_value, EG(active_symbol_table) ? VM_FRAME_TOP_CODE : VM_FRAME_TOP_FUNCTION TSRMLS_CC); + zend_{%EXECUTOR_NAME%}_ex(execute_data TSRMLS_CC); } {%EXTERNAL_EXECUTOR%} diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index df127039c6..8859228aad 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -83,7 +83,7 @@ const char *zend_vm_opcodes_map[169] = { "ZEND_END_SILENCE", "ZEND_INIT_FCALL_BY_NAME", "ZEND_DO_FCALL", - "ZEND_DO_FCALL_BY_NAME", + "ZEND_INIT_FCALL", "ZEND_RETURN", "ZEND_RECV", "ZEND_RECV_INIT", diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index df499f946b..7d74a807b5 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -84,7 +84,7 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode); #define ZEND_END_SILENCE 58 #define ZEND_INIT_FCALL_BY_NAME 59 #define ZEND_DO_FCALL 60 -#define ZEND_DO_FCALL_BY_NAME 61 +#define ZEND_INIT_FCALL 61 #define ZEND_RETURN 62 #define ZEND_RECV 63 #define ZEND_RECV_INIT 64 diff --git a/build/libtool.m4 b/build/libtool.m4 index 56658ccbb4..4d948b9078 100644 --- a/build/libtool.m4 +++ b/build/libtool.m4 @@ -1532,10 +1532,6 @@ dgux*) shlibpath_var=LD_LIBRARY_PATH ;; -freebsd1*) - dynamic_linker=no - ;; - freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. @@ -5843,10 +5839,6 @@ _LT_EOF _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; - freebsd1*) - _LT_AC_TAGVAR(ld_shlibs, $1)=no - ;; - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little diff --git a/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp b/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp index 36a3a8d20d..c13a432605 100644 --- a/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp +++ b/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp @@ -217,10 +217,10 @@ U_CFUNC PHP_FUNCTION(rbbi_get_binary_rules) RETURN_FALSE; } - char *ret_rules = static_cast<char*>(emalloc(rules_len + 1)); - memcpy(ret_rules, rules, rules_len); - ret_rules[rules_len] = '\0'; + zend_string *ret_rules = STR_ALLOC(rules_len, 0); + memcpy(ret_rules->val, rules, rules_len); + ret_rules->val[rules_len] = '\0'; - RETURN_STRINGL(ret_rules, rules_len, 0); + RETURN_STR(ret_rules); } #endif diff --git a/ext/intl/idn/idn.c b/ext/intl/idn/idn.c index f59fea494b..5b463ea58a 100644 --- a/ext/intl/idn/idn.c +++ b/ext/intl/idn/idn.c @@ -140,38 +140,39 @@ static void php_intl_idn_to_46(INTERNAL_FUNCTION_PARAMETERS, UIDNA *uts46; int32_t len; int32_t buffer_capac = 255; /* no domain name may exceed this */ - char *buffer = emalloc(buffer_capac); + zend_string *buffer = STR_ALLOC(buffer_capac, 0); UIDNAInfo info = UIDNA_INFO_INITIALIZER; int buffer_used = 0; uts46 = uidna_openUTS46(option, &status); if (php_intl_idn_check_status(status, "failed to open UIDNA instance", mode TSRMLS_CC) == FAILURE) { - efree(buffer); + STR_FREE(buffer); RETURN_FALSE; } if (mode == INTL_IDN_TO_ASCII) { len = uidna_nameToASCII_UTF8(uts46, domain, (int32_t)domain_len, - buffer, buffer_capac, &info, &status); + buffer->val, buffer_capac, &info, &status); } else { len = uidna_nameToUnicodeUTF8(uts46, domain, (int32_t)domain_len, - buffer, buffer_capac, &info, &status); + buffer->val, buffer_capac, &info, &status); } if (php_intl_idn_check_status(status, "failed to convert name", mode TSRMLS_CC) == FAILURE) { uidna_close(uts46); - efree(buffer); + STR_FREE(buffer); RETURN_FALSE; } if (len >= 255) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "ICU returned an unexpected length"); } - buffer[len] = '\0'; + buffer->val[len] = '\0'; + buffer->len = len; if (info.errors == 0) { - RETVAL_STRINGL(buffer, len, 0); + RETVAL_STR(buffer); buffer_used = 1; } else { RETVAL_FALSE; @@ -180,21 +181,20 @@ static void php_intl_idn_to_46(INTERNAL_FUNCTION_PARAMETERS, if (idna_info) { if (buffer_used) { /* used in return_value then */ zval_addref_p(return_value); - add_assoc_zval_ex(idna_info, "result", sizeof("result"), return_value); + add_assoc_zval_ex(idna_info, "result", sizeof("result")-1, return_value); } else { - zval *zv; - ALLOC_INIT_ZVAL(zv); - ZVAL_STRINGL(zv, buffer, len, 0); + zval zv; + ZVAL_STR(&zv, buffer); buffer_used = 1; - add_assoc_zval_ex(idna_info, "result", sizeof("result"), zv); + add_assoc_zval_ex(idna_info, "result", sizeof("result")-1, &zv); } add_assoc_bool_ex(idna_info, "isTransitionalDifferent", - sizeof("isTransitionalDifferent"), info.isTransitionalDifferent); - add_assoc_long_ex(idna_info, "errors", sizeof("errors"), (long)info.errors); + sizeof("isTransitionalDifferent")-1, info.isTransitionalDifferent); + add_assoc_long_ex(idna_info, "errors", sizeof("errors")-1, (long)info.errors); } if (!buffer_used) { - efree(buffer); + STR_FREE(buffer); } uidna_close(uts46); diff --git a/ext/intl/locale/locale_methods.c b/ext/intl/locale/locale_methods.c index f58f24a36e..01cbddd062 100644 --- a/ext/intl/locale/locale_methods.c +++ b/ext/intl/locale/locale_methods.c @@ -272,8 +272,7 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int* grOffset = findOffset( LOC_GRANDFATHERED , loc_name ); if( grOffset >= 0 ){ if( strcmp(tag_name , LOC_LANG_TAG)==0 ){ - tag_value = estrdup(loc_name); - return tag_value; + return estrdup(loc_name); } else { /* Since Grandfathered , no value , do nothing , retutn NULL */ return NULL; @@ -283,8 +282,8 @@ static char* get_icu_value_internal( const char* loc_name , char* tag_name, int* if( fromParseLocale==1 ){ /* Handle singletons */ if( strcmp(tag_name , LOC_LANG_TAG)==0 ){ - if( strlen(loc_name)>1 && (isIDPrefix(loc_name) ==1 ) ){ - return (char *)loc_name; + if( strlen(loc_name)>1 && (isIDPrefix(loc_name) == 1) ){ + return estrdup(loc_name); } } @@ -504,6 +503,14 @@ static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAME RETURN_FALSE; } + if(loc_name_len > ULOC_FULLNAME_CAPACITY) { + /* See bug 67397: overlong locale names cause trouble in uloc_getDisplayName */ + spprintf(&msg , 0, "locale_get_display_%s : name too long", tag_name ); + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, msg , 1 TSRMLS_CC ); + efree(msg); + RETURN_FALSE; + } + if(loc_name_len == 0) { loc_name = intl_locale_get_default(TSRMLS_C); } diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp index fc7315aefc..1c18c6c969 100644 --- a/ext/intl/msgformat/msgformat_helpers.cpp +++ b/ext/intl/msgformat/msgformat_helpers.cpp @@ -183,10 +183,10 @@ static HashTable *umsg_parse_format(MessageFormatter_object *mfo, if (name_part.getType() == UMSGPAT_PART_TYPE_ARG_NAME) { UnicodeString argName = mp.getSubstring(name_part); - if ((storedType = zend_hash_str_find_ptr(ret, (char*)argName.getBuffer(), argName.length())) == NULL) { + if ((storedType = (Formattable::Type*)zend_hash_str_find_ptr(ret, (char*)argName.getBuffer(), argName.length())) == NULL) { /* not found already; create new entry in HT */ Formattable::Type bogusType = Formattable::kObject; - if ((storedType = zend_hash_str_update_mem(ret, (char*)argName.getBuffer(), argName.length(), + if ((storedType = (Formattable::Type*)zend_hash_str_update_mem(ret, (char*)argName.getBuffer(), argName.length(), (void*)&bogusType, sizeof(bogusType))) == NULL) { intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR, "Write to argument types hash table failed", 0 TSRMLS_CC); @@ -200,10 +200,10 @@ static HashTable *umsg_parse_format(MessageFormatter_object *mfo, "Found part with negative number", 0 TSRMLS_CC); continue; } - if ((storedType = zend_hash_index_find_ptr(ret, (ulong)argNumber)) == NULL) { + if ((storedType = (Formattable::Type*)zend_hash_index_find_ptr(ret, (ulong)argNumber)) == NULL) { /* not found already; create new entry in HT */ Formattable::Type bogusType = Formattable::kObject; - if ((storedType = zend_hash_index_update_mem(ret, (ulong)argNumber, (void*)&bogusType, sizeof(bogusType))) == NULL) { + if ((storedType = (Formattable::Type*)zend_hash_index_update_mem(ret, (ulong)argNumber, (void*)&bogusType, sizeof(bogusType))) == NULL) { intl_errors_set(&err, U_MEMORY_ALLOCATION_ERROR, "Write to argument types hash table failed", 0 TSRMLS_CC); continue; diff --git a/ext/intl/tests/bug62082.phpt b/ext/intl/tests/bug62082.phpt index e6ca73e300..dab1252afd 100644 --- a/ext/intl/tests/bug62082.phpt +++ b/ext/intl/tests/bug62082.phpt @@ -10,6 +10,7 @@ var_dump(locale_get_display_name(str_repeat("a", 300), null)); var_dump(locale_get_display_name(str_repeat("a", 512), null)); var_dump(locale_get_display_name(str_repeat("a", 600), null)); --EXPECT-- -string(300) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -string(512) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -string(600) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +bool(false) +bool(false) +bool(false) + diff --git a/ext/intl/tests/bug67397.phpt b/ext/intl/tests/bug67397.phpt new file mode 100644 index 0000000000..b2b2911f8a --- /dev/null +++ b/ext/intl/tests/bug67397.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #67397 (Buffer overflow in locale_get_display_name->uloc_getDisplayName (libicu 4.8.1)) +--SKIPIF-- +<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?> +--FILE-- +<?php + +function ut_main() +{ + $ret = var_export(ut_loc_get_display_name(str_repeat('*', 256), 'en_us'), true); + $ret .= "\n"; + $ret .= var_export(intl_get_error_message(), true); + return $ret; +} + +include_once( 'ut_common.inc' ); +ut_run(); +?> +--EXPECTF-- +false +'locale_get_display_name : name too long: U_ILLEGAL_ARGUMENT_ERROR' diff --git a/ext/intl/tests/locale_parse_locale2.phpt b/ext/intl/tests/locale_parse_locale2.phpt index 6012862a48..30cc8cc0ae 100644 --- a/ext/intl/tests/locale_parse_locale2.phpt +++ b/ext/intl/tests/locale_parse_locale2.phpt @@ -63,7 +63,8 @@ function ut_main() //Some Invalid Tags: 'de-419-DE', 'a-DE', - 'ar-a-aaa-b-bbb-a-ccc' + 'ar-a-aaa-b-bbb-a-ccc', + 'x-AAAAAA', ); @@ -201,3 +202,6 @@ No values found from Locale parsing. --------------------- ar-a-aaa-b-bbb-a-ccc: language : 'ar' , +--------------------- +x-AAAAAA: +private0 : 'AAAAAA' , diff --git a/ext/intl/timezone/timezone_methods.cpp b/ext/intl/timezone/timezone_methods.cpp index cde090c243..2b1bcfab92 100644 --- a/ext/intl/timezone/timezone_methods.cpp +++ b/ext/intl/timezone/timezone_methods.cpp @@ -245,9 +245,9 @@ U_CFUNC PHP_FUNCTION(intltz_create_time_zone_id_enumeration) /* must come before zpp because zpp would convert the arg in the stack to 0 */ if (ZEND_NUM_ARGS() == 3) { - zval **dummy, **zvoffset; + zval *dummy, *zvoffset; arg3isnull = zend_get_parameters_ex(3, &dummy, &dummy, &zvoffset) - != FAILURE && Z_TYPE_PP(zvoffset) == IS_NULL; + != FAILURE && Z_TYPE_P(zvoffset) == IS_NULL; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s!l", diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 7baebd36d8..a3b6d08578 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -1958,7 +1958,6 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char * case ZEND_ASSIGN: case ZEND_ASSIGN_REF: case ZEND_DO_FCALL: - case ZEND_DO_FCALL_BY_NAME: if (ZEND_RESULT_TYPE(opline) == IS_VAR) { #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO ZEND_RESULT_TYPE(opline) |= EXT_TYPE_UNUSED; diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c index 26af07a189..480e4f92fe 100644 --- a/ext/opcache/Optimizer/compact_literals.c +++ b/ext/opcache/Optimizer/compact_literals.c @@ -108,8 +108,8 @@ static void optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_c end = opline + op_array->last; while (opline < end) { switch (opline->opcode) { - case ZEND_DO_FCALL: - LITERAL_INFO(opline->op1.constant, LITERAL_FUNC, 1, 1, 1); + case ZEND_INIT_FCALL: + LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 1); break; case ZEND_INIT_FCALL_BY_NAME: if (ZEND_OP2_TYPE(opline) == IS_CONST) { diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c index cd27704de5..3f755bed18 100644 --- a/ext/opcache/Optimizer/optimize_func_calls.c +++ b/ext/opcache/Optimizer/optimize_func_calls.c @@ -12,9 +12,15 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx zend_op *opline = op_array->opcodes; zend_op *end = opline + op_array->last; int call = 0; - void *checkpoint = zend_arena_checkpoint(ctx->arena); - optimizer_call_info *call_stack = zend_arena_calloc(&ctx->arena, op_array->nested_calls + 1, sizeof(optimizer_call_info)); + void *checkpoint; + optimizer_call_info *call_stack; + if (op_array->last < 2) { + return; + } + + checkpoint = zend_arena_checkpoint(ctx->arena); + call_stack = zend_arena_calloc(&ctx->arena, op_array->last / 2, sizeof(optimizer_call_info)); while (opline < end) { switch (opline->opcode) { case ZEND_INIT_FCALL_BY_NAME: @@ -31,23 +37,27 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx case ZEND_NEW: case ZEND_INIT_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL: + case ZEND_INIT_FCALL: call_stack[call].opline = opline; call++; break; - case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_FCALL: call--; if (call_stack[call].func && call_stack[call].opline) { zend_op *fcall = call_stack[call].opline; - opline->opcode = ZEND_DO_FCALL; - ZEND_OP1_TYPE(opline) = IS_CONST; - opline->op1.constant = fcall->op2.constant + 1; - Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]); - literal_dtor(&ZEND_OP2_LITERAL(fcall)); - if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { + if (fcall->opcode == ZEND_INIT_FCALL_BY_NAME) { + fcall->opcode = ZEND_INIT_FCALL; + literal_dtor(&ZEND_OP2_LITERAL(fcall)); + fcall->op2.constant = fcall->op2.constant + 1; + } else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { + fcall->opcode = ZEND_INIT_FCALL; + literal_dtor(&op_array->literals[fcall->op2.constant]); literal_dtor(&op_array->literals[fcall->op2.constant + 2]); + fcall->op2.constant = fcall->op2.constant + 1; + } else { + ZEND_ASSERT(0); } - MAKE_NOP(fcall); } else if (opline->extended_value == 0 && call_stack[call].opline && call_stack[call].opline->opcode == ZEND_INIT_FCALL_BY_NAME && @@ -55,12 +65,9 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx zend_op *fcall = call_stack[call].opline; - opline->opcode = ZEND_DO_FCALL; - ZEND_OP1_TYPE(opline) = IS_CONST; - opline->op1.constant = fcall->op2.constant + 1; - Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]); + fcall->opcode = ZEND_INIT_FCALL; literal_dtor(&ZEND_OP2_LITERAL(fcall)); - MAKE_NOP(fcall); + fcall->op2.constant = fcall->op2.constant + 1; } call_stack[call].func = NULL; call_stack[call].opline = NULL; @@ -79,21 +86,21 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx } break; case ZEND_SEND_VAL: - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) { + if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) && call_stack[call - 1].func) { if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) { /* We won't convert it into_DO_FCALL to emit error at run-time */ call_stack[call - 1].opline = NULL; } else { - opline->extended_value = ZEND_DO_FCALL; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; } } break; case ZEND_SEND_VAR: - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) { + if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) && call_stack[call - 1].func) { if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) { opline->opcode = ZEND_SEND_REF; } - opline->extended_value = ZEND_DO_FCALL; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; } break; case ZEND_SEND_VAR_NO_REF: @@ -104,12 +111,12 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND; } else { opline->opcode = ZEND_SEND_VAR; - opline->extended_value = ZEND_DO_FCALL; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; } } break; case ZEND_SEND_REF: - if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) { + if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND && call_stack[call - 1].func) { /* We won't handle run-time pass by reference */ call_stack[call - 1].opline = NULL; } diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c index 73fa0d02f9..de97f64db8 100644 --- a/ext/opcache/Optimizer/pass1_5.c +++ b/ext/opcache/Optimizer/pass1_5.c @@ -320,22 +320,25 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { #endif break; - case ZEND_DO_FCALL: + case ZEND_INIT_FCALL: /* define("name", scalar); */ if (collect_constants && - opline->extended_value == 2 && - ZEND_OP1_TYPE(opline) == IS_CONST && - Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && - Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("define")-1 && - zend_binary_strcasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), "define", sizeof("define")-1) == 0 && - (opline-1)->opcode == ZEND_SEND_VAL && - ZEND_OP1_TYPE(opline-1) == IS_CONST && - Z_TYPE(ZEND_OP1_LITERAL(opline-1)) <= IS_STRING && - (opline-2)->opcode == ZEND_SEND_VAL && - ZEND_OP1_TYPE(opline-2) == IS_CONST && - Z_TYPE(ZEND_OP1_LITERAL(opline-2)) == IS_STRING) { - zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline-2), &ZEND_OP1_LITERAL(opline-1)); - break; + ZEND_OP2_TYPE(opline) == IS_CONST && + Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING && + Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("define")-1 && + zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), "define", sizeof("define")-1) == 0) { + + if ((opline+1)->opcode == ZEND_SEND_VAL && + ZEND_OP1_TYPE(opline+1) == IS_CONST && + Z_TYPE(ZEND_OP1_LITERAL(opline+1)) == IS_STRING && + (opline+2)->opcode == ZEND_SEND_VAL && + ZEND_OP1_TYPE(opline+2) == IS_CONST && + Z_TYPE(ZEND_OP1_LITERAL(opline+2)) <= IS_STRING && + (opline+3)->opcode == ZEND_DO_FCALL) { + + zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline+1), &ZEND_OP1_LITERAL(opline+2)); + break; + } } else { /* don't colllect constants after any other function call */ collect_constants = 0; @@ -348,40 +351,42 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { is_callable(x) extension_loaded(x) */ - if (opline->extended_value == 1 && (opline - 1)->opcode == ZEND_SEND_VAL && - ZEND_OP1_TYPE(opline - 1) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline - 1)) == IS_STRING && - ZEND_OP1_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) { - if ((Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("function_exists")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + if ((opline + 1)->opcode == ZEND_SEND_VAL && + (opline + 2)->opcode == ZEND_DO_FCALL && + ZEND_OP1_TYPE(opline + 1) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline + 1)) == IS_STRING && + ZEND_OP2_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) { + if ((Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("function_exists")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "function_exists", sizeof("function_exists")-1)) || - (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("is_callable")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("is_callable")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "is_callable", sizeof("is_callable")))) { zend_internal_function *func; char *lc_name = zend_str_tolower_dup( - Z_STRVAL(ZEND_OP1_LITERAL(opline - 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline - 1))); + Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1))); - if ((func = zend_hash_str_find_ptr(EG(function_table), lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline - 1)))) != NULL && + if ((func = zend_hash_str_find_ptr(EG(function_table), lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)))) != NULL && func->type == ZEND_INTERNAL_FUNCTION && func->module->type == MODULE_PERSISTENT) { zval t; ZVAL_BOOL(&t, 1); - if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) { - literal_dtor(&ZEND_OP1_LITERAL(opline - 1)); - MAKE_NOP((opline - 1)); - literal_dtor(&ZEND_OP1_LITERAL(opline)); + if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) { + literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); + literal_dtor(&ZEND_OP1_LITERAL(opline + 1)); + MAKE_NOP(opline + 1); + MAKE_NOP(opline + 2); } } efree(lc_name); - } else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("extension_loaded")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + } else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("extension_loaded")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "extension_loaded", sizeof("extension_loaded")-1)) { zval t; char *lc_name = zend_str_tolower_dup( - Z_STRVAL(ZEND_OP1_LITERAL(opline - 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline - 1))); + Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1))); zend_module_entry *m = zend_hash_str_find_ptr(&module_registry, - lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline - 1))); + lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1))); efree(lc_name); if (!m) { @@ -398,51 +403,55 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { } } - if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) { - literal_dtor(&ZEND_OP1_LITERAL(opline - 1)); - MAKE_NOP((opline - 1)); - literal_dtor(&ZEND_OP1_LITERAL(opline)); + if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) { + literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); + literal_dtor(&ZEND_OP1_LITERAL(opline + 1)); + MAKE_NOP(opline + 1); + MAKE_NOP(opline + 2); } - } else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("defined")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + } else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("defined")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "defined", sizeof("defined")-1)) { zval t; - if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline - 1)), &t, 0 TSRMLS_CC)) { + if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline + 1)), &t, 0 TSRMLS_CC)) { ZVAL_BOOL(&t, 1); - if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) { - literal_dtor(&ZEND_OP1_LITERAL(opline - 1)); - MAKE_NOP((opline - 1)); - literal_dtor(&ZEND_OP1_LITERAL(opline)); + if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) { + literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); + literal_dtor(&ZEND_OP1_LITERAL(opline + 1)); + MAKE_NOP(opline + 1); + MAKE_NOP(opline + 2); } } - } else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("constant")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + } else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("constant")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "constant", sizeof("constant")-1)) { zval t; - if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline - 1)), &t, 1 TSRMLS_CC)) { - if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) { - literal_dtor(&ZEND_OP1_LITERAL(opline - 1)); - MAKE_NOP((opline - 1)); - literal_dtor(&ZEND_OP1_LITERAL(opline)); + if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline + 1)), &t, 1 TSRMLS_CC)) { + if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) { + literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); + literal_dtor(&ZEND_OP1_LITERAL(opline + 1)); + MAKE_NOP(opline + 1); + MAKE_NOP(opline + 2); } } - } else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("strlen")-1 && - !memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), + } else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("strlen")-1 && + !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "strlen", sizeof("strlen")-1)) { zval t; - ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline - 1))); - if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) { - literal_dtor(&ZEND_OP1_LITERAL(opline - 1)); - MAKE_NOP((opline - 1)); - literal_dtor(&ZEND_OP1_LITERAL(opline)); + ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1))); + if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) { + literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); + literal_dtor(&ZEND_OP1_LITERAL(opline + 1)); + MAKE_NOP(opline + 1); + MAKE_NOP(opline + 2); } } } @@ -485,7 +494,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { case ZEND_FE_RESET: case ZEND_FE_FETCH: case ZEND_NEW: - case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_FCALL: #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO case ZEND_JMP_SET: #endif diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 2ea6544e23..681a54a74e 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -178,12 +178,6 @@ static void update_op1_const(zend_op_array *op_array, zend_optimizer_add_literal(op_array, val TSRMLS_CC); STR_HASH_VAL(Z_STR(op_array->literals[opline->op1.constant+1])); break; - case ZEND_DO_FCALL: - zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); - opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC); - STR_HASH_VAL(Z_STR(ZEND_OP1_LITERAL(opline))); - Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->last_cache_slot++; - break; default: opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC); STR_HASH_VAL(Z_STR(ZEND_OP1_LITERAL(opline))); @@ -204,6 +198,13 @@ static void update_op2_const(zend_op_array *op_array, { ZEND_OP2_TYPE(opline) = IS_CONST; #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO + if (opline->opcode == ZEND_INIT_FCALL) { + zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); + opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC); + STR_HASH_VAL(Z_STR(ZEND_OP2_LITERAL(opline))); + Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->last_cache_slot++; + return; + } opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC); if (Z_TYPE_P(val) == IS_STRING) { STR_HASH_VAL(Z_STR(ZEND_OP2_LITERAL(opline))); @@ -340,9 +341,9 @@ static int replace_var_by_const(zend_op_array *op_array, if (opline->extended_value & ZEND_ARG_SEND_BY_REF) { return 0; } - opline->extended_value = ZEND_DO_FCALL; + opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; } else { - opline->extended_value = ZEND_DO_FCALL_BY_NAME; + opline->extended_value = 0; } opline->opcode = ZEND_SEND_VAL; break; diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 0ae3feb2ee..361d1207f8 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -44,7 +44,7 @@ #define INV_EX_COND_EX(op) ((op) == ZEND_JMPZ_EX ? ZEND_JMPNZ_EX : ZEND_JMPZ_EX) #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO -# define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(opline->result)); memset(&opline->op1,0,sizeof(opline->op1)); memset(&opline->op2,0,sizeof(opline->op2)); opline->result_type=opline->op1_type=opline->op2_type=IS_UNUSED; opline->handler = zend_opcode_handlers[ZEND_NOP]; } +# define MAKE_NOP(opline) { (opline)->opcode = ZEND_NOP; memset(&(opline)->result, 0, sizeof((opline)->result)); memset(&(opline)->op1, 0, sizeof((opline)->op1)); memset(&(opline)->op2, 0, sizeof((opline)->op2));(opline)->result_type=(opline)->op1_type=(opline)->op2_type=IS_UNUSED; (opline)->handler = zend_opcode_handlers[ZEND_NOP]; } # define RESULT_USED(op) (((op->result_type & IS_VAR) && !(op->result_type & EXT_TYPE_UNUSED)) || op->result_type == IS_TMP_VAR) # define RESULT_UNUSED(op) ((op->result_type & EXT_TYPE_UNUSED) != 0) # define SAME_VAR(op1, op2) ((((op1 ## _type & IS_VAR) && (op2 ## _type & IS_VAR)) || (op1 ## _type == IS_TMP_VAR && op2 ## _type == IS_TMP_VAR)) && op1.var == op2.var) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index b5f2c95efe..048362d3ec 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -286,6 +286,10 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char EG(active_op_array) = new_op_array; zend_try { + if (EG(current_execute_data)) { + EG(current_execute_data)->call = zend_vm_stack_push_call_frame( + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EG(current_execute_data)->call TSRMLS_CC); + } zend_execute(new_op_array, &result TSRMLS_CC); if (PHAR_G(cwd)) { efree(PHAR_G(cwd)); diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 22e2a0c671..5ec20cd563 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -292,6 +292,10 @@ static int spl_autoload(zend_string *class_name, zend_string *lc_name, const cha } ZVAL_UNDEF(&result); + if (EG(current_execute_data)) { + EG(current_execute_data)->call = zend_vm_stack_push_call_frame( + (zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EG(current_execute_data)->call TSRMLS_CC); + } zend_execute(new_op_array, &result TSRMLS_CC); destroy_op_array(new_op_array TSRMLS_CC); diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 3e688aaf88..24556b532c 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1831,7 +1831,9 @@ SPL_METHOD(Array, unserialize) } ++p; - if (!php_var_unserialize(&members, &p, s + buf_len, &var_hash TSRMLS_CC)) { + ZVAL_UNDEF(&members); + if (!php_var_unserialize(&members, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE(members) != IS_ARRAY) { + zval_ptr_dtor(&members); goto outexcept; } diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index a13a7db155..bdfff35506 100644 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -891,7 +891,9 @@ SPL_METHOD(SplObjectStorage, unserialize) } ++p; - if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) { + ZVAL_UNDEF(&pmembers); + if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE(pmembers) != IS_ARRAY) { + zval_ptr_dtor(&pmembers); goto outexcept; } diff --git a/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt b/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt index a525317093..8f0676de3b 100644 --- a/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt +++ b/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt @@ -7,6 +7,7 @@ $badblobs = array( 'x:i:2;i:0;,i:1;;i:0;,i:2;;m:a:0:{}', 'x:i:3;O:8:"stdClass":0:{},O:8:"stdClass":0:{};R:2;,i:1;;O:8:"stdClass":0:{},r:2;;m:a:0:{}', 'x:i:3;O:8:"stdClass":0:{},O:8:"stdClass":0:{};r:2;,i:1;;O:8:"stdClass":0:{},r:2;;m:a:0:{}', +'x:i:1;O:8:"stdClass":0:{},N;;m:s:40:"1234567890123456789012345678901234567890"', ); foreach($badblobs as $blob) { try { @@ -17,6 +18,7 @@ try { echo $e->getMessage()."\n"; } } +echo "DONE\n"; --EXPECTF-- Error at offset 6 of 34 bytes Error at offset 46 of 89 bytes @@ -42,4 +44,5 @@ object(SplObjectStorage)#2 (1) { } } } - +Error at offset 79 of 78 bytes +DONE diff --git a/ext/standard/info.c b/ext/standard/info.c index 19f8ebff44..ef397473c2 100644 --- a/ext/standard/info.c +++ b/ext/standard/info.c @@ -861,16 +861,16 @@ PHPAPI void php_print_info(int flag TSRMLS_DC) php_info_print_table_start(); php_info_print_table_header(2, "Variable", "Value"); - if ((data = zend_hash_str_find(&EG(symbol_table).ht, "PHP_SELF", sizeof("PHP_SELF")-1)) != NULL) { + if ((data = zend_hash_str_find(&EG(symbol_table).ht, "PHP_SELF", sizeof("PHP_SELF")-1)) != NULL && Z_TYPE_P(data) == IS_STRING) { php_info_print_table_row(2, "PHP_SELF", Z_STRVAL_P(data)); } - if ((data = zend_hash_str_find(&EG(symbol_table).ht, "PHP_AUTH_TYPE", sizeof("PHP_AUTH_TYPE")-1)) != NULL) { + if ((data = zend_hash_str_find(&EG(symbol_table).ht, "PHP_AUTH_TYPE", sizeof("PHP_AUTH_TYPE")-1)) != NULL && Z_TYPE_P(data) == IS_STRING) { php_info_print_table_row(2, "PHP_AUTH_TYPE", Z_STRVAL_P(data)); } - if ((data = zend_hash_str_find(&EG(symbol_table).ht, "PHP_AUTH_USER", sizeof("PHP_AUTH_USER")-1)) != NULL) { + if ((data = zend_hash_str_find(&EG(symbol_table).ht, "PHP_AUTH_USER", sizeof("PHP_AUTH_USER")-1)) != NULL && Z_TYPE_P(data) == IS_STRING) { php_info_print_table_row(2, "PHP_AUTH_USER", Z_STRVAL_P(data)); } - if ((data = zend_hash_str_find(&EG(symbol_table).ht, "PHP_AUTH_PW", sizeof("PHP_AUTH_PW")-1)) != NULL) { + if ((data = zend_hash_str_find(&EG(symbol_table).ht, "PHP_AUTH_PW", sizeof("PHP_AUTH_PW")-1)) != NULL && Z_TYPE_P(data) == IS_STRING) { php_info_print_table_row(2, "PHP_AUTH_PW", Z_STRVAL_P(data)); } php_print_gpcse_array(ZEND_STRL("_REQUEST") TSRMLS_CC); diff --git a/ext/standard/tests/general_functions/bug67498.phpt b/ext/standard/tests/general_functions/bug67498.phpt new file mode 100644 index 0000000000..5b5951b0f8 --- /dev/null +++ b/ext/standard/tests/general_functions/bug67498.phpt @@ -0,0 +1,15 @@ +--TEST-- +phpinfo() Type Confusion Information Leak Vulnerability +--FILE-- +<?php +$PHP_SELF = 1; +phpinfo(INFO_VARIABLES); + +?> +==DONE== +--EXPECTF-- +phpinfo() + +PHP Variables +%A +==DONE== 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_conf.c b/sapi/fpm/fpm/fpm_conf.c index ae7908642c..34e0480101 100644 --- a/sapi/fpm/fpm/fpm_conf.c +++ b/sapi/fpm/fpm/fpm_conf.c @@ -1075,6 +1075,9 @@ static int fpm_conf_process_all_pools() /* {{{ */ } } for (kv = wp->config->php_admin_values; kv; kv = kv->next) { + if (!strcasecmp(kv->key, "error_log") && !strcasecmp(kv->value, "syslog")) { + continue; + } for (p = options; *p; p++) { if (!strcasecmp(kv->key, *p)) { fpm_evaluate_full_path(&kv->value, wp, NULL, 0); diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index 78566be956..60f8e465eb 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -1137,19 +1137,6 @@ static void init_request_info(TSRMLS_D) TRANSLATE_SLASHES(env_document_root); } - if (env_path_translated != NULL && env_redirect_url != NULL && - env_path_translated != script_path_translated && - strcmp(env_path_translated, script_path_translated) != 0) { - /* - * pretty much apache specific. If we have a redirect_url - * then our script_filename and script_name point to the - * php executable - */ - script_path_translated = env_path_translated; - /* we correct SCRIPT_NAME now in case we don't have PATH_INFO */ - env_script_name = env_redirect_url; - } - #ifdef __riscos__ /* Convert path to unix format*/ __riscosify_control |= __RISCOSIFY_DONT_CHECK_DIR; @@ -1318,7 +1305,7 @@ static void init_request_info(TSRMLS_D) efree(pt); } } else { - /* make sure path_info/translated are empty */ + /* make sure original values are remembered in ORIG_ copies if we've changed them */ if (!orig_script_filename || (script_path_translated != orig_script_filename && strcmp(script_path_translated, orig_script_filename) != 0)) { @@ -1327,16 +1314,6 @@ static void init_request_info(TSRMLS_D) } script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", script_path_translated TSRMLS_CC); } - if (env_redirect_url) { - if (orig_path_info) { - _sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC); - _sapi_cgibin_putenv("PATH_INFO", NULL TSRMLS_CC); - } - if (orig_path_translated) { - _sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC); - _sapi_cgibin_putenv("PATH_TRANSLATED", NULL TSRMLS_CC); - } - } if (env_script_name != orig_script_name) { if (orig_script_name) { _sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC); diff --git a/sapi/fpm/fpm/fpm_php_trace.c b/sapi/fpm/fpm/fpm_php_trace.c index 925f2de64e..d5b4242fc3 100644 --- a/sapi/fpm/fpm/fpm_php_trace.c +++ b/sapi/fpm/fpm/fpm_php_trace.c @@ -42,6 +42,8 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC) /* {{{ */ { +// TODO: fpm_php_trace_dump() has to be reimplemented ??? +#if 0 int callers_limit = 20; pid_t pid = child->pid; struct timeval tv; @@ -131,6 +133,7 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC break; } } +#endif return 0; } /* }}} */ diff --git a/sapi/phpdbg/Makefile.frag b/sapi/phpdbg/Makefile.frag index d787b0fb18..b276aaaa53 100644 --- a/sapi/phpdbg/Makefile.frag +++ b/sapi/phpdbg/Makefile.frag @@ -26,6 +26,9 @@ install-phpdbg: $(BUILD_BINARY) @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/log @$(mkinstalldirs) $(INSTALL_ROOT)$(localstatedir)/run @$(INSTALL) -m 0755 $(BUILD_BINARY) $(INSTALL_ROOT)$(bindir)/$(program_prefix)phpdbg$(program_suffix)$(EXEEXT) + @echo "Installing phpdbg man page: $(INSTALL_ROOT)$(mandir)/man1/" + @$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man1 + @$(INSTALL_DATA) sapi/phpdbg/phpdbg.1 $(INSTALL_ROOT)$(mandir)/man1/$(program_prefix)phpdbg$(program_suffix).1 clean-phpdbg: @echo "Cleaning phpdbg object files ..." diff --git a/sapi/phpdbg/config.m4 b/sapi/phpdbg/config.m4 index 1a6640eaca..d78a439af0 100644 --- a/sapi/phpdbg/config.m4 +++ b/sapi/phpdbg/config.m4 @@ -21,7 +21,7 @@ if test "$PHP_PHPDBG" != "no"; then PHP_PHPDBG_CFLAGS="-D_GNU_SOURCE" PHP_PHPDBG_FILES="phpdbg.c phpdbg_parser.c phpdbg_lexer.c phpdbg_prompt.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_info.c phpdbg_cmd.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c" - if test "$PHP_READLINE" != "no"; then + if test "$PHP_READLINE" != "no" -o "$PHP_LIBEDIT" != "no"; then PHPDBG_EXTRA_LIBS="$PHP_READLINE_LIBS" fi diff --git a/sapi/phpdbg/phpdbg.1 b/sapi/phpdbg/phpdbg.1 new file mode 100644 index 0000000000..5e4d144c83 --- /dev/null +++ b/sapi/phpdbg/phpdbg.1 @@ -0,0 +1,59 @@ +.TH PHPDBG 1 +.SH NAME +phpdbg \- The interactive PHP debugger +.SH SYNOPSIS +.B phpdbg +[OPTION] +[\fB\-e\fIFILE\fR] +.SH DESCRIPTION +.B phpdbg +a lightweight, powerful, easy to use debugging platform for PHP5. +.SH OPTIONS +The following switches are implemented (just like cli SAPI): +.TP +.BR \-n +No \fBphp.ini\fR file will be used +.TP +.BR \-c \fIpath\fB|\fIfile\fR +Look for \fBphp.ini\fR file in the directory \fIpath\fR or use the specified \fIfile\fR +.TP +.BR \-z \fIfile\fR +Load Zend extension \fIfile\fR +.TP +.BR \-d \fIfoo\fB[=\fIbar\fB]\fR +Define INI entry \fIfoo\fR with value \fIbar\fR +.PP The following switches change the default behaviour of phpdbg: +.TP +.BR \-v +Disables quietness +.TP +.BR \-s +Enabled stepping +.TP +.BR -e \fIfile\fR +Sets execution context +.TP +.BR \-b +Disables use of colour on the console +.TP +.BR \-I +Ignore .phpdbginit (default init file) +.TP +.BR \-i \fIpath\fB|\ffile\fR +Override .phpgdbinit location (implies -I) +.TP +.BR \-O \fIfile\fR +Set oplog output to \fIfile\fR +.TP +.BR \-q +Do not print banner on startup +.TP +.BR \-r +Jump straight to run +.TP +.BR \-E +Enable step through eval() +.SH NOTES +Passing -rr will cause phpdbg to quit after execution, rather than returning to the console +.SH AUTHOR +Written by Felipe Pena, Joe Watkins and Bob Weinand, formatted by Ondřej Surý for Debian project. diff --git a/sapi/phpdbg/phpdbg.h b/sapi/phpdbg/phpdbg.h index 12350d5425..eb4faf1f94 100644 --- a/sapi/phpdbg/phpdbg.h +++ b/sapi/phpdbg/phpdbg.h @@ -64,10 +64,13 @@ # include "TSRM.h" #endif -#ifdef HAVE_LIBREADLINE +#ifdef LIBREADLINE # include <readline/readline.h> # include <readline/history.h> #endif +#ifdef HAVE_LIBEDIT +# include <editline/readline.h> +#endif #include "phpdbg_lexer.h" #include "phpdbg_cmd.h" diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c index d4ce8ebc55..a45513bee6 100644 --- a/sapi/phpdbg/phpdbg_cmd.c +++ b/sapi/phpdbg/phpdbg_cmd.c @@ -792,7 +792,7 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why TSRMLS_DC) PHPDBG_API char* phpdbg_read_input(char *buffered TSRMLS_DC) /* {{{ */ { char *cmd = NULL; -#ifndef HAVE_LIBREADLINE +#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT) char buf[PHPDBG_MAX_CMD]; #endif char *buffer = NULL; @@ -811,7 +811,7 @@ disconnect: return NULL; } -#ifndef HAVE_LIBREADLINE +#if !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDIT) if (!(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { if (!phpdbg_write("%s", phpdbg_get_prompt(TSRMLS_C))) { goto disconnect; @@ -850,7 +850,7 @@ readline: buffer = estrdup(cmd); -#ifdef HAVE_LIBREADLINE +#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) if (!buffered && cmd && !(PHPDBG_G(flags) & PHPDBG_IS_REMOTE)) { free(cmd); diff --git a/sapi/phpdbg/phpdbg_help.c b/sapi/phpdbg/phpdbg_help.c index f2d074ded6..1e58dc69ca 100644 --- a/sapi/phpdbg/phpdbg_help.c +++ b/sapi/phpdbg/phpdbg_help.c @@ -318,8 +318,9 @@ phpdbg_help_text_t phpdbg_help_text[] = { "**Information**" CR " **list** list PHP source" CR " **info** displays information on the debug session" CR -" **print** show opcodes " CR +" **print** show opcodes" CR " **frame** select a stack frame and print a stack frame summary" CR +" **back** shows the current backtrace" CR " **help** provide help on a topic" CR CR "**Starting and Stopping Execution**" CR @@ -613,7 +614,7 @@ phpdbg_help_text_t phpdbg_help_text[] = { {"finish", "The **finish** command causes control to be passed back to the vm, continuing execution. Any " "breakpoints that are encountered within the current stack frame will be skipped. Execution " -"will then continue until the next breakpoint after leaving the stack frame or unitil " +"will then continue until the next breakpoint after leaving the stack frame or until " "completion of the script" CR CR "Note when **step**ping is enabled, any opcode steps within the current stack frame are also " @@ -629,7 +630,7 @@ phpdbg_help_text_t phpdbg_help_text[] = { "**Examples**" CR CR " $P frame 2" CR -" $P E $count" CR +" $P ev $count" CR " Go to frame 2 and print out variable **$count** in that frame" CR CR "Note that this frame scope is discarded when execution continues, with the execution frame " diff --git a/sapi/phpdbg/phpdbg_lexer.c b/sapi/phpdbg/phpdbg_lexer.c index 420dcac042..3092dc396d 100644 --- a/sapi/phpdbg/phpdbg_lexer.c +++ b/sapi/phpdbg/phpdbg_lexer.c @@ -96,33 +96,49 @@ yyc_INITIAL: }; YYDEBUG(0, *YYCURSOR); - YYFILL(3); + YYFILL(4); yych = *YYCURSOR; - if (yych <= 0x1F) { - if (yych <= '\t') { + if (yych <= 'D') { + if (yych <= '\n') { if (yych <= 0x00) goto yy6; if (yych <= 0x08) goto yy11; + if (yych >= '\n') goto yy4; } else { - if (yych <= '\n') goto yy4; - if (yych != '\r') goto yy11; + if (yych <= '\r') { + if (yych <= '\f') goto yy11; + } else { + if (yych != ' ') goto yy11; + } } } else { - if (yych <= 'e') { - if (yych <= ' ') goto yy2; - if (yych <= 'd') goto yy11; - goto yy7; + if (yych <= 'd') { + if (yych <= 'Q') { + if (yych <= 'E') goto yy7; + goto yy11; + } else { + if (yych <= 'R') goto yy10; + if (yych <= 'S') goto yy8; + goto yy11; + } } else { - if (yych <= 'q') goto yy11; - if (yych <= 'r') goto yy9; - if (yych <= 's') goto yy8; - goto yy11; + if (yych <= 'q') { + if (yych <= 'e') goto yy7; + goto yy11; + } else { + if (yych <= 'r') goto yy9; + if (yych <= 's') goto yy8; + goto yy11; + } } } -yy2: YYDEBUG(2, *YYCURSOR); ++YYCURSOR; - if (yybm[0+(yych = *YYCURSOR)] & 128) { - goto yy19; + if ((yych = *YYCURSOR) <= '\f') { + if (yych <= 0x08) goto yy3; + if (yych <= '\n') goto yy26; + } else { + if (yych <= '\r') goto yy26; + if (yych == ' ') goto yy26; } yy3: YYDEBUG(3, *YYCURSOR); @@ -134,49 +150,60 @@ yy3: YYCURSOR = LEX(text); goto restart; } -#line 138 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 154 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" yy4: YYDEBUG(4, *YYCURSOR); ++YYCURSOR; - if (yybm[0+(yych = *YYCURSOR)] & 128) { - goto yy19; + if ((yych = *YYCURSOR) <= '\f') { + if (yych <= 0x08) goto yy5; + if (yych <= '\n') goto yy26; + } else { + if (yych <= '\r') goto yy26; + if (yych == ' ') goto yy26; } +yy5: YYDEBUG(5, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 151 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 172 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" yy6: YYDEBUG(6, *YYCURSOR); yych = *++YYCURSOR; goto yy3; yy7: YYDEBUG(7, *YYCURSOR); - yych = *++YYCURSOR; - if (yych == 'v') goto yy17; + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'V') goto yy22; + if (yych == 'v') goto yy22; goto yy3; yy8: YYDEBUG(8, *YYCURSOR); - yych = *++YYCURSOR; - if (yych == 'h') goto yy15; + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'H') goto yy18; + if (yych == 'h') goto yy18; goto yy3; yy9: YYDEBUG(9, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy15; + } + if (yych == 'U') goto yy12; if (yych == 'u') goto yy12; + goto yy3; yy10: YYDEBUG(10, *YYCURSOR); - yyleng = (size_t) YYCURSOR - (size_t) yytext; -#line 155 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" - { - YYSETCONDITION(RAW); - phpdbg_init_param(yylval, EMPTY_PARAM); - return T_RUN; -} -#line 180 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'U') goto yy12; + if (yych == 'u') goto yy12; + goto yy3; yy11: YYDEBUG(11, *YYCURSOR); yych = *++YYCURSOR; @@ -184,18 +211,62 @@ yy11: yy12: YYDEBUG(12, *YYCURSOR); yych = *++YYCURSOR; + if (yych == 'N') goto yy14; if (yych == 'n') goto yy14; +yy13: YYDEBUG(13, *YYCURSOR); YYCURSOR = YYMARKER; - goto yy10; + goto yy3; yy14: YYDEBUG(14, *YYCURSOR); yych = *++YYCURSOR; - goto yy10; + if (yybm[0+yych] & 128) { + goto yy15; + } + goto yy13; yy15: YYDEBUG(15, *YYCURSOR); ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; YYDEBUG(16, *YYCURSOR); + if (yybm[0+yych] & 128) { + goto yy15; + } + YYDEBUG(17, *YYCURSOR); + yyleng = (size_t) YYCURSOR - (size_t) yytext; +#line 155 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" + { + YYSETCONDITION(RAW); + phpdbg_init_param(yylval, EMPTY_PARAM); + return T_RUN; +} +#line 245 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy18: + YYDEBUG(18, *YYCURSOR); + yych = *++YYCURSOR; + if (yych <= '\f') { + if (yych <= 0x08) goto yy13; + if (yych >= '\v') goto yy13; + } else { + if (yych <= '\r') goto yy19; + if (yych != ' ') goto yy13; + } +yy19: + YYDEBUG(19, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(20, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy21; + if (yych <= '\n') goto yy19; + } else { + if (yych <= '\r') goto yy19; + if (yych == ' ') goto yy19; + } +yy21: + YYDEBUG(21, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 150 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -203,11 +274,32 @@ yy15: phpdbg_init_param(yylval, EMPTY_PARAM); return T_SHELL; } -#line 207 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy17: - YYDEBUG(17, *YYCURSOR); +#line 278 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy22: + YYDEBUG(22, *YYCURSOR); + yych = *++YYCURSOR; + if (yych <= '\f') { + if (yych <= 0x08) goto yy13; + if (yych >= '\v') goto yy13; + } else { + if (yych <= '\r') goto yy23; + if (yych != ' ') goto yy13; + } +yy23: + YYDEBUG(23, *YYCURSOR); ++YYCURSOR; - YYDEBUG(18, *YYCURSOR); + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(24, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy25; + if (yych <= '\n') goto yy23; + } else { + if (yych <= '\r') goto yy23; + if (yych == ' ') goto yy23; + } +yy25: + YYDEBUG(25, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 145 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -215,17 +307,22 @@ yy17: phpdbg_init_param(yylval, EMPTY_PARAM); return T_EVAL; } -#line 219 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy19: - YYDEBUG(19, *YYCURSOR); +#line 311 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy26: + YYDEBUG(26, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(20, *YYCURSOR); - if (yybm[0+yych] & 128) { - goto yy19; + YYDEBUG(27, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy28; + if (yych <= '\n') goto yy26; + } else { + if (yych <= '\r') goto yy26; + if (yych == ' ') goto yy26; } - YYDEBUG(21, *YYCURSOR); +yy28: + YYDEBUG(28, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -233,7 +330,7 @@ yy19: goto restart; } -#line 237 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 334 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" } /* *********************************** */ yyc_NORMAL: @@ -272,71 +369,60 @@ yyc_NORMAL: 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, }; - YYDEBUG(22, *YYCURSOR); + YYDEBUG(29, *YYCURSOR); YYFILL(11); yych = *YYCURSOR; - if (yych <= ':') { - if (yych <= ' ') { - if (yych <= '\n') { - if (yych <= 0x00) goto yy29; - if (yych <= 0x08) goto yy32; - if (yych >= '\n') goto yy27; - } else { - if (yych == '\r') goto yy24; - if (yych <= 0x1F) goto yy32; - } - } else { - if (yych <= '.') { - if (yych == '#') goto yy47; - if (yych <= '-') goto yy32; - goto yy34; - } else { - if (yych <= '/') goto yy32; - if (yych <= '0') goto yy37; - if (yych <= '9') goto yy34; - goto yy49; - } - } - } else { - if (yych <= 'i') { - if (yych <= 'd') { - if (yych == 'Z') goto yy38; - if (yych <= 'c') goto yy32; - goto yy39; - } else { - if (yych <= 'e') goto yy40; - if (yych <= 'f') goto yy41; - if (yych <= 'h') goto yy32; - goto yy30; - } - } else { - if (yych <= 's') { - if (yych <= 'm') goto yy32; - if (yych <= 'n') goto yy42; - if (yych <= 'o') goto yy43; - goto yy32; - } else { - if (yych <= 'x') { - if (yych <= 't') goto yy44; - goto yy32; - } else { - if (yych <= 'y') goto yy45; - if (yych <= 'z') goto yy46; - goto yy32; - } - } - } + YYDEBUG(-1, yych); + switch (yych) { + case 0x00: goto yy36; + case '\t': + case '\r': + case ' ': goto yy31; + case '\n': goto yy34; + case '#': goto yy55; + case '-': goto yy41; + case '.': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': goto yy42; + case '0': goto yy45; + case ':': goto yy57; + case 'D': + case 'd': goto yy46; + case 'E': + case 'e': goto yy47; + case 'F': + case 'f': goto yy48; + case 'I': + case 'i': goto yy37; + case 'N': + case 'n': goto yy49; + case 'O': + case 'o': goto yy50; + case 'T': + case 't': goto yy51; + case 'Y': + case 'y': goto yy52; + case 'Z': goto yy53; + case 'z': goto yy54; + default: goto yy39; } -yy24: - YYDEBUG(24, *YYCURSOR); +yy31: + YYDEBUG(31, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(25, *YYCURSOR); + YYDEBUG(32, *YYCURSOR); if (yybm[0+yych] & 8) { - goto yy24; + goto yy31; } - YYDEBUG(26, *YYCURSOR); + YYDEBUG(33, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -344,33 +430,34 @@ yy24: goto restart; } -#line 348 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy27: - YYDEBUG(27, *YYCURSOR); +#line 434 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy34: + YYDEBUG(34, *YYCURSOR); ++YYCURSOR; if (yybm[0+(yych = *YYCURSOR)] & 8) { - goto yy24; + goto yy31; } -yy28: - YYDEBUG(28, *YYCURSOR); +yy35: + YYDEBUG(35, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 362 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy29: - YYDEBUG(29, *YYCURSOR); +#line 448 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy36: + YYDEBUG(36, *YYCURSOR); yych = *++YYCURSOR; - goto yy28; -yy30: - YYDEBUG(30, *YYCURSOR); + goto yy35; +yy37: + YYDEBUG(37, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'f') goto yy94; - goto yy33; -yy31: - YYDEBUG(31, *YYCURSOR); + if (yych == 'F') goto yy106; + if (yych == 'f') goto yy106; + goto yy40; +yy38: + YYDEBUG(38, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 125 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -379,48 +466,56 @@ yy31: yylval->len = yyleng; return T_ID; } -#line 383 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy32: - YYDEBUG(32, *YYCURSOR); +#line 470 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy39: + YYDEBUG(39, *YYCURSOR); yyaccept = 0; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; -yy33: - YYDEBUG(33, *YYCURSOR); +yy40: + YYDEBUG(40, *YYCURSOR); if (yybm[0+yych] & 16) { - goto yy32; + goto yy39; } - if (yych <= '9') goto yy31; - goto yy54; -yy34: - YYDEBUG(34, *YYCURSOR); + if (yych <= '9') goto yy38; + goto yy62; +yy41: + YYDEBUG(41, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 32) { + goto yy42; + } + goto yy40; +yy42: + YYDEBUG(42, *YYCURSOR); yyaccept = 1; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(35, *YYCURSOR); + YYDEBUG(43, *YYCURSOR); if (yybm[0+yych] & 32) { - goto yy34; + goto yy42; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy36; - if (yych <= 0x08) goto yy32; + if (yych <= 0x00) goto yy44; + if (yych <= 0x08) goto yy39; } else { - if (yych != '\r') goto yy32; + if (yych != '\r') goto yy39; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy36; - if (yych <= '"') goto yy32; + if (yych <= ' ') goto yy44; + if (yych <= '"') goto yy39; } else { - if (yych == ':') goto yy54; - goto yy32; + if (yych == ':') goto yy62; + goto yy39; } } -yy36: - YYDEBUG(36, *YYCURSOR); +yy44: + YYDEBUG(44, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 106 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -428,164 +523,168 @@ yy36: yylval->num = atoi(yytext); return T_DIGITS; } -#line 432 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy37: - YYDEBUG(37, *YYCURSOR); +#line 527 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy45: + YYDEBUG(45, *YYCURSOR); yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); if (yybm[0+yych] & 32) { - goto yy34; + goto yy42; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy36; - if (yych <= 0x08) goto yy33; - goto yy36; + if (yych <= 0x00) goto yy44; + if (yych <= 0x08) goto yy40; + goto yy44; } else { - if (yych == '\r') goto yy36; - goto yy33; + if (yych == '\r') goto yy44; + goto yy40; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy36; - if (yych <= '"') goto yy33; - goto yy36; + if (yych <= ' ') goto yy44; + if (yych <= '"') goto yy40; + goto yy44; } else { - if (yych == 'x') goto yy90; - goto yy33; + if (yych == 'x') goto yy102; + goto yy40; } } -yy38: - YYDEBUG(38, *YYCURSOR); +yy46: + YYDEBUG(46, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'E') goto yy87; - goto yy33; -yy39: - YYDEBUG(39, *YYCURSOR); + if (yych == 'I') goto yy96; + if (yych == 'i') goto yy96; + goto yy40; +yy47: + YYDEBUG(47, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'i') goto yy81; - goto yy33; -yy40: - YYDEBUG(40, *YYCURSOR); + if (yych == 'N') goto yy91; + if (yych == 'n') goto yy91; + goto yy40; +yy48: + YYDEBUG(48, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'n') goto yy76; - goto yy33; -yy41: - YYDEBUG(41, *YYCURSOR); + if (yych == 'A') goto yy88; + if (yych == 'a') goto yy88; + goto yy40; +yy49: + YYDEBUG(49, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'a') goto yy73; - goto yy33; -yy42: - YYDEBUG(42, *YYCURSOR); + if (yych == 'O') goto yy84; + if (yych == 'o') goto yy84; + goto yy40; +yy50: + YYDEBUG(50, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'o') goto yy71; - goto yy33; -yy43: - YYDEBUG(43, *YYCURSOR); + if (yych <= 'N') { + if (yych == 'F') goto yy83; + if (yych <= 'M') goto yy40; + goto yy77; + } else { + if (yych <= 'f') { + if (yych <= 'e') goto yy40; + goto yy83; + } else { + if (yych == 'n') goto yy77; + goto yy40; + } + } +yy51: + YYDEBUG(51, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'f') goto yy70; - if (yych == 'n') goto yy66; - goto yy33; -yy44: - YYDEBUG(44, *YYCURSOR); + if (yych == 'R') goto yy81; + if (yych == 'r') goto yy81; + goto yy40; +yy52: + YYDEBUG(52, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'r') goto yy68; - goto yy33; -yy45: - YYDEBUG(45, *YYCURSOR); + if (yych == 'E') goto yy76; + if (yych == 'e') goto yy76; + goto yy40; +yy53: + YYDEBUG(53, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'e') goto yy65; - goto yy33; -yy46: - YYDEBUG(46, *YYCURSOR); + if (yych == 'E') goto yy73; + goto yy40; +yy54: + YYDEBUG(54, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'e') goto yy53; - goto yy33; -yy47: - YYDEBUG(47, *YYCURSOR); + if (yych == 'e') goto yy61; + goto yy40; +yy55: + YYDEBUG(55, *YYCURSOR); ++YYCURSOR; - YYDEBUG(48, *YYCURSOR); + YYDEBUG(56, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 84 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return T_POUND; } -#line 523 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy49: - YYDEBUG(49, *YYCURSOR); +#line 634 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy57: + YYDEBUG(57, *YYCURSOR); ++YYCURSOR; - if ((yych = *YYCURSOR) == ':') goto yy51; - YYDEBUG(50, *YYCURSOR); + if ((yych = *YYCURSOR) == ':') goto yy59; + YYDEBUG(58, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 90 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return T_COLON; } -#line 534 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy51: - YYDEBUG(51, *YYCURSOR); +#line 645 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy59: + YYDEBUG(59, *YYCURSOR); ++YYCURSOR; - YYDEBUG(52, *YYCURSOR); + YYDEBUG(60, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 87 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return T_DCOLON; } -#line 544 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy53: - YYDEBUG(53, *YYCURSOR); +#line 655 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy61: + YYDEBUG(61, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'n') goto yy59; - goto yy33; -yy54: - YYDEBUG(54, *YYCURSOR); + if (yych == 'n') goto yy67; + goto yy40; +yy62: + YYDEBUG(62, *YYCURSOR); yych = *++YYCURSOR; - if (yych == '/') goto yy56; -yy55: - YYDEBUG(55, *YYCURSOR); + if (yych == '/') goto yy64; +yy63: + YYDEBUG(63, *YYCURSOR); YYCURSOR = YYMARKER; - if (yyaccept <= 3) { - if (yyaccept <= 1) { - if (yyaccept <= 0) { - goto yy31; - } else { - goto yy36; - } + if (yyaccept <= 1) { + if (yyaccept <= 0) { + goto yy38; } else { - if (yyaccept <= 2) { - goto yy64; - } else { - goto yy67; - } + goto yy44; } } else { - if (yyaccept <= 5) { - if (yyaccept <= 4) { - goto yy72; - } else { - goto yy93; - } + if (yyaccept <= 2) { + goto yy72; } else { - goto yy95; + goto yy105; } } -yy56: - YYDEBUG(56, *YYCURSOR); +yy64: + YYDEBUG(64, *YYCURSOR); yych = *++YYCURSOR; - if (yych != '/') goto yy55; - YYDEBUG(57, *YYCURSOR); + if (yych != '/') goto yy63; + YYDEBUG(65, *YYCURSOR); ++YYCURSOR; - YYDEBUG(58, *YYCURSOR); + YYDEBUG(66, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 78 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -594,52 +693,52 @@ yy56: yylval->len = yyleng; return T_PROTO; } -#line 598 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy59: - YYDEBUG(59, *YYCURSOR); +#line 697 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy67: + YYDEBUG(67, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'd') goto yy33; - YYDEBUG(60, *YYCURSOR); + if (yych != 'd') goto yy40; + YYDEBUG(68, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != '_') goto yy33; -yy61: - YYDEBUG(61, *YYCURSOR); + if (yych != '_') goto yy40; +yy69: + YYDEBUG(69, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); if (yybm[0+yych] & 64) { - goto yy62; + goto yy70; } - goto yy33; -yy62: - YYDEBUG(62, *YYCURSOR); + goto yy40; +yy70: + YYDEBUG(70, *YYCURSOR); yyaccept = 2; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(63, *YYCURSOR); + YYDEBUG(71, *YYCURSOR); if (yybm[0+yych] & 64) { - goto yy62; + goto yy70; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy64; - if (yych <= 0x08) goto yy32; + if (yych <= 0x00) goto yy72; + if (yych <= 0x08) goto yy39; } else { - if (yych != '\r') goto yy32; + if (yych != '\r') goto yy39; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy64; - if (yych <= '"') goto yy32; + if (yych <= ' ') goto yy72; + if (yych <= '"') goto yy39; } else { - if (yych == ':') goto yy54; - goto yy32; + if (yych == ':') goto yy62; + goto yy39; } } -yy64: - YYDEBUG(64, *YYCURSOR); +yy72: + YYDEBUG(72, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 118 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -648,32 +747,53 @@ yy64: yylval->len = yyleng; return T_OPCODE; } -#line 652 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy65: - YYDEBUG(65, *YYCURSOR); +#line 751 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy73: + YYDEBUG(73, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 's') goto yy33; -yy66: - YYDEBUG(66, *YYCURSOR); - yyaccept = 3; + if (yych != 'N') goto yy40; + YYDEBUG(74, *YYCURSOR); + yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '\r') { - if (yych <= 0x08) { - if (yych >= 0x01) goto yy33; - } else { - if (yych <= '\n') goto yy67; - if (yych <= '\f') goto yy33; - } + if (yych != 'D') goto yy40; + YYDEBUG(75, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '_') goto yy69; + goto yy40; +yy76: + YYDEBUG(76, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'S') goto yy77; + if (yych != 's') goto yy40; +yy77: + YYDEBUG(77, *YYCURSOR); + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy40; + if (yych >= '\v') goto yy40; } else { - if (yych <= ' ') { - if (yych <= 0x1F) goto yy33; - } else { - if (yych != '#') goto yy33; - } + if (yych <= '\r') goto yy78; + if (yych != ' ') goto yy40; } -yy67: - YYDEBUG(67, *YYCURSOR); +yy78: + YYDEBUG(78, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(79, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy80; + if (yych <= '\n') goto yy78; + } else { + if (yych <= '\r') goto yy78; + if (yych == ' ') goto yy78; + } +yy80: + YYDEBUG(80, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 94 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -681,42 +801,52 @@ yy67: yylval->num = 1; return T_TRUTHY; } -#line 685 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy68: - YYDEBUG(68, *YYCURSOR); +#line 805 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy81: + YYDEBUG(81, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'u') goto yy33; - YYDEBUG(69, *YYCURSOR); + if (yych == 'U') goto yy82; + if (yych != 'u') goto yy40; +yy82: + YYDEBUG(82, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'e') goto yy66; - goto yy33; -yy70: - YYDEBUG(70, *YYCURSOR); + if (yych == 'E') goto yy77; + if (yych == 'e') goto yy77; + goto yy40; +yy83: + YYDEBUG(83, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'f') goto yy33; -yy71: - YYDEBUG(71, *YYCURSOR); - yyaccept = 4; + if (yych == 'F') goto yy84; + if (yych != 'f') goto yy40; +yy84: + YYDEBUG(84, *YYCURSOR); + yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '\r') { - if (yych <= 0x08) { - if (yych >= 0x01) goto yy33; - } else { - if (yych <= '\n') goto yy72; - if (yych <= '\f') goto yy33; - } + if (yych <= '\f') { + if (yych <= 0x08) goto yy40; + if (yych >= '\v') goto yy40; } else { - if (yych <= ' ') { - if (yych <= 0x1F) goto yy33; - } else { - if (yych != '#') goto yy33; - } + if (yych <= '\r') goto yy85; + if (yych != ' ') goto yy40; } -yy72: - YYDEBUG(72, *YYCURSOR); +yy85: + YYDEBUG(85, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(86, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy87; + if (yych <= '\n') goto yy85; + } else { + if (yych <= '\r') goto yy85; + if (yych == ' ') goto yy85; + } +yy87: + YYDEBUG(87, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 100 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -724,119 +854,130 @@ yy72: yylval->num = 0; return T_FALSY; } -#line 728 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy73: - YYDEBUG(73, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'l') goto yy33; - YYDEBUG(74, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych != 's') goto yy33; - YYDEBUG(75, *YYCURSOR); - yyaccept = 0; - yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'e') goto yy71; - goto yy33; -yy76: - YYDEBUG(76, *YYCURSOR); +#line 858 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy88: + YYDEBUG(88, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'a') goto yy33; - YYDEBUG(77, *YYCURSOR); + if (yych == 'L') goto yy89; + if (yych != 'l') goto yy40; +yy89: + YYDEBUG(89, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'b') goto yy33; - YYDEBUG(78, *YYCURSOR); + if (yych == 'S') goto yy90; + if (yych != 's') goto yy40; +yy90: + YYDEBUG(90, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'l') goto yy33; - YYDEBUG(79, *YYCURSOR); + if (yych == 'E') goto yy84; + if (yych == 'e') goto yy84; + goto yy40; +yy91: + YYDEBUG(91, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'e') goto yy33; - YYDEBUG(80, *YYCURSOR); + if (yych == 'A') goto yy92; + if (yych != 'a') goto yy40; +yy92: + YYDEBUG(92, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'd') goto yy66; - goto yy33; -yy81: - YYDEBUG(81, *YYCURSOR); + if (yych == 'B') goto yy93; + if (yych != 'b') goto yy40; +yy93: + YYDEBUG(93, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 's') goto yy33; - YYDEBUG(82, *YYCURSOR); + if (yych == 'L') goto yy94; + if (yych != 'l') goto yy40; +yy94: + YYDEBUG(94, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'a') goto yy33; - YYDEBUG(83, *YYCURSOR); + if (yych == 'E') goto yy95; + if (yych != 'e') goto yy40; +yy95: + YYDEBUG(95, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'b') goto yy33; - YYDEBUG(84, *YYCURSOR); + if (yych == 'D') goto yy77; + if (yych == 'd') goto yy77; + goto yy40; +yy96: + YYDEBUG(96, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'l') goto yy33; - YYDEBUG(85, *YYCURSOR); + if (yych == 'S') goto yy97; + if (yych != 's') goto yy40; +yy97: + YYDEBUG(97, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'e') goto yy33; - YYDEBUG(86, *YYCURSOR); + if (yych == 'A') goto yy98; + if (yych != 'a') goto yy40; +yy98: + YYDEBUG(98, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'd') goto yy71; - goto yy33; -yy87: - YYDEBUG(87, *YYCURSOR); + if (yych == 'B') goto yy99; + if (yych != 'b') goto yy40; +yy99: + YYDEBUG(99, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'N') goto yy33; - YYDEBUG(88, *YYCURSOR); + if (yych == 'L') goto yy100; + if (yych != 'l') goto yy40; +yy100: + YYDEBUG(100, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych != 'D') goto yy33; - YYDEBUG(89, *YYCURSOR); + if (yych == 'E') goto yy101; + if (yych != 'e') goto yy40; +yy101: + YYDEBUG(101, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == '_') goto yy61; - goto yy33; -yy90: - YYDEBUG(90, *YYCURSOR); + if (yych == 'D') goto yy84; + if (yych == 'd') goto yy84; + goto yy40; +yy102: + YYDEBUG(102, *YYCURSOR); yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); if (yybm[0+yych] & 128) { - goto yy91; + goto yy103; } - goto yy33; -yy91: - YYDEBUG(91, *YYCURSOR); - yyaccept = 5; + goto yy40; +yy103: + YYDEBUG(103, *YYCURSOR); + yyaccept = 3; YYMARKER = ++YYCURSOR; YYFILL(3); yych = *YYCURSOR; - YYDEBUG(92, *YYCURSOR); + YYDEBUG(104, *YYCURSOR); if (yybm[0+yych] & 128) { - goto yy91; + goto yy103; } if (yych <= 0x1F) { if (yych <= '\n') { - if (yych <= 0x00) goto yy93; - if (yych <= 0x08) goto yy32; + if (yych <= 0x00) goto yy105; + if (yych <= 0x08) goto yy39; } else { - if (yych != '\r') goto yy32; + if (yych != '\r') goto yy39; } } else { if (yych <= '#') { - if (yych <= ' ') goto yy93; - if (yych <= '"') goto yy32; + if (yych <= ' ') goto yy105; + if (yych <= '"') goto yy39; } else { - if (yych == ':') goto yy54; - goto yy32; + if (yych == ':') goto yy62; + goto yy39; } } -yy93: - YYDEBUG(93, *YYCURSOR); +yy105: + YYDEBUG(105, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 112 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -844,27 +985,33 @@ yy93: yylval->addr = strtoul(yytext, 0, 16); return T_ADDR; } -#line 848 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy94: - YYDEBUG(94, *YYCURSOR); - yyaccept = 6; +#line 989 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy106: + YYDEBUG(106, *YYCURSOR); + yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= '\r') { - if (yych <= 0x08) { - if (yych >= 0x01) goto yy33; - } else { - if (yych <= '\n') goto yy95; - if (yych <= '\f') goto yy33; - } + if (yych <= '\f') { + if (yych <= 0x08) goto yy40; + if (yych >= '\v') goto yy40; } else { - if (yych <= ' ') { - if (yych <= 0x1F) goto yy33; - } else { - if (yych != '#') goto yy33; - } + if (yych <= '\r') goto yy107; + if (yych != ' ') goto yy40; } -yy95: - YYDEBUG(95, *YYCURSOR); +yy107: + YYDEBUG(107, *YYCURSOR); + ++YYCURSOR; + YYFILL(1); + yych = *YYCURSOR; + YYDEBUG(108, *YYCURSOR); + if (yych <= '\f') { + if (yych <= 0x08) goto yy109; + if (yych <= '\n') goto yy107; + } else { + if (yych <= '\r') goto yy107; + if (yych == ' ') goto yy107; + } +yy109: + YYDEBUG(109, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 72 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -872,7 +1019,7 @@ yy95: phpdbg_init_param(yylval, EMPTY_PARAM); return T_IF; } -#line 876 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 1023 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" } /* *********************************** */ yyc_RAW: @@ -911,29 +1058,29 @@ yyc_RAW: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, }; - YYDEBUG(96, *YYCURSOR); + YYDEBUG(110, *YYCURSOR); YYFILL(2); yych = *YYCURSOR; if (yybm[0+yych] & 32) { - goto yy98; + goto yy112; } - if (yych <= 0x00) goto yy103; - if (yych == '\n') goto yy101; - goto yy104; -yy98: - YYDEBUG(98, *YYCURSOR); + if (yych <= 0x00) goto yy117; + if (yych == '\n') goto yy115; + goto yy118; +yy112: + YYDEBUG(112, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(99, *YYCURSOR); + YYDEBUG(113, *YYCURSOR); if (yybm[0+yych] & 32) { - goto yy98; + goto yy112; } - if (yych <= 0x00) goto yy100; - if (yych == '\n') goto yy106; - goto yy104; -yy100: - YYDEBUG(100, *YYCURSOR); + if (yych <= 0x00) goto yy114; + if (yych == '\n') goto yy120; + goto yy118; +yy114: + YYDEBUG(114, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 132 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -942,45 +1089,45 @@ yy100: yylval->len = yyleng; return T_INPUT; } -#line 946 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy101: - YYDEBUG(101, *YYCURSOR); +#line 1093 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy115: + YYDEBUG(115, *YYCURSOR); ++YYCURSOR; if (yybm[0+(yych = *YYCURSOR)] & 128) { - goto yy106; + goto yy120; } -yy102: - YYDEBUG(102, *YYCURSOR); +yy116: + YYDEBUG(116, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 68 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { return 0; } -#line 960 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" -yy103: - YYDEBUG(103, *YYCURSOR); +#line 1107 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +yy117: + YYDEBUG(117, *YYCURSOR); yych = *++YYCURSOR; - goto yy102; -yy104: - YYDEBUG(104, *YYCURSOR); + goto yy116; +yy118: + YYDEBUG(118, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(105, *YYCURSOR); + YYDEBUG(119, *YYCURSOR); if (yybm[0+yych] & 64) { - goto yy104; + goto yy118; } - goto yy100; -yy106: - YYDEBUG(106, *YYCURSOR); + goto yy114; +yy120: + YYDEBUG(120, *YYCURSOR); ++YYCURSOR; YYFILL(1); yych = *YYCURSOR; - YYDEBUG(107, *YYCURSOR); + YYDEBUG(121, *YYCURSOR); if (yybm[0+yych] & 128) { - goto yy106; + goto yy120; } - YYDEBUG(108, *YYCURSOR); + YYDEBUG(122, *YYCURSOR); yyleng = (size_t) YYCURSOR - (size_t) yytext; #line 139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" { @@ -988,7 +1135,7 @@ yy106: goto restart; } -#line 992 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" +#line 1139 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.c" } } #line 168 "/var/root/php-src/sapi/phpdbg/phpdbg_lexer.l" diff --git a/sapi/phpdbg/phpdbg_lexer.l b/sapi/phpdbg/phpdbg_lexer.l index 4d9c837f1e..7b3ce38c47 100644 --- a/sapi/phpdbg/phpdbg_lexer.l +++ b/sapi/phpdbg/phpdbg_lexer.l @@ -43,21 +43,21 @@ restart: /*!re2c re2c:yyfill:check = 0; -T_TRUE "true" -T_YES "yes" -T_ON "on" -T_ENABLED "enabled" -T_FALSE "false" -T_NO "no" -T_OFF "off" -T_DISABLED "disabled" -T_EVAL "ev" -T_SHELL "sh" -T_IF "if" -T_RUN "run" +T_TRUE 'true' +T_YES 'yes' +T_ON 'on' +T_ENABLED 'enabled' +T_FALSE 'false' +T_NO 'no' +T_OFF 'off' +T_DISABLED 'disabled' +T_EVAL 'ev' +T_SHELL 'sh' +T_IF 'if' +T_RUN 'run' T_RUN_SHORT "r" WS [ \r\n\t]+ -DIGITS [0-9\.]+ +DIGITS [-]?[0-9\.]+ ID [^ \r\n\t:#\000]+ ADDR [0][x][a-fA-F0-9]+ OPCODE (ZEND_|zend_)([A-Za-z])+ @@ -69,7 +69,7 @@ INPUT [^\n\000]+ return 0; } -<NORMAL>{T_IF} { +<NORMAL>{T_IF}{WS} { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_IF; @@ -91,13 +91,13 @@ INPUT [^\n\000]+ return T_COLON; } -<NORMAL>{T_YES}|{T_ON}|{T_ENABLED}|{T_TRUE} { +<NORMAL>({T_YES}|{T_ON}|{T_ENABLED}|{T_TRUE}){WS} { phpdbg_init_param(yylval, NUMERIC_PARAM); yylval->num = 1; return T_TRUTHY; } -<NORMAL>{T_NO}|{T_OFF}|{T_DISABLED}|{T_FALSE} { +<NORMAL>({T_NO}|{T_OFF}|{T_DISABLED}|{T_FALSE}){WS} { phpdbg_init_param(yylval, NUMERIC_PARAM); yylval->num = 0; return T_FALSY; @@ -142,17 +142,17 @@ INPUT [^\n\000]+ goto restart; } -<INITIAL>{T_EVAL} { +<INITIAL>{T_EVAL}{WS} { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_EVAL; } -<INITIAL>{T_SHELL} { +<INITIAL>{T_SHELL}{WS} { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_SHELL; } -<INITIAL>{T_RUN}|{T_RUN_SHORT} { +<INITIAL>({T_RUN}|{T_RUN_SHORT}){WS} { YYSETCONDITION(RAW); phpdbg_init_param(yylval, EMPTY_PARAM); return T_RUN; diff --git a/sapi/phpdbg/phpdbg_list.c b/sapi/phpdbg/phpdbg_list.c index 037c6c38b2..e8db4e605c 100644 --- a/sapi/phpdbg/phpdbg_list.c +++ b/sapi/phpdbg/phpdbg_list.c @@ -130,14 +130,14 @@ void phpdbg_list_file(const char *filename, long count, long offset, int highlig char *opened = NULL; char buffer[8096] = {0,}; long line = 0; - + php_stream *stream = NULL; if (VCWD_STAT(filename, &st) == FAILURE) { phpdbg_error("Failed to stat file %s", filename); return; } - + stream = php_stream_open_wrapper(filename, "rb", USE_PATH, &opened); if (!stream) { @@ -145,11 +145,17 @@ void phpdbg_list_file(const char *filename, long count, long offset, int highlig return; } + if (offset < 0) { + count += offset; + offset = 0; + } + while (php_stream_gets(stream, buffer, sizeof(buffer)) != NULL) { + long linelen = strlen(buffer); + ++line; - if (!offset || offset <= line) { - /* Without offset, or offset reached */ + if (offset <= line) { if (!highlight) { phpdbg_write("%05ld: %s", line, buffer); } else { @@ -159,10 +165,15 @@ void phpdbg_list_file(const char *filename, long count, long offset, int highlig phpdbg_write(">%05ld: %s", line, buffer); } } + + if (buffer[linelen - 1] != '\n') { + phpdbg_write("\n"); + } } - - if ((count + (offset-1)) == line) + + if (count > 0 && count + offset - 1 < line) { break; + } } php_stream_close(stream); diff --git a/sapi/phpdbg/phpdbg_parser.c b/sapi/phpdbg/phpdbg_parser.c index f9a3e4d299..e34c2f48ff 100644 --- a/sapi/phpdbg/phpdbg_parser.c +++ b/sapi/phpdbg/phpdbg_parser.c @@ -436,7 +436,7 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 25 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 41 +#define YYLAST 42 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 21 @@ -493,8 +493,8 @@ static const yytype_uint8 yytranslate[] = static const yytype_uint8 yyprhs[] = { 0, 0, 3, 5, 7, 8, 10, 13, 17, 22, - 27, 33, 37, 43, 47, 49, 51, 53, 55, 57, - 59, 61, 64, 67, 70, 72 + 27, 33, 37, 43, 47, 50, 52, 54, 56, 58, + 60, 62, 64, 67, 70, 72 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ @@ -504,9 +504,9 @@ static const yytype_int8 yyrhs[] = 23, 24, -1, 18, 10, 14, -1, 18, 10, 12, 14, -1, 13, 18, 10, 14, -1, 13, 18, 10, 12, 14, -1, 18, 11, 18, -1, 18, 11, 18, - 12, 14, -1, 18, 12, 14, -1, 17, -1, 16, - -1, 15, -1, 7, -1, 8, -1, 14, -1, 18, - -1, 6, 19, -1, 3, 19, -1, 5, 19, -1, + 12, 14, -1, 18, 12, 14, -1, 6, 19, -1, + 17, -1, 16, -1, 15, -1, 7, -1, 8, -1, + 14, -1, 18, -1, 3, 19, -1, 5, 19, -1, 4, -1, 4, 19, -1 }; @@ -514,8 +514,8 @@ static const yytype_int8 yyrhs[] = static const yytype_uint8 yyrline[] = { 0, 66, 66, 67, 68, 72, 73, 77, 82, 87, - 97, 107, 112, 118, 124, 125, 126, 127, 128, 129, - 130, 134, 139, 144, 149, 153 + 97, 107, 112, 118, 124, 129, 130, 131, 132, 133, + 134, 135, 139, 144, 149, 153 }; #endif @@ -552,15 +552,15 @@ static const yytype_uint8 yyr1[] = { 0, 21, 22, 22, 22, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 25, 25, 25, 25, 25 + 24, 24, 25, 25, 25, 25 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 1, 0, 1, 2, 3, 4, 4, - 5, 3, 5, 3, 1, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 1, 2 + 5, 3, 5, 3, 2, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 1, 2 }; /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. @@ -568,9 +568,9 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 4, 0, 24, 0, 0, 17, 18, 0, 19, 16, - 15, 14, 20, 0, 2, 5, 3, 22, 25, 23, - 21, 0, 0, 0, 0, 1, 6, 0, 0, 7, + 4, 0, 24, 0, 0, 18, 19, 0, 20, 17, + 16, 15, 21, 0, 2, 5, 3, 22, 25, 23, + 14, 0, 0, 0, 0, 1, 6, 0, 0, 7, 11, 13, 0, 9, 8, 0, 10, 12 }; @@ -585,16 +585,16 @@ static const yytype_int8 yydefgoto[] = #define YYPACT_NINF -11 static const yytype_int8 yypact[] = { - -3, -10, 10, 11, 12, -11, -11, 14, -11, -11, - -11, -11, -4, 28, 9, -11, -11, -11, -11, -11, - -11, 23, 6, 16, 21, -11, -11, 7, 22, -11, - 25, -11, 24, -11, -11, 26, -11, -11 + -3, -10, 11, 12, 13, -11, -11, 15, -11, -11, + -11, -11, -4, 29, 10, -11, -11, -11, -11, -11, + -11, 24, 7, 17, 22, -11, -11, 8, 23, -11, + 26, -11, 25, -11, -11, 27, -11, -11 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -11, -11, -11, 27, -11 + -11, -11, -11, 28, -11 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -604,10 +604,10 @@ static const yytype_int8 yypgoto[] = static const yytype_uint8 yytable[] = { 1, 2, 3, 4, 5, 6, 22, 23, 24, 17, - 7, 8, 9, 10, 11, 12, 5, 6, 28, 32, - 29, 33, 7, 8, 9, 10, 11, 12, 25, 18, - 19, 20, 21, 27, 30, 31, 34, 35, 36, 0, - 37, 26 + 7, 8, 9, 10, 11, 12, 4, 5, 6, 28, + 32, 29, 33, 7, 8, 9, 10, 11, 12, 25, + 18, 19, 20, 21, 27, 30, 31, 34, 35, 36, + 0, 37, 26 }; #define yypact_value_is_default(yystate) \ @@ -619,10 +619,10 @@ static const yytype_uint8 yytable[] = static const yytype_int8 yycheck[] = { 3, 4, 5, 6, 7, 8, 10, 11, 12, 19, - 13, 14, 15, 16, 17, 18, 7, 8, 12, 12, - 14, 14, 13, 14, 15, 16, 17, 18, 0, 19, - 19, 19, 18, 10, 18, 14, 14, 12, 14, -1, - 14, 14 + 13, 14, 15, 16, 17, 18, 6, 7, 8, 12, + 12, 14, 14, 13, 14, 15, 16, 17, 18, 0, + 19, 19, 19, 18, 10, 18, 14, 14, 12, 14, + -1, 14, 14 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -1563,53 +1563,53 @@ yyreduce: case 14: /* Line 1802 of yacc.c */ #line 124 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" - { (yyval) = (yyvsp[(1) - (1)]); } + { + (yyval).type = COND_PARAM; + (yyval).str = (yyvsp[(2) - (2)]).str; + (yyval).len = (yyvsp[(2) - (2)]).len; + } break; case 15: /* Line 1802 of yacc.c */ -#line 125 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 129 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 16: /* Line 1802 of yacc.c */ -#line 126 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 130 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 17: /* Line 1802 of yacc.c */ -#line 127 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 131 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 18: /* Line 1802 of yacc.c */ -#line 128 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 132 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 19: /* Line 1802 of yacc.c */ -#line 129 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 133 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 20: /* Line 1802 of yacc.c */ -#line 130 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" +#line 134 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 21: /* Line 1802 of yacc.c */ -#line 134 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" - { - (yyval).type = COND_PARAM; - (yyval).str = (yyvsp[(2) - (2)]).str; - (yyval).len = (yyvsp[(2) - (2)]).len; - } +#line 135 "/var/root/php-src/sapi/phpdbg/phpdbg_parser.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 22: diff --git a/sapi/phpdbg/phpdbg_parser.y b/sapi/phpdbg/phpdbg_parser.y index fd81edfc29..702bf78455 100644 --- a/sapi/phpdbg/phpdbg_parser.y +++ b/sapi/phpdbg/phpdbg_parser.y @@ -121,6 +121,11 @@ parameter $$.len = $1.len; $$.num = $3.num; } + | T_IF T_INPUT { + $$.type = COND_PARAM; + $$.str = $2.str; + $$.len = $2.len; + } | T_OPCODE { $$ = $1; } | T_ADDR { $$ = $1; } | T_LITERAL { $$ = $1; } @@ -131,12 +136,7 @@ parameter ; full_expression - : T_IF T_INPUT { - $$.type = COND_PARAM; - $$.str = $2.str; - $$.len = $2.len; - } - | T_EVAL T_INPUT { + : T_EVAL T_INPUT { $$.type = EVAL_PARAM; $$.str = $2.str; $$.len = $2.len; diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 5379e77586..d91ef3f3f5 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -732,6 +732,11 @@ PHPDBG_COMMAND(print) /* {{{ */ #else phpdbg_writeln("Readline\tno"); #endif +#ifdef HAVE_LIBEDIT + phpdbg_writeln("Libedit\t\tyes"); +#else + phpdbg_writeln("Libedit\t\tno"); +#endif phpdbg_writeln("Exec\t\t%s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none"); phpdbg_writeln("Compiled\t%s", PHPDBG_G(ops) ? "yes" : "no"); diff --git a/sapi/phpdbg/phpdbg_utils.c b/sapi/phpdbg/phpdbg_utils.c index 98748b202a..3ce2fade17 100644 --- a/sapi/phpdbg/phpdbg_utils.c +++ b/sapi/phpdbg/phpdbg_utils.c @@ -400,12 +400,16 @@ PHPDBG_API const char *phpdbg_get_prompt(TSRMLS_D) /* {{{ */ } /* create cached prompt */ +#ifndef HAVE_LIBEDIT + /* TODO: libedit doesn't seems to support coloured prompt */ if ((PHPDBG_G(flags) & PHPDBG_IS_COLOURED)) { asprintf( &PHPDBG_G(prompt)[1], "\033[%sm%s\033[0m ", PHPDBG_G(colors)[PHPDBG_COLOR_PROMPT]->code, PHPDBG_G(prompt)[0]); - } else { + } else +#endif + { asprintf( &PHPDBG_G(prompt)[1], "%s ", PHPDBG_G(prompt)[0]); diff --git a/travis/compile.sh b/travis/compile.sh index 6ad3bfc396..babb945a04 100755 --- a/travis/compile.sh +++ b/travis/compile.sh @@ -13,6 +13,7 @@ fi ./configure --quiet \ $DEBUG \ $TS \ +--enable-fpm \ --with-pdo-mysql=mysqlnd \ --with-mysql=mysqlnd \ --with-mysqli=mysqlnd \ |