]> granicus.if.org Git - php/commitdiff
Optimized RECV_* opcodes
authorDmitry Stogov <dmitry@zend.com>
Fri, 4 Apr 2014 10:36:34 +0000 (14:36 +0400)
committerDmitry Stogov <dmitry@zend.com>
Fri, 4 Apr 2014 10:36:34 +0000 (14:36 +0400)
Zend/zend_compile.c
Zend/zend_execute.c
Zend/zend_execute.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index e02778f5de1e003befce661af3c3cb60fe5219b1..d4305a042c2983ba58e7ee1c975357bc6f8f4707 100644 (file)
@@ -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;
+       }
 }
 /* }}} */
 
index 5c32ef0705500c55a0caf9c07a231a677c36cbd8..2f867ac5dfe74568a31b2648ec6318757f8450fd 100644 (file)
@@ -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)
index 6170607a4f7b61c36dd096c89c9c254c11bab10c..67bce39748bffebd6e028931d4233eddc9b7391b 100644 (file)
@@ -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)
index 8c95eaeb5f16464eb9deee9eb1fbb465254c003f..75ced021bb3a24e3a2667caa1462141098c086e9 100644 (file)
@@ -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();
 }
index e1c0ee2de4150b3787e5e7febb97ccfdf4637c25..a1360caeae5be4490e0c2e6c86c3a3e8de4f3e77 100644 (file)
@@ -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();