diff options
author | Sergey B Kirpichev <skirpichev@gmail.com> | 2024-10-31 10:37:03 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-31 10:37:03 (GMT) |
commit | 8c22eba877225ab29cd64672dcb97f09a5f7336f (patch) | |
tree | ee74e354c3f99cacf2e3a14d56dbc49e8a08d0a5 /Tools/clinic/libclinic | |
parent | d07dcce6935364cab807e0df931ed09b088ade69 (diff) | |
download | cpython-8c22eba877225ab29cd64672dcb97f09a5f7336f.zip cpython-8c22eba877225ab29cd64672dcb97f09a5f7336f.tar.gz cpython-8c22eba877225ab29cd64672dcb97f09a5f7336f.tar.bz2 |
gh-90370: Argument Clinic: avoid temporary tuple creation for varargs (#126064)
Avoid temporary tuple creation when all arguments either positional-only
or vararg.
Objects/setobject.c and Modules/gcmodule.c adapted. This fixes slight
performance regression for set methods, introduced by gh-115112.
Diffstat (limited to 'Tools/clinic/libclinic')
-rw-r--r-- | Tools/clinic/libclinic/clanguage.py | 15 | ||||
-rw-r--r-- | Tools/clinic/libclinic/parse_args.py | 35 |
2 files changed, 24 insertions, 26 deletions
diff --git a/Tools/clinic/libclinic/clanguage.py b/Tools/clinic/libclinic/clanguage.py index 73d4783..32aba81 100644 --- a/Tools/clinic/libclinic/clanguage.py +++ b/Tools/clinic/libclinic/clanguage.py @@ -15,7 +15,7 @@ from libclinic.function import ( Module, Class, Function, Parameter, permute_optional_groups, GETTER, SETTER, METHOD_INIT) -from libclinic.converters import self_converter +from libclinic.converters import defining_class_converter, self_converter from libclinic.parse_args import ParseArgsCodeGen if TYPE_CHECKING: from libclinic.app import Clinic @@ -396,6 +396,12 @@ class CLanguage(Language): first_optional = len(selfless) positional = selfless and selfless[-1].is_positional_only() has_option_groups = False + requires_defining_class = (len(selfless) + and isinstance(selfless[0].converter, + defining_class_converter)) + pass_vararg_directly = (all(p.is_positional_only() or p.is_vararg() + for p in selfless) + and not requires_defining_class) # offset i by -1 because first_optional needs to ignore self for i, p in enumerate(parameters, -1): @@ -404,7 +410,7 @@ class CLanguage(Language): if (i != -1) and (p.default is not unspecified): first_optional = min(first_optional, i) - if p.is_vararg(): + if p.is_vararg() and not pass_vararg_directly: data.cleanup.append(f"Py_XDECREF({c.parser_name});") # insert group variable @@ -418,6 +424,11 @@ class CLanguage(Language): data.impl_parameters.append("int " + group_name) has_option_groups = True + if p.is_vararg() and pass_vararg_directly: + data.impl_arguments.append('nvararg') + data.impl_parameters.append('Py_ssize_t nargs') + p.converter.type = 'PyObject *const *' + c.render(p, data) if has_option_groups and (not positional): diff --git a/Tools/clinic/libclinic/parse_args.py b/Tools/clinic/libclinic/parse_args.py index 96c9b91..559d4fb 100644 --- a/Tools/clinic/libclinic/parse_args.py +++ b/Tools/clinic/libclinic/parse_args.py @@ -469,7 +469,11 @@ class ParseArgsCodeGen: nargs = 'PyTuple_GET_SIZE(args)' argname_fmt = 'PyTuple_GET_ITEM(args, %d)' - left_args = f"{nargs} - {self.max_pos}" + if self.vararg != NO_VARARG: + self.declarations = f"Py_ssize_t nvararg = {nargs} - {self.max_pos};" + else: + self.declarations = "" + max_args = NO_VARARG if (self.vararg != NO_VARARG) else self.max_pos if self.limited_capi: parser_code = [] @@ -518,30 +522,13 @@ class ParseArgsCodeGen: use_parser_code = True for i, p in enumerate(self.parameters): if p.is_vararg(): + var = p.converter.parser_name if self.fastcall: - parser_code.append(libclinic.normalize_snippet(""" - %s = PyTuple_New(%s); - if (!%s) {{ - goto exit; - }} - for (Py_ssize_t i = 0; i < %s; ++i) {{ - PyTuple_SET_ITEM(%s, i, Py_NewRef(args[%d + i])); - }} - """ % ( - p.converter.parser_name, - left_args, - p.converter.parser_name, - left_args, - p.converter.parser_name, - self.max_pos - ), indent=4)) + code = f"{var} = args + {self.vararg};" else: - parser_code.append(libclinic.normalize_snippet(""" - %s = PyTuple_GetSlice(%d, -1); - """ % ( - p.converter.parser_name, - self.max_pos - ), indent=4)) + code = f"{var} = _PyTuple_CAST(args)->ob_item;" + formatted_code = libclinic.normalize_snippet(code, indent=4) + parser_code.append(formatted_code) continue displayname = p.get_displayname(i+1) @@ -588,7 +575,7 @@ class ParseArgsCodeGen: goto exit; }} """, indent=4)] - self.parser_body(*parser_code) + self.parser_body(*parser_code, declarations=self.declarations) def parse_general(self, clang: CLanguage) -> None: parsearg: str | None |