Skip to content

gh-106084: Remove _PyObject_CallMethod() function #106159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 1 addition & 73 deletions Include/cpython/abstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);

Expand Down Expand Up @@ -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. */
Expand Down
105 changes: 96 additions & 9 deletions Include/internal/pycore_call.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down
5 changes: 5 additions & 0 deletions Modules/_bisectmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion Modules/_io/iobase.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
3 changes: 2 additions & 1 deletion Modules/_io/textio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions Modules/arraymodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions Objects/descrobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
1 change: 1 addition & 0 deletions Objects/methodobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
3 changes: 2 additions & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down