Don't count variadic argument in zend_func.common.num_args. This allows faster CALL...
authorDmitry Stogov <dmitry@zend.com>
Mon, 22 Dec 2014 13:44:39 +0000 (16:44 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 22 Dec 2014 13:44:39 +0000 (16:44 +0300)
14 files changed:
UPGRADING
Zend/zend_API.c
Zend/zend_builtin_functions.c
Zend/zend_closures.c
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_execute.h
Zend/zend_inheritance.c
Zend/zend_opcode.c
ext/opcache/zend_persist.c
ext/opcache/zend_persist_calc.c
ext/pdo/pdo_dbh.c
ext/reflection/php_reflection.c

index 915ead48f92ba61d36f7ef0e305d312376e8c515..3e4fbf83d36d0497eafae0f9817183a2194859ea 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -51,6 +51,7 @@ PHP X.Y UPGRADE NOTES
     and heredocs means that \u{ followed by an invalid sequence will now error.
     However, \u without a following { is unaffected, so "\u202e" won't error and
     will work the same as before.
+  . zend_function.common.num_args don't include the variadic argument anymore.
 
 - DBA
   . dba_delete() now returns false if the key was not found for the inifile
index f6fcd356f5cc51a84d43b68e7fc73e91f330c612..4f19e480331ee8cc5a37be275a1198dc5bb49422 100644 (file)
@@ -2206,6 +2206,8 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
                        }
                        if (ptr->arg_info[ptr->num_args].is_variadic) {
                                internal_function->fn_flags |= ZEND_ACC_VARIADIC;
+                               /* Don't count the variadic argument */
+                               internal_function->num_args--;
                        }
                } else {
                        internal_function->arg_info = NULL;
index f956f492b433de2dac585684915eb757429e38c1..ed1a1c7a2c06f94803e485675e187715434881a0 100644 (file)
@@ -443,9 +443,6 @@ ZEND_FUNCTION(func_get_arg)
        }
 
        first_extra_arg = ex->func->op_array.num_args;
-       if (ex->func->op_array.fn_flags & ZEND_ACC_VARIADIC) {
-               first_extra_arg--;
-       }
        if (requested_offset >= first_extra_arg && (ZEND_CALL_NUM_ARGS(ex) > first_extra_arg)) {
                arg = ZEND_CALL_VAR_NUM(ex, ex->func->op_array.last_var + ex->func->op_array.T) + (requested_offset - first_extra_arg);
        } else {
@@ -476,9 +473,6 @@ ZEND_FUNCTION(func_get_args)
                Bucket *q;              
 
                first_extra_arg = ex->func->op_array.num_args;
-               if (ex->func->op_array.fn_flags & ZEND_ACC_VARIADIC) {
-                       first_extra_arg--;
-               }
                zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
                i = 0;
                q = Z_ARRVAL_P(return_value)->arData;
@@ -2136,9 +2130,6 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /
                if (call->func->type == ZEND_USER_FUNCTION) {
                        uint32_t first_extra_arg = call->func->op_array.num_args;
                        
-                       if (call->func->op_array.fn_flags & ZEND_ACC_VARIADIC) {
-                               first_extra_arg--;
-                       }
                        if (ZEND_CALL_NUM_ARGS(call) > first_extra_arg) {
                                while (i < first_extra_arg) {
                                        if (Z_REFCOUNTED_P(p)) Z_ADDREF_P(p);
index 0b0ae2e4d4d6d98fe7ccc1df6939a125c49cc3a8..51585fec913047ab6faaa03243fa4b0f9b801591 100644 (file)
@@ -361,11 +361,15 @@ static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp) /* {{{
                }
 
                if (arg_info) {
-                       uint32_t i, required = closure->func.common.required_num_args;
+                       uint32_t i, num_args, required = closure->func.common.required_num_args;
 
                        array_init(&val);
 
-                       for (i = 0; i < closure->func.common.num_args; i++) {
+                       num_args = closure->func.common.num_args;
+                       if (closure->func.common.fn_flags & ZEND_ACC_VARIADIC) {
+                               num_args++;
+                       }
+                       for (i = 0; i < num_args; i++) {
                                zend_string *name;
                                zval info;
                                if (arg_info->name) {
index c159fcc6e198eb35e8684a6ec9853aba78678323..7c323def84d70638ad77ac49e83e3911826ec889 100644 (file)
@@ -3884,6 +3884,11 @@ void zend_compile_params(zend_ast *ast) /* {{{ */
        /* 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;
+
+       /* Don't count the variadic argument */
+       if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
+               op_array->num_args--;
+       }               
 }
 /* }}} */
 
index 9b0bfda273f3171a7e0cb3ac4570bfcbbe8b0505..541c5f06fb1135cb7de3ae58a9afbb1a565ac43e 100644 (file)
@@ -835,13 +835,14 @@ static zend_always_inline int zend_check_arg_send_type(const zend_function *zf,
        if (UNEXPECTED(zf->common.arg_info == NULL)) {
                return 0;
        }
-       if (UNEXPECTED(arg_num > zf->common.num_args)) {
+       arg_num--;
+       if (UNEXPECTED(arg_num >= zf->common.num_args)) {
                if (EXPECTED((zf->common.fn_flags & ZEND_ACC_VARIADIC) == 0)) {
                        return 0;
                }
                arg_num = zf->common.num_args;
        }
-       return UNEXPECTED((zf->common.arg_info[arg_num-1].pass_by_reference & mask) != 0);
+       return UNEXPECTED((zf->common.arg_info[arg_num].pass_by_reference & mask) != 0);
 }
 
 #define ARG_MUST_BE_SENT_BY_REF(zf, arg_num) \
index f7dc69c0995d5e18653287cf6aa39cc6961f2abf..aaa25cabcaf873ac1b0f9c215e713fdf392acde2 100644 (file)
@@ -622,7 +622,7 @@ static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, z
        if (EXPECTED(arg_num <= zf->internal_function.num_args)) {
                cur_arg_info = &zf->internal_function.arg_info[arg_num-1];
        } else if (zf->internal_function.fn_flags & ZEND_ACC_VARIADIC) {
-               cur_arg_info = &zf->internal_function.arg_info[zf->internal_function.num_args-1];
+               cur_arg_info = &zf->internal_function.arg_info[zf->internal_function.num_args];
        } else {
                return;
        }
@@ -671,7 +671,7 @@ static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg,
        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];
+               cur_arg_info = &zf->common.arg_info[zf->common.num_args];
        } else {
                return;
        }
@@ -720,7 +720,7 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_n
        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];
