[Python-checkins] bpo-45439: Move _PyObject_VectorcallTstate() to pycore_call.h (GH-28893)

vstinner webhook-mailer at python.org
Thu Oct 14 15:53:13 EDT 2021


https://github.com/python/cpython/commit/3cc56c828d2d8f8659ea49447234bf0d2b87cd64
commit: 3cc56c828d2d8f8659ea49447234bf0d2b87cd64
branch: main
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2021-10-14T21:53:04+02:00
summary:

bpo-45439: Move _PyObject_VectorcallTstate() to pycore_call.h (GH-28893)

* Move _PyObject_VectorcallTstate() and _PyObject_FastCallTstate() to
  pycore_call.h (internal C API).
* Convert PyObject_CallOneArg(), PyObject_Vectorcall(),
  _PyObject_FastCall() and PyVectorcall_Function() static inline
  functions to regular functions.
* Add _PyVectorcall_FunctionInline() static inline function.
* PyObject_Vectorcall(), _PyObject_FastCall(), and
  PyObject_CallOneArg() now call _PyThreadState_GET() rather
  than PyThreadState_Get().

files:
M Include/cpython/abstract.h
M Include/internal/pycore_call.h
M Modules/_functoolsmodule.c
M Objects/call.c
M Objects/classobject.c
M Python/context.c

diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h
index 0814bfa62e1a4..55a742c31fada 100644
--- a/Include/cpython/abstract.h
+++ b/Include/cpython/abstract.h
@@ -58,72 +58,13 @@ PyVectorcall_NARGS(size_t n)
     return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET;
 }
 
-static inline vectorcallfunc
-PyVectorcall_Function(PyObject *callable)
-{
-    PyTypeObject *tp;
-    Py_ssize_t offset;
-    vectorcallfunc ptr;
-
-    assert(callable != NULL);
-    tp = Py_TYPE(callable);
-    if (!PyType_HasFeature(tp, Py_TPFLAGS_HAVE_VECTORCALL)) {
-        return NULL;
-    }
-    assert(PyCallable_Check(callable));
-
-    offset = tp->tp_vectorcall_offset;
-    assert(offset > 0);
-    memcpy(&ptr, (char *) callable + offset, sizeof(ptr));
-    return ptr;
-}
-
-/* Call the callable object 'callable' with the "vectorcall" calling
-   convention.
-
-   args is a C array for positional arguments.
-
-   nargsf is the number of positional arguments plus optionally the flag
-   PY_VECTORCALL_ARGUMENTS_OFFSET which means that the caller is allowed to
-   modify args[-1].
-
-   kwnames is a tuple of keyword names. The values of the keyword arguments
-   are stored in "args" after the positional arguments (note that the number
-   of keyword arguments does not change nargsf). kwnames can also be NULL if
-   there are no keyword arguments.
+PyAPI_FUNC(vectorcallfunc) PyVectorcall_Function(PyObject *callable);
 
-   keywords must only contain strings and all keys must be unique.
-
-   Return the result on success. Raise an exception and return NULL on
-   error. */
-static inline PyObject *
-_PyObject_VectorcallTstate(PyThreadState *tstate, PyObject *callable,
-                           PyObject *const *args, size_t nargsf,
-                           PyObject *kwnames)
-{
-    vectorcallfunc func;
-    PyObject *res;
-
-    assert(kwnames == NULL || PyTuple_Check(kwnames));
-    assert(args != NULL || PyVectorcall_NARGS(nargsf) == 0);
-
-    func = PyVectorcall_Function(callable);
-    if (func == NULL) {
-        Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
-        return _PyObject_MakeTpCall(tstate, callable, args, nargs, kwnames);
-    }
-    res = func(callable, args, nargsf, kwnames);
-    return _Py_CheckFunctionResult(tstate, callable, res, NULL);
-}
-
-static inline PyObject *
-PyObject_Vectorcall(PyObject *callable, PyObject *const *args,
-                     size_t nargsf, PyObject *kwnames)
-{
-    PyThreadState *tstate = PyThreadState_Get();
-    return _PyObject_VectorcallTstate(tstate, callable,
-                                      args, nargsf, kwnames);
-}
+PyAPI_FUNC(PyObject *) PyObject_Vectorcall(
+    PyObject *callable,
+    PyObject *const *args,
+    size_t nargsf,
+    PyObject *kwnames);
 
 // Backwards compatibility aliases for API that was provisional in Python 3.8
 #define _PyObject_Vectorcall PyObject_Vectorcall
@@ -146,35 +87,13 @@ PyAPI_FUNC(PyObject *) PyObject_VectorcallDict(
    "tuple" and keyword arguments "dict". "dict" may also be NULL */
 PyAPI_FUNC(PyObject *) PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict);
 
