summaryrefslogtreecommitdiffstats
path: root/Objects/classobject.c
diff options
context:
space:
mode:
authorJeroen Demeyer <J.Demeyer@UGent.be>2019-05-29 18:31:52 (GMT)
committerPetr Viktorin <encukou@gmail.com>2019-05-29 18:31:52 (GMT)
commitaacc77fbd77640a8f03638216fa09372cc21673d (patch)
treefd64be1c4c1167a8bf708d1fd22c733cf3a9a30f /Objects/classobject.c
parentd30da5dd9a8a965cf24a22bbaff8a5b1341c2944 (diff)
downloadcpython-aacc77fbd77640a8f03638216fa09372cc21673d.zip
cpython-aacc77fbd77640a8f03638216fa09372cc21673d.tar.gz
cpython-aacc77fbd77640a8f03638216fa09372cc21673d.tar.bz2
bpo-36974: implement PEP 590 (GH-13185)
Co-authored-by: Jeroen Demeyer <J.Demeyer@UGent.be> Co-authored-by: Mark Shannon <mark@hotpy.org>
Diffstat (limited to 'Objects/classobject.c')
-rw-r--r--Objects/classobject.c45
1 files changed, 43 insertions, 2 deletions
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 @@ PyMethod_Self(PyObject *im)
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 @@ PyMethod_New(PyObject *func, PyObject *self)
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 @@ PyTypeObject PyMethod_Type = {
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 @@ PyTypeObject PyMethod_Type = {
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 */