+               cur_arg_info = &zf->common.arg_info[zf->common.num_args];
        } else {
                return 1;
        }
@@ -1626,9 +1626,6 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu
 
        /* Handle arguments */
        first_extra_arg = op_array->num_args;
-       if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_VARIADIC) != 0)) {
-               first_extra_arg--;
-       }
        num_args = EX_NUM_ARGS();
        if (UNEXPECTED(num_args > first_extra_arg)) {
                zval *end, *src, *dst;
@@ -1721,9 +1718,6 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
                
                /* Handle arguments */
                first_extra_arg = op_array->num_args;
-               if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_VARIADIC) != 0)) {
-                       first_extra_arg--;
-               }
                num_args = EX_NUM_ARGS();
                if (UNEXPECTED(num_args > first_extra_arg)) {
                        zval *end, *src, *dst;
index 0d58c6195dc735dadaa68551cfc81b00211d0c24..9197e4c9e574e74f840384fc3671f0594caf4ea2 100644 (file)
@@ -176,7 +176,7 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(uint3
 
 static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call)
 {
-       uint32_t first_extra_arg = call->func->op_array.num_args - ((call->func->common.fn_flags & ZEND_ACC_VARIADIC) != 0);
+       uint32_t first_extra_arg = call->func->op_array.num_args;
 
        if (UNEXPECTED(ZEND_CALL_NUM_ARGS(call) > first_extra_arg)) {
                zval *end = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T);
index 5f7b17277b5e113b64e7e0067ab3ee765bfe03ee..b7730be8f0335dec3681415c085894fcbb5b0ed5 100644 (file)
@@ -261,9 +261,14 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
         * go through all the parameters of the function and not just those present in the
         * prototype. */
        num_args = proto->common.num_args;
-       if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
-               && fe->common.num_args > proto->common.num_args) {
-               num_args = fe->common.num_args;
+       if (proto->common.fn_flags & ZEND_ACC_VARIADIC) {
+               num_args++;
+        if (fe->common.num_args >= proto->common.num_args) {
+                       num_args = fe->common.num_args;
+                       if (fe->common.fn_flags & ZEND_ACC_VARIADIC) {
+                               num_args++;
+                       }
+               }
        }
 
        for (i = 0; i < num_args; i++) {
@@ -273,7 +278,7 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
                if (i < proto->common.num_args) {
                        proto_arg_info = &proto->common.arg_info[i];
                } else {
-                       proto_arg_info = &proto->common.arg_info[proto->common.num_args-1];
+                       proto_arg_info = &proto->common.arg_info[proto->common.num_args];
                }
 
                if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) {
@@ -380,11 +385,15 @@ static zend_string *zend_get_function_declaration(zend_function *fptr) /* {{{ */
        smart_str_appendc(&str, '(');
 
        if (fptr->common.arg_info) {
-               uint32_t i, required;
+               uint32_t i, num_args, required;
                zend_arg_info *arg_info = fptr->common.arg_info;
 
                required = fptr->common.required_num_args;
-               for (i = 0; i < fptr->common.num_args;) {
+               num_args = fptr->common.num_args;
+               if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
+                       num_args++;
+               }
+               for (i = 0; i < num_args;) {
                        if (arg_info->class_name) {
                                const char *class_name;
                                size_t class_name_len;
@@ -486,7 +495,7 @@ static zend_string *zend_get_function_declaration(zend_function *fptr) /* {{{ */
                                }
                        }
 
-                       if (++i < fptr->common.num_args) {
+                       if (++i < num_args) {
                                smart_str_appends(&str, ", ");
                        }
                        arg_info++;
index 82c87c5cd2e4d861d659f81e04abc0c5f16e2dbc..fc29e2aadc846ee9e11cad52c0464cd61cf6d572 100644 (file)
@@ -368,7 +368,12 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
                zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array);
        }
        if (op_array->arg_info) {
-               for (i=0; i<op_array->num_args; i++) {
+               uint32_t num_args = op_array->num_args;
+
+               if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
+                       num_args++;
+               }
+               for (i = 0; i < num_args; i++) {
                        zend_string_release(op_array->arg_info[i].name);
                        if (op_array->arg_info[i].class_name) {
                                zend_string_release(op_array->arg_info[i].class_name);
index cb4f63b0efeb35acf221563962315baaeaf8bddb..53811f626ef75b067853b34bf5083dd2b345bc37 100644 (file)
@@ -419,10 +419,14 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
                        ZEND_ASSERT(new_ptr != NULL);
                        op_array->arg_info = new_ptr;
                } else {
-                       uint32_t i;
+                       uint32_t i, num_args;
 
-                       zend_accel_store(op_array->arg_info, sizeof(zend_arg_info) * op_array->num_args);
-                       for (i = 0; i < op_array->num_args; i++) {
+                       num_args = op_array->num_args;
+                       if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
+                               num_args++;
+                       }
+                       zend_accel_store(op_array->arg_info, sizeof(zend_arg_info) * num_args);
+                       for (i = 0; i < num_args; i++) {
                                if (op_array->arg_info[i].name) {
                                        zend_accel_store_interned_string(op_array->arg_info[i].name);
                                }
index 9e96d5da4241abb420060b016cdcb2c2195c92c0..f3fb7c081d65a04a1758bea99ff2bceebd711212 100644 (file)
@@ -194,10 +194,14 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
        }
 
        if (op_array->arg_info) {
-               uint32_t i;
+               uint32_t i, num_args;
 
-               ADD_DUP_SIZE(op_array->arg_info, sizeof(zend_arg_info) * op_array->num_args);
-               for (i = 0; i < op_array->num_args; i++) {
+               num_args = op_array->num_args;
+               if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
+                       num_args++;
+               }
+               ADD_DUP_SIZE(op_array->arg_info, sizeof(zend_arg_info) * num_args);
+               for (i = 0; i < num_args; i++) {
                        if (op_array->arg_info[i].name) {
                                ADD_INTERNED_STRING(op_array->arg_info[i].name, 1);
                        }
index 9cc1c7dfbf62ecd450805c3e3a0d47fbcfb3235f..16ad2c077dba56f2330b78d17031333e5424d3e1 100644 (file)
@@ -1312,6 +1312,8 @@ int pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind)
                        }
                        if (funcs->arg_info[funcs->num_args].is_variadic) {
                                ifunc->fn_flags |= ZEND_ACC_VARIADIC;
+                               /* Don't count the variadic argument */
+                               ifunc->num_args--;
                        }
                } else {
                        ifunc->arg_info = NULL;
index 6a59a5ce371e0b9ed456f9ca70425ad75b53b6b1..7238212564a3d9e9f453019a99c587fd6b9fdefc 100644 (file)
@@ -758,15 +758,19 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg
 static void _function_parameter_string(string *str, zend_function *fptr, char* indent)
 {
        struct _zend_arg_info *arg_info = fptr->common.arg_info;
-       uint32_t i, required = fptr->common.required_num_args;
+       uint32_t i, num_args, required = fptr->common.required_num_args;
 
        if (!arg_info) {
                return;
        }
 
+       num_args = fptr->common.num_args;
+       if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
+               num_args++;
+       }
        string_printf(str, "\n");
-       string_printf(str, "%s- Parameters [%d] {\n", indent, fptr->common.num_args);
-       for (i = 0; i < fptr->common.num_args; i++) {
+       string_printf(str, "%s- Parameters [%d] {\n", indent, num_args);
+       for (i = 0; i < num_args; i++) {
                string_printf(str, "%s  ", indent);
                _parameter_string(str, fptr, arg_info, i, required, indent);
                string_write(str, "\n", sizeof("\n")-1);
@@ -2019,11 +2023,17 @@ ZEND_METHOD(reflection_function, getNumberOfParameters)
 {
        reflection_object *intern;
        zend_function *fptr;
+       uint32_t num_args;
 
        METHOD_NOTSTATIC(reflection_function_abstract_ptr);
        GET_REFLECTION_OBJECT_PTR(fptr);
 
-       RETURN_LONG(fptr->common.num_args);
+       num_args = fptr->common.num_args;
+       if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
+               num_args++;
+       }
+
+       RETURN_LONG(num_args);
 }
 /* }}} */
 
@@ -2047,16 +2057,20 @@ ZEND_METHOD(reflection_function, getParameters)
 {
        reflection_object *intern;
        zend_function *fptr;
-       uint32_t i;
+       uint32_t i, num_args;
        struct _zend_arg_info *arg_info;
 
        METHOD_NOTSTATIC(reflection_function_abstract_ptr);
        GET_REFLECTION_OBJECT_PTR(fptr);
 
        arg_info= fptr->common.arg_info;
+       num_args = fptr->common.num_args;
+       if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
+               num_args++;
+       }
 
        array_init(return_value);
-       for (i = 0; i < fptr->common.num_args; i++) {
+       for (i = 0; i < num_args; i++) {
                zval parameter;
 
                reflection_parameter_factory(_copy_function(fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, arg_info, i, fptr->common.required_num_args, &parameter);
@@ -2135,6 +2149,7 @@ ZEND_METHOD(reflection_parameter, __construct)
        zend_function *fptr;
        struct _zend_arg_info *arg_info;
        int position;
+       uint32_t num_args;
        zend_class_entry *ce = NULL;
        zend_bool is_closure = 0;
        zend_bool is_invoke = 0;
@@ -2235,9 +2250,13 @@ ZEND_METHOD(reflection_parameter, __construct)
 
        /* Now, search for the parameter */
        arg_info = fptr->common.arg_info;
+       num_args = fptr->common.num_args;
+       if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
+               num_args++;
+       }
        if (Z_TYPE_P(parameter) == IS_LONG) {
                position= (int)Z_LVAL_P(parameter);
-               if (position < 0 || (uint32_t)position >= fptr->common.num_args) {
+               if (position < 0 || (uint32_t)position >= num_args) {
                        if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) {
                                if (fptr->type != ZEND_OVERLOADED_FUNCTION) {
                                        zend_string_release(fptr->common.function_name);
@@ -2256,7 +2275,7 @@ ZEND_METHOD(reflection_parameter, __construct)
                position= -1;
                convert_to_string_ex(parameter);
                if (!is_invoke && fptr->type == ZEND_INTERNAL_FUNCTION) {
-                       for (i = 0; i < fptr->common.num_args; i++) {
+                       for (i = 0; i < num_args; i++) {
                                if (arg_info[i].name) {
                                        if (strcmp(((zend_internal_arg_info*)arg_info)[i].name, Z_STRVAL_P(parameter)) == 0) {
                                                position= i;
@@ -2266,7 +2285,7 @@ ZEND_METHOD(reflection_parameter, __construct)
                                }
                        }
                } else {
-                       for (i = 0; i < fptr->common.num_args; i++) {
+                       for (i = 0; i < num_args; i++) {
                                if (arg_info[i].name) {
                                        if (strcmp(arg_info[i].name->val, Z_STRVAL_P(parameter)) == 0) {
                                                position= i;