mirror of https://github.com/python/cpython
gh-114626: add PyCFunctionFast and PyCFunctionFastWithKeywords (GH-114627)
Co-authored-by: Petr Viktorin <encukou@gmail.com>
This commit is contained in:
parent
32f8ab1ab6
commit
9e3729bbd7
|
@ -187,23 +187,23 @@ Implementing functions and methods
|
||||||
PyObject *kwargs);
|
PyObject *kwargs);
|
||||||
|
|
||||||
|
|
||||||
.. c:type:: _PyCFunctionFast
|
.. c:type:: PyCFunctionFast
|
||||||
|
|
||||||
Type of the functions used to implement Python callables in C
|
Type of the functions used to implement Python callables in C
|
||||||
with signature :c:macro:`METH_FASTCALL`.
|
with signature :c:macro:`METH_FASTCALL`.
|
||||||
The function signature is::
|
The function signature is::
|
||||||
|
|
||||||
PyObject *_PyCFunctionFast(PyObject *self,
|
PyObject *PyCFunctionFast(PyObject *self,
|
||||||
PyObject *const *args,
|
PyObject *const *args,
|
||||||
Py_ssize_t nargs);
|
Py_ssize_t nargs);
|
||||||
|
|
||||||
.. c:type:: _PyCFunctionFastWithKeywords
|
.. c:type:: PyCFunctionFastWithKeywords
|
||||||
|
|
||||||
Type of the functions used to implement Python callables in C
|
Type of the functions used to implement Python callables in C
|
||||||
with signature :ref:`METH_FASTCALL | METH_KEYWORDS <METH_FASTCALL-METH_KEYWORDS>`.
|
with signature :ref:`METH_FASTCALL | METH_KEYWORDS <METH_FASTCALL-METH_KEYWORDS>`.
|
||||||
The function signature is::
|
The function signature is::
|
||||||
|
|
||||||
PyObject *_PyCFunctionFastWithKeywords(PyObject *self,
|
PyObject *PyCFunctionFastWithKeywords(PyObject *self,
|
||||||
PyObject *const *args,
|
PyObject *const *args,
|
||||||
Py_ssize_t nargs,
|
Py_ssize_t nargs,
|
||||||
PyObject *kwnames);
|
PyObject *kwnames);
|
||||||
|
@ -290,7 +290,7 @@ There are these calling conventions:
|
||||||
.. c:macro:: METH_FASTCALL
|
.. c:macro:: METH_FASTCALL
|
||||||
|
|
||||||
Fast calling convention supporting only positional arguments.
|
Fast calling convention supporting only positional arguments.
|
||||||
The methods have the type :c:type:`_PyCFunctionFast`.
|
The methods have the type :c:type:`PyCFunctionFast`.
|
||||||
The first parameter is *self*, the second parameter is a C array
|
The first parameter is *self*, the second parameter is a C array
|
||||||
of :c:expr:`PyObject*` values indicating the arguments and the third
|
of :c:expr:`PyObject*` values indicating the arguments and the third
|
||||||
parameter is the number of arguments (the length of the array).
|
parameter is the number of arguments (the length of the array).
|
||||||
|
@ -306,7 +306,7 @@ There are these calling conventions:
|
||||||
|
|
||||||
:c:expr:`METH_FASTCALL | METH_KEYWORDS`
|
:c:expr:`METH_FASTCALL | METH_KEYWORDS`
|
||||||
Extension of :c:macro:`METH_FASTCALL` supporting also keyword arguments,
|
Extension of :c:macro:`METH_FASTCALL` supporting also keyword arguments,
|
||||||
with methods of type :c:type:`_PyCFunctionFastWithKeywords`.
|
with methods of type :c:type:`PyCFunctionFastWithKeywords`.
|
||||||
Keyword arguments are passed the same way as in the
|
Keyword arguments are passed the same way as in the
|
||||||
:ref:`vectorcall protocol <vectorcall>`:
|
:ref:`vectorcall protocol <vectorcall>`:
|
||||||
there is an additional fourth :c:expr:`PyObject*` parameter
|
there is an additional fourth :c:expr:`PyObject*` parameter
|
||||||
|
|
|
@ -42,6 +42,8 @@ function,PyBytes_Repr,3.2,,
|
||||||
function,PyBytes_Size,3.2,,
|
function,PyBytes_Size,3.2,,
|
||||||
var,PyBytes_Type,3.2,,
|
var,PyBytes_Type,3.2,,
|
||||||
type,PyCFunction,3.2,,
|
type,PyCFunction,3.2,,
|
||||||
|
type,PyCFunctionFast,3.13,,
|
||||||
|
type,PyCFunctionFastWithKeywords,3.13,,
|
||||||
type,PyCFunctionWithKeywords,3.2,,
|
type,PyCFunctionWithKeywords,3.2,,
|
||||||
function,PyCFunction_GetFlags,3.2,,
|
function,PyCFunction_GetFlags,3.2,,
|
||||||
function,PyCFunction_GetFunction,3.2,,
|
function,PyCFunction_GetFunction,3.2,,
|
||||||
|
|
|
@ -17,15 +17,22 @@ PyAPI_DATA(PyTypeObject) PyCFunction_Type;
|
||||||
#define PyCFunction_Check(op) PyObject_TypeCheck((op), &PyCFunction_Type)
|
#define PyCFunction_Check(op) PyObject_TypeCheck((op), &PyCFunction_Type)
|
||||||
|
|
||||||
typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
|
typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
|
||||||
typedef PyObject *(*_PyCFunctionFast) (PyObject *, PyObject *const *, Py_ssize_t);
|
typedef PyObject *(*PyCFunctionFast) (PyObject *, PyObject *const *, Py_ssize_t);
|
||||||
typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *,
|
typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *,
|
||||||
PyObject *);
|
PyObject *);
|
||||||
typedef PyObject *(*_PyCFunctionFastWithKeywords) (PyObject *,
|
typedef PyObject *(*PyCFunctionFastWithKeywords) (PyObject *,
|
||||||
PyObject *const *, Py_ssize_t,
|
PyObject *const *, Py_ssize_t,
|
||||||
PyObject *);
|
PyObject *);
|
||||||
typedef PyObject *(*PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *,
|
typedef PyObject *(*PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *,
|
||||||
size_t, PyObject *);
|
size_t, PyObject *);
|
||||||
|
|
||||||
|
// For backwards compatibility. `METH_FASTCALL` was added to the stable API in
|
||||||
|
// 3.10 alongside `_PyCFunctionFastWithKeywords` and `_PyCFunctionFast`.
|
||||||
|
// Note that the underscore-prefixed names were documented in public docs;
|
||||||
|
// people may be using them.
|
||||||
|
typedef PyCFunctionFast _PyCFunctionFast;
|
||||||
|
typedef PyCFunctionWithKeywords _PyCFunctionWithKeywords;
|
||||||
|
|
||||||
// Cast an function to the PyCFunction type to use it with PyMethodDef.
|
// Cast an function to the PyCFunction type to use it with PyMethodDef.
|
||||||
//
|
//
|
||||||
// This macro can be used to prevent compiler warnings if the first parameter
|
// This macro can be used to prevent compiler warnings if the first parameter
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add ``PyCFunctionFast`` and ``PyCFunctionFastWithKeywords`` typedefs (identical to the existing ``_PyCFunctionFast`` and ``_PyCFunctionFastWithKeywords`` typedefs, just without a leading ``_`` prefix).
|
|
@ -2489,3 +2489,10 @@
|
||||||
added = '3.13'
|
added = '3.13'
|
||||||
[function.PyList_GetItemRef]
|
[function.PyList_GetItemRef]
|
||||||
added = '3.13'
|
added = '3.13'
|
||||||
|
[typedef.PyCFunctionFast]
|
||||||
|
added = '3.13'
|
||||||
|
# "abi-only" since 3.10. (Callback type names aren't used in C code,
|
||||||
|
# but this function signature was expected with METH_FASTCALL.)
|
||||||
|
[typedef.PyCFunctionFastWithKeywords]
|
||||||
|
added = '3.13'
|
||||||
|
# "abi-only" since 3.10. (Same story as PyCFunctionFast.)
|
||||||
|
|
|
@ -393,7 +393,7 @@ method_vectorcall_FASTCALL(
|
||||||
if (method_check_args(func, args, nargs, kwnames)) {
|
if (method_check_args(func, args, nargs, kwnames)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
_PyCFunctionFast meth = (_PyCFunctionFast)
|
PyCFunctionFast meth = (PyCFunctionFast)
|
||||||
method_enter_call(tstate, func);
|
method_enter_call(tstate, func);
|
||||||
if (meth == NULL) {
|
if (meth == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -412,7 +412,7 @@ method_vectorcall_FASTCALL_KEYWORDS(
|
||||||
if (method_check_args(func, args, nargs, NULL)) {
|
if (method_check_args(func, args, nargs, NULL)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
_PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)
|
PyCFunctionFastWithKeywords meth = (PyCFunctionFastWithKeywords)
|
||||||
method_enter_call(tstate, func);
|
method_enter_call(tstate, func);
|
||||||
if (meth == NULL) {
|
if (meth == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -417,7 +417,7 @@ cfunction_vectorcall_FASTCALL(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
|
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
|
||||||
_PyCFunctionFast meth = (_PyCFunctionFast)
|
PyCFunctionFast meth = (PyCFunctionFast)
|
||||||
cfunction_enter_call(tstate, func);
|
cfunction_enter_call(tstate, func);
|
||||||
if (meth == NULL) {
|
if (meth == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -433,7 +433,7 @@ cfunction_vectorcall_FASTCALL_KEYWORDS(
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
|
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
|
||||||
_PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)
|
PyCFunctionFastWithKeywords meth = (PyCFunctionFastWithKeywords)
|
||||||
cfunction_enter_call(tstate, func);
|
cfunction_enter_call(tstate, func);
|
||||||
if (meth == NULL) {
|
if (meth == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -552,4 +552,3 @@ cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
|
||||||
}
|
}
|
||||||
return _Py_CheckFunctionResult(tstate, func, result, NULL);
|
return _Py_CheckFunctionResult(tstate, func, result, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3376,7 +3376,7 @@ dummy_func(
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
|
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
|
||||||
/* res = func(self, args, nargs) */
|
/* res = func(self, args, nargs) */
|
||||||
res = ((_PyCFunctionFast)(void(*)(void))cfunc)(
|
res = ((PyCFunctionFast)(void(*)(void))cfunc)(
|
||||||
PyCFunction_GET_SELF(callable),
|
PyCFunction_GET_SELF(callable),
|
||||||
args,
|
args,
|
||||||
total_args);
|
total_args);
|
||||||
|
@ -3407,8 +3407,8 @@ dummy_func(
|
||||||
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != (METH_FASTCALL | METH_KEYWORDS));
|
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != (METH_FASTCALL | METH_KEYWORDS));
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
/* res = func(self, args, nargs, kwnames) */
|
/* res = func(self, args, nargs, kwnames) */
|
||||||
_PyCFunctionFastWithKeywords cfunc =
|
PyCFunctionFastWithKeywords cfunc =
|
||||||
(_PyCFunctionFastWithKeywords)(void(*)(void))
|
(PyCFunctionFastWithKeywords)(void(*)(void))
|
||||||
PyCFunction_GET_FUNCTION(callable);
|
PyCFunction_GET_FUNCTION(callable);
|
||||||
res = cfunc(PyCFunction_GET_SELF(callable), args, total_args, NULL);
|
res = cfunc(PyCFunction_GET_SELF(callable), args, total_args, NULL);
|
||||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
|
@ -3539,8 +3539,8 @@ dummy_func(
|
||||||
DEOPT_IF(!Py_IS_TYPE(self, d_type));
|
DEOPT_IF(!Py_IS_TYPE(self, d_type));
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
int nargs = total_args - 1;
|
int nargs = total_args - 1;
|
||||||
_PyCFunctionFastWithKeywords cfunc =
|
PyCFunctionFastWithKeywords cfunc =
|
||||||
(_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
|
(PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
|
||||||
res = cfunc(self, args + 1, nargs, NULL);
|
res = cfunc(self, args + 1, nargs, NULL);
|
||||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
|
|
||||||
|
@ -3597,8 +3597,8 @@ dummy_func(
|
||||||
PyObject *self = args[0];
|
PyObject *self = args[0];
|
||||||
DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type));
|
DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type));
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
_PyCFunctionFast cfunc =
|
PyCFunctionFast cfunc =
|
||||||
(_PyCFunctionFast)(void(*)(void))meth->ml_meth;
|
(PyCFunctionFast)(void(*)(void))meth->ml_meth;
|
||||||
int nargs = total_args - 1;
|
int nargs = total_args - 1;
|
||||||
res = cfunc(self, args + 1, nargs);
|
res = cfunc(self, args + 1, nargs);
|
||||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
|
|
|
@ -2843,7 +2843,7 @@
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
|
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
|
||||||
/* res = func(self, args, nargs) */
|
/* res = func(self, args, nargs) */
|
||||||
res = ((_PyCFunctionFast)(void(*)(void))cfunc)(
|
res = ((PyCFunctionFast)(void(*)(void))cfunc)(
|
||||||
PyCFunction_GET_SELF(callable),
|
PyCFunction_GET_SELF(callable),
|
||||||
args,
|
args,
|
||||||
total_args);
|
total_args);
|
||||||
|
@ -2884,8 +2884,8 @@
|
||||||
if (PyCFunction_GET_FLAGS(callable) != (METH_FASTCALL | METH_KEYWORDS)) goto deoptimize;
|
if (PyCFunction_GET_FLAGS(callable) != (METH_FASTCALL | METH_KEYWORDS)) goto deoptimize;
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
/* res = func(self, args, nargs, kwnames) */
|
/* res = func(self, args, nargs, kwnames) */
|
||||||
_PyCFunctionFastWithKeywords cfunc =
|
PyCFunctionFastWithKeywords cfunc =
|
||||||
(_PyCFunctionFastWithKeywords)(void(*)(void))
|
(PyCFunctionFastWithKeywords)(void(*)(void))
|
||||||
PyCFunction_GET_FUNCTION(callable);
|
PyCFunction_GET_FUNCTION(callable);
|
||||||
res = cfunc(PyCFunction_GET_SELF(callable), args, total_args, NULL);
|
res = cfunc(PyCFunction_GET_SELF(callable), args, total_args, NULL);
|
||||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
|
@ -3036,8 +3036,8 @@
|
||||||
if (!Py_IS_TYPE(self, d_type)) goto deoptimize;
|
if (!Py_IS_TYPE(self, d_type)) goto deoptimize;
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
int nargs = total_args - 1;
|
int nargs = total_args - 1;
|
||||||
_PyCFunctionFastWithKeywords cfunc =
|
PyCFunctionFastWithKeywords cfunc =
|
||||||
(_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
|
(PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
|
||||||
res = cfunc(self, args + 1, nargs, NULL);
|
res = cfunc(self, args + 1, nargs, NULL);
|
||||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
/* Free the arguments. */
|
/* Free the arguments. */
|
||||||
|
@ -3115,8 +3115,8 @@
|
||||||
PyObject *self = args[0];
|
PyObject *self = args[0];
|
||||||
if (!Py_IS_TYPE(self, method->d_common.d_type)) goto deoptimize;
|
if (!Py_IS_TYPE(self, method->d_common.d_type)) goto deoptimize;
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
_PyCFunctionFast cfunc =
|
PyCFunctionFast cfunc =
|
||||||
(_PyCFunctionFast)(void(*)(void))meth->ml_meth;
|
(PyCFunctionFast)(void(*)(void))meth->ml_meth;
|
||||||
int nargs = total_args - 1;
|
int nargs = total_args - 1;
|
||||||
res = cfunc(self, args + 1, nargs);
|
res = cfunc(self, args + 1, nargs);
|
||||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
|
|
|
@ -1069,7 +1069,7 @@
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
|
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
|
||||||
/* res = func(self, args, nargs) */
|
/* res = func(self, args, nargs) */
|
||||||
res = ((_PyCFunctionFast)(void(*)(void))cfunc)(
|
res = ((PyCFunctionFast)(void(*)(void))cfunc)(
|
||||||
PyCFunction_GET_SELF(callable),
|
PyCFunction_GET_SELF(callable),
|
||||||
args,
|
args,
|
||||||
total_args);
|
total_args);
|
||||||
|
@ -1115,8 +1115,8 @@
|
||||||
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != (METH_FASTCALL | METH_KEYWORDS), CALL);
|
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != (METH_FASTCALL | METH_KEYWORDS), CALL);
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
/* res = func(self, args, nargs, kwnames) */
|
/* res = func(self, args, nargs, kwnames) */
|
||||||
_PyCFunctionFastWithKeywords cfunc =
|
PyCFunctionFastWithKeywords cfunc =
|
||||||
(_PyCFunctionFastWithKeywords)(void(*)(void))
|
(PyCFunctionFastWithKeywords)(void(*)(void))
|
||||||
PyCFunction_GET_FUNCTION(callable);
|
PyCFunction_GET_FUNCTION(callable);
|
||||||
res = cfunc(PyCFunction_GET_SELF(callable), args, total_args, NULL);
|
res = cfunc(PyCFunction_GET_SELF(callable), args, total_args, NULL);
|
||||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
|
@ -1523,8 +1523,8 @@
|
||||||
PyObject *self = args[0];
|
PyObject *self = args[0];
|
||||||
DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL);
|
DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL);
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
_PyCFunctionFast cfunc =
|
PyCFunctionFast cfunc =
|
||||||
(_PyCFunctionFast)(void(*)(void))meth->ml_meth;
|
(PyCFunctionFast)(void(*)(void))meth->ml_meth;
|
||||||
int nargs = total_args - 1;
|
int nargs = total_args - 1;
|
||||||
res = cfunc(self, args + 1, nargs);
|
res = cfunc(self, args + 1, nargs);
|
||||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
|
@ -1568,8 +1568,8 @@
|
||||||
DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL);
|
DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL);
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
int nargs = total_args - 1;
|
int nargs = total_args - 1;
|
||||||
_PyCFunctionFastWithKeywords cfunc =
|
PyCFunctionFastWithKeywords cfunc =
|
||||||
(_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
|
(PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
|
||||||
res = cfunc(self, args + 1, nargs, NULL);
|
res = cfunc(self, args + 1, nargs, NULL);
|
||||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
/* Free the arguments. */
|
/* Free the arguments. */
|
||||||
|
|
Loading…
Reference in New Issue