[Python-checkins] gh-106084: Remove _PyObject_CallMethod() function (#106159)
vstinner
webhook-mailer at python.org
Tue Jun 27 19:34:41 EDT 2023
https://github.com/python/cpython/commit/84caa3324aaefb900895de2f946607cfdbe1be70
commit: 84caa3324aaefb900895de2f946607cfdbe1be70
branch: main
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2023-06-28T01:34:37+02:00
summary:
gh-106084: Remove _PyObject_CallMethod() function (#106159)
Remove the following private functions from the public C API:
* _Py_CheckFunctionResult()
* _PyObject_CallMethod()
* _PyObject_CallMethodId()
* _PyObject_CallMethodIdNoArgs()
* _PyObject_CallMethodIdObjArgs()
* _PyObject_CallMethodIdOneArg()
* _PyObject_MakeTpCall()
* _PyObject_VectorcallMethodId()
* _PyStack_AsDict()
Move these functions to the internal C API (pycore_call.h).
No longer export the following functions:
* _PyObject_Call()
* _PyObject_CallMethod()
* _PyObject_CallMethodId()
* _PyObject_CallMethodIdObjArgs()
* _PyObject_Call_Prepend()
* _PyObject_FastCallDictTstate()
* _PyStack_AsDict()
The following functions are still exported for stdlib shared
extensions:
* _Py_CheckFunctionResult()
* _PyObject_MakeTpCall()
Mark the following internal functions as extern:
* _PyStack_UnpackDict()
* _PyStack_UnpackDict_Free()
* _PyStack_UnpackDict_FreeNoDecRef()
files:
M Include/cpython/abstract.h
M Include/internal/pycore_call.h
M Modules/_bisectmodule.c
M Modules/_io/iobase.c
M Modules/_io/textio.c
M Modules/arraymodule.c
M Objects/descrobject.c
M Objects/methodobject.c
M Python/pylifecycle.c
diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h
index 5eb22ff61ecdd..2e76ff49a81dd 100644
--- a/Include/cpython/abstract.h
+++ b/Include/cpython/abstract.h
@@ -4,20 +4,6 @@
/* === Object Protocol ================================================== */
-/* Convert keyword arguments from the FASTCALL (stack: C array, kwnames: tuple)
- format to a Python dictionary ("kwargs" dict).
-
- The type of kwnames keys is not checked. The final function getting
- arguments is responsible to check if all keys are strings, for example using
- PyArg_ParseTupleAndKeywords() or PyArg_ValidateKeywordArguments().
-
- Duplicate keys are merged using the last value. If duplicate keys must raise
- an exception, the caller is responsible to implement an explicit keys on
- kwnames. */
-PyAPI_FUNC(PyObject *) _PyStack_AsDict(
- PyObject *const *values,
- PyObject *kwnames);
-
/* Suggested size (number of positional arguments) for arrays of PyObject*
allocated on a C stack to avoid allocating memory on the heap memory. Such
array is used to pass positional arguments to call functions of the
@@ -29,32 +15,17 @@ PyAPI_FUNC(PyObject *) _PyStack_AsDict(
40 bytes on the stack. */
#define _PY_FASTCALL_SMALL_STACK 5
-PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(
- PyThreadState *tstate,
- PyObject *callable,
- PyObject *result,
- const char *where);
-
/* === Vectorcall protocol (PEP 590) ============================= */
-/* Call callable using tp_call. Arguments are like PyObject_Vectorcall()
- or PyObject_FastCallDict() (both forms are supported),
- except that nargs is plainly the number of arguments without flags. */
-PyAPI_FUNC(PyObject *) _PyObject_MakeTpCall(
- PyThreadState *tstate,
- PyObject *callable,
- PyObject *const *args, Py_ssize_t nargs,
- PyObject *keywords);
-
// PyVectorcall_NARGS() is exported as a function for the stable ABI.
// Here (when we are not using the stable ABI), the name is overridden to
// call a static inline function for best performance.
-#define PyVectorcall_NARGS(n) _PyVectorcall_NARGS(n)
static inline Py_ssize_t
_PyVectorcall_NARGS(size_t n)
{
return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET;
}
+#define PyVectorcall_NARGS(n) _PyVectorcall_NARGS(n)
PyAPI_FUNC(vectorcallfunc) PyVectorcall_Function(PyObject *callable);
@@ -90,49 +61,6 @@ PyObject_CallMethodOneArg(PyObject *self, PyObject *name, PyObject *arg)
return PyObject_VectorcallMethod(name, args, nargsf, _Py_NULL);
}
-PyAPI_FUNC(PyObject *) _PyObject_CallMethod(PyObject *obj,
- PyObject *name,
- const char *format, ...);
-
-/* Like PyObject_CallMethod(), but expect a _Py_Identifier*
- as the method name. */
-PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *obj,
- _Py_Identifier *name,
- const char *format, ...);
-
-PyAPI_FUNC(PyObject *) _PyObject_CallMethodIdObjArgs(
- PyObject *obj,
- _Py_Identifier *name,
- ...);
-
-static inline PyObject *
-_PyObject_VectorcallMethodId(
- _Py_Identifier *name, PyObject *const *args,
- size_t nargsf, PyObject *kwnames)
-{
- PyObject *oname = _PyUnicode_FromId(name); /* borrowed */
- if (!oname) {
- return _Py_NULL;
- }
- return PyObject_VectorcallMethod(oname, args, nargsf, kwnames);
-}
-
-static inline PyObject *
-_PyObject_CallMethodIdNoArgs(PyObject *self, _Py_Identifier *name)
-{
- size_t nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET;
- return _PyObject_VectorcallMethodId(name, &self, nargsf, _Py_NULL);
-}
-
-static inline PyObject *
-_PyObject_CallMethodIdOneArg(PyObject *self, _Py_Identifier *name, PyObject *arg)
-{
- PyObject *args[2] = {self, arg};
- size_t nargsf = 2 | PY_VECTORCALL_ARGUMENTS_OFFSET;
- assert(arg != NULL);
- return _PyObject_VectorcallMethodId(name, args, nargsf, _Py_NULL);
-}
-
/* Guess the size of object 'o' using len(o) or o.__length_hint__().
If neither of those return a non-negative value, then return the default
value. If one of the calls fails, this function returns -1. */
diff --git a/Include/internal/pycore_call.h b/Include/internal/pycore_call.h
index 5d9342b562b00..3caf504a96aa3 100644
--- a/Include/internal/pycore_call.h
+++ b/Include/internal/pycore_call.h
@@ -10,29 +10,112 @@ extern "C" {
#include "pycore_pystate.h" // _PyThreadState_GET()
-PyAPI_FUNC(PyObject *) _PyObject_Call_Prepend(
+// Export for shared stdlib extensions like the math extension,
+// function used via inlined _PyObject_VectorcallTstate() function.
+PyAPI_FUNC(PyObject*) _Py_CheckFunctionResult(
+ PyThreadState *tstate,
+ PyObject *callable,
+ PyObject *result,
+ const char *where);
+
+/* Convert keyword arguments from the FASTCALL (stack: C array, kwnames: tuple)
+ format to a Python dictionary ("kwargs" dict).
+
+ The type of kwnames keys is not checked. The final function getting
+ arguments is responsible to check if all keys are strings, for example using
+ PyArg_ParseTupleAndKeywords() or PyArg_ValidateKeywordArguments().
+
+ Duplicate keys are merged using the last value. If duplicate keys must raise
+ an exception, the caller is responsible to implement an explicit keys on
+ kwnames. */
+extern PyObject* _PyStack_AsDict(PyObject *const *values, PyObject *kwnames);
+
+extern PyObject* _PyObject_Call_Prepend(
PyThreadState *tstate,
PyObject *callable,
PyObject *obj,
PyObject *args,
PyObject *kwargs);
-PyAPI_FUNC(PyObject *) _PyObject_FastCallDictTstate(
+extern PyObject* _PyObject_FastCallDictTstate(
PyThreadState *tstate,
PyObject *callable,
PyObject *const *args,
size_t nargsf,
PyObject *kwargs);
-PyAPI_FUNC(PyObject *) _PyObject_Call(
+extern PyObject* _PyObject_Call(
PyThreadState *tstate,
PyObject *callable,
PyObject *args,
PyObject *kwargs);
extern PyObject * _PyObject_CallMethodFormat(
- PyThreadState *tstate, PyObject *callable, const char *format, ...);
+ PyThreadState *tstate,
+ PyObject *callable,
+ const char *format,
+ ...);
+// Export for shared stdlib extensions like the array extension
+PyAPI_FUNC(PyObject*) _PyObject_CallMethod(
+ PyObject *obj,
+ PyObject *name,
+ const char *format, ...);
+
+/* Like PyObject_CallMethod(), but expect a _Py_Identifier*
+ as the method name. */
+extern PyObject* _PyObject_CallMethodId(
+ PyObject *obj,
+ _Py_Identifier *name,
+ const char *format, ...);
+
+extern PyObject* _PyObject_CallMethodIdObjArgs(
+ PyObject *obj,
+ _Py_Identifier *name,
+ ...);
+
+static inline PyObject *
+_PyObject_VectorcallMethodId(
+ _Py_Identifier *name, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames)
+{
+ PyObject *oname = _PyUnicode_FromId(name); /* borrowed */
+ if (!oname) {
+ return _Py_NULL;
+ }
+ return PyObject_VectorcallMethod(oname, args, nargsf, kwnames);
+}
+
+static inline PyObject *
+_PyObject_CallMethodIdNoArgs(PyObject *self, _Py_Identifier *name)
+{
+ size_t nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET;
+ return _PyObject_VectorcallMethodId(name, &self, nargsf, _Py_NULL);
+}
+
+static inline PyObject *
+_PyObject_CallMethodIdOneArg(PyObject *self, _Py_Identifier *name, PyObject *arg)
+{
+ PyObject *args[2] = {self, arg};
+ size_t nargsf = 2 | PY_VECTORCALL_ARGUMENTS_OFFSET;
+ assert(arg != NULL);
+ return _PyObject_VectorcallMethodId(name, args, nargsf, _Py_NULL);
+}
+
+
+/* === Vectorcall protocol (PEP 590) ============================= */
+
+// Call callable using tp_call. Arguments are like PyObject_Vectorcall()
+// or PyObject_FastCallDict() (both forms are supported),
+// except that nargs is plainly the number of arguments without flags.
+//
+// Export for shared stdlib extensions like the math extension,
+// function used via inlined _PyObject_VectorcallTstate() function.
+PyAPI_FUNC(PyObject*) _PyObject_MakeTpCall(
+ PyThreadState *tstate,
+ PyObject *callable,
+ PyObject *const *args, Py_ssize_t nargs,
+ PyObject *keywords);
// Static inline variant of public PyVectorcall_Function().
static inline vectorcallfunc
@@ -110,22 +193,26 @@ _PyObject_CallNoArgs(PyObject *func) {
static inline PyObject *
-_PyObject_FastCallTstate(PyThreadState *tstate, PyObject *func, PyObject *const *args, Py_ssize_t nargs)
+_PyObject_FastCallTstate(PyThreadState *tstate, PyObject *func,
+ PyObject *const *args, Py_ssize_t nargs)
{
EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_API, func);
return _PyObject_VectorcallTstate(tstate, func, args, (size_t)nargs, NULL);
}
-PyObject *const *
+extern PyObject *const *
_PyStack_UnpackDict(PyThreadState *tstate,
PyObject *const *args, Py_ssize_t nargs,
PyObject *kwargs, PyObject **p_kwnames);
-void
-_PyStack_UnpackDict_Free(PyObject *const *stack, Py_ssize_t nargs,
+extern void _PyStack_UnpackDict_Free(
+ PyObject *const *stack,
+ Py_ssize_t nargs,
PyObject *kwnames);
-void _PyStack_UnpackDict_FreeNoDecRef(PyObject *const *stack, PyObject *kwnames);
+extern void _PyStack_UnpackDict_FreeNoDecRef(
+ PyObject *const *stack,
+ PyObject *kwnames);
#ifdef __cplusplus
}
diff --git a/Modules/_bisectmodule.c b/Modules/_bisectmodule.c
index 0773bbd191931..60f4dc69dc05d 100644
--- a/Modules/_bisectmodule.c
+++ b/Modules/_bisectmodule.c
@@ -3,8 +3,13 @@
Converted to C by Dmitry Vasiliev (dima at hlabs.spb.ru).
*/
+#ifndef Py_BUILD_CORE_BUILTIN
+# define Py_BUILD_CORE_MODULE 1
+#endif
+
#define PY_SSIZE_T_CLEAN
#include "Python.h"
+#include "pycore_call.h" // _PyObject_CallMethod()
/*[clinic input]
module _bisect
diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c
index f98e75ce2d1ed..5cd679c68b128 100644
--- a/Modules/_io/iobase.c
+++ b/Modules/_io/iobase.c
@@ -10,8 +10,9 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
+#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_long.h" // _PyLong_GetOne()
-#include "pycore_object.h"
+#include "pycore_object.h" // _PyType_HasFeature()
#include <stddef.h> // offsetof()
#include "_iomodule.h"
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index 0ea7458df559b..e6b1306c2f3f0 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -8,10 +8,11 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
+#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_interp.h" // PyInterpreterState.fs_codec
#include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_fileutils.h" // _Py_GetLocaleEncoding()
-#include "pycore_object.h"
+#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "structmember.h" // PyMemberDef
#include "_iomodule.h"
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 8132689c66c0a..15f7766a8dd28 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -9,6 +9,7 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
+#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_bytesobject.h" // _PyBytes_Repeat
#include "structmember.h" // PyMemberDef
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 89bac99bb9d63..a81490285eed4 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -2,6 +2,7 @@
#include "Python.h"
#include "pycore_abstract.h" // _PyObject_RealIsSubclass()
+#include "pycore_call.h" // _PyStack_AsDict()
#include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pystate.h" // _PyThreadState_GET()
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index 51752dec3dd08..fe081992d51fd 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -2,6 +2,7 @@
/* Method object implementation */
#include "Python.h"
+#include "pycore_call.h" // _Py_CheckFunctionResult()
#include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate()
#include "pycore_object.h"
#include "pycore_pyerrors.h"
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 6117f3a19a550..1df35ef427867 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -2,10 +2,11 @@
#include "Python.h"
+#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_ceval.h" // _PyEval_FiniGIL()
#include "pycore_context.h" // _PyContext_Init()
-#include "pycore_exceptions.h" // _PyExc_InitTypes()
#include "pycore_dict.h" // _PyDict_Fini()
+#include "pycore_exceptions.h" // _PyExc_InitTypes()
#include "pycore_fileutils.h" // _Py_ResetForceASCII()
#include "pycore_floatobject.h" // _PyFloat_InitTypes()
#include "pycore_genobject.h" // _PyAsyncGen_Fini()
More information about the Python-checkins
mailing list