From d2306cec4dc393a106aaac6b7c71a9b241be230d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 10 Feb 2017 14:19:36 +0100 Subject: Backed out changeset f23fa1f7b68f Sorry, I didn't want to push this change before the review :-( I was pushing a change into the 2.7 branch. --- Include/eval.h | 22 +- Makefile.pre.in | 1 - Objects/abstract.c | 725 +++++++++++++++++++++++ Objects/call.c | 1368 -------------------------------------------- Objects/methodobject.c | 323 +++++++++++ PCbuild/pythoncore.vcxproj | 3 +- Python/ceval.c | 242 +++++++- Python/modsupport.c | 51 ++ 8 files changed, 1345 insertions(+), 1390 deletions(-) delete mode 100644 Objects/call.c diff --git a/Include/eval.h b/Include/eval.h index 9541e10..a1c6e81 100644 --- a/Include/eval.h +++ b/Include/eval.h @@ -10,24 +10,14 @@ extern "C" { PyAPI_FUNC(PyObject *) PyEval_EvalCode(PyObject *, PyObject *, PyObject *); PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyObject *co, - PyObject *globals, - PyObject *locals, - PyObject **args, int argc, - PyObject **kwds, int kwdc, - PyObject **defs, int defc, - PyObject *kwdefs, PyObject *closure); + PyObject *globals, + PyObject *locals, + PyObject **args, int argc, + PyObject **kwds, int kwdc, + PyObject **defs, int defc, + PyObject *kwdefs, PyObject *closure); #ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyEval_EvalCodeWithName( - PyObject *co, - PyObject *globals, PyObject *locals, - PyObject **args, Py_ssize_t argcount, - PyObject **kwnames, PyObject **kwargs, - Py_ssize_t kwcount, int kwstep, - PyObject **defs, Py_ssize_t defcount, - PyObject *kwdefs, PyObject *closure, - PyObject *name, PyObject *qualname); - PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args); #endif diff --git a/Makefile.pre.in b/Makefile.pre.in index c1b4538..8752a02 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -409,7 +409,6 @@ OBJECT_OBJS= \ Objects/bytes_methods.o \ Objects/bytearrayobject.o \ Objects/bytesobject.o \ - Objects/call.o \ Objects/cellobject.o \ Objects/classobject.o \ Objects/codeobject.o \ diff --git a/Objects/abstract.c b/Objects/abstract.c index 589d9e8..6c66b03 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2168,6 +2168,731 @@ PyMapping_Values(PyObject *o) return fast; } +/* Operations on callable objects */ + +/* XXX PyCallable_Check() is in object.c */ + +PyObject * +PyObject_CallObject(PyObject *callable, PyObject *args) +{ + return PyEval_CallObjectWithKeywords(callable, args, NULL); +} + +PyObject* +_Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where) +{ + int err_occurred = (PyErr_Occurred() != NULL); + + assert((callable != NULL) ^ (where != NULL)); + + if (result == NULL) { + if (!err_occurred) { + if (callable) + PyErr_Format(PyExc_SystemError, + "%R returned NULL without setting an error", + callable); + else + PyErr_Format(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 (err_occurred) { + Py_DECREF(result); + + if (callable) { + _PyErr_FormatFromCause(PyExc_SystemError, + "%R returned a result with an error set", + callable); + } + else { + _PyErr_FormatFromCause(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; +} + +PyObject * +PyObject_Call(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()); + assert(PyTuple_Check(args)); + assert(kwargs == NULL || PyDict_Check(kwargs)); + + if (PyFunction_Check(callable)) { + return _PyFunction_FastCallDict(callable, + &PyTuple_GET_ITEM(args, 0), + PyTuple_GET_SIZE(args), + kwargs); + } + else if (PyCFunction_Check(callable)) { + return PyCFunction_Call(callable, args, kwargs); + } + else { + call = callable->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + callable->ob_type->tp_name); + return NULL; + } + + if (Py_EnterRecursiveCall(" while calling a Python object")) + return NULL; + + result = (*call)(callable, args, kwargs); + + Py_LeaveRecursiveCall(); + + return _Py_CheckFunctionResult(callable, result, NULL); + } +} + +/* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their + stack consumption, Disable inlining to optimize the stack consumption. */ +PyObject* _Py_NO_INLINE +_PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) +{ + PyObject *args; + Py_ssize_t i; + + args = PyTuple_New(nargs); + if (args == NULL) { + return NULL; + } + + for (i=0; i < nargs; i++) { + PyObject *item = stack[i]; + Py_INCREF(item); + PyTuple_SET_ITEM(args, i, item); + } + return args; +} + +PyObject* +_PyStack_AsTupleSlice(PyObject **stack, Py_ssize_t nargs, + Py_ssize_t start, Py_ssize_t end) +{ + PyObject *args; + Py_ssize_t i; + + assert(0 <= start); + assert(end <= nargs); + assert(start <= end); + + args = PyTuple_New(end - start); + if (args == NULL) { + return NULL; + } + + for (i=start; i < end; i++) { + PyObject *item = stack[i]; + Py_INCREF(item); + PyTuple_SET_ITEM(args, i - start, item); + } + return args; +} + +PyObject * +_PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + /* _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()); + + assert(callable != NULL); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + assert(kwargs == NULL || PyDict_Check(kwargs)); + + if (PyFunction_Check(callable)) { + return _PyFunction_FastCallDict(callable, args, nargs, kwargs); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCallDict(callable, args, nargs, kwargs); + } + else { + PyObject *argstuple, *result; + ternaryfunc call; + + /* Slow-path: build a temporary tuple */ + call = callable->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + callable->ob_type->tp_name); + return NULL; + } + + argstuple = _PyStack_AsTuple(args, nargs); + if (argstuple == NULL) { + return NULL; + } + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + Py_DECREF(argstuple); + return NULL; + } + + result = (*call)(callable, argstuple, kwargs); + + Py_LeaveRecursiveCall(); + Py_DECREF(argstuple); + + result = _Py_CheckFunctionResult(callable, result, NULL); + return result; + } +} + +/* Positional arguments are obj followed by args: + call callable(obj, *args, **kwargs) */ +PyObject * +_PyObject_FastCall_Prepend(PyObject *callable, + PyObject *obj, PyObject **args, Py_ssize_t nargs) +{ + PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; + PyObject **args2; + PyObject *result; + + nargs++; + if (nargs <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { + args2 = small_stack; + } + else { + args2 = PyMem_Malloc(nargs * sizeof(PyObject *)); + if (args2 == NULL) { + PyErr_NoMemory(); + return NULL; + } + } + + /* use borrowed references */ + args2[0] = obj; + memcpy(&args2[1], + args, + (nargs - 1)* sizeof(PyObject *)); + + result = _PyObject_FastCall(callable, args2, nargs); + if (args2 != small_stack) { + PyMem_Free(args2); + } + return result; +} + + +/* Call callable(obj, *args, **kwargs). */ +PyObject * +_PyObject_Call_Prepend(PyObject *callable, + PyObject *obj, PyObject *args, PyObject *kwargs) +{ + PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; + PyObject **stack; + Py_ssize_t argcount; + PyObject *result; + + assert(PyTuple_Check(args)); + + 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_GET_ITEM(args, 0), + argcount * sizeof(PyObject *)); + + result = _PyObject_FastCallDict(callable, + stack, argcount + 1, + kwargs); + if (stack != small_stack) { + PyMem_Free(stack); + } + return result; +} + +PyObject * +_PyStack_AsDict(PyObject **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; +} + +int +_PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, + PyObject ***p_stack, PyObject **p_kwnames) +{ + PyObject **stack, **kwstack; + Py_ssize_t nkwargs; + Py_ssize_t pos, i; + PyObject *key, *value; + PyObject *kwnames; + + assert(nargs >= 0); + assert(kwargs == NULL || PyDict_CheckExact(kwargs)); + + if (kwargs == NULL || (nkwargs = PyDict_GET_SIZE(kwargs)) == 0) { + *p_stack = args; + *p_kwnames = NULL; + return 0; + } + + if ((size_t)nargs > PY_SSIZE_T_MAX / sizeof(stack[0]) - (size_t)nkwargs) { + PyErr_NoMemory(); + return -1; + } + + stack = PyMem_Malloc((nargs + nkwargs) * sizeof(stack[0])); + if (stack == NULL) { + PyErr_NoMemory(); + return -1; + } + + kwnames = PyTuple_New(nkwargs); + if (kwnames == NULL) { + PyMem_Free(stack); + return -1; + } + + /* Copy position arguments (borrowed references) */ + memcpy(stack, args, nargs * sizeof(stack[0])); + + kwstack = stack + nargs; + pos = i = 0; + /* 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. */ + while (PyDict_Next(kwargs, &pos, &key, &value)) { + Py_INCREF(key); + PyTuple_SET_ITEM(kwnames, i, key); + /* The stack contains borrowed references */ + kwstack[i] = value; + i++; + } + + *p_stack = stack; + *p_kwnames = kwnames; + return 0; +} + +PyObject * +_PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t nargs, + PyObject *kwnames) +{ + /* _PyObject_FastCallKeywords() 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()); + + assert(nargs >= 0); + assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); + + /* kwnames must only contains str strings, no subclass, and all keys must + be unique: these checks are implemented in Python/ceval.c and + _PyArg_ParseStackAndKeywords(). */ + + if (PyFunction_Check(callable)) { + return _PyFunction_FastCallKeywords(callable, stack, nargs, kwnames); + } + if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCallKeywords(callable, stack, nargs, kwnames); + } + else { + /* Slow-path: build a temporary tuple for positional arguments and a + temporary dictionary for keyword arguments (if any) */ + + ternaryfunc call; + PyObject *argstuple; + PyObject *kwdict, *result; + Py_ssize_t nkwargs; + + nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + assert((nargs == 0 && nkwargs == 0) || stack != NULL); + + call = callable->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + callable->ob_type->tp_name); + return NULL; + } + + argstuple = _PyStack_AsTuple(stack, nargs); + if (argstuple == NULL) { + return NULL; + } + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(stack + nargs, kwnames); + if (kwdict == NULL) { + Py_DECREF(argstuple); + return NULL; + } + } + else { + kwdict = NULL; + } + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + Py_DECREF(argstuple); + Py_XDECREF(kwdict); + return NULL; + } + + result = (*call)(callable, argstuple, kwdict); + + Py_LeaveRecursiveCall(); + + Py_DECREF(argstuple); + Py_XDECREF(kwdict); + + result = _Py_CheckFunctionResult(callable, result, NULL); + return result; + } +} + +static PyObject * +_PyObject_CallFunctionVa(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(); + } + + if (!format || !*format) { + return _PyObject_CallNoArg(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_FastCall(callable, + &PyTuple_GET_ITEM(args, 0), + PyTuple_GET_SIZE(args)); + } + else { + result = _PyObject_FastCall(callable, stack, nargs); + } + + 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; + + va_start(va, format); + result = _PyObject_CallFunctionVa(callable, format, va, 0); + va_end(va); + + return result; +} + +PyObject * +_PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) +{ + va_list va; + PyObject *result; + + va_start(va, format); + result = _PyObject_CallFunctionVa(callable, format, va, 1); + va_end(va); + + return result; +} + +static PyObject* +callmethod(PyObject* callable, const char *format, va_list va, int is_size_t) +{ + assert(callable != NULL); + + if (!PyCallable_Check(callable)) { + type_error("attribute of type '%.200s' is not callable", callable); + return NULL; + } + + return _PyObject_CallFunctionVa(callable, format, va, is_size_t); +} + +PyObject * +PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) +{ + va_list va; + PyObject *callable, *retval; + + if (obj == NULL || name == NULL) { + return null_error(); + } + + callable = PyObject_GetAttrString(obj, name); + if (callable == NULL) + return NULL; + + va_start(va, format); + retval = callmethod(callable, format, va, 0); + va_end(va); + + Py_DECREF(callable); + return retval; +} + +PyObject * +_PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, + const char *format, ...) +{ + va_list va; + PyObject *callable, *retval; + + if (obj == NULL || name == NULL) { + return null_error(); + } + + callable = _PyObject_GetAttrId(obj, name); + if (callable == NULL) + return NULL; + + va_start(va, format); + retval = callmethod(callable, format, va, 0); + va_end(va); + + Py_DECREF(callable); + return retval; +} + +PyObject * +_PyObject_CallMethod_SizeT(PyObject *obj, const char *name, + const char *format, ...) +{ + va_list va; + PyObject *callable, *retval; + + if (obj == NULL || name == NULL) { + return null_error(); + } + + callable = PyObject_GetAttrString(obj, name); + if (callable == NULL) + return NULL; + + va_start(va, format); + retval = callmethod(callable, format, va, 1); + va_end(va); + + Py_DECREF(callable); + return retval; +} + +PyObject * +_PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, + const char *format, ...) +{ + va_list va; + PyObject *callable, *retval; + + if (obj == NULL || name == NULL) { + return null_error(); + } + + callable = _PyObject_GetAttrId(obj, name); + if (callable == NULL) { + return NULL; + } + + va_start(va, format); + retval = callmethod(callable, format, va, 1); + va_end(va); + + Py_DECREF(callable); + return retval; +} + +static PyObject * +object_vacall(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(); + } + + /* Count the number of arguments */ + va_copy(countva, vargs); + nargs = 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; + } + } + + for (i = 0; i < nargs; ++i) { + stack[i] = va_arg(vargs, PyObject *); + } + + /* Call the function */ + result = _PyObject_FastCall(callable, stack, nargs); + + if (stack != small_stack) { + PyMem_Free(stack); + } + return result; +} + +PyObject * +PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) +{ + va_list vargs; + PyObject *result; + + if (callable == NULL || name == NULL) { + return null_error(); + } + + callable = PyObject_GetAttr(callable, name); + if (callable == NULL) { + return NULL; + } + + va_start(vargs, name); + result = object_vacall(callable, vargs); + va_end(vargs); + + Py_DECREF(callable); + return result; +} + +PyObject * +_PyObject_CallMethodIdObjArgs(PyObject *obj, + struct _Py_Identifier *name, ...) +{ + va_list vargs; + PyObject *callable, *result; + + if (obj == NULL || name == NULL) { + return null_error(); + } + + callable = _PyObject_GetAttrId(obj, name); + if (callable == NULL) { + return NULL; + } + + va_start(vargs, name); + result = object_vacall(callable, vargs); + va_end(vargs); + + Py_DECREF(callable); + return result; +} + +PyObject * +PyObject_CallFunctionObjArgs(PyObject *callable, ...) +{ + va_list vargs; + PyObject *result; + + va_start(vargs, callable); + result = object_vacall(callable, vargs); + va_end(vargs); + + return result; +} + + /* isinstance(), issubclass() */ /* abstract_get_bases() has logically 4 return states: diff --git a/Objects/call.c b/Objects/call.c deleted file mode 100644 index bc32090..0000000 --- a/Objects/call.c +++ /dev/null @@ -1,1368 +0,0 @@ -#include "Python.h" -#include "frameobject.h" - - -static PyObject * -null_error(void) -{ - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_SystemError, - "null argument to internal routine"); - return NULL; -} - - -PyObject* -_Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where) -{ - int err_occurred = (PyErr_Occurred() != NULL); - - assert((callable != NULL) ^ (where != NULL)); - - if (result == NULL) { - if (!err_occurred) { - if (callable) - PyErr_Format(PyExc_SystemError, - "%R returned NULL without setting an error", - callable); - else - PyErr_Format(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 (err_occurred) { - Py_DECREF(result); - - if (callable) { - _PyErr_FormatFromCause(PyExc_SystemError, - "%R returned a result with an error set", - callable); - } - else { - _PyErr_FormatFromCause(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 ------------------------------- */ - -PyObject * -_PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs, - PyObject *kwargs) -{ - /* _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()); - - assert(callable != NULL); - assert(nargs >= 0); - assert(nargs == 0 || args != NULL); - assert(kwargs == NULL || PyDict_Check(kwargs)); - - if (PyFunction_Check(callable)) { - return _PyFunction_FastCallDict(callable, args, nargs, kwargs); - } - else if (PyCFunction_Check(callable)) { - return _PyCFunction_FastCallDict(callable, args, nargs, kwargs); - } - else { - PyObject *argstuple, *result; - ternaryfunc call; - - /* Slow-path: build a temporary tuple */ - call = callable->ob_type->tp_call; - if (call == NULL) { - PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - callable->ob_type->tp_name); - return NULL; - } - - argstuple = _PyStack_AsTuple(args, nargs); - if (argstuple == NULL) { - return NULL; - } - - if (Py_EnterRecursiveCall(" while calling a Python object")) { - Py_DECREF(argstuple); - return NULL; - } - - result = (*call)(callable, argstuple, kwargs); - - Py_LeaveRecursiveCall(); - Py_DECREF(argstuple); - - result = _Py_CheckFunctionResult(callable, result, NULL); - return result; - } -} - - -PyObject * -_PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t nargs, - PyObject *kwnames) -{ - /* _PyObject_FastCallKeywords() 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()); - - assert(nargs >= 0); - assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - - /* kwnames must only contains str strings, no subclass, and all keys must - be unique: these checks are implemented in Python/ceval.c and - _PyArg_ParseStackAndKeywords(). */ - - if (PyFunction_Check(callable)) { - return _PyFunction_FastCallKeywords(callable, stack, nargs, kwnames); - } - if (PyCFunction_Check(callable)) { - return _PyCFunction_FastCallKeywords(callable, stack, nargs, kwnames); - } - else { - /* Slow-path: build a temporary tuple for positional arguments and a - temporary dictionary for keyword arguments (if any) */ - - ternaryfunc call; - PyObject *argstuple; - PyObject *kwdict, *result; - Py_ssize_t nkwargs; - - nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); - - call = callable->ob_type->tp_call; - if (call == NULL) { - PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - callable->ob_type->tp_name); - return NULL; - } - - argstuple = _PyStack_AsTuple(stack, nargs); - if (argstuple == NULL) { - return NULL; - } - - if (nkwargs > 0) { - kwdict = _PyStack_AsDict(stack + nargs, kwnames); - if (kwdict == NULL) { - Py_DECREF(argstuple); - return NULL; - } - } - else { - kwdict = NULL; - } - - if (Py_EnterRecursiveCall(" while calling a Python object")) { - Py_DECREF(argstuple); - Py_XDECREF(kwdict); - return NULL; - } - - result = (*call)(callable, argstuple, kwdict); - - Py_LeaveRecursiveCall(); - - Py_DECREF(argstuple); - Py_XDECREF(kwdict); - - result = _Py_CheckFunctionResult(callable, result, NULL); - return result; - } -} - - -PyObject * -PyObject_Call(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()); - assert(PyTuple_Check(args)); - assert(kwargs == NULL || PyDict_Check(kwargs)); - - if (PyFunction_Check(callable)) { - return _PyFunction_FastCallDict(callable, - &PyTuple_GET_ITEM(args, 0), - PyTuple_GET_SIZE(args), - kwargs); - } - else if (PyCFunction_Check(callable)) { - return PyCFunction_Call(callable, args, kwargs); - } - else { - call = callable->ob_type->tp_call; - if (call == NULL) { - PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - callable->ob_type->tp_name); - return NULL; - } - - if (Py_EnterRecursiveCall(" while calling a Python object")) - return NULL; - - result = (*call)(callable, args, kwargs); - - Py_LeaveRecursiveCall(); - - return _Py_CheckFunctionResult(callable, result, NULL); - } -} - - -/* --- PyFunction call functions ---------------------------------- */ - -static PyObject* _Py_HOT_FUNCTION -function_code_fastcall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, - PyObject *globals) -{ - PyFrameObject *f; - PyThreadState *tstate = PyThreadState_GET(); - PyObject **fastlocals; - Py_ssize_t i; - PyObject *result; - - 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. - */ - assert(tstate != NULL); - f = _PyFrame_New_NoTrack(tstate, co, globals, NULL); - if (f == NULL) { - return NULL; - } - - fastlocals = f->f_localsplus; - - for (i = 0; i < nargs; i++) { - Py_INCREF(*args); - fastlocals[i] = *args++; - } - result = PyEval_EvalFrameEx(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_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, - PyObject *kwargs) -{ - PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); - PyObject *globals = PyFunction_GET_GLOBALS(func); - PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - PyObject *kwdefs, *closure, *name, *qualname; - PyObject *kwtuple, **k; - PyObject **d; - Py_ssize_t nd, nk; - PyObject *result; - - assert(func != NULL); - assert(nargs >= 0); - assert(nargs == 0 || args != NULL); - assert(kwargs == NULL || PyDict_Check(kwargs)); - - if (co->co_kwonlyargcount == 0 && - (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) && - co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) - { - /* Fast paths */ - if (argdefs == NULL && co->co_argcount == nargs) { - return function_code_fastcall(co, args, nargs, globals); - } - else if (nargs == 0 && argdefs != NULL - && co->co_argcount == Py_SIZE(argdefs)) { - /* function called with no arguments, but all parameters have - a default value: use default values as arguments .*/ - args = &PyTuple_GET_ITEM(argdefs, 0); - return function_code_fastcall(co, args, Py_SIZE(argdefs), globals); - } - } - - nk = (kwargs != NULL) ? PyDict_GET_SIZE(kwargs) : 0; - if (nk != 0) { - Py_ssize_t pos, i; - - /* Issue #29318: Caller and callee functions must not share the - dictionary: kwargs must be copied. */ - kwtuple = PyTuple_New(2 * nk); - if (kwtuple == NULL) { - return NULL; - } - - k = &PyTuple_GET_ITEM(kwtuple, 0); - pos = i = 0; - while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { - /* We must hold strong references because keyword arguments can be - indirectly modified while the function is called: - see issue #2016 and test_extcall */ - Py_INCREF(k[i]); - Py_INCREF(k[i+1]); - i += 2; - } - nk = i / 2; - } - else { - kwtuple = NULL; - k = NULL; - } - - kwdefs = PyFunction_GET_KW_DEFAULTS(func); - closure = PyFunction_GET_CLOSURE(func); - name = ((PyFunctionObject *)func) -> func_name; - qualname = ((PyFunctionObject *)func) -> func_qualname; - - if (argdefs != NULL) { - d = &PyTuple_GET_ITEM(argdefs, 0); - nd = Py_SIZE(argdefs); - } - else { - d = NULL; - nd = 0; - } - - result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL, - args, nargs, - k, k + 1, nk, 2, - d, nd, kwdefs, - closure, name, qualname); - Py_XDECREF(kwtuple); - return result; -} - -PyObject * -_PyFunction_FastCallKeywords(PyObject *func, PyObject **stack, - Py_ssize_t nargs, PyObject *kwnames) -{ - PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); - PyObject *globals = PyFunction_GET_GLOBALS(func); - PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - PyObject *kwdefs, *closure, *name, *qualname; - PyObject **d; - Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); - Py_ssize_t nd; - - assert(PyFunction_Check(func)); - assert(nargs >= 0); - assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); - /* kwnames must only contains str strings, no subclass, and all keys must - be unique */ - - if (co->co_kwonlyargcount == 0 && nkwargs == 0 && - co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) - { - if (argdefs == NULL && co->co_argcount == nargs) { - return function_code_fastcall(co, stack, nargs, globals); - } - else if (nargs == 0 && argdefs != NULL - && co->co_argcount == Py_SIZE(argdefs)) { - /* function called with no arguments, but all parameters have - a default value: use default values as arguments .*/ - stack = &PyTuple_GET_ITEM(argdefs, 0); - return function_code_fastcall(co, stack, Py_SIZE(argdefs), globals); - } - } - - kwdefs = PyFunction_GET_KW_DEFAULTS(func); - closure = PyFunction_GET_CLOSURE(func); - name = ((PyFunctionObject *)func) -> func_name; - qualname = ((PyFunctionObject *)func) -> func_qualname; - - if (argdefs != NULL) { - d = &PyTuple_GET_ITEM(argdefs, 0); - nd = Py_SIZE(argdefs); - } - else { - d = NULL; - nd = 0; - } - return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL, - stack, nargs, - nkwargs ? &PyTuple_GET_ITEM(kwnames, 0) : NULL, - stack + nargs, - nkwargs, 1, - d, (int)nd, kwdefs, - closure, name, qualname); -} - - -/* --- PyCFunction call functions --------------------------------- */ - -PyObject * -_PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args, - Py_ssize_t nargs, PyObject *kwargs) -{ - /* _PyMethodDef_RawFastCallDict() 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()); - - assert(method != NULL); - assert(nargs >= 0); - assert(nargs == 0 || args != NULL); - assert(kwargs == NULL || PyDict_Check(kwargs)); - - PyCFunction meth = method->ml_meth; - int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); - PyObject *result = NULL; - - if (Py_EnterRecursiveCall(" while calling a Python object")) { - return NULL; - } - - switch (flags) - { - case METH_NOARGS: - if (nargs != 0) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%zd given)", - method->ml_name, nargs); - goto exit; - } - - if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { - goto no_keyword_error; - } - - result = (*meth) (self, NULL); - break; - - case METH_O: - if (nargs != 1) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes exactly one argument (%zd given)", - method->ml_name, nargs); - goto exit; - } - - if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { - goto no_keyword_error; - } - - result = (*meth) (self, args[0]); - break; - - case METH_VARARGS: - if (!(flags & METH_KEYWORDS) - && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { - goto no_keyword_error; - } - /* fall through next case */ - - case METH_VARARGS | METH_KEYWORDS: - { - /* Slow-path: create a temporary tuple for positional arguments */ - PyObject *argstuple = _PyStack_AsTuple(args, nargs); - if (argstuple == NULL) { - goto exit; - } - - if (flags & METH_KEYWORDS) { - result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs); - } - else { - result = (*meth) (self, argstuple); - } - Py_DECREF(argstuple); - break; - } - - case METH_FASTCALL: - { - PyObject **stack; - PyObject *kwnames; - _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth; - - if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) { - goto exit; - } - - result = (*fastmeth) (self, stack, nargs, kwnames); - if (stack != args) { - PyMem_Free(stack); - } - Py_XDECREF(kwnames); - break; - } - - default: - PyErr_SetString(PyExc_SystemError, - "Bad call flags in _PyMethodDef_RawFastCallDict. " - "METH_OLDARGS is no longer supported!"); - goto exit; - } - - goto exit; - -no_keyword_error: - PyErr_Format(PyExc_TypeError, - "%.200s() takes no keyword arguments", - method->ml_name, nargs); - -exit: - Py_LeaveRecursiveCall(); - return result; -} - - -PyObject * -_PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, - PyObject *kwargs) -{ - PyObject *result; - - assert(func != NULL); - assert(PyCFunction_Check(func)); - - result = _PyMethodDef_RawFastCallDict(((PyCFunctionObject*)func)->m_ml, - PyCFunction_GET_SELF(func), - args, nargs, kwargs); - result = _Py_CheckFunctionResult(func, result, NULL); - return result; -} - - -PyObject * -_PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject **args, - Py_ssize_t nargs, PyObject *kwnames) -{ - /* _PyMethodDef_RawFastCallKeywords() 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()); - - assert(method != NULL); - assert(nargs >= 0); - assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - /* kwnames must only contains str strings, no subclass, and all keys must - be unique */ - - PyCFunction meth = method->ml_meth; - int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); - Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames); - PyObject *result = NULL; - - if (Py_EnterRecursiveCall(" while calling a Python object")) { - return NULL; - } - - switch (flags) - { - case METH_NOARGS: - if (nargs != 0) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%zd given)", - method->ml_name, nargs); - goto exit; - } - - if (nkwargs) { - goto no_keyword_error; - } - - result = (*meth) (self, NULL); - break; - - case METH_O: - if (nargs != 1) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes exactly one argument (%zd given)", - method->ml_name, nargs); - goto exit; - } - - if (nkwargs) { - goto no_keyword_error; - } - - result = (*meth) (self, args[0]); - break; - - case METH_FASTCALL: - /* Fast-path: avoid temporary dict to pass keyword arguments */ - result = ((_PyCFunctionFast)meth) (self, args, nargs, kwnames); - break; - - case METH_VARARGS: - case METH_VARARGS | METH_KEYWORDS: - { - /* Slow-path: create a temporary tuple for positional arguments - and a temporary dict for keyword arguments */ - PyObject *argtuple; - - if (!(flags & METH_KEYWORDS) && nkwargs) { - goto no_keyword_error; - } - - argtuple = _PyStack_AsTuple(args, nargs); - if (argtuple == NULL) { - goto exit; - } - - if (flags & METH_KEYWORDS) { - PyObject *kwdict; - - if (nkwargs > 0) { - kwdict = _PyStack_AsDict(args + nargs, kwnames); - if (kwdict == NULL) { - Py_DECREF(argtuple); - goto exit; - } - } - else { - kwdict = NULL; - } - - result = (*(PyCFunctionWithKeywords)meth) (self, argtuple, kwdict); - Py_XDECREF(kwdict); - } - else { - result = (*meth) (self, argtuple); - } - Py_DECREF(argtuple); - break; - } - - default: - PyErr_SetString(PyExc_SystemError, - "Bad call flags in _PyCFunction_FastCallKeywords. " - "METH_OLDARGS is no longer supported!"); - goto exit; - } - - goto exit; - -no_keyword_error: - PyErr_Format(PyExc_TypeError, - "%.200s() takes no keyword arguments", - method->ml_name); - -exit: - Py_LeaveRecursiveCall(); - return result; -} - - -PyObject * -_PyCFunction_FastCallKeywords(PyObject *func, PyObject **args, - Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *result; - - assert(func != NULL); - assert(PyCFunction_Check(func)); - - result = _PyMethodDef_RawFastCallKeywords(((PyCFunctionObject*)func)->m_ml, - PyCFunction_GET_SELF(func), - args, nargs, kwnames); - result = _Py_CheckFunctionResult(func, result, NULL); - return result; -} - - -static PyObject * -cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs) -{ - assert(!PyErr_Occurred()); - - PyCFunction meth = PyCFunction_GET_FUNCTION(func); - PyObject *self = PyCFunction_GET_SELF(func); - PyObject *result; - - if (PyCFunction_GET_FLAGS(func) & METH_KEYWORDS) { - if (Py_EnterRecursiveCall(" while calling a Python object")) { - return NULL; - } - - result = (*(PyCFunctionWithKeywords)meth)(self, args, kwargs); - - Py_LeaveRecursiveCall(); - } - else { - if (kwargs != NULL && PyDict_Size(kwargs) != 0) { - PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", - ((PyCFunctionObject*)func)->m_ml->ml_name); - return NULL; - } - - if (Py_EnterRecursiveCall(" while calling a Python object")) { - return NULL; - } - - result = (*meth)(self, args); - - Py_LeaveRecursiveCall(); - } - - return _Py_CheckFunctionResult(func, result, NULL); -} - - -PyObject * -PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs) -{ - /* first try METH_VARARGS to pass directly args tuple unchanged. - _PyMethodDef_RawFastCallDict() creates a new temporary tuple - for METH_VARARGS. */ - if (PyCFunction_GET_FLAGS(func) & METH_VARARGS) { - return cfunction_call_varargs(func, args, kwargs); - } - else { - return _PyCFunction_FastCallDict(func, - &PyTuple_GET_ITEM(args, 0), - PyTuple_GET_SIZE(args), - kwargs); - } -} - - -/* --- 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) -{ -#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()); -#endif - - if (args == NULL) { - return _PyObject_FastCallDict(callable, NULL, 0, kwargs); - } - - if (!PyTuple_Check(args)) { - PyErr_SetString(PyExc_TypeError, - "argument list must be a tuple"); - return NULL; - } - - if (kwargs != NULL && !PyDict_Check(kwargs)) { - PyErr_SetString(PyExc_TypeError, - "keyword list must be a dictionary"); - return NULL; - } - - return PyObject_Call(callable, args, kwargs); -} - - -PyObject * -PyObject_CallObject(PyObject *callable, PyObject *args) -{ - return PyEval_CallObjectWithKeywords(callable, args, NULL); -} - - -/* Positional arguments are obj followed by args: - call callable(obj, *args, **kwargs) */ -PyObject * -_PyObject_FastCall_Prepend(PyObject *callable, - PyObject *obj, PyObject **args, Py_ssize_t nargs) -{ - PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; - PyObject **args2; - PyObject *result; - - nargs++; - if (nargs <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { - args2 = small_stack; - } - else { - args2 = PyMem_Malloc(nargs * sizeof(PyObject *)); - if (args2 == NULL) { - PyErr_NoMemory(); - return NULL; - } - } - - /* use borrowed references */ - args2[0] = obj; - memcpy(&args2[1], - args, - (nargs - 1)* sizeof(PyObject *)); - - result = _PyObject_FastCall(callable, args2, nargs); - if (args2 != small_stack) { - PyMem_Free(args2); - } - return result; -} - - -/* Call callable(obj, *args, **kwargs). */ -PyObject * -_PyObject_Call_Prepend(PyObject *callable, - PyObject *obj, PyObject *args, PyObject *kwargs) -{ - PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; - PyObject **stack; - Py_ssize_t argcount; - PyObject *result; - - assert(PyTuple_Check(args)); - - 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_GET_ITEM(args, 0), - argcount * sizeof(PyObject *)); - - result = _PyObject_FastCallDict(callable, - stack, argcount + 1, - kwargs); - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; -} - - -/* --- Call with a format string ---------------------------------- */ - -static PyObject * -_PyObject_CallFunctionVa(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(); - } - - if (!format || !*format) { - return _PyObject_CallNoArg(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_FastCall(callable, - &PyTuple_GET_ITEM(args, 0), - PyTuple_GET_SIZE(args)); - } - else { - result = _PyObject_FastCall(callable, stack, nargs); - } - - 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; - - va_start(va, format); - result = _PyObject_CallFunctionVa(callable, format, va, 0); - va_end(va); - - return result; -} - - -PyObject * -PyEval_CallFunction(PyObject *callable, const char *format, ...) -{ - va_list vargs; - PyObject *args; - PyObject *res; - - va_start(vargs, format); - - args = Py_VaBuildValue(format, vargs); - va_end(vargs); - - if (args == NULL) - return NULL; - - res = PyEval_CallObject(callable, args); - Py_DECREF(args); - - return res; -} - - -PyObject * -_PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) -{ - va_list va; - PyObject *result; - - va_start(va, format); - result = _PyObject_CallFunctionVa(callable, format, va, 1); - va_end(va); - - return result; -} - - -static PyObject* -callmethod(PyObject* callable, const char *format, va_list va, int is_size_t) -{ - assert(callable != NULL); - - if (!PyCallable_Check(callable)) { - PyErr_Format(PyExc_TypeError, - "attribute of type '%.200s' is not callable", - Py_TYPE(callable)->tp_name); - return NULL; - } - - return _PyObject_CallFunctionVa(callable, format, va, is_size_t); -} - - -PyObject * -PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) -{ - va_list va; - PyObject *callable, *retval; - - if (obj == NULL || name == NULL) { - return null_error(); - } - - callable = PyObject_GetAttrString(obj, name); - if (callable == NULL) - return NULL; - - va_start(va, format); - retval = callmethod(callable, format, va, 0); - va_end(va); - - Py_DECREF(callable); - return retval; -} - - -PyObject * -PyEval_CallMethod(PyObject *obj, const char *name, const char *format, ...) -{ - va_list vargs; - PyObject *meth; - PyObject *args; - PyObject *res; - - meth = PyObject_GetAttrString(obj, name); - if (meth == NULL) - return NULL; - - va_start(vargs, format); - - args = Py_VaBuildValue(format, vargs); - va_end(vargs); - - if (args == NULL) { - Py_DECREF(meth); - return NULL; - } - - res = PyEval_CallObject(meth, args); - Py_DECREF(meth); - Py_DECREF(args); - - return res; -} - - -PyObject * -_PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, - const char *format, ...) -{ - va_list va; - PyObject *callable, *retval; - - if (obj == NULL || name == NULL) { - return null_error(); - } - - callable = _PyObject_GetAttrId(obj, name); - if (callable == NULL) - return NULL; - - va_start(va, format); - retval = callmethod(callable, format, va, 0); - va_end(va); - - Py_DECREF(callable); - return retval; -} - - -PyObject * -_PyObject_CallMethod_SizeT(PyObject *obj, const char *name, - const char *format, ...) -{ - va_list va; - PyObject *callable, *retval; - - if (obj == NULL || name == NULL) { - return null_error(); - } - - callable = PyObject_GetAttrString(obj, name); - if (callable == NULL) - return NULL; - - va_start(va, format); - retval = callmethod(callable, format, va, 1); - va_end(va); - - Py_DECREF(callable); - return retval; -} - - -PyObject * -_PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, - const char *format, ...) -{ - va_list va; - PyObject *callable, *retval; - - if (obj == NULL || name == NULL) { - return null_error(); - } - - callable = _PyObject_GetAttrId(obj, name); - if (callable == NULL) { - return NULL; - } - - va_start(va, format); - retval = callmethod(callable, format, va, 1); - va_end(va); - - Py_DECREF(callable); - return retval; -} - - -/* --- Call with "..." arguments ---------------------------------- */ - -static PyObject * -object_vacall(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(); - } - - /* Count the number of arguments */ - va_copy(countva, vargs); - nargs = 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; - } - } - - for (i = 0; i < nargs; ++i) { - stack[i] = va_arg(vargs, PyObject *); - } - - /* Call the function */ - result = _PyObject_FastCall(callable, stack, nargs); - - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; -} - - -PyObject * -PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) -{ - va_list vargs; - PyObject *result; - - if (callable == NULL || name == NULL) { - return null_error(); - } - - callable = PyObject_GetAttr(callable, name); - if (callable == NULL) { - return NULL; - } - - va_start(vargs, name); - result = object_vacall(callable, vargs); - va_end(vargs); - - Py_DECREF(callable); - return result; -} - - -PyObject * -_PyObject_CallMethodIdObjArgs(PyObject *obj, - struct _Py_Identifier *name, ...) -{ - va_list vargs; - PyObject *callable, *result; - - if (obj == NULL || name == NULL) { - return null_error(); - } - - callable = _PyObject_GetAttrId(obj, name); - if (callable == NULL) { - return NULL; - } - - va_start(vargs, name); - result = object_vacall(callable, vargs); - va_end(vargs); - - Py_DECREF(callable); - return result; -} - - -PyObject * -PyObject_CallFunctionObjArgs(PyObject *callable, ...) -{ - va_list vargs; - PyObject *result; - - va_start(vargs, callable); - result = object_vacall(callable, vargs); - va_end(vargs); - - return result; -} - - -/* --- PyStack functions ------------------------------------------ */ - -/* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their - stack consumption, Disable inlining to optimize the stack consumption. */ -PyObject* _Py_NO_INLINE -_PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) -{ - PyObject *args; - Py_ssize_t i; - - args = PyTuple_New(nargs); - if (args == NULL) { - return NULL; - } - - for (i=0; i < nargs; i++) { - PyObject *item = stack[i]; - Py_INCREF(item); - PyTuple_SET_ITEM(args, i, item); - } - return args; -} - - -PyObject* -_PyStack_AsTupleSlice(PyObject **stack, Py_ssize_t nargs, - Py_ssize_t start, Py_ssize_t end) -{ - PyObject *args; - Py_ssize_t i; - - assert(0 <= start); - assert(end <= nargs); - assert(start <= end); - - args = PyTuple_New(end - start); - if (args == NULL) { - return NULL; - } - - for (i=start; i < end; i++) { - PyObject *item = stack[i]; - Py_INCREF(item); - PyTuple_SET_ITEM(args, i - start, item); - } - return args; -} - - -PyObject * -_PyStack_AsDict(PyObject **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; -} - - -int -_PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, - PyObject ***p_stack, PyObject **p_kwnames) -{ - PyObject **stack, **kwstack; - Py_ssize_t nkwargs; - Py_ssize_t pos, i; - PyObject *key, *value; - PyObject *kwnames; - - assert(nargs >= 0); - assert(kwargs == NULL || PyDict_CheckExact(kwargs)); - - if (kwargs == NULL || (nkwargs = PyDict_GET_SIZE(kwargs)) == 0) { - *p_stack = args; - *p_kwnames = NULL; - return 0; - } - - if ((size_t)nargs > PY_SSIZE_T_MAX / sizeof(stack[0]) - (size_t)nkwargs) { - PyErr_NoMemory(); - return -1; - } - - stack = PyMem_Malloc((nargs + nkwargs) * sizeof(stack[0])); - if (stack == NULL) { - PyErr_NoMemory(); - return -1; - } - - kwnames = PyTuple_New(nkwargs); - if (kwnames == NULL) { - PyMem_Free(stack); - return -1; - } - - /* Copy position arguments (borrowed references) */ - memcpy(stack, args, nargs * sizeof(stack[0])); - - kwstack = stack + nargs; - pos = i = 0; - /* 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. */ - while (PyDict_Next(kwargs, &pos, &key, &value)) { - Py_INCREF(key); - PyTuple_SET_ITEM(kwnames, i, key); - /* The stack contains borrowed references */ - kwstack[i] = value; - i++; - } - - *p_stack = stack; - *p_kwnames = kwnames; - return 0; -} diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 4050922..d0fbefd 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -77,6 +77,329 @@ PyCFunction_GetFlags(PyObject *op) return PyCFunction_GET_FLAGS(op); } +static PyObject * +cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs) +{ + assert(!PyErr_Occurred()); + + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + PyObject *result; + + if (PyCFunction_GET_FLAGS(func) & METH_KEYWORDS) { + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + result = (*(PyCFunctionWithKeywords)meth)(self, args, kwargs); + + Py_LeaveRecursiveCall(); + } + else { + if (kwargs != NULL && PyDict_Size(kwargs) != 0) { + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + ((PyCFunctionObject*)func)->m_ml->ml_name); + return NULL; + } + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + result = (*meth)(self, args); + + Py_LeaveRecursiveCall(); + } + + return _Py_CheckFunctionResult(func, result, NULL); +} + + +PyObject * +PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs) +{ + /* first try METH_VARARGS to pass directly args tuple unchanged. + _PyMethodDef_RawFastCallDict() creates a new temporary tuple + for METH_VARARGS. */ + if (PyCFunction_GET_FLAGS(func) & METH_VARARGS) { + return cfunction_call_varargs(func, args, kwargs); + } + else { + return _PyCFunction_FastCallDict(func, + &PyTuple_GET_ITEM(args, 0), + PyTuple_GET_SIZE(args), + kwargs); + } +} + +PyObject * +_PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args, + Py_ssize_t nargs, PyObject *kwargs) +{ + /* _PyMethodDef_RawFastCallDict() 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()); + + assert(method != NULL); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + assert(kwargs == NULL || PyDict_Check(kwargs)); + + PyCFunction meth = method->ml_meth; + int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + PyObject *result = NULL; + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + switch (flags) + { + case METH_NOARGS: + if (nargs != 0) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + method->ml_name, nargs); + goto exit; + } + + if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { + goto no_keyword_error; + } + + result = (*meth) (self, NULL); + break; + + case METH_O: + if (nargs != 1) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%zd given)", + method->ml_name, nargs); + goto exit; + } + + if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { + goto no_keyword_error; + } + + result = (*meth) (self, args[0]); + break; + + case METH_VARARGS: + if (!(flags & METH_KEYWORDS) + && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { + goto no_keyword_error; + } + /* fall through next case */ + + case METH_VARARGS | METH_KEYWORDS: + { + /* Slow-path: create a temporary tuple for positional arguments */ + PyObject *argstuple = _PyStack_AsTuple(args, nargs); + if (argstuple == NULL) { + goto exit; + } + + if (flags & METH_KEYWORDS) { + result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs); + } + else { + result = (*meth) (self, argstuple); + } + Py_DECREF(argstuple); + break; + } + + case METH_FASTCALL: + { + PyObject **stack; + PyObject *kwnames; + _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth; + + if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) { + goto exit; + } + + result = (*fastmeth) (self, stack, nargs, kwnames); + if (stack != args) { + PyMem_Free(stack); + } + Py_XDECREF(kwnames); + break; + } + + default: + PyErr_SetString(PyExc_SystemError, + "Bad call flags in _PyMethodDef_RawFastCallDict. " + "METH_OLDARGS is no longer supported!"); + goto exit; + } + + goto exit; + +no_keyword_error: + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", + method->ml_name, nargs); + +exit: + Py_LeaveRecursiveCall(); + return result; +} + +PyObject * +_PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + PyObject *result; + + assert(func != NULL); + assert(PyCFunction_Check(func)); + + result = _PyMethodDef_RawFastCallDict(((PyCFunctionObject*)func)->m_ml, + PyCFunction_GET_SELF(func), + args, nargs, kwargs); + result = _Py_CheckFunctionResult(func, result, NULL); + return result; +} + +PyObject * +_PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject **args, + Py_ssize_t nargs, PyObject *kwnames) +{ + /* _PyMethodDef_RawFastCallKeywords() 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()); + + assert(method != NULL); + assert(nargs >= 0); + assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); + /* kwnames must only contains str strings, no subclass, and all keys must + be unique */ + + PyCFunction meth = method->ml_meth; + int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames); + PyObject *result = NULL; + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + switch (flags) + { + case METH_NOARGS: + if (nargs != 0) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + method->ml_name, nargs); + goto exit; + } + + if (nkwargs) { + goto no_keyword_error; + } + + result = (*meth) (self, NULL); + break; + + case METH_O: + if (nargs != 1) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%zd given)", + method->ml_name, nargs); + goto exit; + } + + if (nkwargs) { + goto no_keyword_error; + } + + result = (*meth) (self, args[0]); + break; + + case METH_FASTCALL: + /* Fast-path: avoid temporary dict to pass keyword arguments */ + result = ((_PyCFunctionFast)meth) (self, args, nargs, kwnames); + break; + + case METH_VARARGS: + case METH_VARARGS | METH_KEYWORDS: + { + /* Slow-path: create a temporary tuple for positional arguments + and a temporary dict for keyword arguments */ + PyObject *argtuple; + + if (!(flags & METH_KEYWORDS) && nkwargs) { + goto no_keyword_error; + } + + argtuple = _PyStack_AsTuple(args, nargs); + if (argtuple == NULL) { + goto exit; + } + + if (flags & METH_KEYWORDS) { + PyObject *kwdict; + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(args + nargs, kwnames); + if (kwdict == NULL) { + Py_DECREF(argtuple); + goto exit; + } + } + else { + kwdict = NULL; + } + + result = (*(PyCFunctionWithKeywords)meth) (self, argtuple, kwdict); + Py_XDECREF(kwdict); + } + else { + result = (*meth) (self, argtuple); + } + Py_DECREF(argtuple); + break; + } + + default: + PyErr_SetString(PyExc_SystemError, + "Bad call flags in _PyCFunction_FastCallKeywords. " + "METH_OLDARGS is no longer supported!"); + goto exit; + } + + goto exit; + +no_keyword_error: + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", + method->ml_name); + +exit: + Py_LeaveRecursiveCall(); + return result; +} + +PyObject * +_PyCFunction_FastCallKeywords(PyObject *func, PyObject **args, + Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *result; + + assert(func != NULL); + assert(PyCFunction_Check(func)); + + result = _PyMethodDef_RawFastCallKeywords(((PyCFunctionObject*)func)->m_ml, + PyCFunction_GET_SELF(func), + args, nargs, kwnames); + result = _Py_CheckFunctionResult(func, result, NULL); + return result; +} + /* Methods (the standard built-in methods, that is) */ static void diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index c18c174..6b23d8e 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -294,10 +294,9 @@ - + - diff --git a/Python/ceval.c b/Python/ceval.c index 66fd361..5800779 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -37,6 +37,7 @@ typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *); /* Forward declarations */ Py_LOCAL_INLINE(PyObject *) call_function(PyObject ***, Py_ssize_t, PyObject *); +static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, PyObject *); static PyObject * do_call_core(PyObject *, PyObject *, PyObject *); #ifdef LLTRACE @@ -3894,7 +3895,7 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount, PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust the test in the if statements in Misc/gdbinit (pystack and pystackv). */ -PyObject * +static PyObject * _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals, PyObject **args, Py_ssize_t argcount, PyObject **kwnames, PyObject **kwargs, @@ -4731,6 +4732,39 @@ PyEval_MergeCompilerFlags(PyCompilerFlags *cf) } +/* External interface to call any callable object. + The arg must be a tuple or NULL. The kw must be a dict or NULL. */ + +PyObject * +PyEval_CallObjectWithKeywords(PyObject *callable, + PyObject *args, PyObject *kwargs) +{ +#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()); +#endif + + if (args == NULL) { + return _PyObject_FastCallDict(callable, NULL, 0, kwargs); + } + + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, + "argument list must be a tuple"); + return NULL; + } + + if (kwargs != NULL && !PyDict_Check(kwargs)) { + PyErr_SetString(PyExc_TypeError, + "keyword list must be a dictionary"); + return NULL; + } + + return PyObject_Call(callable, args, kwargs); +} + const char * PyEval_GetFuncName(PyObject *func) { @@ -4831,7 +4865,7 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames) } if (PyFunction_Check(func)) { - x = _PyFunction_FastCallKeywords(func, stack, nargs, kwnames); + x = fast_function(func, stack, nargs, kwnames); } else { x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames); @@ -4841,7 +4875,10 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames) assert((x != NULL) ^ (PyErr_Occurred() != NULL)); - /* Clear the stack of the function object. */ + /* Clear the stack of the function object. Also removes + the arguments in case they weren't consumed already + (fast_function() and err_args() leave them on the stack). + */ while ((*pp_stack) > pfunc) { w = EXT_POP(*pp_stack); Py_DECREF(w); @@ -4850,6 +4887,205 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames) return x; } +/* The fast_function() function optimize calls for which no argument + tuple is necessary; the objects are passed directly from the stack. + For the simplest case -- a function that takes only positional + arguments and is called with only positional arguments -- it + inlines the most primitive frame setup code from + PyEval_EvalCodeEx(), which vastly reduces the checks that must be + done before evaluating the frame. +*/ + +static PyObject* _Py_HOT_FUNCTION +_PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, + PyObject *globals) +{ + PyFrameObject *f; + PyThreadState *tstate = PyThreadState_GET(); + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + + 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. + */ + assert(tstate != NULL); + f = _PyFrame_New_NoTrack(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + + fastlocals = f->f_localsplus; + + for (i = 0; i < nargs; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(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; +} + +static PyObject * +fast_function(PyObject *func, PyObject **stack, + Py_ssize_t nargs, PyObject *kwnames) +{ + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *kwdefs, *closure, *name, *qualname; + PyObject **d; + Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + Py_ssize_t nd; + + assert(PyFunction_Check(func)); + assert(nargs >= 0); + assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); + assert((nargs == 0 && nkwargs == 0) || stack != NULL); + /* kwnames must only contains str strings, no subclass, and all keys must + be unique */ + + if (co->co_kwonlyargcount == 0 && nkwargs == 0 && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) + { + if (argdefs == NULL && co->co_argcount == nargs) { + return _PyFunction_FastCall(co, stack, nargs, globals); + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + stack = &PyTuple_GET_ITEM(argdefs, 0); + return _PyFunction_FastCall(co, stack, Py_SIZE(argdefs), globals); + } + } + + kwdefs = PyFunction_GET_KW_DEFAULTS(func); + closure = PyFunction_GET_CLOSURE(func); + name = ((PyFunctionObject *)func) -> func_name; + qualname = ((PyFunctionObject *)func) -> func_qualname; + + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } + return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL, + stack, nargs, + nkwargs ? &PyTuple_GET_ITEM(kwnames, 0) : NULL, + stack + nargs, + nkwargs, 1, + d, (int)nd, kwdefs, + closure, name, qualname); +} + +PyObject * +_PyFunction_FastCallKeywords(PyObject *func, PyObject **stack, + Py_ssize_t nargs, PyObject *kwnames) +{ + return fast_function(func, stack, nargs, kwnames); +} + +PyObject * +_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *kwdefs, *closure, *name, *qualname; + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd, nk; + PyObject *result; + + assert(func != NULL); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + assert(kwargs == NULL || PyDict_Check(kwargs)); + + if (co->co_kwonlyargcount == 0 && + (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) + { + /* Fast paths */ + if (argdefs == NULL && co->co_argcount == nargs) { + return _PyFunction_FastCall(co, args, nargs, globals); + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + return _PyFunction_FastCall(co, args, Py_SIZE(argdefs), globals); + } + } + + nk = (kwargs != NULL) ? PyDict_GET_SIZE(kwargs) : 0; + if (nk != 0) { + Py_ssize_t pos, i; + + /* Issue #29318: Caller and callee functions must not share the + dictionary: kwargs must be copied. */ + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + return NULL; + } + + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + /* We must hold strong references because keyword arguments can be + indirectly modified while the function is called: + see issue #2016 and test_extcall */ + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + + kwdefs = PyFunction_GET_KW_DEFAULTS(func); + closure = PyFunction_GET_CLOSURE(func); + name = ((PyFunctionObject *)func) -> func_name; + qualname = ((PyFunctionObject *)func) -> func_qualname; + + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } + + result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL, + args, nargs, + k, k + 1, nk, 2, + d, nd, kwdefs, + closure, name, qualname); + Py_XDECREF(kwtuple); + return result; +} + static PyObject * do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict) { diff --git a/Python/modsupport.c b/Python/modsupport.c index 9637191..e9e025b 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -586,6 +586,57 @@ va_build_stack(PyObject **small_stack, Py_ssize_t small_stack_len, } +PyObject * +PyEval_CallFunction(PyObject *callable, const char *format, ...) +{ + va_list vargs; + PyObject *args; + PyObject *res; + + va_start(vargs, format); + + args = Py_VaBuildValue(format, vargs); + va_end(vargs); + + if (args == NULL) + return NULL; + + res = PyEval_CallObject(callable, args); + Py_DECREF(args); + + return res; +} + + +PyObject * +PyEval_CallMethod(PyObject *obj, const char *name, const char *format, ...) +{ + va_list vargs; + PyObject *meth; + PyObject *args; + PyObject *res; + + meth = PyObject_GetAttrString(obj, name); + if (meth == NULL) + return NULL; + + va_start(vargs, format); + + args = Py_VaBuildValue(format, vargs); + va_end(vargs); + + if (args == NULL) { + Py_DECREF(meth); + return NULL; + } + + res = PyEval_CallObject(meth, args); + Py_DECREF(meth); + Py_DECREF(args); + + return res; +} + int PyModule_AddObject(PyObject *m, const char *name, PyObject *o) { -- cgit v0.12