From: Dmitry Stogov Date: Fri, 4 Apr 2014 10:36:34 +0000 (+0400) Subject: Optimized RECV_* opcodes X-Git-Tag: POST_PHPNG_MERGE~412^2~169 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=eaeb3c39b470a8870fd582d4485cde6b3a6faf71;p=php Optimized RECV_* opcodes --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index e02778f5de..d4305a042c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1961,6 +1961,10 @@ void zend_do_receive_param(zend_uchar op, znode *varname, const znode *initializ } } } + + if (cur_arg_info->class_name || cur_arg_info->type_hint) { + CG(active_op_array)->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS; + } } /* }}} */ diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 5c32ef0705..2f867ac5df 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -342,6 +342,11 @@ static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(const zend_execute_dat return ret; } +static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_W(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC) +{ + return EX_VAR(var); +} + static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_W(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC) { zval *ret = EX_VAR(var); @@ -497,7 +502,7 @@ ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ul } } -ZEND_API int 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 TSRMLS_DC) { zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data; const char *fname = zf->common.function_name->val; @@ -517,63 +522,51 @@ ZEND_API int zend_verify_arg_error(int error_type, const zend_function *zf, zend } 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; } -static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type TSRMLS_DC) +static void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type TSRMLS_DC) { zend_arg_info *cur_arg_info; char *need_msg; zend_class_entry *ce; - if (!zf->common.arg_info) { - return 1; + if (UNEXPECTED(!zf->common.arg_info)) { + return; } - if (arg_num <= zf->common.num_args) { + 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; + return; } if (cur_arg_info->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); 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->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 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); - return 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), "" 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); - } - ZVAL_DEREF(arg); if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { - return 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), "" TSRMLS_CC); } break; 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 || !cur_arg_info->allow_null)) { - return 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), "" TSRMLS_CC); } break; @@ -581,7 +574,63 @@ static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zva zend_error(E_ERROR, "Unknown typehint"); } } - return 1; +} + +static inline int zend_verify_missing_arg_type(zend_function *zf, zend_uint arg_num, ulong fetch_type TSRMLS_DC) +{ + zend_arg_info *cur_arg_info; + char *need_msg; + zend_class_entry *ce; + + if (UNEXPECTED(!zf->common.arg_info)) { + return 1; + } + + 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, fetch_type, &class_name, &ce TSRMLS_CC); + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "" TSRMLS_CC); + } else if (cur_arg_info->type_hint) { + switch(cur_arg_info->type_hint) { + case IS_ARRAY: + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "" TSRMLS_CC); + break; + + case IS_CALLABLE: + zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "" TSRMLS_CC); + break; + + default: + zend_error(E_ERROR, "Unknown typehint"); + } + } + return 0; +} + +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"; + 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); + } else { + zend_error(E_WARNING, "Missing argument %u for %s%s%s()", arg_num, class_name, space, func_name); + } + } } static inline void zend_assign_to_object(zval *retval, zval *object_ptr, zval *property_name, int value_type, znode_op *value_op, const zend_execute_data *execute_data, int opcode, const zend_literal *key TSRMLS_DC) diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 6170607a4f..67bce39748 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -68,7 +68,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 int 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 TSRMLS_DC); static zend_always_inline void i_zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC TSRMLS_DC) { @@ -94,13 +94,6 @@ static zend_always_inline void i_zval_ptr_dtor_nogc(zval *zval_ptr ZEND_FILE_LIN if (!Z_DELREF_P(zval_ptr)) { ZEND_ASSERT(zval_ptr != &EG(uninitialized_zval)); _zval_dtor_func_for_ptr(Z_COUNTED_P(zval_ptr) ZEND_FILE_LINE_CC); -//??? } else { -//??? if (Z_REFCOUNT_P(zval_ptr) == 1 && Z_ISREF_P(zval_ptr)) { - /* convert reference to regular value */ -//??? zend_reference *ref = Z_REF_P(zval_ptr); -//??? ZVAL_COPY_VALUE(zval_ptr, &ref->val); -//??? efree_rel(ref); -//??? } } } } @@ -285,12 +278,8 @@ static zend_always_inline void zend_vm_stack_clear_multiple(int nested TSRMLS_DC static zend_always_inline int zend_vm_stack_get_args_count_ex(zend_execute_data *ex) { - if (ex) { - zval *p = ex->function_state.arguments; - return Z_LVAL_P(p); - } else { - return 0; - } + zval *p = ex->function_state.arguments; + return Z_LVAL_P(p); } static zend_always_inline zval* zend_vm_stack_get_arg_ex(zend_execute_data *ex, int requested_arg) @@ -301,12 +290,16 @@ static zend_always_inline zval* zend_vm_stack_get_arg_ex(zend_execute_data *ex, if (UNEXPECTED(requested_arg > arg_count)) { return NULL; } - return (zval*)p - arg_count + requested_arg - 1; + return p - arg_count + requested_arg - 1; } static zend_always_inline int zend_vm_stack_get_args_count(TSRMLS_D) { - return zend_vm_stack_get_args_count_ex(EG(current_execute_data)->prev_execute_data); + if (EG(current_execute_data)->prev_execute_data) { + return zend_vm_stack_get_args_count_ex(EG(current_execute_data)->prev_execute_data); + } else { + return 0; + } } static zend_always_inline zval* zend_vm_stack_get_arg(int requested_arg TSRMLS_DC) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8c95eaeb5f..75ced021bb 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3337,35 +3337,21 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *param = zend_vm_stack_get_arg_ex(EX(prev_execute_data), arg_num TSRMLS_CC); + zval *arguments = EX(prev_execute_data)->function_state.arguments; + zend_uint arg_count = Z_LVAL_P(arguments); SAVE_OPLINE(); - if (UNEXPECTED(param == NULL)) { - if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) { - const char *space; - const char *class_name; - zend_execute_data *ptr; - - if (EG(active_op_array)->scope) { - class_name = EG(active_op_array)->scope->name->val; - space = "::"; - } else { - class_name = space = ""; - } - 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", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename->val, ptr->opline->lineno); - } else { - zend_error(E_WARNING, "Missing argument %u for %s%s%s()", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C)); - } - } + if (UNEXPECTED(arg_num > arg_count)) { + zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC); } else { zval *var_ptr; + zval *param = arguments - arg_count + arg_num - 1; - zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, param, opline->extended_value TSRMLS_CC); - var_ptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (Z_REFCOUNTED_P(var_ptr)) Z_DELREF_P(var_ptr); + 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); } @@ -3377,13 +3363,14 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *param = zend_vm_stack_get_arg_ex(EX(prev_execute_data), arg_num TSRMLS_CC); + zval *arguments = EX(prev_execute_data)->function_state.arguments; + zend_uint arg_count = Z_LVAL_P(arguments); zval *var_ptr; SAVE_OPLINE(); - var_ptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - zval_ptr_dtor(var_ptr); - if (param == NULL) { + 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); @@ -3394,10 +3381,13 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) } } } else { + zval *param = arguments - arg_count + arg_num - 1; ZVAL_COPY(var_ptr, param); } - zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, var_ptr, opline->extended_value 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, var_ptr, opline->extended_value TSRMLS_CC); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -3407,29 +3397,36 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zend_uint arg_count = zend_vm_stack_get_args_count_ex(EX(prev_execute_data) TSRMLS_CC); + zval *arguments = EX(prev_execute_data)->function_state.arguments; + zend_uint arg_count = Z_LVAL_P(arguments); zval *params; SAVE_OPLINE(); - params = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (Z_REFCOUNTED_P(params)) Z_DELREF_P(params); + 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; array_init_size(params, arg_count - arg_num + 1); + if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + do { + zend_verify_arg_type((zend_function *) EX(op_array), arg_num, param, opline->extended_value TSRMLS_CC); + zend_hash_next_index_insert(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(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } while (++arg_num <= arg_count); + } } else { array_init(params); } - for (; arg_num <= arg_count; ++arg_num) { - zval *param = zend_vm_stack_get_arg_ex(EX(prev_execute_data), arg_num TSRMLS_CC); - zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, param, opline->extended_value TSRMLS_CC); - zend_hash_next_index_insert(Z_ARRVAL_P(params), param); - if (Z_REFCOUNTED_P(param)) { - Z_ADDREF_P(param); - } - } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index e1c0ee2de4..a1360caeae 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -853,35 +853,21 @@ static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *param = zend_vm_stack_get_arg_ex(EX(prev_execute_data), arg_num TSRMLS_CC); + zval *arguments = EX(prev_execute_data)->function_state.arguments; + zend_uint arg_count = Z_LVAL_P(arguments); SAVE_OPLINE(); - if (UNEXPECTED(param == NULL)) { - if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) { - const char *space; - const char *class_name; - zend_execute_data *ptr; - - if (EG(active_op_array)->scope) { - class_name = EG(active_op_array)->scope->name->val; - space = "::"; - } else { - class_name = space = ""; - } - 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", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename->val, ptr->opline->lineno); - } else { - zend_error(E_WARNING, "Missing argument %u for %s%s%s()", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C)); - } - } + if (UNEXPECTED(arg_num > arg_count)) { + zend_verify_missing_arg(execute_data, arg_num TSRMLS_CC); } else { zval *var_ptr; + zval *param = arguments - arg_count + arg_num - 1; - zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, param, opline->extended_value TSRMLS_CC); - var_ptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (Z_REFCOUNTED_P(var_ptr)) Z_DELREF_P(var_ptr); + 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); } @@ -893,29 +879,36 @@ static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR { USE_OPLINE zend_uint arg_num = opline->op1.num; - zend_uint arg_count = zend_vm_stack_get_args_count_ex(EX(prev_execute_data) TSRMLS_CC); + zval *arguments = EX(prev_execute_data)->function_state.arguments; + zend_uint arg_count = Z_LVAL_P(arguments); zval *params; SAVE_OPLINE(); - params = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - if (Z_REFCOUNTED_P(params)) Z_DELREF_P(params); + 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; array_init_size(params, arg_count - arg_num + 1); + if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { + do { + zend_verify_arg_type((zend_function *) EX(op_array), arg_num, param, opline->extended_value TSRMLS_CC); + zend_hash_next_index_insert(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(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } while (++arg_num <= arg_count); + } } else { array_init(params); } - for (; arg_num <= arg_count; ++arg_num) { - zval *param = zend_vm_stack_get_arg_ex(EX(prev_execute_data), arg_num TSRMLS_CC); - zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, param, opline->extended_value TSRMLS_CC); - zend_hash_next_index_insert(Z_ARRVAL_P(params), param); - if (Z_REFCOUNTED_P(param)) { - Z_ADDREF_P(param); - } - } - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -1600,13 +1593,14 @@ static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ { USE_OPLINE zend_uint arg_num = opline->op1.num; - zval *param = zend_vm_stack_get_arg_ex(EX(prev_execute_data), arg_num TSRMLS_CC); + zval *arguments = EX(prev_execute_data)->function_state.arguments; + zend_uint arg_count = Z_LVAL_P(arguments); zval *var_ptr; SAVE_OPLINE(); - var_ptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); - zval_ptr_dtor(var_ptr); - if (param == NULL) { + 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); @@ -1617,10 +1611,13 @@ static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ } } } else { + zval *param = arguments - arg_count + arg_num - 1; ZVAL_COPY(var_ptr, param); } - zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, var_ptr, opline->extended_value 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, var_ptr, opline->extended_value TSRMLS_CC); + } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE();