Issue43447
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2021-03-09 11:34 by vstinner, last changed 2022-04-11 14:59 by admin.
Messages (2) | |||
---|---|---|---|
msg388354 - (view) | Author: STINNER Victor (vstinner) * | Date: 2021-03-09 11:34 | |
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: -------------- static PyObject * 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: return return_value; } /*[clinic input] @classmethod float.__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]*/ static PyObject * 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(); } return float_subtype_new(type, x); /* Wimp out */ } if (x == NULL) { return PyFloat_FromDouble(0.0); } /* If it's a string, but not a string subclass, use PyFloat_FromString. */ if (PyUnicode_CheckExact(x)) return PyFloat_FromString(x); return PyNumber_Float(x); } static PyObject * float_vectorcall(PyObject *type, PyObject * const*args, size_t nargsf, PyObject *kwnames) { if (!_PyArg_NoKwnames("float", kwnames)) { return NULL; } Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (!_PyArg_CheckPositional("float", nargs, 0, 1)) { return NULL; } PyObject *x = nargs >= 1 ? args[0] : NULL; return float_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: -------------- static PyObject * float_vectorcall(PyObject *type, PyObject * const*args, size_t nargsf, PyObject *kwnames) { if (!_PyArg_NoKwnames("float", kwnames)) { return NULL; } Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (!_PyArg_CheckPositional("float", nargs, 0, 1)) { return NULL; } PyObject *x = nargs >= 1 ? args[0] : NULL; return float_vectorcall_impl(type, x); } static PyObject * float_vectorcall_impl(PyObject *type, PyObject *x) { return float_new_impl((PyTypeObject *)type, x); } -------------- 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! |
|||
msg389214 - (view) | Author: Dong-hee Na (corona10) * | Date: 2021-03-21 03:46 | |
I agree with we should update AC to generate vectorcall. I am going to investigate what we can :) |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:59:42 | admin | set | github: 87613 |
2022-03-06 09:38:05 | kumaraditya | set | nosy:
+ kumaraditya |
2021-04-06 13:21:23 | corona10 | set | assignee: corona10 |
2021-03-22 09:38:40 | erlendaasland | set | nosy:
+ erlendaasland |
2021-03-21 03:46:26 | corona10 | set | messages: + msg389214 |
2021-03-09 11:34:23 | vstinner | create |