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()
This commit is contained in:
Victor Stinner 2023-06-28 01:34:37 +02:00 committed by GitHub
parent 6b5166fb12
commit 84caa3324a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 111 additions and 85 deletions

View file

@ -4,20 +4,6 @@
/* === Object Protocol ================================================== */ /* === 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* /* Suggested size (number of positional arguments) for arrays of PyObject*
allocated on a C stack to avoid allocating memory on the heap memory. Such 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 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. */ 40 bytes on the stack. */
#define _PY_FASTCALL_SMALL_STACK 5 #define _PY_FASTCALL_SMALL_STACK 5
PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(
PyThreadState *tstate,
PyObject *callable,
PyObject *result,
const char *where);
/* === Vectorcall protocol (PEP 590) ============================= */ /* === 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. // 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 // Here (when we are not using the stable ABI), the name is overridden to
// call a static inline function for best performance. // call a static inline function for best performance.
#define PyVectorcall_NARGS(n) _PyVectorcall_NARGS(n)
static inline Py_ssize_t static inline Py_ssize_t
_PyVectorcall_NARGS(size_t n) _PyVectorcall_NARGS(size_t n)
{ {
return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET; return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET;
} }
#define PyVectorcall_NARGS(n) _PyVectorcall_NARGS(n)
PyAPI_FUNC(vectorcallfunc) PyVectorcall_Function(PyObject *callable); 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); 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__(). /* 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 If neither of those return a non-negative value, then return the default
value. If one of the calls fails, this function returns -1. */ value. If one of the calls fails, this function returns -1. */

View file

@ -10,29 +10,112 @@ extern "C" {
#include "pycore_pystate.h" // _PyThreadState_GET() #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, PyThreadState *tstate,
PyObject *callable, PyObject *callable,
PyObject *obj, PyObject *obj,
PyObject *args, PyObject *args,
PyObject *kwargs); PyObject *kwargs);
PyAPI_FUNC(PyObject *) _PyObject_FastCallDictTstate( extern PyObject* _PyObject_FastCallDictTstate(
PyThreadState *tstate, PyThreadState *tstate,
PyObject *callable, PyObject *callable,
PyObject *const *args, PyObject *const *args,
size_t nargsf, size_t nargsf,
PyObject *kwargs); PyObject *kwargs);
PyAPI_FUNC(PyObject *) _PyObject_Call( extern PyObject* _PyObject_Call(
PyThreadState *tstate, PyThreadState *tstate,
PyObject *callable, PyObject *callable,
PyObject *args, PyObject *args,
PyObject *kwargs); PyObject *kwargs);
extern PyObject * _PyObject_CallMethodFormat( 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 variant of public PyVectorcall_Function().
static inline vectorcallfunc static inline vectorcallfunc
@ -110,22 +193,26 @@ _PyObject_CallNoArgs(PyObject *func) {
static inline PyObject * 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); EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_API, func);
return _PyObject_VectorcallTstate(tstate, func, args, (size_t)nargs, NULL); return _PyObject_VectorcallTstate(tstate, func, args, (size_t)nargs, NULL);
} }
PyObject *const * extern PyObject *const *
_PyStack_UnpackDict(PyThreadState *tstate, _PyStack_UnpackDict(PyThreadState *tstate,
PyObject *const *args, Py_ssize_t nargs, PyObject *const *args, Py_ssize_t nargs,
PyObject *kwargs, PyObject **p_kwnames); PyObject *kwargs, PyObject **p_kwnames);
void extern void _PyStack_UnpackDict_Free(
_PyStack_UnpackDict_Free(PyObject *const *stack, Py_ssize_t nargs, PyObject *const *stack,
Py_ssize_t nargs,
PyObject *kwnames); PyObject *kwnames);
void _PyStack_UnpackDict_FreeNoDecRef(PyObject *const *stack, PyObject *kwnames); extern void _PyStack_UnpackDict_FreeNoDecRef(
PyObject *const *stack,
PyObject *kwnames);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -3,8 +3,13 @@
Converted to C by Dmitry Vasiliev (dima at hlabs.spb.ru). 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 #define PY_SSIZE_T_CLEAN
#include "Python.h" #include "Python.h"
#include "pycore_call.h" // _PyObject_CallMethod()
/*[clinic input] /*[clinic input]
module _bisect module _bisect

View file

@ -10,8 +10,9 @@
#define PY_SSIZE_T_CLEAN #define PY_SSIZE_T_CLEAN
#include "Python.h" #include "Python.h"
#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_long.h" // _PyLong_GetOne() #include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_object.h" #include "pycore_object.h" // _PyType_HasFeature()
#include <stddef.h> // offsetof() #include <stddef.h> // offsetof()
#include "_iomodule.h" #include "_iomodule.h"

View file

@ -8,10 +8,11 @@
#define PY_SSIZE_T_CLEAN #define PY_SSIZE_T_CLEAN
#include "Python.h" #include "Python.h"
#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_interp.h" // PyInterpreterState.fs_codec #include "pycore_interp.h" // PyInterpreterState.fs_codec
#include "pycore_long.h" // _PyLong_GetZero() #include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_fileutils.h" // _Py_GetLocaleEncoding() #include "pycore_fileutils.h" // _Py_GetLocaleEncoding()
#include "pycore_object.h" #include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "structmember.h" // PyMemberDef #include "structmember.h" // PyMemberDef
#include "_iomodule.h" #include "_iomodule.h"

View file

@ -9,6 +9,7 @@
#define PY_SSIZE_T_CLEAN #define PY_SSIZE_T_CLEAN
#include "Python.h" #include "Python.h"
#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_bytesobject.h" // _PyBytes_Repeat #include "pycore_bytesobject.h" // _PyBytes_Repeat
#include "structmember.h" // PyMemberDef #include "structmember.h" // PyMemberDef

View file

@ -2,6 +2,7 @@
#include "Python.h" #include "Python.h"
#include "pycore_abstract.h" // _PyObject_RealIsSubclass() #include "pycore_abstract.h" // _PyObject_RealIsSubclass()
#include "pycore_call.h" // _PyStack_AsDict()
#include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate()
#include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_pystate.h" // _PyThreadState_GET()

View file

@ -2,6 +2,7 @@
/* Method object implementation */ /* Method object implementation */
#include "Python.h" #include "Python.h"
#include "pycore_call.h" // _Py_CheckFunctionResult()
#include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate()
#include "pycore_object.h" #include "pycore_object.h"
#include "pycore_pyerrors.h" #include "pycore_pyerrors.h"

View file

@ -2,10 +2,11 @@
#include "Python.h" #include "Python.h"
#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_ceval.h" // _PyEval_FiniGIL() #include "pycore_ceval.h" // _PyEval_FiniGIL()
#include "pycore_context.h" // _PyContext_Init() #include "pycore_context.h" // _PyContext_Init()
#include "pycore_exceptions.h" // _PyExc_InitTypes()
#include "pycore_dict.h" // _PyDict_Fini() #include "pycore_dict.h" // _PyDict_Fini()
#include "pycore_exceptions.h" // _PyExc_InitTypes()
#include "pycore_fileutils.h" // _Py_ResetForceASCII() #include "pycore_fileutils.h" // _Py_ResetForceASCII()
#include "pycore_floatobject.h" // _PyFloat_InitTypes() #include "pycore_floatobject.h" // _PyFloat_InitTypes()
#include "pycore_genobject.h" // _PyAsyncGen_Fini() #include "pycore_genobject.h" // _PyAsyncGen_Fini()