You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Generate vectorcall code to parse arguments using Argument Clinic #87613
To optimize the creation of objects, a lot of "tp_new" methods are defined twice: once in the legacy way (tp_new slot), once with the new VECTORCALL calling convention (tp_vectorcall slot). My concern is that the VECTORCALL implementation copy/paste most of the code just to parse arguments, whereas the specific code is just a few lines.
Example with the float type constructor:
--------------
staticPyObject*float_new(PyTypeObject*type, PyObject*args, PyObject*kwargs)
{
PyObject*return_value=NULL;
PyObject*x=NULL;
if ((type==&PyFloat_Type) &&
!_PyArg_NoKeywords("float", kwargs)) {
goto exit;
}
if (!_PyArg_CheckPositional("float", PyTuple_GET_SIZE(args), 0, 1)) {
goto exit;
}
if (PyTuple_GET_SIZE(args) <1) {
goto skip_optional;
}
x=PyTuple_GET_ITEM(args, 0);
skip_optional:
return_value=float_new_impl(type, x);
exit:
returnreturn_value;
}
/*[clinic input]@classmethodfloat.\_\_new__ as float_new x: object(c_default="NULL") = 0 /Convert a string or number to a floating point number, if possible.[clinic start generated code]*/staticPyObject*float_new_impl(PyTypeObject*type, PyObject*x)
/*[clinic end generated code: output=ccf1e8dc460ba6ba input=f43661b7de03e9d8]*/
{
if (type!=&PyFloat_Type) {
if (x==NULL) {
x=_PyLong_GetZero();
}
returnfloat_subtype_new(type, x); /* Wimp out */
}
if (x==NULL) {
returnPyFloat_FromDouble(0.0);
}
/* If it's a string, but not a string subclass, use PyFloat_FromString. */if (PyUnicode_CheckExact(x))
returnPyFloat_FromString(x);
returnPyNumber_Float(x);
}
staticPyObject*float_vectorcall(PyObject*type, PyObject*const*args,
size_tnargsf, PyObject*kwnames)
{
if (!_PyArg_NoKwnames("float", kwnames)) {
returnNULL;
}
Py_ssize_tnargs=PyVectorcall_NARGS(nargsf);
if (!_PyArg_CheckPositional("float", nargs, 0, 1)) {
returnNULL;
}
PyObject*x=nargs >= 1 ? args[0] : NULL;
returnfloat_new_impl((PyTypeObject*)type, x);
}
Here the float_new() function (tp_new slot) is implemented with Argument Clinic: float_new() C code is generated from the [clinic input] DSL: good!
My concern is that float_vectorcall() code is hand written, it's boring to write and boring to maintain.
Would it be possible to add a new [clinic input] DSL for vectorcall? I expect something like that:
--------------
where float_vectorcall() C code would be generated, and float_vectorcall_impl() would be the only part written manually. float_vectorcall_impl() gets a clean API and its body is way simpler to write and to maintain!
Activity
vstinner commentedon Mar 9, 2021
To optimize the creation of objects, a lot of "tp_new" methods are defined twice: once in the legacy way (tp_new slot), once with the new VECTORCALL calling convention (tp_vectorcall slot). My concern is that the VECTORCALL implementation copy/paste most of the code just to parse arguments, whereas the specific code is just a few lines.
Example with the float type constructor:
--------------
Here the float_new() function (tp_new slot) is implemented with Argument Clinic: float_new() C code is generated from the [clinic input] DSL: good!
My concern is that float_vectorcall() code is hand written, it's boring to write and boring to maintain.
Would it be possible to add a new [clinic input] DSL for vectorcall? I expect something like that:
--------------
where float_vectorcall() C code would be generated, and float_vectorcall_impl() would be the only part written manually. float_vectorcall_impl() gets a clean API and its body is way simpler to write and to maintain!
corona10 commentedon Mar 21, 2021
I agree with we should update AC to generate vectorcall.
I am going to investigate what we can :)
vstinner commentedon Nov 3, 2022
I don't have the bandwidth to work on this issue, so I just close it.
84 remaining items
gh-87613: Use AC vectorcall for bytes and bytearray (#158891)
pythongh-87613: Use Argument Clinic @vectorcall for decimal.Decimal
gh-87613: Allow Argument Clinic vectorcall on heap types (#160115)
gh-87613: Use AC vectorcall for weakref.ref() (#159470)
cmaloney commentedon Oct 28, 2026
Devguide update: python/devguide#1948
pythongh-87613: Fold AC vectorcall *args tests into existing cases
pythongh-87613: Generate the AC @vectorcall helper in fastcall mode
pythongh-87613: Reuse the positional parser for AC **kwargs
pythongh-87613: Merge the inline AC vectorcall paths
pythongh-87613: Pick the AC **kwargs no-positional check with the con…
pythongh-87613: Declare the AC keyword parser locals in the conventio…
pythongh-87613: Warn on deprecated keywords passed to an AC vectorcall
pythongh-87613: Build the AC @vectorcall **kwargs dict inline