diff options
Diffstat (limited to 'Objects/call.c')
-rw-r--r-- | Objects/call.c | 1026 |
1 files changed, 0 insertions, 1026 deletions
diff --git a/Objects/call.c b/Objects/call.c deleted file mode 100644 index 0f8cb5a..0000000 --- a/Objects/call.c +++ /dev/null @@ -1,1026 +0,0 @@ -#include "Python.h" -#include "pycore_call.h" -#include "pycore_ceval.h" /* _PyEval_EvalFrame() */ -#include "pycore_object.h" -#include "pycore_pyerrors.h" -#include "pycore_pystate.h" -#include "pycore_tupleobject.h" -#include "frameobject.h" - - -static PyObject *const * -_PyStack_UnpackDict(PyThreadState *tstate, - PyObject *const *args, Py_ssize_t nargs, - PyObject *kwargs, PyObject **p_kwnames); - -static void -_PyStack_UnpackDict_Free(PyObject *const *stack, Py_ssize_t nargs, - PyObject *kwnames); - - -static PyObject * -null_error(PyThreadState *tstate) -{ - if (!_PyErr_Occurred(tstate)) { - _PyErr_SetString(tstate, PyExc_SystemError, - "null argument to internal routine"); - } - return NULL; -} - - -PyObject* -_Py_CheckFunctionResult(PyThreadState *tstate, PyObject *callable, - PyObject *result, const char *where) -{ - assert((callable != NULL) ^ (where != NULL)); - - if (result == NULL) { - if (!_PyErr_Occurred(tstate)) { - if (callable) - _PyErr_Format(tstate, PyExc_SystemError, - "%R returned NULL without setting an error", - callable); - else - _PyErr_Format(tstate, PyExc_SystemError, - "%s returned NULL without setting an error", - where); -#ifdef Py_DEBUG - /* Ensure that the bug is caught in debug mode */ - Py_FatalError("a function returned NULL without setting an error"); -#endif - return NULL; - } - } - else { - if (_PyErr_Occurred(tstate)) { - Py_DECREF(result); - - if (callable) { - _PyErr_FormatFromCauseTstate( - tstate, PyExc_SystemError, - "%R returned a result with an error set", callable); - } - else { - _PyErr_FormatFromCauseTstate( - tstate, PyExc_SystemError, - "%s returned a result with an error set", where); - } -#ifdef Py_DEBUG - /* Ensure that the bug is caught in debug mode */ - Py_FatalError("a function returned a result with an error set"); -#endif - return NULL; - } - } - return result; -} - - -/* --- Core PyObject call functions ------------------------------- */ - -/* Call a callable Python object without any arguments */ -PyObject * -PyObject_CallNoArgs(PyObject *func) -{ - PyThreadState *tstate = _PyThreadState_GET(); - return _PyObject_CallNoArgTstate(tstate, func); -} - - -PyObject * -_PyObject_FastCallDictTstate(PyThreadState *tstate, PyObject *callable, - PyObject *const *args, size_t nargsf, - PyObject *kwargs) -{ - assert(callable != NULL); - - /* _PyObject_FastCallDict() must not be called with an exception set, - because it can clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!_PyErr_Occurred(tstate)); - - Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); - assert(nargs >= 0); - assert(nargs == 0 || args != NULL); - assert(kwargs == NULL || PyDict_Check(kwargs)); - - vectorcallfunc func = _PyVectorcall_Function(callable); - if (func == NULL) { - /* Use tp_call instead */ - return _PyObject_MakeTpCall(tstate, callable, args, nargs, kwargs); - } - - PyObject *res; - if (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) { - res = func(callable, args, nargsf, NULL); - } - else { - PyObject *kwnames; - PyObject *const *newargs; - newargs = _PyStack_UnpackDict(tstate, - args, nargs, - kwargs, &kwnames); - if (newargs == NULL) { - return NULL; - } - res = func(callable, newargs, - nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames); - _PyStack_UnpackDict_Free(newargs, nargs, kwnames); - } - return _Py_CheckFunctionResult(tstate, callable, res, NULL); -} - - -PyObject * -_PyObject_FastCallDict(PyObject *callable, PyObject *const *args, - size_t nargsf, PyObject *kwargs) -{ - PyThreadState *tstate = _PyThreadState_GET(); - return _PyObject_FastCallDictTstate(tstate, callable, args, nargsf, kwargs); -} - - -PyObject * -_PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable, - PyObject *const *args, Py_ssize_t nargs, - PyObject *keywords) -{ - assert(nargs >= 0); - assert(nargs == 0 || args != NULL); - assert(keywords == NULL || PyTuple_Check(keywords) || PyDict_Check(keywords)); - - /* Slow path: build a temporary tuple for positional arguments and a - * temporary dictionary for keyword arguments (if any) */ - ternaryfunc call = Py_TYPE(callable)->tp_call; - if (call == NULL) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object is not callable", - Py_TYPE(callable)->tp_name); - return NULL; - } - - PyObject *argstuple = _PyTuple_FromArray(args, nargs); - if (argstuple == NULL) { - return NULL; - } - - PyObject *kwdict; - if (keywords == NULL || PyDict_Check(keywords)) { - kwdict = keywords; - } - else { - if (PyTuple_GET_SIZE(keywords)) { - assert(args != NULL); - kwdict = _PyStack_AsDict(args + nargs, keywords); - if (kwdict == NULL) { - Py_DECREF(argstuple); - return NULL; - } - } - else { - keywords = kwdict = NULL; - } - } - - PyObject *result = NULL; - if (_Py_EnterRecursiveCall(tstate, " while calling a Python object") == 0) - { - result = call(callable, argstuple, kwdict); - _Py_LeaveRecursiveCall(tstate); - } - - Py_DECREF(argstuple); - if (kwdict != keywords) { - Py_DECREF(kwdict); - } - - return _Py_CheckFunctionResult(tstate, callable, result, NULL); -} - - -PyObject * -PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs) -{ - PyThreadState *tstate = _PyThreadState_GET(); - - /* 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) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object does not support vectorcall", - Py_TYPE(callable)->tp_name); - return NULL; - } - vectorcallfunc func = *(vectorcallfunc *)(((char *)callable) + offset); - if (func == NULL) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object does not support vectorcall", - Py_TYPE(callable)->tp_name); - return NULL; - } - - Py_ssize_t nargs = PyTuple_GET_SIZE(tuple); - - /* Fast path for no keywords */ - if (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) { - return func(callable, _PyTuple_ITEMS(tuple), nargs, NULL); - } - - /* Convert arguments & call */ - PyObject *const *args; - PyObject *kwnames; - args = _PyStack_UnpackDict(tstate, - _PyTuple_ITEMS(tuple), nargs, - kwargs, &kwnames); - if (args == NULL) { - return NULL; - } - PyObject *result = func(callable, args, - nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames); - _PyStack_UnpackDict_Free(args, nargs, kwnames); - - return _Py_CheckFunctionResult(tstate, callable, result, NULL); -} - - -PyObject * -_PyObject_Call(PyThreadState *tstate, PyObject *callable, - PyObject *args, PyObject *kwargs) -{ - ternaryfunc call; - PyObject *result; - - /* PyObject_Call() must not be called with an exception set, - because it can clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!_PyErr_Occurred(tstate)); - assert(PyTuple_Check(args)); - assert(kwargs == NULL || PyDict_Check(kwargs)); - - if (_PyVectorcall_Function(callable) != NULL) { - return PyVectorcall_Call(callable, args, kwargs); - } - else { - call = callable->ob_type->tp_call; - if (call == NULL) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object is not callable", - callable->ob_type->tp_name); - return NULL; - } - - if (_Py_EnterRecursiveCall(tstate, " while calling a Python object")) { - return NULL; - } - - result = (*call)(callable, args, kwargs); - - _Py_LeaveRecursiveCall(tstate); - - return _Py_CheckFunctionResult(tstate, callable, result, NULL); - } -} - -PyObject * -PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) -{ - PyThreadState *tstate = _PyThreadState_GET(); - return _PyObject_Call(tstate, callable, args, kwargs); -} - - -PyObject * -PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs) -{ - PyThreadState *tstate = _PyThreadState_GET(); - return _PyObject_Call(tstate, callable, args, kwargs); -} - - -/* --- PyFunction call functions ---------------------------------- */ - -static PyObject* _Py_HOT_FUNCTION -function_code_fastcall(PyThreadState *tstate, PyCodeObject *co, - PyObject *const *args, Py_ssize_t nargs, - PyObject *globals) -{ - assert(tstate != NULL); - assert(globals != NULL); - - /* XXX Perhaps we should create a specialized - _PyFrame_New_NoTrack() that doesn't take locals, but does - take builtins without sanity checking them. - */ - PyFrameObject *f = _PyFrame_New_NoTrack(tstate, co, globals, NULL); - if (f == NULL) { - return NULL; - } - - PyObject **fastlocals = f->f_localsplus; - - for (Py_ssize_t i = 0; i < nargs; i++) { - Py_INCREF(*args); - fastlocals[i] = *args++; - } - PyObject *result = _PyEval_EvalFrame(tstate, f, 0); - - if (Py_REFCNT(f) > 1) { - Py_DECREF(f); - _PyObject_GC_TRACK(f); - } - else { - ++tstate->recursion_depth; - Py_DECREF(f); - --tstate->recursion_depth; - } - return result; -} - - -PyObject * -_PyFunction_Vectorcall(PyObject *func, PyObject* const* stack, - size_t nargsf, PyObject *kwnames) -{ - assert(PyFunction_Check(func)); - assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - - Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); - assert(nargs >= 0); - Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); - /* kwnames must only contain strings and all keys must be unique */ - - PyThreadState *tstate = _PyThreadState_GET(); - PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); - PyObject *globals = PyFunction_GET_GLOBALS(func); - PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - - if (co->co_kwonlyargcount == 0 && nkwargs == 0 && - (co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) - { - if (argdefs == NULL && co->co_argcount == nargs) { - return function_code_fastcall(tstate, co, stack, nargs, globals); - } - else if (nargs == 0 && argdefs != NULL - && co->co_argcount == PyTuple_GET_SIZE(argdefs)) { - /* function called with no arguments, but all parameters have - a default value: use default values as arguments .*/ - stack = _PyTuple_ITEMS(argdefs); - return function_code_fastcall(tstate, co, - stack, PyTuple_GET_SIZE(argdefs), - globals); - } - } - - PyObject *kwdefs = PyFunction_GET_KW_DEFAULTS(func); - PyObject *closure = PyFunction_GET_CLOSURE(func); - PyObject *name = ((PyFunctionObject *)func) -> func_name; - PyObject *qualname = ((PyFunctionObject *)func) -> func_qualname; - - PyObject **d; - Py_ssize_t nd; - if (argdefs != NULL) { - d = _PyTuple_ITEMS(argdefs); - nd = PyTuple_GET_SIZE(argdefs); - assert(nd <= INT_MAX); - } - else { - d = NULL; - nd = 0; - } - return _PyEval_EvalCode(tstate, - (PyObject*)co, globals, (PyObject *)NULL, - stack, nargs, - nkwargs ? _PyTuple_ITEMS(kwnames) : NULL, - stack + nargs, - nkwargs, 1, - d, (int)nd, kwdefs, - closure, name, qualname); -} - - -/* --- More complex call functions -------------------------------- */ - -/* External interface to call any callable object. - The args must be a tuple or NULL. The kwargs must be a dict or NULL. */ -PyObject * -PyEval_CallObjectWithKeywords(PyObject *callable, - PyObject *args, PyObject *kwargs) -{ - PyThreadState *tstate = _PyThreadState_GET(); -#ifdef Py_DEBUG - /* PyEval_CallObjectWithKeywords() must not be called with an exception - set. It raises a new exception if parameters are invalid or if - PyTuple_New() fails, and so the original exception is lost. */ - assert(!_PyErr_Occurred(tstate)); -#endif - - if (args != NULL && !PyTuple_Check(args)) { - _PyErr_SetString(tstate, PyExc_TypeError, - "argument list must be a tuple"); - return NULL; - } - - if (kwargs != NULL && !PyDict_Check(kwargs)) { - _PyErr_SetString(tstate, PyExc_TypeError, - "keyword list must be a dictionary"); - return NULL; - } - - if (args == NULL) { - return _PyObject_FastCallDictTstate(tstate, callable, NULL, 0, kwargs); - } - else { - return _PyObject_Call(tstate, callable, args, kwargs); - } -} - - -PyObject * -PyObject_CallObject(PyObject *callable, PyObject *args) -{ - PyThreadState *tstate = _PyThreadState_GET(); - assert(!_PyErr_Occurred(tstate)); - if (args == NULL) { - return _PyObject_CallNoArgTstate(tstate, callable); - } - if (!PyTuple_Check(args)) { - _PyErr_SetString(tstate, PyExc_TypeError, - "argument list must be a tuple"); - return NULL; - } - return _PyObject_Call(tstate, callable, args, NULL); -} - - -/* Call callable(obj, *args, **kwargs). */ -PyObject * -_PyObject_Call_Prepend(PyThreadState *tstate, PyObject *callable, - PyObject *obj, PyObject *args, PyObject *kwargs) -{ - assert(PyTuple_Check(args)); - - PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; - PyObject **stack; - - Py_ssize_t argcount = PyTuple_GET_SIZE(args); - if (argcount + 1 <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { - stack = small_stack; - } - else { - stack = PyMem_Malloc((argcount + 1) * sizeof(PyObject *)); - if (stack == NULL) { - PyErr_NoMemory(); - return NULL; - } - } - - /* use borrowed references */ - stack[0] = obj; - memcpy(&stack[1], - _PyTuple_ITEMS(args), - argcount * sizeof(PyObject *)); - - PyObject *result = _PyObject_FastCallDictTstate(tstate, callable, - stack, argcount + 1, - kwargs); - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; -} - - -/* --- Call with a format string ---------------------------------- */ - -static PyObject * -_PyObject_CallFunctionVa(PyThreadState *tstate, PyObject *callable, - const char *format, va_list va, int is_size_t) -{ - PyObject* small_stack[_PY_FASTCALL_SMALL_STACK]; - const Py_ssize_t small_stack_len = Py_ARRAY_LENGTH(small_stack); - PyObject **stack; - Py_ssize_t nargs, i; - PyObject *result; - - if (callable == NULL) { - return null_error(tstate); - } - - if (!format || !*format) { - return _PyObject_CallNoArgTstate(tstate, callable); - } - - if (is_size_t) { - stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, - format, va, &nargs); - } - else { - stack = _Py_VaBuildStack(small_stack, small_stack_len, - format, va, &nargs); - } - if (stack == NULL) { - return NULL; - } - - if (nargs == 1 && PyTuple_Check(stack[0])) { - /* Special cases for backward compatibility: - - PyObject_CallFunction(func, "O", tuple) calls func(*tuple) - - PyObject_CallFunction(func, "(OOO)", arg1, arg2, arg3) calls - func(*(arg1, arg2, arg3)): func(arg1, arg2, arg3) */ - PyObject *args = stack[0]; - result = _PyObject_VectorcallTstate(tstate, callable, - _PyTuple_ITEMS(args), - PyTuple_GET_SIZE(args), - NULL); - } - else { - result = _PyObject_VectorcallTstate(tstate, callable, - stack, nargs, NULL); - } - - for (i = 0; i < nargs; ++i) { - Py_DECREF(stack[i]); - } - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; -} - - -PyObject * -PyObject_CallFunction(PyObject *callable, const char *format, ...) -{ - va_list va; - PyObject *result; - PyThreadState *tstate = _PyThreadState_GET(); - - va_start(va, format); - result = _PyObject_CallFunctionVa(tstate, callable, format, va, 0); - va_end(va); - - return result; -} - - -/* PyEval_CallFunction is exact copy of PyObject_CallFunction. - * This function is kept for backward compatibility. - */ -PyObject * -PyEval_CallFunction(PyObject *callable, const char *format, ...) -{ - va_list va; - PyObject *result; - PyThreadState *tstate = _PyThreadState_GET(); - - va_start(va, format); - result = _PyObject_CallFunctionVa(tstate, callable, format, va, 0); - va_end(va); - - return result; -} - - -PyObject * -_PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) -{ - PyThreadState *tstate = _PyThreadState_GET(); - - va_list va; - va_start(va, format); - PyObject *result = _PyObject_CallFunctionVa(tstate, callable, format, va, 1); - va_end(va); - - return result; -} - - -static PyObject* -callmethod(PyThreadState *tstate, PyObject* callable, const char *format, va_list va, int is_size_t) -{ - assert(callable != NULL); - if (!PyCallable_Check(callable)) { - _PyErr_Format(tstate, PyExc_TypeError, - "attribute of type '%.200s' is not callable", - Py_TYPE(callable)->tp_name); - return NULL; - } - - return _PyObject_CallFunctionVa(tstate, callable, format, va, is_size_t); -} - - -PyObject * -PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) -{ - PyThreadState *tstate = _PyThreadState_GET(); - - if (obj == NULL || name == NULL) { - return null_error(tstate); - } - - PyObject *callable = PyObject_GetAttrString(obj, name); - if (callable == NULL) { - return NULL; - } - - va_list va; - va_start(va, format); - PyObject *retval = callmethod(tstate, callable, format, va, 0); - va_end(va); - - Py_DECREF(callable); - return retval; -} - - -/* PyEval_CallMethod is exact copy of PyObject_CallMethod. - * This function is kept for backward compatibility. - */ -PyObject * -PyEval_CallMethod(PyObject *obj, const char *name, const char *format, ...) -{ - PyThreadState *tstate = _PyThreadState_GET(); - if (obj == NULL || name == NULL) { - return null_error(tstate); - } - - PyObject *callable = PyObject_GetAttrString(obj, name); - if (callable == NULL) { - return NULL; - } - - va_list va; - va_start(va, format); - PyObject *retval = callmethod(tstate, callable, format, va, 0); - va_end(va); - - Py_DECREF(callable); - return retval; -} - - -PyObject * -_PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, - const char *format, ...) -{ - PyThreadState *tstate = _PyThreadState_GET(); - if (obj == NULL || name == NULL) { - return null_error(tstate); - } - - PyObject *callable = _PyObject_GetAttrId(obj, name); - if (callable == NULL) { - return NULL; - } - - va_list va; - va_start(va, format); - PyObject *retval = callmethod(tstate, callable, format, va, 0); - va_end(va); - - Py_DECREF(callable); - return retval; -} - - -PyObject * -_PyObject_CallMethod_SizeT(PyObject *obj, const char *name, - const char *format, ...) -{ - PyThreadState *tstate = _PyThreadState_GET(); - if (obj == NULL || name == NULL) { - return null_error(tstate); - } - - PyObject *callable = PyObject_GetAttrString(obj, name); - if (callable == NULL) { - return NULL; - } - - va_list va; - va_start(va, format); - PyObject *retval = callmethod(tstate, callable, format, va, 1); - va_end(va); - - Py_DECREF(callable); - return retval; -} - - -PyObject * -_PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, - const char *format, ...) -{ - PyThreadState *tstate = _PyThreadState_GET(); - if (obj == NULL || name == NULL) { - return null_error(tstate); - } - - PyObject *callable = _PyObject_GetAttrId(obj, name); - if (callable == NULL) { - return NULL; - } - - va_list va; - va_start(va, format); - PyObject *retval = callmethod(tstate, callable, format, va, 1); - va_end(va); - - Py_DECREF(callable); - return retval; -} - - -/* --- Call with "..." arguments ---------------------------------- */ - -static PyObject * -object_vacall(PyThreadState *tstate, PyObject *base, - PyObject *callable, va_list vargs) -{ - PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; - PyObject **stack; - Py_ssize_t nargs; - PyObject *result; - Py_ssize_t i; - va_list countva; - - if (callable == NULL) { - return null_error(tstate); - } - - /* Count the number of arguments */ - va_copy(countva, vargs); - nargs = base ? 1 : 0; - while (1) { - PyObject *arg = va_arg(countva, PyObject *); - if (arg == NULL) { - break; - } - nargs++; - } - va_end(countva); - - /* Copy arguments */ - if (nargs <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { - stack = small_stack; - } - else { - stack = PyMem_Malloc(nargs * sizeof(stack[0])); - if (stack == NULL) { - PyErr_NoMemory(); - return NULL; - } - } - - i = 0; - if (base) { - stack[i++] = base; - } - - for (; i < nargs; ++i) { - stack[i] = va_arg(vargs, PyObject *); - } - - /* Call the function */ - result = _PyObject_VectorcallTstate(tstate, callable, stack, nargs, NULL); - - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; -} - - -PyObject * -_PyObject_VectorcallMethod(PyObject *name, PyObject *const *args, - size_t nargsf, PyObject *kwnames) -{ - assert(name != NULL); - assert(args != NULL); - assert(PyVectorcall_NARGS(nargsf) >= 1); - - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *callable = NULL; - /* Use args[0] as "self" argument */ - int unbound = _PyObject_GetMethod(args[0], name, &callable); - if (callable == NULL) { - return NULL; - } - - if (unbound) { - /* We must remove PY_VECTORCALL_ARGUMENTS_OFFSET since - * that would be interpreted as allowing to change args[-1] */ - nargsf &= ~PY_VECTORCALL_ARGUMENTS_OFFSET; - } - else { - /* Skip "self". We can keep PY_VECTORCALL_ARGUMENTS_OFFSET since - * args[-1] in the onward call is args[0] here. */ - args++; - nargsf--; - } - PyObject *result = _PyObject_VectorcallTstate(tstate, callable, - args, nargsf, kwnames); - Py_DECREF(callable); - return result; -} - - -PyObject * -PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...) -{ - PyThreadState *tstate = _PyThreadState_GET(); - if (obj == NULL || name == NULL) { - return null_error(tstate); - } - - PyObject *callable = NULL; - int is_method = _PyObject_GetMethod(obj, name, &callable); - if (callable == NULL) { - return NULL; - } - obj = is_method ? obj : NULL; - - va_list vargs; - va_start(vargs, name); - PyObject *result = object_vacall(tstate, obj, callable, vargs); - va_end(vargs); - - Py_DECREF(callable); - return result; -} - - -PyObject * -_PyObject_CallMethodIdObjArgs(PyObject *obj, - struct _Py_Identifier *name, ...) -{ - PyThreadState *tstate = _PyThreadState_GET(); - if (obj == NULL || name == NULL) { - return null_error(tstate); - } - - PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ - if (!oname) { - return NULL; - } - - PyObject *callable = NULL; - int is_method = _PyObject_GetMethod(obj, oname, &callable); - if (callable == NULL) { - return NULL; - } - obj = is_method ? obj : NULL; - - va_list vargs; - va_start(vargs, name); - PyObject *result = object_vacall(tstate, obj, callable, vargs); - va_end(vargs); - - Py_DECREF(callable); - return result; -} - - -PyObject * -PyObject_CallFunctionObjArgs(PyObject *callable, ...) -{ - PyThreadState *tstate = _PyThreadState_GET(); - va_list vargs; - PyObject *result; - - va_start(vargs, callable); - result = object_vacall(tstate, NULL, callable, vargs); - va_end(vargs); - - return result; -} - - -/* --- PyStack functions ------------------------------------------ */ - -PyObject * -_PyStack_AsDict(PyObject *const *values, PyObject *kwnames) -{ - Py_ssize_t nkwargs; - PyObject *kwdict; - Py_ssize_t i; - - assert(kwnames != NULL); - nkwargs = PyTuple_GET_SIZE(kwnames); - kwdict = _PyDict_NewPresized(nkwargs); - if (kwdict == NULL) { - return NULL; - } - - for (i = 0; i < nkwargs; i++) { - PyObject *key = PyTuple_GET_ITEM(kwnames, i); - PyObject *value = *values++; - /* If key already exists, replace it with the new value */ - if (PyDict_SetItem(kwdict, key, value)) { - Py_DECREF(kwdict); - return NULL; - } - } - return kwdict; -} - - -/* Convert (args, nargs, kwargs: dict) into a (stack, nargs, kwnames: tuple). - - Allocate a new argument vector and keyword names tuple. Return the argument - vector; return NULL with exception set on error. Return the keyword names - tuple in *p_kwnames. - - This also checks that all keyword names are strings. If not, a TypeError is - raised. - - The newly allocated argument vector supports PY_VECTORCALL_ARGUMENTS_OFFSET. - - When done, you must call _PyStack_UnpackDict_Free(stack, nargs, kwnames) */ -static PyObject *const * -_PyStack_UnpackDict(PyThreadState *tstate, - PyObject *const *args, Py_ssize_t nargs, - PyObject *kwargs, PyObject **p_kwnames) -{ - assert(nargs >= 0); - assert(kwargs != NULL); - assert(PyDict_Check(kwargs)); - - Py_ssize_t nkwargs = PyDict_GET_SIZE(kwargs); - /* Check for overflow in the PyMem_Malloc() call below. The subtraction - * in this check cannot overflow: both maxnargs and nkwargs are - * non-negative signed integers, so their difference fits in the type. */ - Py_ssize_t maxnargs = PY_SSIZE_T_MAX / sizeof(args[0]) - 1; - if (nargs > maxnargs - nkwargs) { - _PyErr_NoMemory(tstate); - return NULL; - } - - /* Add 1 to support PY_VECTORCALL_ARGUMENTS_OFFSET */ - PyObject **stack = PyMem_Malloc((1 + nargs + nkwargs) * sizeof(args[0])); - if (stack == NULL) { - _PyErr_NoMemory(tstate); - return NULL; - } - - PyObject *kwnames = PyTuple_New(nkwargs); - if (kwnames == NULL) { - PyMem_Free(stack); - return NULL; - } - - stack++; /* For PY_VECTORCALL_ARGUMENTS_OFFSET */ - - /* Copy positional arguments */ - for (Py_ssize_t i = 0; i < nargs; i++) { - Py_INCREF(args[i]); - stack[i] = args[i]; - } - - PyObject **kwstack = stack + nargs; - /* This loop doesn't support lookup function mutating the dictionary - to change its size. It's a deliberate choice for speed, this function is - called in the performance critical hot code. */ - Py_ssize_t pos = 0, i = 0; - PyObject *key, *value; - unsigned long keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; - while (PyDict_Next(kwargs, &pos, &key, &value)) { - keys_are_strings &= Py_TYPE(key)->tp_flags; - Py_INCREF(key); - Py_INCREF(value); - PyTuple_SET_ITEM(kwnames, i, key); - kwstack[i] = value; - i++; - } - - /* keys_are_strings has the value Py_TPFLAGS_UNICODE_SUBCLASS if that - * flag is set for all keys. Otherwise, keys_are_strings equals 0. - * We do this check once at the end instead of inside the loop above - * because it simplifies the deallocation in the failing case. - * It happens to also make the loop above slightly more efficient. */ - if (!keys_are_strings) { - _PyErr_SetString(tstate, PyExc_TypeError, - "keywords must be strings"); - _PyStack_UnpackDict_Free(stack, nargs, kwnames); - return NULL; - } - - *p_kwnames = kwnames; - return stack; -} - -static void -_PyStack_UnpackDict_Free(PyObject *const *stack, Py_ssize_t nargs, - PyObject *kwnames) -{ - Py_ssize_t n = PyTuple_GET_SIZE(kwnames) + nargs; - for (Py_ssize_t i = 0; i < n; i++) { - Py_DECREF(stack[i]); - } - PyMem_Free((PyObject **)stack - 1); - Py_DECREF(kwnames); -} |