bpo-36974: implement PEP 590 (GH-13185)
Co-authored-by: Jeroen Demeyer <J.Demeyer@UGent.be>
Co-authored-by: Mark Shannon <mark@hotpy.org>
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 1ee8978..cfc2446 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -40,6 +40,45 @@
return ((PyMethodObject *)im)->im_self;
}
+
+static PyObject *
+method_vectorcall(PyObject *method, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames)
+{
+ assert(Py_TYPE(method) == &PyMethod_Type);
+ PyObject *self, *func, *result;
+ self = PyMethod_GET_SELF(method);
+ func = PyMethod_GET_FUNCTION(method);
+ Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+
+ if (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET) {
+ /* PY_VECTORCALL_ARGUMENTS_OFFSET is set, so we are allowed to mutate the vector */
+ PyObject **newargs = (PyObject**)args - 1;
+ nargs += 1;
+ PyObject *tmp = newargs[0];
+ newargs[0] = self;
+ result = _PyObject_Vectorcall(func, newargs, nargs, kwnames);
+ newargs[0] = tmp;
+ }
+ else {
+ Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
+ PyObject **newargs;
+ Py_ssize_t totalargs = nargs + nkwargs;
+ newargs = PyMem_Malloc((totalargs+1) * sizeof(PyObject *));
+ if (newargs == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ /* use borrowed references */
+ newargs[0] = self;
+ memcpy(newargs + 1, args, totalargs * sizeof(PyObject *));
+ result = _PyObject_Vectorcall(func, newargs, nargs+1, kwnames);
+ PyMem_Free(newargs);
+ }
+ return result;
+}
+
+
/* Method objects are used for bound instance methods returned by
instancename.methodname. ClassName.methodname returns an ordinary
function.
@@ -69,6 +108,7 @@
im->im_func = func;
Py_XINCREF(self);
im->im_self = self;
+ im->vectorcall = method_vectorcall;
_PyObject_GC_TRACK(im);
return (PyObject *)im;
}
@@ -309,7 +349,7 @@
sizeof(PyMethodObject),
0,
(destructor)method_dealloc, /* tp_dealloc */
- 0, /* tp_print */
+ offsetof(PyMethodObject, vectorcall), /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
@@ -323,7 +363,8 @@
method_getattro, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ _Py_TPFLAGS_HAVE_VECTORCALL, /* tp_flags */
method_doc, /* tp_doc */
(traverseproc)method_traverse, /* tp_traverse */
0, /* tp_clear */