-static inline PyObject *
-_PyObject_FastCallTstate(PyThreadState *tstate, PyObject *func, PyObject *const *args, Py_ssize_t nargs)
-{
-    return _PyObject_VectorcallTstate(tstate, func, args, (size_t)nargs, NULL);
-}
-
-/* Same as PyObject_Vectorcall except without keyword arguments */
-static inline PyObject *
-_PyObject_FastCall(PyObject *func, PyObject *const *args, Py_ssize_t nargs)
-{
-    PyThreadState *tstate = PyThreadState_Get();
-    return _PyObject_FastCallTstate(tstate, func, args, nargs);
-}
-
-static inline PyObject *
-PyObject_CallOneArg(PyObject *func, PyObject *arg)
-{
-    PyObject *_args[2];
-    PyObject **args;
-    PyThreadState *tstate;
-    size_t nargsf;
+// Same as PyObject_Vectorcall(), except without keyword arguments
+PyAPI_FUNC(PyObject *) _PyObject_FastCall(
+    PyObject *func,
+    PyObject *const *args,
+    Py_ssize_t nargs);
 
-    assert(arg != NULL);
-    args = _args + 1;  // For PY_VECTORCALL_ARGUMENTS_OFFSET
-    args[0] = arg;
-    tstate = PyThreadState_Get();
-    nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET;
-    return _PyObject_VectorcallTstate(tstate, func, args, nargsf, NULL);
-}
+PyAPI_FUNC(PyObject *) PyObject_CallOneArg(PyObject *func, PyObject *arg);
 
 PyAPI_FUNC(PyObject *) PyObject_VectorcallMethod(
     PyObject *name, PyObject *const *args,
diff --git a/Include/internal/pycore_call.h b/Include/internal/pycore_call.h
index 933d714f13377..f2cfd2fd53ed9 100644
--- a/Include/internal/pycore_call.h
+++ b/Include/internal/pycore_call.h
@@ -30,11 +30,73 @@ PyAPI_FUNC(PyObject *) _PyObject_Call(
     PyObject *args,
     PyObject *kwargs);
 
+
+// Static inline variant of public PyVectorcall_Function().
+static inline vectorcallfunc
+_PyVectorcall_FunctionInline(PyObject *callable)
+{
+    assert(callable != NULL);
+
+    PyTypeObject *tp = Py_TYPE(callable);
+    if (!PyType_HasFeature(tp, Py_TPFLAGS_HAVE_VECTORCALL)) {
+        return NULL;
+    }
+    assert(PyCallable_Check(callable));
+
+    Py_ssize_t offset = tp->tp_vectorcall_offset;
+    assert(offset > 0);
+
+    vectorcallfunc ptr;
+    memcpy(&ptr, (char *) callable + offset, sizeof(ptr));
+    return ptr;
+}
+
+
+/* Call the callable object 'callable' with the "vectorcall" calling
+   convention.
+
+   args is a C array for positional arguments.
+
+   nargsf is the number of positional arguments plus optionally the flag
+   PY_VECTORCALL_ARGUMENTS_OFFSET which means that the caller is allowed to
+   modify args[-1].
+
+   kwnames is a tuple of keyword names. The values of the keyword arguments
+   are stored in "args" after the positional arguments (note that the number
+   of keyword arguments does not change nargsf). kwnames can also be NULL if
+   there are no keyword arguments.
+
+   keywords must only contain strings and all keys must be unique.
+
+   Return the result on success. Raise an exception and return NULL on
+   error. */
+static inline PyObject *
+_PyObject_VectorcallTstate(PyThreadState *tstate, PyObject *callable,
+                           PyObject *const *args, size_t nargsf,
+                           PyObject *kwnames)
+{
+    vectorcallfunc func;
+    PyObject *res;
+
+    assert(kwnames == NULL || PyTuple_Check(kwnames));
+    assert(args != NULL || PyVectorcall_NARGS(nargsf) == 0);
+
+    func = _PyVectorcall_FunctionInline(callable);
+    if (func == NULL) {
+        Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+        return _PyObject_MakeTpCall(tstate, callable, args, nargs, kwnames);
+    }
+    res = func(callable, args, nargsf, kwnames);
+    return _Py_CheckFunctionResult(tstate, callable, res, NULL);
+}
+
+
 static inline PyObject *
 _PyObject_CallNoArgsTstate(PyThreadState *tstate, PyObject *func) {
     return _PyObject_VectorcallTstate(tstate, func, NULL, 0, NULL);
 }
 
+
 // Private static inline function variant of public PyObject_CallNoArgs()
 static inline PyObject *
 _PyObject_CallNoArgs(PyObject *func) {
@@ -42,6 +104,14 @@ _PyObject_CallNoArgs(PyObject *func) {
     return _PyObject_VectorcallTstate(tstate, func, NULL, 0, NULL);
 }
 
+
+static inline PyObject *
+_PyObject_FastCallTstate(PyThreadState *tstate, PyObject *func, PyObject *const *args, Py_ssize_t nargs)
+{
+    return _PyObject_VectorcallTstate(tstate, func, args, (size_t)nargs, NULL);
+}
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index 4c77ee7b7a53c..1f6b852f6d99b 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -269,7 +269,7 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,
 static void
 partial_setvectorcall(partialobject *pto)
 {
-    if (PyVectorcall_Function(pto->fn) == NULL) {
+    if (_PyVectorcall_Function(pto->fn) == NULL) {
         /* Don't use vectorcall if the underlying function doesn't support it */
         pto->vectorcall = NULL;
     }
diff --git a/Objects/call.c b/Objects/call.c
index cfcd4220f3cf7..5e55518b04cbf 100644
--- a/Objects/call.c
+++ b/Objects/call.c
@@ -109,8 +109,7 @@ _Py_CheckSlotResult(PyObject *obj, const char *slot_name, int success)
 PyObject *
 PyObject_CallNoArgs(PyObject *func)
 {
-    PyThreadState *tstate = _PyThreadState_GET();
-    return _PyObject_CallNoArgsTstate(tstate, func);
+    return _PyObject_CallNoArgs(func);
 }
 
 
@@ -131,7 +130,7 @@ _PyObject_FastCallDictTstate(PyThreadState *tstate, PyObject *callable,
     assert(nargs == 0 || args != NULL);
     assert(kwargs == NULL || PyDict_Check(kwargs));
 
-    vectorcallfunc func = PyVectorcall_Function(callable);
+    vectorcallfunc func = _PyVectorcall_Function(callable);
     if (func == NULL) {
         /* Use tp_call instead */
         return _PyObject_MakeTpCall(tstate, callable, args, nargs, kwargs);
@@ -225,6 +224,13 @@ _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable,
 }
 
 
+vectorcallfunc
+PyVectorcall_Function(PyObject *callable)
+{
+    return _PyVectorcall_FunctionInline(callable);
+}
+
+
 static PyObject *
 _PyVectorcall_Call(PyThreadState *tstate, vectorcallfunc func,
                    PyObject *callable, PyObject *tuple, PyObject *kwargs)
@@ -260,7 +266,7 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
 {
     PyThreadState *tstate = _PyThreadState_GET();
 
-    /* get vectorcallfunc as in PyVectorcall_Function, but without
+    /* get vectorcallfunc as in _PyVectorcall_Function, but without
      * the Py_TPFLAGS_HAVE_VECTORCALL check */
     Py_ssize_t offset = Py_TYPE(callable)->tp_vectorcall_offset;
     if (offset <= 0) {
@@ -284,6 +290,24 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
 }
 
 
+PyObject *
+PyObject_Vectorcall(PyObject *callable, PyObject *const *args,
+                     size_t nargsf, PyObject *kwnames)
+{
+    PyThreadState *tstate = _PyThreadState_GET();
+    return _PyObject_VectorcallTstate(tstate, callable,
+                                      args, nargsf, kwnames);
+}
+
+
+PyObject *
+_PyObject_FastCall(PyObject *func, PyObject *const *args, Py_ssize_t nargs)
+{
+    PyThreadState *tstate = _PyThreadState_GET();
+    return _PyObject_FastCallTstate(tstate, func, args, nargs);
+}
+
+
 PyObject *
 _PyObject_Call(PyThreadState *tstate, PyObject *callable,
                PyObject *args, PyObject *kwargs)
@@ -298,7 +322,7 @@ _PyObject_Call(PyThreadState *tstate, PyObject *callable,
     assert(PyTuple_Check(args));
     assert(kwargs == NULL || PyDict_Check(kwargs));
 
-    vectorcallfunc vector_func = PyVectorcall_Function(callable);
+    vectorcallfunc vector_func = _PyVectorcall_Function(callable);
     if (vector_func != NULL) {
         return _PyVectorcall_Call(tstate, vector_func, callable, args, kwargs);
     }
@@ -339,6 +363,19 @@ PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
 }
 
 
+PyObject *
+PyObject_CallOneArg(PyObject *func, PyObject *arg)
+{
+    assert(arg != NULL);
+    PyObject *_args[2];
+    PyObject **args = _args + 1;  // For PY_VECTORCALL_ARGUMENTS_OFFSET
+    args[0] = arg;
+    PyThreadState *tstate = _PyThreadState_GET();
+    size_t nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET;
+    return _PyObject_VectorcallTstate(tstate, func, args, nargsf, NULL);
+}
+
+
 /* --- PyFunction call functions ---------------------------------- */
 
 PyObject *
diff --git a/Objects/classobject.c b/Objects/classobject.c
index af73be3d26241..9d4fc99f1f858 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -1,6 +1,7 @@
 /* Class object implementation (dead now except for methods) */
 
 #include "Python.h"
+#include "pycore_call.h"          // _PyObject_VectorcallTstate()
 #include "pycore_object.h"
 #include "pycore_pyerrors.h"
 #include "pycore_pystate.h"       // _PyThreadState_GET()
diff --git a/Python/context.c b/Python/context.c
index ad47992d9e3cd..d78f7f993bb89 100644
--- a/Python/context.c
+++ b/Python/context.c
@@ -1,5 +1,5 @@
 #include "Python.h"
-
+#include "pycore_call.h"          // _PyObject_VectorcallTstate()
 #include "pycore_context.h"
 #include "pycore_gc.h"            // _PyObject_GC_MAY_BE_TRACKED()
 #include "pycore_hamt.h"



More information about the Python-checkins mailing list