From: Bob Weinand Date: Sun, 23 Nov 2014 22:50:47 +0000 (+0100) Subject: Merge remote-tracking branch 'origin/PHP-5.6' X-Git-Tag: PRE_NATIVE_TLS_MERGE~150^2~38 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=38229d13d14bb0bda736d52a9a4f25c121445692;p=php Merge remote-tracking branch 'origin/PHP-5.6' Conflicts: Zend/zend_compile.c Zend/zend_execute.c Zend/zend_vm_def.h Zend/zend_vm_execute.h --- 38229d13d14bb0bda736d52a9a4f25c121445692 diff --cc Zend/zend_compile.c index d15b85fc0b,e023b24a8e..ee3aa75ad1 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@@ -3749,160 -5059,141 +3749,164 @@@ void zend_compile_stmt_list(zend_ast *a } /* }}} */ -void zend_do_default_before_statement(const znode *case_list, znode *default_token TSRMLS_DC) /* {{{ */ +void zend_compile_params(zend_ast *ast TSRMLS_DC) /* {{{ */ { - int next_op_number = get_next_op_number(CG(active_op_array)); - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - zend_switch_entry *switch_entry_ptr; + zend_ast_list *list = zend_ast_get_list(ast); + uint32_t i; + zend_op_array *op_array = CG(active_op_array); + zend_arg_info *arg_infos; - zend_stack_top(&CG(switch_cond_stack), (void **) &switch_entry_ptr); + if (list->children == 0) { + return; + } + + arg_infos = safe_emalloc(sizeof(zend_arg_info), list->children, 0); + for (i = 0; i < list->children; ++i) { + zend_ast *param_ast = list->child[i]; + zend_ast *type_ast = param_ast->child[0]; + zend_ast *var_ast = param_ast->child[1]; + zend_ast *default_ast = param_ast->child[2]; + zend_string *name = zend_ast_get_str(var_ast); + zend_bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0; + zend_bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0; + + znode var_node, default_node; + zend_uchar opcode; + zend_op *opline; + zend_arg_info *arg_info; - opline->opcode = ZEND_JMP; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2); - default_token->u.op.opline_num = next_op_number; + if (zend_is_auto_global(name TSRMLS_CC)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s", + name->val); + } - next_op_number = get_next_op_number(CG(active_op_array)); - switch_entry_ptr->default_case = next_op_number; + var_node.op_type = IS_CV; + var_node.u.op.var = lookup_cv(CG(active_op_array), zend_string_copy(name) TSRMLS_CC); - if (case_list->op_type==IS_UNUSED) { - return; - } - CG(active_op_array)->opcodes[case_list->u.op.opline_num].op1.opline_num = next_op_number; -} -/* }}} */ - -void zend_do_begin_class_declaration(const znode *class_token, znode *class_name, const znode *parent_class_name TSRMLS_DC) /* {{{ */ -{ - zend_op *opline; - int doing_inheritance = 0; - zend_class_entry *new_class_entry; - char *lcname; - int error = 0; - zval **ns_name, key; + if (EX_VAR_TO_NUM(var_node.u.op.var) != i) { + zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter $%s", + name->val); + } else if (zend_string_equals_literal(name, "this")) { + if (op_array->scope && (op_array->fn_flags & ZEND_ACC_STATIC) == 0) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); + } + op_array->this_var = var_node.u.op.var; + } - if (CG(active_class_entry)) { - zend_error_noreturn(E_COMPILE_ERROR, "Class declarations may not be nested"); - return; - } + if (op_array->fn_flags & ZEND_ACC_VARIADIC) { + zend_error_noreturn(E_COMPILE_ERROR, "Only the last parameter can be variadic"); + } - lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant)); + if (is_variadic) { + opcode = ZEND_RECV_VARIADIC; + default_node.op_type = IS_UNUSED; + op_array->fn_flags |= ZEND_ACC_VARIADIC; - if (!(strcmp(lcname, "self") && strcmp(lcname, "parent"))) { - efree(lcname); - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", Z_STRVAL(class_name->u.constant)); - } + if (default_ast) { + zend_error_noreturn(E_COMPILE_ERROR, + "Variadic parameter cannot have a default value"); + } + } else if (default_ast) { + opcode = ZEND_RECV_INIT; + default_node.op_type = IS_CONST; + zend_const_expr_to_zval(&default_node.u.constant, default_ast TSRMLS_CC); + } else { + opcode = ZEND_RECV; + default_node.op_type = IS_UNUSED; + op_array->required_num_args = i + 1; + } + + opline = zend_emit_op(NULL, opcode, NULL, &default_node TSRMLS_CC); + SET_NODE(opline->result, &var_node); + opline->op1.num = i + 1; + + arg_info = &arg_infos[i]; + arg_info->name = estrndup(name->val, name->len); + arg_info->name_len = (uint32_t)name->len; + arg_info->pass_by_reference = is_ref; + arg_info->is_variadic = is_variadic; + arg_info->type_hint = 0; + arg_info->allow_null = 1; + arg_info->class_name = NULL; + arg_info->class_name_len = 0; + + if (type_ast) { - zend_bool has_null_default = default_ast - && (Z_TYPE(default_node.u.constant) == IS_NULL - || (Z_TYPE(default_node.u.constant) == IS_CONSTANT - && strcasecmp(Z_STRVAL(default_node.u.constant), "NULL") == 0) - || Z_TYPE(default_node.u.constant) == IS_CONSTANT_AST); // ??? ++ zend_bool has_null_default = 0; ++ ++ if (default_ast) { ++ if (!(has_null_default = (Z_TYPE(default_node.u.constant) == IS_NULL || (Z_TYPE(default_node.u.constant) == IS_CONSTANT && strcasecmp(Z_STRVAL(default_node.u.constant), "NULL") == 0)))) { ++ if (Z_OPT_CONSTANT(default_node.u.constant)) { ++ has_null_default = 2; ++ } ++ } ++ } - /* Class name must not conflict with import names */ - if (CG(current_import) && - zend_hash_find(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&ns_name) == SUCCESS) { - error = 1; - } + op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; + arg_info->allow_null = has_null_default; + + if (type_ast->kind == ZEND_AST_TYPE) { + arg_info->type_hint = type_ast->attr; + if (arg_info->type_hint == IS_ARRAY) { + if (default_ast && !has_null_default + && Z_TYPE(default_node.u.constant) != IS_ARRAY + ) { + zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " + "with array type hint can only be an array or NULL"); + } + } else if (arg_info->type_hint == IS_CALLABLE && default_ast) { + if (!has_null_default) { + zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " + "with callable type hint can only be NULL"); + } + } + } else { + zend_string *class_name = zend_ast_get_str(type_ast); - if (CG(current_namespace)) { - /* Prefix class name with name of current namespace */ - znode tmp; + if (zend_is_const_default_class_ref(type_ast)) { + class_name = zend_resolve_class_name_ast(type_ast TSRMLS_CC); + } else { + zend_string_addref(class_name); + } - tmp.op_type = IS_CONST; - tmp.u.constant = *CG(current_namespace); - zval_copy_ctor(&tmp.u.constant); - zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); - *class_name = tmp; - efree(lcname); - lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant)); - } + arg_info->type_hint = IS_OBJECT; + arg_info->class_name = estrndup(class_name->val, class_name->len); + arg_info->class_name_len = (uint32_t)class_name->len; - if (error) { - char *tmp = zend_str_tolower_dup(Z_STRVAL_PP(ns_name), Z_STRLEN_PP(ns_name)); + zend_string_release(class_name); - if (Z_STRLEN_PP(ns_name) != Z_STRLEN(class_name->u.constant) || - memcmp(tmp, lcname, Z_STRLEN(class_name->u.constant))) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare class %s because the name is already in use", Z_STRVAL(class_name->u.constant)); + if (default_ast && !has_null_default) { + zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters " + "with a class type hint can only be NULL"); + } + } } - efree(tmp); } - new_class_entry = emalloc(sizeof(zend_class_entry)); - new_class_entry->type = ZEND_USER_CLASS; - new_class_entry->name = zend_new_interned_string(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant) + 1, 1 TSRMLS_CC); - new_class_entry->name_length = Z_STRLEN(class_name->u.constant); - - zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC); - new_class_entry->info.user.filename = zend_get_compiled_filename(TSRMLS_C); - new_class_entry->info.user.line_start = class_token->u.op.opline_num; - new_class_entry->ce_flags |= class_token->EA; - - if (parent_class_name && parent_class_name->op_type != IS_UNUSED) { - switch (parent_class_name->EA) { - case ZEND_FETCH_CLASS_SELF: - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'self' as class name as it is reserved"); - break; - case ZEND_FETCH_CLASS_PARENT: - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'parent' as class name as it is reserved"); - break; - case ZEND_FETCH_CLASS_STATIC: - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'static' as class name as it is reserved"); - break; - default: - break; - } - doing_inheritance = 1; - } + /* These are assigned at the end to avoid unitialized memory in case of an error */ + op_array->num_args = list->children; + op_array->arg_info = arg_infos; +} +/* }}} */ - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->op1_type = IS_CONST; - build_runtime_defined_function_key(&key, lcname, new_class_entry->name_length TSRMLS_CC); - opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC); - Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))); +void zend_compile_closure_uses(zend_ast *ast TSRMLS_DC) /* {{{ */ +{ + zend_ast_list *list = zend_ast_get_list(ast); + uint32_t i; - opline->op2_type = IS_CONST; + for (i = 0; i < list->children; ++i) { + zend_ast *var_ast = list->child[i]; + zend_string *name = zend_ast_get_str(var_ast); + zend_bool by_ref = var_ast->attr; + zval zv; - if (doing_inheritance) { - /* Make sure a trait does not try to extend a class */ - if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { - zend_error_noreturn(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name); + if (zend_string_equals_literal(name, "this")) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as lexical variable"); } - opline->extended_value = parent_class_name->u.op.var; - opline->opcode = ZEND_DECLARE_INHERITED_CLASS; - } else { - opline->opcode = ZEND_DECLARE_CLASS; - } - - LITERAL_STRINGL(opline->op2, lcname, new_class_entry->name_length, 0); - CALCULATE_LITERAL_HASH(opline->op2.constant); - - zend_hash_quick_update(CG(class_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &new_class_entry, sizeof(zend_class_entry *), NULL); - CG(active_class_entry) = new_class_entry; + ZVAL_NULL(&zv); + Z_CONST_FLAGS(zv) = by_ref ? IS_LEXICAL_REF : IS_LEXICAL_VAR; - opline->result.var = get_temporary_variable(CG(active_op_array)); - opline->result_type = IS_VAR; - GET_NODE(&CG(implementing_class), opline->result); - - if (CG(doc_comment)) { - CG(active_class_entry)->info.user.doc_comment = CG(doc_comment); - CG(active_class_entry)->info.user.doc_comment_len = CG(doc_comment_len); - CG(doc_comment) = NULL; - CG(doc_comment_len) = 0; + zend_compile_static_var_common(var_ast, &zv, by_ref TSRMLS_CC); } } /* }}} */ diff --cc Zend/zend_execute.c index 4fcd1de6b8,081af81d50..00e72a0e61 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@@ -568,13 -605,20 +568,23 @@@ ZEND_API void zend_verify_arg_error(in } 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); } - return 0; + + if (arg && zf->common.type == ZEND_USER_FUNCTION) { + ZVAL_COPY_VALUE(arg, &old_arg); + } } - static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg TSRMLS_DC) + static inline int zend_arg_allows_null(zend_bool allow_null, zval *default_value TSRMLS_DC) + { + if (allow_null < 2 || !default_value) { + return allow_null; + } + + /* assuming update_constant_ex done before */ + return Z_TYPE_P(default_value) == IS_NULL; + } + -static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, zval *defaultval, ulong fetch_type TSRMLS_DC) ++static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *defaultval TSRMLS_DC) { zend_arg_info *cur_arg_info; char *need_msg; @@@ -593,71 -637,45 +603,71 @@@ } if (cur_arg_info->class_name) { - const char *class_name; + char *class_name; - if (!arg) { - need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); - return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "" TSRMLS_CC); - } + ZVAL_DEREF(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); + need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce TSRMLS_CC); if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) { - return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name 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) { + } else if (Z_TYPE_P(arg) != IS_NULL || !zend_arg_allows_null(cur_arg_info->allow_null, defaultval TSRMLS_CC)) { - need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); - return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC); + need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce 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) { - switch(cur_arg_info->type_hint) { - case IS_ARRAY: - if (!arg) { - return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "" TSRMLS_CC); - } + 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)) { ++ if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !zend_arg_allows_null(cur_arg_info->allow_null, defaultval 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)) { ++ if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !zend_arg_allows_null(cur_arg_info->allow_null, defaultval 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 { + zend_error(E_ERROR, "Unknown typehint"); +#endif + } + } +} - if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !zend_arg_allows_null(cur_arg_info->allow_null, defaultval TSRMLS_CC))) { - return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "" TSRMLS_CC); - } - break; +static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num TSRMLS_DC) +{ + zend_arg_info *cur_arg_info; + char *need_msg; + zend_class_entry *ce; - case IS_CALLABLE: - if (!arg) { - return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "" TSRMLS_CC); - } - if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !zend_arg_allows_null(cur_arg_info->allow_null, defaultval TSRMLS_CC))) { - return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC); - } - break; + if (UNEXPECTED(!zf->common.arg_info)) { + return 1; + } - default: - zend_error(E_ERROR, "Unknown typehint"); + if (EXPECTED(arg_num <= zf->common.num_args)) { + cur_arg_info = &zf->common.arg_info[arg_num-1]; + } else if (zf->common.fn_flags & ZEND_ACC_VARIADIC) { + cur_arg_info = &zf->common.arg_info[zf->common.num_args-1]; + } else { + return 1; + } + + if (cur_arg_info->class_name) { + char *class_name; + + need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "", NULL TSRMLS_CC); + return 0; + } 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", "", 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", "", NULL TSRMLS_CC); +#if ZEND_DEBUG + } else { + zend_error(E_ERROR, "Unknown typehint"); +#endif } + return 0; } return 1; } diff --cc Zend/zend_vm_def.h index eb181d9c27,65981f6f6f..78ef315ec7 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@@ -2461,351 -2721,122 +2461,351 @@@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_ CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - call->called_scope = ce; - call->object = NULL; - - if (ce->get_static_method) { - call->fbc = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC); + + if (called_scope->get_static_method) { + fbc = called_scope->get_static_method(called_scope, Z_STR_P(method) TSRMLS_CC); + } else { + fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL TSRMLS_CC); + } + if (UNEXPECTED(fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", called_scope->name->val, Z_STRVAL_P(method)); + } + if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_STRICT, + "Non-static method %s::%s() should not be called statically", + fbc->common.scope->name->val, fbc->common.function_name->val); + } else { + zend_error_noreturn( + E_ERROR, + "Non-static method %s::%s() cannot be called statically", + fbc->common.scope->name->val, fbc->common.function_name->val); + } + } + } else { + called_scope = Z_OBJCE_P(obj); + object = Z_OBJ_P(obj); + + 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()", object->ce->name->val, Z_STRVAL_P(method)); + } + + if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + object = NULL; + } else { + GC_REFCOUNT(object)++; /* For $this pointer */ + } + } + FREE_OP2(); + } else { + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Function name must be a string"); + ZEND_VM_CONTINUE(); /* Never reached */ + } + EX(call) = zend_vm_stack_push_call_frame(VM_FRAME_NESTED_FUNCTION, + fbc, opline->extended_value, called_scope, object, EX(call) TSRMLS_CC); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } +} + +ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMP|VAR|CV) +{ + USE_OPLINE + zend_free_op free_op2; + zval *function_name = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); + zend_fcall_info_cache fcc; + char *error = NULL; + zend_function *func; + zend_class_entry *called_scope; + zend_object *object; + + if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error TSRMLS_CC)) { + if (error) { + efree(error); + } + func = fcc.function_handler; + if (func->common.fn_flags & ZEND_ACC_CLOSURE) { + /* Delay closure destruction until its invocation */ + func->common.prototype = (zend_function*)Z_OBJ_P(function_name); + Z_ADDREF_P(function_name); + } + called_scope = fcc.called_scope; + object = fcc.object; + if (object) { + GC_REFCOUNT(object)++; /* For $this pointer */ + } else if (func->common.scope && + !(func->common.fn_flags & ZEND_ACC_STATIC)) { + if (func->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + zend_error(E_STRICT, + "Non-static method %s::%s() should not be called statically", + func->common.scope->name->val, func->common.function_name->val); + } else { + zend_error_noreturn( + E_ERROR, + "Non-static method %s::%s() cannot be called statically", + func->common.scope->name->val, func->common.function_name->val); + } + } + } else { + zend_error(E_WARNING, "%s() expects parameter 1 to be a valid callback, %s", Z_STRVAL_P(opline->op1.zv), error); + efree(error); + func = (zend_function*)&zend_pass_function; + called_scope = NULL; + object = NULL; + } + + EX(call) = zend_vm_stack_push_call_frame(VM_FRAME_NESTED_FUNCTION, + func, opline->extended_value, called_scope, object, EX(call) TSRMLS_CC); + + FREE_OP2(); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) +{ + USE_OPLINE + zval *func_name; + zval *func; + zend_function *fbc; + + func_name = opline->op2.zv + 1; + if (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 { + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); + } + } else { + fbc = Z_FUNC_P(func); + CACHE_PTR(Z_CACHE_SLOT_P(opline->op2.zv), fbc); + } + + EX(call) = zend_vm_stack_push_call_frame(VM_FRAME_NESTED_FUNCTION, + fbc, opline->extended_value, NULL, NULL, EX(call) TSRMLS_CC); + + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, ANY, CONST) +{ + USE_OPLINE + zend_free_op free_op2; + zval *fname = GET_OP2_ZVAL_PTR(BP_VAR_R); + 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(VM_FRAME_NESTED_FUNCTION, + fbc, opline->extended_value, NULL, NULL, EX(call) TSRMLS_CC); + + 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; + zend_object *object = Z_OBJ(call->This); + + SAVE_OPLINE(); + EX(call) = call->prev_execute_data; + 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(); + } + } + } + + LOAD_OPLINE(); + + if (UNEXPECTED(fbc->type == ZEND_INTERNAL_FUNCTION)) { + int should_change_scope = 0; + zval *ret; + + if (fbc->common.scope) { + should_change_scope = 1; + /* 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 + } else { + call->called_scope = EX(called_scope); + Z_OBJ(call->This) = Z_OBJ(EX(This)); + } + + call->prev_execute_data = execute_data; + EG(current_execute_data) = call; + + if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { + uint32_t i; + zval *p = ZEND_CALL_ARG(call, 1); + + for (i = 0; i < call->num_args; ++i) { - zend_verify_arg_type(fbc, i + 1, p TSRMLS_CC); ++ zend_verify_arg_type(fbc, i + 1, p, NULL TSRMLS_CC); + p++; + } + if (UNEXPECTED(EG(exception) != NULL)) { + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call TSRMLS_CC); + zend_vm_stack_free_call_frame(call TSRMLS_CC); + 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 { - call->fbc = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); + ZEND_VM_C_GOTO(fcall_end); } - } else { - call->object = *obj; - ce = call->called_scope = Z_OBJCE_PP(obj); + } + } - call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, Z_STRVAL_PP(method), Z_STRLEN_PP(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_PP(method)); - } + 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 ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { - call->object = NULL; - } else { - if (!PZVAL_IS_REF(call->object)) { - Z_ADDREF_P(call->object); /* For $this pointer */ - } else { - zval *this_ptr; - ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, call->object); - zval_copy_ctor(this_ptr); - call->object = this_ptr; - } - } + if (!zend_execute_internal) { + /* saves one function call if zend_execute_internal is not used */ + fbc->internal_function.handler(call, ret TSRMLS_CC); + } else { + zend_execute_internal(call, ret TSRMLS_CC); + } + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call TSRMLS_CC); + zend_vm_stack_free_call_frame(call 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 (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { + call->scope = EG(scope) = fbc->common.scope; + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (RETURN_VALUE_USED(opline)) { + zend_generator_create_zval(call, &fbc->op_array, EX_VAR(opline->result.var) TSRMLS_CC); + } else { + zend_vm_stack_free_args(call TSRMLS_CC); } + + zend_vm_stack_free_call_frame(call TSRMLS_CC); + } else { + zval *return_value = NULL; + + call->symbol_table = NULL; + if (RETURN_VALUE_USED(opline)) { + return_value = EX_VAR(opline->result.var); - if (UNEXPECTED(call->fbc == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); + ZVAL_NULL(return_value); + Z_VAR_FLAGS_P(return_value) = 0; } - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; + call->prev_execute_data = execute_data; + i_init_func_execute_data(call, &fbc->op_array, return_value TSRMLS_CC); - FREE_OP2(); - CHECK_EXCEPTION(); - ZEND_VM_NEXT_OPCODE(); - } else { - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); + if (EXPECTED(zend_execute_ex == execute_ex)) { + ZEND_VM_ENTER(); + } else { + call->frame_info = VM_FRAME_INFO( + VM_FRAME_TOP_FUNCTION, + VM_FRAME_FLAGS(call->frame_info)); + zend_execute_ex(call TSRMLS_CC); } - zend_error_noreturn(E_ERROR, "Function name must be a string"); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ } - } -} - + } else { /* ZEND_OVERLOADED_FUNCTION */ + EG(scope) = fbc->common.scope; -ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) -{ - USE_OPLINE - zend_literal *func_name; - call_slot *call = EX(call_slots) + opline->result.num; + ZVAL_NULL(EX_VAR(opline->result.var)); - func_name = opline->op2.literal + 1; - if (CACHED_PTR(opline->op2.literal->cache_slot)) { - call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); - } else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE) { - func_name++; - if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE)) { - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); + /* Not sure what should be done here if it's a static method */ + if (EXPECTED(object != NULL)) { + call->prev_execute_data = execute_data; + EG(current_execute_data) = call; + object->handlers->call_method(fbc->common.function_name, object, call, EX_VAR(opline->result.var) TSRMLS_CC); + EG(current_execute_data) = call->prev_execute_data; } else { - CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); + zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } - } else { - CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); - } - - call->object = NULL; - call->called_scope = NULL; - call->num_additional_args = 0; - call->is_ctor_call = 0; - EX(call) = call; - ZEND_VM_NEXT_OPCODE(); -} + zend_vm_stack_free_args(call TSRMLS_CC); -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_stack_free_call_frame(call TSRMLS_CC); -ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) -{ - USE_OPLINE - zend_free_op free_op1; - zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R); - call_slot *call = EX(call_slots) + opline->op2.num; + if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { + zend_string_release(fbc->common.function_name); + } + efree(fbc); - if (CACHED_PTR(opline->op1.literal->cache_slot)) { - EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot); - } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) { - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val); - } else { - CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function); + 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; + } } - 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; +ZEND_VM_C_LABEL(fcall_end_change_scope): + if (object) { + if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) { + if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { + GC_REFCOUNT(object)--; + } + if (GC_REFCOUNT(object) == 1) { + zend_object_store_ctor_failed(object TSRMLS_CC); + } + } + OBJ_RELEASE(object); + } + EG(scope) = EX(scope); - FREE_OP1(); +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_DISPATCH_TO_HELPER(zend_do_fcall_common_helper); + ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) @@@ -3516,47 -3407,52 +3516,56 @@@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VA ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY) +{ + USE_OPLINE + uint32_t arg_num = opline->op1.num; + + SAVE_OPLINE(); + if (UNEXPECTED(arg_num > EX(num_args))) { + zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC); + 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); + - zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC); ++ zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC); + CHECK_EXCEPTION(); + } + + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) { USE_OPLINE - zval *assignment_value, *default_val = NULL; - zend_uint arg_num = opline->op1.num; - zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC); - zval **var_ptr; + uint32_t arg_num = opline->op1.num; - zval *param; ++ zval *param, default_val = {{0}}; SAVE_OPLINE(); - if (IS_CONSTANT_TYPE(Z_TYPE_P(opline->op2.zv))) { - ALLOC_ZVAL(default_val); - *default_val = *opline->op2.zv; - Z_SET_REFCOUNT_P(default_val, 1); ++ if (Z_OPT_CONSTANT_P(opline->op2.zv)) { ++ ZVAL_COPY_VALUE(&default_val, opline->op2.zv); + zval_update_constant(&default_val, 0 TSRMLS_CC); + } - if (param == NULL) { - if (default_val) { - assignment_value = default_val; ++ + 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); ++ if (Z_TYPE(default_val) != IS_UNDEF) { ++ *param = default_val; } else { - ALLOC_ZVAL(assignment_value); - *assignment_value = *opline->op2.zv; - if (Z_TYPE_P(assignment_value) == IS_ARRAY) { - HashTable *ht; - - ALLOC_HASHTABLE(ht); - zend_hash_init(ht, zend_hash_num_elements(Z_ARRVAL_P(assignment_value)), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(ht, Z_ARRVAL_P(assignment_value), (copy_ctor_func_t) zval_deep_copy, NULL, sizeof(zval *)); - Z_ARRVAL_P(assignment_value) = ht; - } else { - zval_copy_ctor(assignment_value); ++ ZVAL_COPY_VALUE(param, opline->op2.zv); + /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */ + if (UNEXPECTED(Z_OPT_COPYABLE_P(param))) { + zval_copy_ctor_func(param); } } - INIT_PZVAL(assignment_value); - } else { - assignment_value = *param; - Z_ADDREF_P(assignment_value); } - zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, default_val, opline->extended_value TSRMLS_CC); - var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - zval_ptr_dtor(var_ptr); - *var_ptr = assignment_value; + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC); ++ zend_verify_arg_type(EX(func), arg_num, param, Z_TYPE(default_val) == IS_UNDEF ? NULL : &default_val TSRMLS_CC); ++ } + - if (default_val && assignment_value != default_val) { - zval_dtor(default_val); - efree(default_val); ++ if (Z_TYPE(default_val) != IS_UNDEF && arg_num <= EX(num_args)) { ++ zval_dtor(&default_val); } CHECK_EXCEPTION(); @@@ -3572,27 -3468,13 +3581,27 @@@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC SAVE_OPLINE(); - var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - Z_DELREF_PP(var_ptr); - MAKE_STD_ZVAL(params); - *var_ptr = params; + params = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); if (arg_num <= arg_count) { + zval *param; + array_init_size(params, arg_count - arg_num + 1); + 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 TSRMLS_CC); ++ zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC); + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } while (++arg_num <= arg_count); + } else { + do { + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } while (++arg_num <= arg_count); + } } else { array_init(params); } diff --cc Zend/zend_vm_execute.h index 2a8e901c57,318f903f77..074dbc2965 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@@ -509,50 -499,49 +509,50 @@@ static int ZEND_FASTCALL ZEND_DO_FCALL } } } - if (fbc->common.scope && - !(fbc->common.fn_flags & ZEND_ACC_STATIC) && - !EX(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, fbc->common.function_name); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); - } + LOAD_OPLINE(); + + if (UNEXPECTED(fbc->type == ZEND_INTERNAL_FUNCTION)) { + int should_change_scope = 0; + zval *ret; + + if (fbc->common.scope) { + should_change_scope = 1; + /* 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 } 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, fbc->common.function_name); + call->called_scope = EX(called_scope); + Z_OBJ(call->This) = Z_OBJ(EX(This)); } - } - - if (fbc->type == ZEND_USER_FUNCTION || fbc->common.scope) { - should_change_scope = 1; - EX(current_this) = EG(This); - EX(current_scope) = EG(scope); - EX(current_called_scope) = EG(called_scope); - EG(This) = EX(object); - EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL; - EG(called_scope) = EX(call)->called_scope; - } - num_args = opline->extended_value + EX(call)->num_additional_args; - if (EX(call)->num_additional_args) { - EX(function_state).arguments = zend_vm_stack_push_args(num_args TSRMLS_CC); - } else { - EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C); - zend_vm_stack_push((void*)(zend_uintptr_t) num_args TSRMLS_CC); - } - LOAD_OPLINE(); + call->prev_execute_data = execute_data; + EG(current_execute_data) = call; - if (fbc->type == ZEND_INTERNAL_FUNCTION) { if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { - zend_uint i; - void **p = EX(function_state).arguments - num_args; + uint32_t i; + zval *p = ZEND_CALL_ARG(call, 1); - for (i = 0; i < num_args; ++i, ++p) { - zend_verify_arg_type(fbc, i + 1, (zval *) *p, NULL, 0 TSRMLS_CC); + for (i = 0; i < call->num_args; ++i) { - zend_verify_arg_type(fbc, i + 1, p TSRMLS_CC); ++ zend_verify_arg_type(fbc, i + 1, p, NULL TSRMLS_CC); + p++; + } + if (UNEXPECTED(EG(exception) != NULL)) { + EG(current_execute_data) = call->prev_execute_data; + zend_vm_stack_free_args(call TSRMLS_CC); + zend_vm_stack_free_call_frame(call TSRMLS_CC); + if (RETURN_VALUE_USED(opline)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } + if (UNEXPECTED(should_change_scope)) { + goto fcall_end_change_scope; + } else { + goto fcall_end; + } } } @@@ -966,61 -894,86 +966,61 @@@ static int ZEND_FASTCALL ZEND_SEND_ARR ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zend_uint arg_num = opline->op1.num; - zend_uint arg_count = zend_vm_stack_get_args_count(TSRMLS_C); - zval **var_ptr, *params; + uint32_t arg_num = opline->op1.num; SAVE_OPLINE(); + if (UNEXPECTED(arg_num > EX(num_args))) { + zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC); + 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); - zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC); - var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - Z_DELREF_PP(var_ptr); - MAKE_STD_ZVAL(params); - *var_ptr = params; - - if (arg_num <= arg_count) { - array_init_size(params, arg_count - arg_num + 1); - } else { - array_init(params); - } - - for (; arg_num <= arg_count; ++arg_num) { - zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC); - zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, NULL, opline->extended_value TSRMLS_CC); - zend_hash_next_index_insert(Z_ARRVAL_P(params), param, sizeof(zval *), NULL); - Z_ADDREF_PP(param); ++ zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC); + CHECK_EXCEPTION(); } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *object_zval; - zend_function *constructor; + uint32_t arg_num = opline->op1.num; + uint32_t arg_count = EX(num_args); + zval *params; SAVE_OPLINE(); - if (UNEXPECTED((EX_T(opline->op1.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) != 0)) { - if (EX_T(opline->op1.var).class_entry->ce_flags & ZEND_ACC_INTERFACE) { - zend_error_noreturn(E_ERROR, "Cannot instantiate interface %s", EX_T(opline->op1.var).class_entry->name); - } else if ((EX_T(opline->op1.var).class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { - zend_error_noreturn(E_ERROR, "Cannot instantiate trait %s", EX_T(opline->op1.var).class_entry->name); - } else { - zend_error_noreturn(E_ERROR, "Cannot instantiate abstract class %s", EX_T(opline->op1.var).class_entry->name); - } - } - ALLOC_ZVAL(object_zval); - object_init_ex(object_zval, EX_T(opline->op1.var).class_entry); - INIT_PZVAL(object_zval); - constructor = Z_OBJ_HT_P(object_zval)->get_constructor(object_zval TSRMLS_CC); + params = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (constructor == NULL) { - if (RETURN_VALUE_USED(opline)) { - AI_SET_PTR(&EX_T(opline->result.var), object_zval); + if (arg_num <= arg_count) { + zval *param; + + array_init_size(params, arg_count - arg_num + 1); + 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 TSRMLS_CC); ++ zend_verify_arg_type(EX(func), arg_num, param, NULL TSRMLS_CC); + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } while (++arg_num <= arg_count); } else { - zval_ptr_dtor(&object_zval); + do { + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } while (++arg_num <= arg_count); } - ZEND_VM_JMP(EX(op_array)->opcodes + opline->op2.opline_num); } else { - call_slot *call = EX(call_slots) + opline->extended_value; - - if (RETURN_VALUE_USED(opline)) { - PZVAL_LOCK(object_zval); - AI_SET_PTR(&EX_T(opline->result.var), object_zval); - } - - /* We are not handling overloaded classes right now */ - call->fbc = constructor; - call->object = object_zval; - call->called_scope = EX_T(opline->op1.var).class_entry; - 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(); + array_init(params); } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } static int ZEND_FASTCALL ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@@ -1644,25 -1615,49 +1644,34 @@@ static int ZEND_FASTCALL ZEND_INIT_FCA static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *assignment_value, *default_val = NULL; - zend_uint arg_num = opline->op1.num; - zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC); - zval **var_ptr; + uint32_t arg_num = opline->op1.num; - zval *param; ++ zval *param, default_val = {{0}}; SAVE_OPLINE(); - if (IS_CONSTANT_TYPE(Z_TYPE_P(opline->op2.zv))) { - ALLOC_ZVAL(default_val); - *default_val = *opline->op2.zv; - Z_SET_REFCOUNT_P(default_val, 1); ++ if (Z_OPT_CONSTANT_P(opline->op2.zv)) { ++ ZVAL_COPY_VALUE(&default_val, opline->op2.zv); + zval_update_constant(&default_val, 0 TSRMLS_CC); + } - if (param == NULL) { - if (default_val) { - assignment_value = default_val; - } else { - ALLOC_ZVAL(assignment_value); - *assignment_value = *opline->op2.zv; - if (Z_TYPE_P(assignment_value) == IS_ARRAY) { - HashTable *ht; + - ALLOC_HASHTABLE(ht); - zend_hash_init(ht, zend_hash_num_elements(Z_ARRVAL_P(assignment_value)), NULL, ZVAL_PTR_DTOR, 0); - zend_hash_copy(ht, Z_ARRVAL_P(assignment_value), (copy_ctor_func_t) zval_deep_copy, NULL, sizeof(zval *)); - Z_ARRVAL_P(assignment_value) = ht; - } else { - zval_copy_ctor(assignment_value); + 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); ++ if (Z_TYPE(default_val) != IS_UNDEF) { ++ *param = default_val; + } else { ++ ZVAL_COPY_VALUE(param, opline->op2.zv); + /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */ + if (UNEXPECTED(Z_OPT_COPYABLE_P(param))) { + zval_copy_ctor_func(param); } } - INIT_PZVAL(assignment_value); - } else { - assignment_value = *param; - Z_ADDREF_P(assignment_value); } - zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, default_val, opline->extended_value TSRMLS_CC); - var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - zval_ptr_dtor(var_ptr); - *var_ptr = assignment_value; + if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type(EX(func), arg_num, param TSRMLS_CC); ++ zend_verify_arg_type(EX(func), arg_num, param, Z_TYPE(default_val) == IS_UNDEF ? NULL : &default_val TSRMLS_CC); ++ } + - if (default_val && assignment_value != default_val) { - zval_dtor(default_val); - efree(default_val); ++ if (Z_TYPE(default_val) != IS_UNDEF && arg_num <= EX(num_args)) { ++ zval_dtor(&default_val); } CHECK_EXCEPTION();