From a9396c4a4a7b7c9cc5a65d08d5e931fb94464eb9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 13 Aug 2024 11:34:07 +0300 Subject: [PATCH] Remove optimization for single var-positional parameter. --- Lib/test/test_clinic.py | 2 +- Modules/_testclinic.c | 8 +- Modules/clinic/_testclinic.c.h | 50 ++++++++- Modules/clinic/gcmodule.c.h | 51 +++++++++- Modules/gcmodule.c | 8 +- Objects/clinic/setobject.c.h | 147 +++++++++++++++++++++++++-- Objects/setobject.c | 26 ++--- Tools/clinic/libclinic/parse_args.py | 22 ---- 8 files changed, 257 insertions(+), 57 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 94e79222934c7a..686a1644995c04 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -2694,7 +2694,7 @@ def test_cli_force(self): # Verify by checking the checksum. checksum = ( "/*[clinic end generated code: " - "output=843576e3ffe85e2d input=9543a8d2da235301]*/\n" + "output=0acbef4794cb933e input=9543a8d2da235301]*/\n" ) with open(fn, encoding='utf-8') as f: generated = f.read() diff --git a/Modules/_testclinic.c b/Modules/_testclinic.c index 025e2fe8dabd80..5d0b3bd4177a6f 100644 --- a/Modules/_testclinic.c +++ b/Modules/_testclinic.c @@ -970,8 +970,8 @@ varpos [clinic start generated code]*/ static PyObject * -varpos(PyObject *module, PyObject *args) -/*[clinic end generated code: output=174bb88a5a80ed51 input=f87cd674145d394c]*/ +varpos_impl(PyObject *module, PyObject *args) +/*[clinic end generated code: output=7b0b9545872bdca4 input=f87cd674145d394c]*/ { return Py_NewRef(args); } @@ -1176,8 +1176,8 @@ Proof-of-concept of GH-99233 refcount error bug. [clinic start generated code]*/ static PyObject * -gh_99233_refcount(PyObject *module, PyObject *args) -/*[clinic end generated code: output=4a8facb62b9a98bb input=eecfdc2092d90dc3]*/ +gh_99233_refcount_impl(PyObject *module, PyObject *args) +/*[clinic end generated code: output=585855abfbca9a7f input=eecfdc2092d90dc3]*/ { Py_RETURN_NONE; } diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index 1f4e6f8b8f10ff..b2db377023f2e6 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -2528,7 +2528,29 @@ PyDoc_STRVAR(varpos__doc__, "\n"); #define VARPOS_METHODDEF \ - {"varpos", (PyCFunction)varpos, METH_VARARGS, varpos__doc__}, + {"varpos", _PyCFunction_CAST(varpos), METH_FASTCALL, varpos__doc__}, + +static PyObject * +varpos_impl(PyObject *module, PyObject *args); + +static PyObject * +varpos(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = varpos_impl(module, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} PyDoc_STRVAR(posonly_varpos__doc__, "posonly_varpos($module, a, b, /, *args)\n" @@ -3211,7 +3233,29 @@ PyDoc_STRVAR(gh_99233_refcount__doc__, "Proof-of-concept of GH-99233 refcount error bug."); #define GH_99233_REFCOUNT_METHODDEF \ - {"gh_99233_refcount", (PyCFunction)gh_99233_refcount, METH_VARARGS, gh_99233_refcount__doc__}, + {"gh_99233_refcount", _PyCFunction_CAST(gh_99233_refcount), METH_FASTCALL, gh_99233_refcount__doc__}, + +static PyObject * +gh_99233_refcount_impl(PyObject *module, PyObject *args); + +static PyObject * +gh_99233_refcount(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = gh_99233_refcount_impl(module, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} PyDoc_STRVAR(gh_99240_double_free__doc__, "gh_99240_double_free($module, a, b, /)\n" @@ -3765,4 +3809,4 @@ _testclinic_TestClass_defclass_posonly_varpos(PyObject *self, PyTypeObject *cls, return return_value; } -/*[clinic end generated code: output=9c2c00c640588af7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=fa10ab215bdd6259 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/gcmodule.c.h b/Modules/clinic/gcmodule.c.h index bed4b82e0053af..fe42131d8413c5 100644 --- a/Modules/clinic/gcmodule.c.h +++ b/Modules/clinic/gcmodule.c.h @@ -8,6 +8,7 @@ preserve #endif #include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +#include "pycore_tuple.h" // _PyTuple_FromArray() PyDoc_STRVAR(gc_enable__doc__, "enable($module, /)\n" @@ -309,7 +310,29 @@ PyDoc_STRVAR(gc_get_referrers__doc__, "Return the list of objects that directly refer to any of \'objs\'."); #define GC_GET_REFERRERS_METHODDEF \ - {"get_referrers", (PyCFunction)gc_get_referrers, METH_VARARGS, gc_get_referrers__doc__}, + {"get_referrers", _PyCFunction_CAST(gc_get_referrers), METH_FASTCALL, gc_get_referrers__doc__}, + +static PyObject * +gc_get_referrers_impl(PyObject *module, PyObject *args); + +static PyObject * +gc_get_referrers(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = gc_get_referrers_impl(module, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} PyDoc_STRVAR(gc_get_referents__doc__, "get_referents($module, /, *objs)\n" @@ -318,7 +341,29 @@ PyDoc_STRVAR(gc_get_referents__doc__, "Return the list of objects that are directly referred to by \'objs\'."); #define GC_GET_REFERENTS_METHODDEF \ - {"get_referents", (PyCFunction)gc_get_referents, METH_VARARGS, gc_get_referents__doc__}, + {"get_referents", _PyCFunction_CAST(gc_get_referents), METH_FASTCALL, gc_get_referents__doc__}, + +static PyObject * +gc_get_referents_impl(PyObject *module, PyObject *args); + +static PyObject * +gc_get_referents(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = gc_get_referents_impl(module, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} PyDoc_STRVAR(gc_get_objects__doc__, "get_objects($module, /, generation=None)\n" @@ -533,4 +578,4 @@ gc_get_freeze_count(PyObject *module, PyObject *Py_UNUSED(ignored)) exit: return return_value; } -/*[clinic end generated code: output=84873dc5565cc70e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=29b60bfc31906600 input=a9049054013a1b77]*/ diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 4fbdf9052816f3..57e4aae9ed557e 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -221,8 +221,8 @@ Return the list of objects that directly refer to any of 'objs'. [clinic start generated code]*/ static PyObject * -gc_get_referrers(PyObject *module, PyObject *args) -/*[clinic end generated code: output=e11e352b7e0cdce0 input=bae96961b14a0922]*/ +gc_get_referrers_impl(PyObject *module, PyObject *args) +/*[clinic end generated code: output=296a09587f6a86b5 input=bae96961b14a0922]*/ { if (PySys_Audit("gc.get_referrers", "(O)", args) < 0) { return NULL; @@ -269,8 +269,8 @@ Return the list of objects that are directly referred to by 'objs'. [clinic start generated code]*/ static PyObject * -gc_get_referents(PyObject *module, PyObject *args) -/*[clinic end generated code: output=9efb544e74953e38 input=b3ceab0c34038cbf]*/ +gc_get_referents_impl(PyObject *module, PyObject *args) +/*[clinic end generated code: output=d47dc02cefd06fe8 input=b3ceab0c34038cbf]*/ { if (PySys_Audit("gc.get_referents", "(O)", args) < 0) { return NULL; diff --git a/Objects/clinic/setobject.c.h b/Objects/clinic/setobject.c.h index 7b55a67f7b81b0..b57b96f9d26f7e 100644 --- a/Objects/clinic/setobject.c.h +++ b/Objects/clinic/setobject.c.h @@ -3,6 +3,7 @@ preserve [clinic start generated code]*/ #include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() +#include "pycore_tuple.h" // _PyTuple_FromArray() PyDoc_STRVAR(set_pop__doc__, "pop($self, /)\n" @@ -37,7 +38,29 @@ PyDoc_STRVAR(set_update__doc__, "Update the set, adding elements from all others."); #define SET_UPDATE_METHODDEF \ - {"update", (PyCFunction)set_update, METH_VARARGS, set_update__doc__}, + {"update", _PyCFunction_CAST(set_update), METH_FASTCALL, set_update__doc__}, + +static PyObject * +set_update_impl(PySetObject *so, PyObject *args); + +static PyObject * +set_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = set_update_impl(so, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} PyDoc_STRVAR(set_copy__doc__, "copy($self, /)\n" @@ -118,7 +141,29 @@ PyDoc_STRVAR(set_union__doc__, "Return a new set with elements from the set and all others."); #define SET_UNION_METHODDEF \ - {"union", (PyCFunction)set_union, METH_VARARGS, set_union__doc__}, + {"union", _PyCFunction_CAST(set_union), METH_FASTCALL, set_union__doc__}, + +static PyObject * +set_union_impl(PySetObject *so, PyObject *args); + +static PyObject * +set_union(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = set_union_impl(so, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} PyDoc_STRVAR(set_intersection_multi__doc__, "intersection($self, /, *others)\n" @@ -127,7 +172,29 @@ PyDoc_STRVAR(set_intersection_multi__doc__, "Return a new set with elements common to the set and all others."); #define SET_INTERSECTION_MULTI_METHODDEF \ - {"intersection", (PyCFunction)set_intersection_multi, METH_VARARGS, set_intersection_multi__doc__}, + {"intersection", _PyCFunction_CAST(set_intersection_multi), METH_FASTCALL, set_intersection_multi__doc__}, + +static PyObject * +set_intersection_multi_impl(PySetObject *so, PyObject *args); + +static PyObject * +set_intersection_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = set_intersection_multi_impl(so, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} PyDoc_STRVAR(set_intersection_update_multi__doc__, "intersection_update($self, /, *others)\n" @@ -136,7 +203,29 @@ PyDoc_STRVAR(set_intersection_update_multi__doc__, "Update the set, keeping only elements found in it and all others."); #define SET_INTERSECTION_UPDATE_MULTI_METHODDEF \ - {"intersection_update", (PyCFunction)set_intersection_update_multi, METH_VARARGS, set_intersection_update_multi__doc__}, + {"intersection_update", _PyCFunction_CAST(set_intersection_update_multi), METH_FASTCALL, set_intersection_update_multi__doc__}, + +static PyObject * +set_intersection_update_multi_impl(PySetObject *so, PyObject *args); + +static PyObject * +set_intersection_update_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = set_intersection_update_multi_impl(so, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} PyDoc_STRVAR(set_isdisjoint__doc__, "isdisjoint($self, other, /)\n" @@ -169,7 +258,29 @@ PyDoc_STRVAR(set_difference_update__doc__, "Update the set, removing elements found in others."); #define SET_DIFFERENCE_UPDATE_METHODDEF \ - {"difference_update", (PyCFunction)set_difference_update, METH_VARARGS, set_difference_update__doc__}, + {"difference_update", _PyCFunction_CAST(set_difference_update), METH_FASTCALL, set_difference_update__doc__}, + +static PyObject * +set_difference_update_impl(PySetObject *so, PyObject *args); + +static PyObject * +set_difference_update(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = set_difference_update_impl(so, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} PyDoc_STRVAR(set_difference_multi__doc__, "difference($self, /, *others)\n" @@ -178,7 +289,29 @@ PyDoc_STRVAR(set_difference_multi__doc__, "Return a new set with elements in the set that are not in the others."); #define SET_DIFFERENCE_MULTI_METHODDEF \ - {"difference", (PyCFunction)set_difference_multi, METH_VARARGS, set_difference_multi__doc__}, + {"difference", _PyCFunction_CAST(set_difference_multi), METH_FASTCALL, set_difference_multi__doc__}, + +static PyObject * +set_difference_multi_impl(PySetObject *so, PyObject *args); + +static PyObject * +set_difference_multi(PySetObject *so, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = set_difference_multi_impl(so, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} PyDoc_STRVAR(set_symmetric_difference_update__doc__, "symmetric_difference_update($self, other, /)\n" @@ -411,4 +544,4 @@ set___sizeof__(PySetObject *so, PyObject *Py_UNUSED(ignored)) return return_value; } -/*[clinic end generated code: output=730d916d496cb8b7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=83ffa2b5a786e53d input=a9049054013a1b77]*/ diff --git a/Objects/setobject.c b/Objects/setobject.c index cf3a41430393e6..c5f96d25585fa4 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1054,8 +1054,8 @@ Update the set, adding elements from all others. [clinic start generated code]*/ static PyObject * -set_update(PySetObject *so, PyObject *args) -/*[clinic end generated code: output=b3516a6b8873ab3d input=df4fe486e38cd337]*/ +set_update_impl(PySetObject *so, PyObject *args) +/*[clinic end generated code: output=34f6371704974c8a input=df4fe486e38cd337]*/ { Py_ssize_t i; @@ -1283,8 +1283,8 @@ Return a new set with elements from the set and all others. [clinic start generated code]*/ static PyObject * -set_union(PySetObject *so, PyObject *args) -/*[clinic end generated code: output=18a3fb9e0825f1e5 input=ddf088706e9577b2]*/ +set_union_impl(PySetObject *so, PyObject *args) +/*[clinic end generated code: output=2c83d05a446a1477 input=ddf088706e9577b2]*/ { PySetObject *result; PyObject *other; @@ -1432,8 +1432,8 @@ Return a new set with elements common to the set and all others. [clinic start generated code]*/ static PyObject * -set_intersection_multi(PySetObject *so, PyObject *args) -/*[clinic end generated code: output=afd6705c675015e6 input=0d9f3805ccbba6a4]*/ +set_intersection_multi_impl(PySetObject *so, PyObject *args) +/*[clinic end generated code: output=2406ef3387adbe2f input=0d9f3805ccbba6a4]*/ { Py_ssize_t i; @@ -1479,12 +1479,12 @@ Update the set, keeping only elements found in it and all others. [clinic start generated code]*/ static PyObject * -set_intersection_update_multi(PySetObject *so, PyObject *args) -/*[clinic end generated code: output=9a7a88d756f4a487 input=223c1e086aa669a9]*/ +set_intersection_update_multi_impl(PySetObject *so, PyObject *args) +/*[clinic end generated code: output=251c1f729063609d input=223c1e086aa669a9]*/ { PyObject *tmp; - tmp = set_intersection_multi(so, args); + tmp = set_intersection_multi_impl(so, args); if (tmp == NULL) return NULL; Py_BEGIN_CRITICAL_SECTION(so); @@ -1666,8 +1666,8 @@ Update the set, removing elements found in others. [clinic start generated code]*/ static PyObject * -set_difference_update(PySetObject *so, PyObject *args) -/*[clinic end generated code: output=3772a59f66245bfe input=024e6baa6fbcbb3d]*/ +set_difference_update_impl(PySetObject *so, PyObject *args) +/*[clinic end generated code: output=28685b2fc63e41c4 input=024e6baa6fbcbb3d]*/ { Py_ssize_t i; @@ -1783,8 +1783,8 @@ Return a new set with elements in the set that are not in the others. [clinic start generated code]*/ static PyObject * -set_difference_multi(PySetObject *so, PyObject *args) -/*[clinic end generated code: output=fd1ef7ff9566b605 input=ba78ea5f099e58df]*/ +set_difference_multi_impl(PySetObject *so, PyObject *args) +/*[clinic end generated code: output=3130c3bb3cac873d input=ba78ea5f099e58df]*/ { Py_ssize_t i; PyObject *result, *other; diff --git a/Tools/clinic/libclinic/parse_args.py b/Tools/clinic/libclinic/parse_args.py index 2c99600fa5bd36..650bed5f2391de 100644 --- a/Tools/clinic/libclinic/parse_args.py +++ b/Tools/clinic/libclinic/parse_args.py @@ -290,12 +290,6 @@ def use_meth_o(self) -> bool: and not self.requires_defining_class and not self.is_new_or_init()) - def use_meth_varargs(self) -> bool: - return (not self.parameters - and self.varpos is not None - and not self.requires_defining_class - and not self.is_new_or_init()) - def use_simple_return(self) -> bool: return (self.func.return_converter.type == 'PyObject *' and not self.func.critical_section) @@ -446,20 +440,6 @@ def parse_one_arg(self) -> None: parser_code = libclinic.normalize_snippet(parsearg, indent=4) self.parser_body(parser_code) - def parse_varpos_only(self) -> None: - self.flags = "METH_VARARGS" - if self.use_simple_return(): - # maps perfectly to METH_VARARGS, doesn't need a return converter. - # so we skip making a parse function - # and call directly into the impl function. - self.impl_prototype = '' - self.impl_definition = METH_O_PROTOTYPE - else: - # SLIGHT HACK - # use impl_parameters for the parser here! - self.parser_prototype = METH_O_PROTOTYPE - self.parser_body() - def parse_option_groups(self) -> None: # positional parameters with option groups # (we have to generate lots of PyArg_ParseTuple calls @@ -978,8 +958,6 @@ def parse_args(self, clang: CLanguage) -> dict[str, str]: self.parse_no_args() elif self.use_meth_o(): self.parse_one_arg() - elif self.use_meth_varargs(): - self.parse_varpos_only() elif self.has_option_groups(): self.parse_option_groups() elif (not self.requires_defining_class