summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeroen Demeyer <J.Demeyer@UGent.be>2019-07-23 10:39:51 (GMT)
committerƁukasz Langa <lukasz@langa.pl>2019-07-23 10:39:51 (GMT)
commitbf8e82f976b37856c7d35cdf88a238cb6f57fe65 (patch)
treeeef98efc9b9f0206ff2ee927e697434003405796
parent5dab5e7d24c790d54b8d1eca0568e798bfda2c68 (diff)
downloadcpython-bf8e82f976b37856c7d35cdf88a238cb6f57fe65.zip
cpython-bf8e82f976b37856c7d35cdf88a238cb6f57fe65.tar.gz
cpython-bf8e82f976b37856c7d35cdf88a238cb6f57fe65.tar.bz2
[3.8] bpo-36974: separate vectorcall functions for each calling convention (GH-13781) (#14782)
-rw-r--r--Include/descrobject.h3
-rw-r--r--Include/methodobject.h5
-rw-r--r--Lib/test/test_call.py2
-rw-r--r--Lib/test/test_gdb.py8
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2019-06-11-12-59-38.bpo-36974.bVYmSA.rst2
-rw-r--r--Objects/call.c21
-rw-r--r--Objects/descrobject.c246
-rw-r--r--Objects/methodobject.c165
-rw-r--r--Python/ceval.c16
-rwxr-xr-xTools/gdb/libpython.py5
10 files changed, 372 insertions, 101 deletions
diff --git a/Include/descrobject.h b/Include/descrobject.h
index d711485..ead269d 100644
--- a/Include/descrobject.h
+++ b/Include/descrobject.h
@@ -91,9 +91,6 @@ PyAPI_FUNC(PyObject *) PyDescr_NewMember(PyTypeObject *,
PyAPI_FUNC(PyObject *) PyDescr_NewGetSet(PyTypeObject *,
struct PyGetSetDef *);
#ifndef Py_LIMITED_API
-
-PyAPI_FUNC(PyObject *) _PyMethodDescr_Vectorcall(
- PyObject *descrobj, PyObject *const *args, size_t nargsf, PyObject *kwnames);
PyAPI_FUNC(PyObject *) PyDescr_NewWrapper(PyTypeObject *,
struct wrapperbase *, void *);
#define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL)
diff --git a/Include/methodobject.h b/Include/methodobject.h
index e92adde..ba3b887 100644
--- a/Include/methodobject.h
+++ b/Include/methodobject.h
@@ -46,11 +46,6 @@ PyAPI_FUNC(PyObject *) _PyCFunction_FastCallDict(PyObject *func,
PyObject *const *args,
Py_ssize_t nargs,
PyObject *kwargs);
-
-PyAPI_FUNC(PyObject *) _PyCFunction_Vectorcall(PyObject *func,
- PyObject *const *stack,
- size_t nargsf,
- PyObject *kwnames);
#endif
struct PyMethodDef {
diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py
index b252ca1..0bff7de 100644
--- a/Lib/test/test_call.py
+++ b/Lib/test/test_call.py
@@ -586,6 +586,8 @@ class TestPEP590(unittest.TestCase):
return super().__call__(*args)
calls += [
+ (dict.update, ({},), {"key":True}, None),
+ ({}.update, ({},), {"key":True}, None),
(MethodDescriptorHeap(), (0,), {}, True),
(MethodDescriptorOverridden(), (0,), {}, 'new'),
(MethodDescriptorSuper(), (0,), {}, True),
diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py
index 1c5e18b..e07d327 100644
--- a/Lib/test/test_gdb.py
+++ b/Lib/test/test_gdb.py
@@ -850,10 +850,10 @@ id(42)
# called, so test a variety of calling conventions.
for py_name, py_args, c_name, expected_frame_number in (
('gmtime', '', 'time_gmtime', 1), # METH_VARARGS
- ('len', '[]', 'builtin_len', 2), # METH_O
- ('locals', '', 'builtin_locals', 2), # METH_NOARGS
- ('iter', '[]', 'builtin_iter', 2), # METH_FASTCALL
- ('sorted', '[]', 'builtin_sorted', 2), # METH_FASTCALL|METH_KEYWORDS
+ ('len', '[]', 'builtin_len', 1), # METH_O
+ ('locals', '', 'builtin_locals', 1), # METH_NOARGS
+ ('iter', '[]', 'builtin_iter', 1), # METH_FASTCALL
+ ('sorted', '[]', 'builtin_sorted', 1), # METH_FASTCALL|METH_KEYWORDS
):
with self.subTest(c_name):
cmd = ('from time import gmtime\n' # (not always needed)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-06-11-12-59-38.bpo-36974.bVYmSA.rst b/Misc/NEWS.d/next/Core and Builtins/2019-06-11-12-59-38.bpo-36974.bVYmSA.rst
new file mode 100644
index 0000000..6080ef3
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-06-11-12-59-38.bpo-36974.bVYmSA.rst
@@ -0,0 +1,2 @@
+Implemented separate vectorcall functions for every calling convention of
+builtin functions and methods. This improves performance for calls.
diff --git a/Objects/call.c b/Objects/call.c
index 1f41f5c..c663898 100644
--- a/Objects/call.c
+++ b/Objects/call.c
@@ -206,7 +206,7 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
Py_DECREF(kwnames);
}
- return result;
+ return _Py_CheckFunctionResult(callable, result, NULL);
}
@@ -723,25 +723,6 @@ exit:
}
-PyObject *
-_PyCFunction_Vectorcall(PyObject *func,
- PyObject *const *args, size_t nargsf,
- PyObject *kwnames)
-{
- PyObject *result;
-
- assert(func != NULL);
- assert(PyCFunction_Check(func));
- Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
-
- result = _PyMethodDef_RawFastCallKeywords(((PyCFunctionObject*)func)->m_ml,
- PyCFunction_GET_SELF(func),
- args, nargs, kwnames);
- result = _Py_CheckFunctionResult(func, result, NULL);
- return result;
-}
-
-
static PyObject *
cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs)
{
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 6c95a87..dbb44de 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -226,80 +226,199 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
return -1;
}
-static PyObject *
-methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
-{
- Py_ssize_t nargs;
- PyObject *self, *result;
- /* Make sure that the first argument is acceptable as 'self' */
- assert(PyTuple_Check(args));
- nargs = PyTuple_GET_SIZE(args);
+/* Vectorcall functions for each of the PyMethodDescr calling conventions.
+ *
+ * First, common helpers
+ */
+static const char *
+get_name(PyObject *func) {
+ assert(PyObject_TypeCheck(func, &PyMethodDescr_Type));
+ return ((PyMethodDescrObject *)func)->d_method->ml_name;
+}
+
+typedef void (*funcptr)(void);
+
+static inline int
+method_check_args(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ assert(!PyErr_Occurred());
+ assert(PyObject_TypeCheck(func, &PyMethodDescr_Type));
if (nargs < 1) {
PyErr_Format(PyExc_TypeError,
- "descriptor '%V' of '%.100s' "
+ "descriptor '%.200s' of '%.100s' "
"object needs an argument",
- descr_name((PyDescrObject *)descr), "?",
- PyDescr_TYPE(descr)->tp_name);
- return NULL;
+ get_name(func), PyDescr_TYPE(func)->tp_name);
+ return -1;
}
- self = PyTuple_GET_ITEM(args, 0);
+ PyObject *self = args[0];
if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
- (PyObject *)PyDescr_TYPE(descr))) {
+ (PyObject *)PyDescr_TYPE(func)))
+ {
PyErr_Format(PyExc_TypeError,
- "descriptor '%V' for '%.100s' objects "
+ "descriptor '%.200s' for '%.100s' objects "
"doesn't apply to a '%.100s' object",
- descr_name((PyDescrObject *)descr), "?",
- PyDescr_TYPE(descr)->tp_name,
- self->ob_type->tp_name);
+ get_name(func), PyDescr_TYPE(func)->tp_name,
+ Py_TYPE(self)->tp_name);
+ return -1;
+ }
+ if (kwnames && PyTuple_GET_SIZE(kwnames)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() takes no keyword arguments", get_name(func));
+ return -1;
+ }
+ return 0;
+}
+
+static inline funcptr
+method_enter_call(PyObject *func)
+{
+ if (Py_EnterRecursiveCall(" while calling a Python object")) {
return NULL;
}
+ return (funcptr)((PyMethodDescrObject *)func)->d_method->ml_meth;
+}
- result = _PyMethodDef_RawFastCallDict(descr->d_method, self,
- &_PyTuple_ITEMS(args)[1], nargs - 1,
- kwargs);
- result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
+/* Now the actual vectorcall functions */
+static PyObject *
+method_vectorcall_VARARGS(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+{
+ Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+ if (method_check_args(func, args, nargs, kwnames)) {
+ return NULL;
+ }
+ PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);
+ if (argstuple == NULL) {
+ return NULL;
+ }
+ PyCFunction meth = (PyCFunction)method_enter_call(func);
+ if (meth == NULL) {
+ Py_DECREF(argstuple);
+ return NULL;
+ }
+ PyObject *result = meth(args[0], argstuple);
+ Py_DECREF(argstuple);
+ Py_LeaveRecursiveCall();
return result;
}
-// same to methoddescr_call(), but use FASTCALL convention.
-PyObject *
-_PyMethodDescr_Vectorcall(PyObject *descrobj,
- PyObject *const *args, size_t nargsf,
- PyObject *kwnames)
+static PyObject *
+method_vectorcall_VARARGS_KEYWORDS(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
{
- assert(Py_TYPE(descrobj) == &PyMethodDescr_Type);
- PyMethodDescrObject *descr = (PyMethodDescrObject *)descrobj;
- PyObject *self, *result;
+ Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+ if (method_check_args(func, args, nargs, NULL)) {
+ return NULL;
+ }
+ PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);
+ if (argstuple == NULL) {
+ return NULL;
+ }
+ PyObject *result = NULL;
+ /* Create a temporary dict for keyword arguments */
+ PyObject *kwdict = NULL;
+ if (kwnames != NULL && PyTuple_GET_SIZE(kwnames) > 0) {
+ kwdict = _PyStack_AsDict(args + nargs, kwnames);
+ if (kwdict == NULL) {
+ goto exit;
+ }
+ }
+ PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords)
+ method_enter_call(func);
+ if (meth == NULL) {
+ goto exit;
+ }
+ result = meth(args[0], argstuple, kwdict);
+ Py_LeaveRecursiveCall();
+exit:
+ Py_DECREF(argstuple);
+ Py_XDECREF(kwdict);
+ return result;
+}
+static PyObject *
+method_vectorcall_FASTCALL(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+{
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
- /* Make sure that the first argument is acceptable as 'self' */
- if (nargs < 1) {
- PyErr_Format(PyExc_TypeError,
- "descriptor '%V' of '%.100s' "
- "object needs an argument",
- descr_name((PyDescrObject *)descr), "?",
- PyDescr_TYPE(descr)->tp_name);
+ if (method_check_args(func, args, nargs, kwnames)) {
return NULL;
}
- self = args[0];
- if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
- (PyObject *)PyDescr_TYPE(descr))) {
+ _PyCFunctionFast meth = (_PyCFunctionFast)
+ method_enter_call(func);
+ if (meth == NULL) {
+ return NULL;
+ }
+ PyObject *result = meth(args[0], args+1, nargs-1);
+ Py_LeaveRecursiveCall();
+ return result;
+}
+
+static PyObject *
+method_vectorcall_FASTCALL_KEYWORDS(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+{
+ Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+ if (method_check_args(func, args, nargs, NULL)) {
+ return NULL;
+ }
+ _PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)
+ method_enter_call(func);
+ if (meth == NULL) {
+ return NULL;
+ }
+ PyObject *result = meth(args[0], args+1, nargs-1, kwnames);
+ Py_LeaveRecursiveCall();
+ return result;
+}
+
+static PyObject *
+method_vectorcall_NOARGS(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+{
+ Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+ if (method_check_args(func, args, nargs, kwnames)) {
+ return NULL;
+ }
+ if (nargs != 1) {
PyErr_Format(PyExc_TypeError,
- "descriptor '%V' for '%.100s' objects "
- "doesn't apply to a '%.100s' object",
- descr_name((PyDescrObject *)descr), "?",
- PyDescr_TYPE(descr)->tp_name,
- self->ob_type->tp_name);
+ "%.200s() takes no arguments (%zd given)", get_name(func), nargs-1);
return NULL;
}
+ PyCFunction meth = (PyCFunction)method_enter_call(func);
+ if (meth == NULL) {
+ return NULL;
+ }
+ PyObject *result = meth(args[0], NULL);
+ Py_LeaveRecursiveCall();
+ return result;
+}
- result = _PyMethodDef_RawFastCallKeywords(descr->d_method, self,
- args+1, nargs-1, kwnames);
- result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
+static PyObject *
+method_vectorcall_O(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+{
+ Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+ if (method_check_args(func, args, nargs, kwnames)) {
+ return NULL;
+ }
+ if (nargs != 2) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() takes exactly one argument (%zd given)",
+ get_name(func), nargs-1);
+ return NULL;
+ }
+ PyCFunction meth = (PyCFunction)method_enter_call(func);
+ if (meth == NULL) {
+ return NULL;
+ }
+ PyObject *result = meth(args[0], args[1]);
+ Py_LeaveRecursiveCall();
return result;
}
+
static PyObject *
classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
PyObject *kwds)
@@ -552,7 +671,7 @@ PyTypeObject PyMethodDescr_Type = {
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
- (ternaryfunc)methoddescr_call, /* tp_call */
+ PyVectorcall_Call, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
@@ -750,13 +869,40 @@ descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)
PyObject *
PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
{
+ /* Figure out correct vectorcall function to use */
+ vectorcallfunc vectorcall;
+ switch (method->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS))
+ {
+ case METH_VARARGS:
+ vectorcall = method_vectorcall_VARARGS;
+ break;
+ case METH_VARARGS | METH_KEYWORDS:
+ vectorcall = method_vectorcall_VARARGS_KEYWORDS;
+ break;
+ case METH_FASTCALL:
+ vectorcall = method_vectorcall_FASTCALL;
+ break;
+ case METH_FASTCALL | METH_KEYWORDS:
+ vectorcall = method_vectorcall_FASTCALL_KEYWORDS;
+ break;
+ case METH_NOARGS:
+ vectorcall = method_vectorcall_NOARGS;
+ break;
+ case METH_O:
+ vectorcall = method_vectorcall_O;
+ break;
+ default:
+ PyErr_SetString(PyExc_SystemError, "bad call flags");
+ return NULL;
+ }
+
PyMethodDescrObject *descr;
descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
type, method->ml_name);
if (descr != NULL) {
descr->d_method = method;
- descr->vectorcall = _PyMethodDescr_Vectorcall;
+ descr->vectorcall = vectorcall;
}
return (PyObject *)descr;
}
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index c3bc018..3494f11 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -19,6 +19,17 @@ static int numfree = 0;
/* undefine macro trampoline to PyCFunction_NewEx */
#undef PyCFunction_New
+/* Forward declarations */
+static PyObject * cfunction_vectorcall_FASTCALL(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
+static PyObject * cfunction_vectorcall_FASTCALL_KEYWORDS(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
+static PyObject * cfunction_vectorcall_NOARGS(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
+static PyObject * cfunction_vectorcall_O(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
+
+
PyObject *
PyCFunction_New(PyMethodDef *ml, PyObject *self)
{
@@ -28,6 +39,33 @@ PyCFunction_New(PyMethodDef *ml, PyObject *self)
PyObject *
PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
{
+ /* Figure out correct vectorcall function to use */
+ vectorcallfunc vectorcall;
+ switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS))
+ {
+ case METH_VARARGS:
+ case METH_VARARGS | METH_KEYWORDS:
+ /* For METH_VARARGS functions, it's more efficient to use tp_call
+ * instead of vectorcall. */
+ vectorcall = NULL;
+ break;
+ case METH_FASTCALL:
+ vectorcall = cfunction_vectorcall_FASTCALL;
+ break;
+ case METH_FASTCALL | METH_KEYWORDS:
+ vectorcall = cfunction_vectorcall_FASTCALL_KEYWORDS;
+ break;
+ case METH_NOARGS:
+ vectorcall = cfunction_vectorcall_NOARGS;
+ break;
+ case METH_O:
+ vectorcall = cfunction_vectorcall_O;
+ break;
+ default:
+ PyErr_SetString(PyExc_SystemError, "bad call flags");
+ return NULL;
+ }
+
PyCFunctionObject *op;
op = free_list;
if (op != NULL) {
@@ -46,14 +84,7 @@ PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
op->m_self = self;
Py_XINCREF(module);
op->m_module = module;
- if (ml->ml_flags & METH_VARARGS) {
- /* For METH_VARARGS functions, it's more efficient to use tp_call
- * instead of vectorcall. */
- op->vectorcall = NULL;
- }
- else {
- op->vectorcall = _PyCFunction_Vectorcall;
- }
+ op->vectorcall = vectorcall;
_PyObject_GC_TRACK(op);
return (PyObject *)op;
}
@@ -333,3 +364,121 @@ _PyCFunction_DebugMallocStats(FILE *out)
"free PyCFunctionObject",
numfree, sizeof(PyCFunctionObject));
}
+
+
+/* Vectorcall functions for each of the PyCFunction calling conventions,
+ * except for METH_VARARGS (possibly combined with METH_KEYWORDS) which
+ * doesn't use vectorcall.
+ *
+ * First, common helpers
+ */
+static const char *
+get_name(PyObject *func)
+{
+ assert(PyCFunction_Check(func));
+ PyMethodDef *method = ((PyCFunctionObject *)func)->m_ml;
+ return method->ml_name;
+}
+
+typedef void (*funcptr)(void);
+
+static inline int
+cfunction_check_kwargs(PyObject *func, PyObject *kwnames)
+{
+ assert(!PyErr_Occurred());
+ assert(PyCFunction_Check(func));
+ if (kwnames && PyTuple_GET_SIZE(kwnames)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() takes no keyword arguments", get_name(func));
+ return -1;
+ }
+ return 0;
+}
+
+static inline funcptr
+cfunction_enter_call(PyObject *func)
+{
+ if (Py_EnterRecursiveCall(" while calling a Python object")) {
+ return NULL;
+ }
+ return (funcptr)PyCFunction_GET_FUNCTION(func);
+}
+
+/* Now the actual vectorcall functions */
+static PyObject *
+cfunction_vectorcall_FASTCALL(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+{
+ if (cfunction_check_kwargs(func, kwnames)) {
+ return NULL;
+ }
+ Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+ _PyCFunctionFast meth = (_PyCFunctionFast)
+ cfunction_enter_call(func);
+ if (meth == NULL) {
+ return NULL;
+ }
+ PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs);
+ Py_LeaveRecursiveCall();
+ return result;
+}
+
+static PyObject *
+cfunction_vectorcall_FASTCALL_KEYWORDS(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+{
+ Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+ _PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)
+ cfunction_enter_call(func);
+ if (meth == NULL) {
+ return NULL;
+ }
+ PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs, kwnames);
+ Py_LeaveRecursiveCall();
+ return result;
+}
+
+static PyObject *
+cfunction_vectorcall_NOARGS(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+{
+ if (cfunction_check_kwargs(func, kwnames)) {
+ return NULL;
+ }
+ Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+ if (nargs != 0) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() takes no arguments (%zd given)", get_name(func), nargs);
+ return NULL;
+ }
+ PyCFunction meth = (PyCFunction)cfunction_enter_call(func);
+ if (meth == NULL) {
+ return NULL;
+ }
+ PyObject *result = meth(PyCFunction_GET_SELF(func), NULL);
+ Py_LeaveRecursiveCall();
+ return result;
+}
+
+static PyObject *
+cfunction_vectorcall_O(
+ PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+{
+ if (cfunction_check_kwargs(func, kwnames)) {
+ return NULL;
+ }
+ Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+ if (nargs != 1) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() takes exactly one argument (%zd given)",
+ get_name(func), nargs);
+ return NULL;
+ }
+ PyCFunction meth = (PyCFunction)cfunction_enter_call(func);
+ if (meth == NULL) {
+ return NULL;
+ }
+ PyObject *result = meth(PyCFunction_GET_SELF(func), args[0]);
+ Py_LeaveRecursiveCall();
+ return result;
+}
diff --git a/Python/ceval.c b/Python/ceval.c
index eddcc8d..546a426 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -4943,7 +4943,7 @@ trace_call_function(PyThreadState *tstate,
{
PyObject *x;
if (PyCFunction_Check(func)) {
- C_TRACE(x, _PyCFunction_Vectorcall(func, args, nargs, kwnames));
+ C_TRACE(x, _PyObject_Vectorcall(func, args, nargs, kwnames));
return x;
}
else if (Py_TYPE(func) == &PyMethodDescr_Type && nargs > 0) {
@@ -4959,9 +4959,9 @@ trace_call_function(PyThreadState *tstate,
if (func == NULL) {
return NULL;
}
- C_TRACE(x, _PyCFunction_Vectorcall(func,
- args+1, nargs-1,
- kwnames));
+ C_TRACE(x, _PyObject_Vectorcall(func,
+ args+1, nargs-1,
+ kwnames));
Py_DECREF(func);
return x;
}
@@ -5023,10 +5023,10 @@ do_call_core(PyThreadState *tstate, PyObject *func, PyObject *callargs, PyObject
return NULL;
}
- C_TRACE(result, _PyCFunction_FastCallDict(func,
- &_PyTuple_ITEMS(callargs)[1],
- nargs - 1,
- kwdict));
+ C_TRACE(result, _PyObject_FastCallDict(func,
+ &_PyTuple_ITEMS(callargs)[1],
+ nargs - 1,
+ kwdict));
Py_DECREF(func);
return result;
}
diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py
index 93f720a..e40f79b 100755
--- a/Tools/gdb/libpython.py
+++ b/Tools/gdb/libpython.py
@@ -1563,9 +1563,8 @@ class Frame(object):
if not caller:
return False
- if caller in ('_PyCFunction_FastCallDict',
- '_PyCFunction_Vectorcall',
- 'cfunction_call_varargs'):
+ if (caller.startswith('cfunction_vectorcall_') or
+ caller == 'cfunction_call_varargs'):
arg_name = 'func'
# Within that frame:
# "func" is the local containing the PyObject* of the