mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	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().
This commit is contained in:
		
							parent
							
								
									39aa98346d
								
							
						
					
					
						commit
						3cc56c828d
					
				
					 6 changed files with 127 additions and 100 deletions
				
			
		|  | @ -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; | ||||
| PyAPI_FUNC(vectorcallfunc) PyVectorcall_Function(PyObject *callable); | ||||
| 
 | ||||
|     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. | ||||
| 
 | ||||
|    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
 | ||||
| PyAPI_FUNC(PyObject *) _PyObject_FastCall( | ||||
|     PyObject *func, | ||||
|     PyObject *const *args, | ||||
|     Py_ssize_t nargs); | ||||
| 
 | ||||
| /* 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; | ||||
| 
 | ||||
|     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, | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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; | ||||
|     } | ||||
|  |  | |||
|  | @ -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 * | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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" | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Victor Stinner
						Victor Stinner