From 2646f7bcb98dcdd322ea21701c8bb101104ea619 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 22 Dec 2014 16:44:39 +0300 Subject: [PATCH] Don't count variadic argument in zend_func.common.num_args. This allows faster CALL/RETURN code. --- UPGRADING | 1 + Zend/zend_API.c | 2 ++ Zend/zend_builtin_functions.c | 9 -------- Zend/zend_closures.c | 8 +++++-- Zend/zend_compile.c | 5 +++++ Zend/zend_compile.h | 5 +++-- Zend/zend_execute.c | 12 +++-------- Zend/zend_execute.h | 2 +- Zend/zend_inheritance.c | 23 +++++++++++++------- Zend/zend_opcode.c | 7 ++++++- ext/opcache/zend_persist.c | 10 ++++++--- ext/opcache/zend_persist_calc.c | 10 ++++++--- ext/pdo/pdo_dbh.c | 2 ++ ext/reflection/php_reflection.c | 37 +++++++++++++++++++++++++-------- 14 files changed, 87 insertions(+), 46 deletions(-) diff --git a/UPGRADING b/UPGRADING index 915ead48f92ba..3e4fbf83d36d0 100644 --- 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 diff --git a/Zend/zend_API.c b/Zend/zend_API.c index f6fcd356f5cc5..4f19e480331ee 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -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; diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index f956f492b433d..ed1a1c7a2c06f 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -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); diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 0b0ae2e4d4d6d..51585fec91304 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -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) { diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c159fcc6e198e..7c323def84d70 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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--; + } } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 9b0bfda273f31..541c5f06fb113 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -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) \ diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index f7dc69c0995d5..aaa25cabcaf87 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -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; diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 0d58c6195dc73..9197e4c9e574e 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -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); diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 5f7b17277b5e1..b7730be8f0335 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -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++; diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 82c87c5cd2e4d..fc29e2aadc846 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -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; inum_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); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index cb4f63b0efeb3..53811f626ef75 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -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); } diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 9e96d5da4241a..f3fb7c081d65a 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -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); } diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 9cc1c7dfbf62e..16ad2c077dba5 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -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; diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 6a59a5ce371e0..7238212564a3d 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -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, ¶meter); @@ -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;