| #ifndef Py_INTERNAL_CALL_H | |
| #define Py_INTERNAL_CALL_H | |
| #ifdef __cplusplus | |
| extern "C" { | |
| #endif | |
| #ifndef Py_BUILD_CORE | |
| # error "this header requires Py_BUILD_CORE define" | |
| #endif | |
| #include "pycore_code.h" // EVAL_CALL_STAT_INC_IF_FUNCTION() | |
| #include "pycore_pystate.h" // _PyThreadState_GET() | |
| #include "pycore_stats.h" | |
| /* Flags that determine the C calling convention. */ | |
| #define _Py_METH_CALL_FLAGS \ | |
| (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | \ | |
| METH_KEYWORDS | METH_METHOD) | |
| /* 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 | |
| PyObject_Vectorcall() family. | |
| The size is chosen to not abuse the C stack and so limit the risk of stack | |
| overflow. The size is also chosen to allow using the small stack for most | |
| function calls of the Python standard library. On 64-bit CPU, it allocates | |
| 40 bytes on the stack. */ | |
| #define _PY_FASTCALL_SMALL_STACK 5 | |
| // Export for 'math' shared extension, used via _PyObject_VectorcallTstate() | |
| // static inline function. | |
| PyAPI_FUNC(PyObject*) _Py_CheckFunctionResult( | |
| PyThreadState *tstate, | |
| PyObject *callable, | |
| PyObject *result, | |
| const char *where); | |
| extern PyObject* _PyObject_Call_Prepend( | |
| PyThreadState *tstate, | |
| PyObject *callable, | |
| PyObject *obj, | |
| PyObject *args, | |
| PyObject *kwargs); | |
| extern PyObject* _PyObject_VectorcallDictTstate( | |
| PyThreadState *tstate, | |
| PyObject *callable, | |
| PyObject *const *args, | |
| size_t nargsf, | |
| PyObject *kwargs); | |
| extern PyObject* _PyObject_Call( | |
| PyThreadState *tstate, | |
| PyObject *callable, | |
| PyObject *args, | |
| PyObject *kwargs); | |
| // Export for 'array' shared extension | |
| PyAPI_FUNC(PyObject*) _PyObject_CallMethod( | |
| PyObject *obj, | |
| PyObject *name, | |
| const char *format, ...); | |
| extern PyObject *_PyObject_VectorcallPrepend( | |
| PyThreadState *tstate, | |
| PyObject *callable, | |
| PyObject *arg, | |
| PyObject *const *args, | |
| size_t nargsf, | |
| PyObject *kwnames); | |
| /* === Vectorcall protocol (PEP 590) ============================= */ | |
| // Call callable using tp_call. Arguments are like PyObject_Vectorcall(), | |
| // except that nargs is plainly the number of arguments without flags. | |
| // | |
| // Export for 'math' shared extension, used via _PyObject_VectorcallTstate() | |
| // static inline 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 | |
| _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) { | |
| EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_API, func); | |
| PyThreadState *tstate = _PyThreadState_GET(); | |
| return _PyObject_VectorcallTstate(tstate, func, NULL, 0, NULL); | |
| } | |
| PyAPI_FUNC(PyObject *const *) | |
| _PyStack_UnpackDict(PyThreadState *tstate, | |
| PyObject *const *args, Py_ssize_t nargs, | |
| PyObject *kwargs, PyObject **p_kwnames); | |
| // Exported for external JIT support | |
| PyAPI_FUNC(void) _PyStack_UnpackDict_Free( | |
| PyObject *const *stack, | |
| Py_ssize_t nargs, | |
| PyObject *kwnames); | |
| PyAPI_FUNC(void) _PyStack_UnpackDict_FreeNoDecRef( | |
| PyObject *const *stack, | |
| PyObject *kwnames); | |
| #ifdef __cplusplus | |
| } | |
| #endif | |
| #endif /* !Py_INTERNAL_CALL_H */ |