diff -r e06af4027546 Include/abstract.h --- a/Include/abstract.h Mon Feb 06 07:15:57 2017 -0800 +++ b/Include/abstract.h Tue Feb 07 02:09:45 2017 +0100 @@ -209,6 +209,11 @@ PyAPI_FUNC(int) _PyStack_UnpackDict( 40 bytes on the stack. */ #define _PY_FASTCALL_SMALL_STACK 5 +PyAPI_FUNC(PyObject *) _PyObject_FastCall( + PyObject *callable, + PyObject **stack, + Py_ssize_t nargs); + /* Call the callable object 'callable' with the "fast call" calling convention: args is a C array for positional arguments (nargs is the number of positional arguments), kwargs is a dictionary for keyword arguments. @@ -245,11 +250,8 @@ PyAPI_FUNC(PyObject *) _PyObject_FastCal Py_ssize_t nargs, PyObject *kwnames); -#define _PyObject_FastCall(func, args, nargs) \ - _PyObject_FastCallDict((func), (args), (nargs), NULL) - #define _PyObject_CallNoArg(func) \ - _PyObject_FastCallDict((func), NULL, 0, NULL) + _PyObject_FastCall((func), NULL, 0) PyAPI_FUNC(PyObject *) _PyObject_Call_Prepend( PyObject *callable, diff -r e06af4027546 Include/ceval.h --- a/Include/ceval.h Mon Feb 06 07:15:57 2017 -0800 +++ b/Include/ceval.h Tue Feb 07 02:09:45 2017 +0100 @@ -13,8 +13,7 @@ PyAPI_FUNC(PyObject *) PyEval_CallObject PyObject *kwargs); /* Inline this */ -#define PyEval_CallObject(callable, arg) \ - PyEval_CallObjectWithKeywords(callable, arg, (PyObject *)NULL) +#define PyEval_CallObject(callable, args) PyObject_CallObject(callable, args) PyAPI_FUNC(PyObject *) PyEval_CallFunction(PyObject *callable, const char *format, ...); diff -r e06af4027546 Include/funcobject.h --- a/Include/funcobject.h Mon Feb 06 07:15:57 2017 -0800 +++ b/Include/funcobject.h Tue Feb 07 02:09:45 2017 +0100 @@ -59,6 +59,11 @@ PyAPI_FUNC(PyObject *) PyFunction_GetAnn PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *); #ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) _PyFunction_FastCall( + PyObject *func, + PyObject **args, + Py_ssize_t nargs); + PyAPI_FUNC(PyObject *) _PyFunction_FastCallDict( PyObject *func, PyObject **args, diff -r e06af4027546 Include/methodobject.h --- a/Include/methodobject.h Mon Feb 06 07:15:57 2017 -0800 +++ b/Include/methodobject.h Tue Feb 07 02:09:45 2017 +0100 @@ -40,6 +40,11 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyO PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *); #ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyCFunction_FastCall( + PyObject *func, + PyObject **args, + Py_ssize_t nargs); + PyAPI_FUNC(PyObject *) _PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, diff -r e06af4027546 Objects/abstract.c --- a/Objects/abstract.c Mon Feb 06 07:15:57 2017 -0800 +++ b/Objects/abstract.c Tue Feb 07 02:09:45 2017 +0100 @@ -2175,7 +2175,24 @@ PyMapping_Values(PyObject *o) PyObject * PyObject_CallObject(PyObject *callable, PyObject *args) { - return PyEval_CallObjectWithKeywords(callable, args, NULL); +#ifdef Py_DEBUG + /* PyObject_CallObject() 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_CallNoArg(callable); + } + + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, + "argument list must be a tuple"); + return NULL; + } + + return PyObject_Call(callable, args, NULL); } PyObject* @@ -2226,34 +2243,65 @@ PyObject* return result; } -PyObject * -PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) +/* Disable inlining to reduce the stack consumption */ +static PyObject* _Py_NO_INLINE +object_fastcall_slow(PyObject *callable, PyObject **stack, Py_ssize_t nargs) { + /* Slow-path: build a temporary tuple for positional arguments */ + ternaryfunc call; + PyObject *argtuple; PyObject *result; - /* PyObject_Call() must not be called with an exception set, + result = NULL; + assert(nargs == 0 || stack != NULL); + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + call = callable->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + callable->ob_type->tp_name); + goto exit; + } + + argtuple = _PyStack_AsTuple(stack, nargs); + if (argtuple == NULL) { + goto exit; + } + + result = (*call)(callable, argtuple, NULL); + Py_DECREF(argtuple); + + result = _Py_CheckFunctionResult(callable, result, NULL); + +exit: + Py_LeaveRecursiveCall(); + return result; +} + +/* This function is inlined manually in _PyObject_FastCallDict() and + _PyObject_FastCallKeywords() to reduce the stack consumption and for best + performances, since these functions are performance critical. */ +PyObject * +_PyObject_FastCall(PyObject *callable, PyObject **args, Py_ssize_t nargs) +{ + /* _PyObject_FastCall() 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)); - - 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 (PyFunction_Check(callable)) { + return _PyFunction_FastCall(callable, args, nargs); } - - if (Py_EnterRecursiveCall(" while calling a Python object")) - return NULL; - - result = (*call)(callable, args, kwargs); - - Py_LeaveRecursiveCall(); - - return _Py_CheckFunctionResult(callable, result, NULL); + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCall(callable, args, nargs); + } + else { + return object_fastcall_slow(callable, args, nargs); + } } /* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their @@ -2301,11 +2349,38 @@ PyObject* return args; } +static PyObject * _Py_NO_INLINE +object_fastcalldict_slow(PyObject *callable, PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + ternaryfunc call; + PyObject *tuple; + PyObject *result; + + /* 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; + } + + tuple = _PyStack_AsTuple(args, nargs); + if (tuple == NULL) { + return NULL; + } + + result = (*call)(callable, tuple, kwargs); + Py_DECREF(tuple); + + result = _Py_CheckFunctionResult(callable, result, NULL); + return result; +} + PyObject * _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { - ternaryfunc call; PyObject *result = NULL; /* _PyObject_FastCallDict() must not be called with an exception set, @@ -2318,42 +2393,88 @@ PyObject * assert(nargs == 0 || args != NULL); assert(kwargs == NULL || PyDict_Check(kwargs)); - if (Py_EnterRecursiveCall(" while calling a Python object")) { - return NULL; - } - - if (PyFunction_Check(callable)) { - result = _PyFunction_FastCallDict(callable, args, nargs, kwargs); - } - else if (PyCFunction_Check(callable)) { - result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs); + if (kwargs == NULL) { + if (PyFunction_Check(callable)) { + return _PyFunction_FastCall(callable, args, nargs); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCall(callable, args, nargs); + } + else { + return object_fastcall_slow(callable, args, nargs); + } } else { - PyObject *tuple; - - /* 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); - goto exit; + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; } - tuple = _PyStack_AsTuple(args, nargs); - if (tuple == NULL) { - goto exit; + if (PyFunction_Check(callable)) { + result = _PyFunction_FastCallDict(callable, args, nargs, kwargs); } - - result = (*call)(callable, tuple, kwargs); - Py_DECREF(tuple); - - result = _Py_CheckFunctionResult(callable, result, NULL); + else if (PyCFunction_Check(callable)) { + result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs); + } + else { + result = object_fastcalldict_slow(callable, args, nargs, kwargs); + } + + Py_LeaveRecursiveCall(); + + return result; } - -exit: - Py_LeaveRecursiveCall(); - - return result; +} + +PyObject * +PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) +{ + PyObject **stack; + Py_ssize_t nargs; + + /* 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(args != NULL); + assert(PyTuple_Check(args)); + assert(kwargs == NULL || PyDict_Check(kwargs)); + + stack = &PyTuple_GET_ITEM(args, 0); + nargs = PyTuple_GET_SIZE(args); + + if (kwargs == NULL) { + if (PyFunction_Check(callable)) { + return _PyFunction_FastCall(callable, stack, nargs); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCall(callable, stack, nargs); + } + else { + return object_fastcall_slow(callable, stack, nargs); + } + } + else { + PyObject *result; + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + if (PyFunction_Check(callable)) { + result = _PyFunction_FastCallDict(callable, stack, nargs, kwargs); + } + else if (PyCFunction_Check(callable)) { + result = _PyCFunction_FastCallDict(callable, stack, nargs, kwargs); + } + else { + result = object_fastcalldict_slow(callable, stack, nargs, kwargs); + } + + Py_LeaveRecursiveCall(); + + return result; + } } /* Positional arguments are obj followed by args: @@ -2479,8 +2600,63 @@ int return 0; } +/* Disable inlining to reduce the stack consumption */ +static PyObject * _Py_NO_INLINE +object_fastcallkw_slow(PyObject *callable, PyObject **stack, Py_ssize_t nargs, + PyObject *kwnames) +{ + /* Slow-path: build a temporary tuple for positional arguments and a + temporary dictionary for keyword arguments (if any) */ + + ternaryfunc call; + PyObject *argtuple; + PyObject *kwdict, *result; + Py_ssize_t nkwargs; + + result = NULL; + nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + assert((nargs == 0 && nkwargs == 0) || stack != NULL); + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + call = callable->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + callable->ob_type->tp_name); + goto exit; + } + + argtuple = _PyStack_AsTuple(stack, nargs); + if (argtuple == NULL) { + goto exit; + } + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(stack + nargs, kwnames); + if (kwdict == NULL) { + Py_DECREF(argtuple); + goto exit; + } + } + else { + kwdict = NULL; + } + + result = (*call)(callable, argtuple, kwdict); + Py_DECREF(argtuple); + Py_XDECREF(kwdict); + + result = _Py_CheckFunctionResult(callable, result, NULL); + +exit: + Py_LeaveRecursiveCall(); + return result; +} + PyObject * -_PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t nargs, +_PyObject_FastCallKeywords(PyObject *callable, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { /* _PyObject_FastCallKeywords() must not be called with an exception set, @@ -2491,71 +2667,37 @@ PyObject * 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); + if (kwnames == NULL) { + if (PyFunction_Check(callable)) { + return _PyFunction_FastCall(callable, args, nargs); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCall(callable, args, nargs); + } + else { + return object_fastcall_slow(callable, args, nargs); + } } else { - /* Slow-path: build a temporary tuple for positional arguments and a - temporary dictionary for keyword arguments (if any) */ - - ternaryfunc call; - PyObject *argtuple; - PyObject *kwdict, *result; - Py_ssize_t nkwargs; - - result = NULL; - nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); - - if (Py_EnterRecursiveCall(" while calling a Python object")) { - return NULL; + /* 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, args, nargs, kwnames); } - - call = callable->ob_type->tp_call; - if (call == NULL) { - PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - callable->ob_type->tp_name); - goto exit; - } - - argtuple = _PyStack_AsTuple(stack, nargs); - if (argtuple == NULL) { - goto exit; - } - - if (nkwargs > 0) { - kwdict = _PyStack_AsDict(stack + nargs, kwnames); - if (kwdict == NULL) { - Py_DECREF(argtuple); - goto exit; - } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCallKeywords(callable, args, nargs, kwnames); } else { - kwdict = NULL; + return object_fastcallkw_slow(callable, args, nargs, kwnames); } - - result = (*call)(callable, argtuple, kwdict); - Py_DECREF(argtuple); - Py_XDECREF(kwdict); - - result = _Py_CheckFunctionResult(callable, result, NULL); - - exit: - Py_LeaveRecursiveCall(); - return result; } } static PyObject * _PyObject_CallFunctionVa(PyObject *callable, const char *format, - va_list va, int is_size_t) + va_list vargs, int is_size_t) { PyObject* small_stack[_PY_FASTCALL_SMALL_STACK]; const Py_ssize_t small_stack_len = Py_ARRAY_LENGTH(small_stack); @@ -2567,15 +2709,15 @@ static PyObject * return null_error(); } - if (!format || !*format) { + if (!format || !format[0]) { return _PyObject_CallNoArg(callable); } if (is_size_t) { - stack = _Py_VaBuildStack(small_stack, small_stack_len, format, va, &nargs); + stack = _Py_VaBuildStack(small_stack, small_stack_len, format, vargs, &nargs); } else { - stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, format, va, &nargs); + stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, format, vargs, &nargs); } if (stack == NULL) { return NULL; @@ -2586,10 +2728,9 @@ static PyObject * - 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)); + &PyTuple_GET_ITEM(stack[0], 0), + PyTuple_GET_SIZE(stack[0])); } else { result = _PyObject_FastCall(callable, stack, nargs); @@ -2607,12 +2748,25 @@ static PyObject * PyObject * PyObject_CallFunction(PyObject *callable, const char *format, ...) { - va_list va; + va_list vargs; PyObject *result; - va_start(va, format); - result = _PyObject_CallFunctionVa(callable, format, va, 0); - va_end(va); + va_start(vargs, format); + result = _PyObject_CallFunctionVa(callable, format, vargs, 0); + va_end(vargs); + + return result; +} + +PyObject * +PyEval_CallFunction(PyObject *callable, const char *format, ...) +{ + va_list vargs; + PyObject *result; + + va_start(vargs, format); + result = _PyObject_CallFunctionVa(callable, format, vargs, 0); + va_end(vargs); return result; } @@ -2620,18 +2774,18 @@ PyObject_CallFunction(PyObject *callable PyObject * _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) { - va_list va; + va_list vargs; PyObject *result; - va_start(va, format); - result = _PyObject_CallFunctionVa(callable, format, va, 1); - va_end(va); + va_start(vargs, format); + result = _PyObject_CallFunctionVa(callable, format, vargs, 1); + va_end(vargs); return result; } static PyObject* -callmethod(PyObject* callable, const char *format, va_list va, int is_size_t) +callmethod(PyObject* callable, const char *format, va_list vargs, int is_size_t) { assert(callable != NULL); @@ -2640,13 +2794,13 @@ callmethod(PyObject* callable, const cha return NULL; } - return _PyObject_CallFunctionVa(callable, format, va, is_size_t); + return _PyObject_CallFunctionVa(callable, format, vargs, is_size_t); } PyObject * PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) { - va_list va; + va_list vargs; PyObject *callable, *retval; if (obj == NULL || name == NULL) { @@ -2657,9 +2811,9 @@ PyObject_CallMethod(PyObject *obj, const if (callable == NULL) return NULL; - va_start(va, format); - retval = callmethod(callable, format, va, 0); - va_end(va); + va_start(vargs, format); + retval = callmethod(callable, format, vargs, 0); + va_end(vargs); Py_DECREF(callable); return retval; @@ -2669,7 +2823,7 @@ PyObject * _PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, const char *format, ...) { - va_list va; + va_list vargs; PyObject *callable, *retval; if (obj == NULL || name == NULL) { @@ -2680,9 +2834,9 @@ PyObject * if (callable == NULL) return NULL; - va_start(va, format); - retval = callmethod(callable, format, va, 0); - va_end(va); + va_start(vargs, format); + retval = callmethod(callable, format, vargs, 0); + va_end(vargs); Py_DECREF(callable); return retval; @@ -2692,7 +2846,7 @@ PyObject * _PyObject_CallMethod_SizeT(PyObject *obj, const char *name, const char *format, ...) { - va_list va; + va_list vargs; PyObject *callable, *retval; if (obj == NULL || name == NULL) { @@ -2703,9 +2857,9 @@ PyObject * if (callable == NULL) return NULL; - va_start(va, format); - retval = callmethod(callable, format, va, 1); - va_end(va); + va_start(vargs, format); + retval = callmethod(callable, format, vargs, 1); + va_end(vargs); Py_DECREF(callable); return retval; @@ -2715,7 +2869,7 @@ PyObject * _PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, const char *format, ...) { - va_list va; + va_list vargs; PyObject *callable, *retval; if (obj == NULL || name == NULL) { @@ -2727,14 +2881,32 @@ PyObject * return NULL; } - va_start(va, format); - retval = callmethod(callable, format, va, 1); - va_end(va); + va_start(vargs, format); + retval = callmethod(callable, format, vargs, 1); + va_end(vargs); Py_DECREF(callable); return retval; } +PyObject * +PyEval_CallMethod(PyObject *obj, const char *name, const char *format, ...) +{ + va_list vargs; + PyObject *callable, *result; + + callable = PyObject_GetAttrString(obj, name); + if (callable == NULL) + return NULL; + + va_start(vargs, format); + result = callmethod(callable, format, vargs, 0); + va_end(vargs); + + Py_DECREF(callable); + return result; +} + static PyObject * object_vacall(PyObject *callable, va_list vargs) { diff -r e06af4027546 Objects/methodobject.c --- a/Objects/methodobject.c Mon Feb 06 07:15:57 2017 -0800 +++ b/Objects/methodobject.c Tue Feb 07 02:09:45 2017 +0100 @@ -87,6 +87,83 @@ PyCFunction_Call(PyObject *func, PyObjec } PyObject * +_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs) +{ + /* _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(func != NULL); + assert(PyCFunction_Check(func)); + + assert(nargs >= 0); + + PyMethodDef *method = ((PyCFunctionObject*)func)->m_ml; + PyCFunction meth = method->ml_meth; + PyObject *self = PyCFunction_GET_SELF(func); + int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + PyObject *result; + + switch (flags) + { + case METH_NOARGS: + if (nargs != 0) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + method->ml_name, nargs); + return NULL; + } + + 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); + return NULL; + } + + result = (*meth) (self, args[0]); + break; + + case METH_FASTCALL: + result = ((_PyCFunctionFast)meth) (self, args, nargs, NULL); + break; + + case METH_VARARGS: + case METH_VARARGS | METH_KEYWORDS: + { + /* Slow-path: create a temporary tuple for positional arguments */ + PyObject *argtuple = _PyStack_AsTuple(args, nargs); + if (argtuple == NULL) { + return NULL; + } + + if (flags & METH_KEYWORDS) { + result = (*(PyCFunctionWithKeywords)meth) (self, argtuple, NULL); + } + 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!"); + return NULL; + } + + result = _Py_CheckFunctionResult(func, result, NULL); + return result; +} + +PyObject * _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { diff -r e06af4027546 Python/ceval.c --- a/Python/ceval.c Mon Feb 06 07:15:57 2017 -0800 +++ b/Python/ceval.c Tue Feb 07 02:09:45 2017 +0100 @@ -4747,7 +4747,12 @@ PyEval_CallObjectWithKeywords(PyObject * #endif if (args == NULL) { - return _PyObject_FastCallDict(callable, NULL, 0, kwargs); + if (kwargs == NULL) { + return _PyObject_CallNoArg(callable); + } + else { + return _PyObject_FastCallDict(callable, NULL, 0, kwargs); + } } if (!PyTuple_Check(args)) { @@ -4897,8 +4902,8 @@ call_function(PyObject ***pp_stack, Py_s */ static PyObject* _Py_HOT_FUNCTION -_PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, - PyObject *globals) +function_fastcall_impl(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, + PyObject *globals) { PyFrameObject *f; PyThreadState *tstate = PyThreadState_GET(); @@ -4937,6 +4942,55 @@ static PyObject* _Py_HOT_FUNCTION return result; } +PyObject* +_PyFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs) +{ + 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 nd; + + assert(PyFunction_Check(func)); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + + if (co->co_kwonlyargcount == 0 && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) + { + if (argdefs == NULL && co->co_argcount == nargs) { + return function_fastcall_impl(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_fastcall_impl(co, args, 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, + args, nargs, + NULL, NULL, 0, 0, + d, (int)nd, kwdefs, + closure, name, qualname); +} + static PyObject * fast_function(PyObject *func, PyObject **stack, Py_ssize_t nargs, PyObject *kwnames) @@ -4960,14 +5014,14 @@ fast_function(PyObject *func, PyObject * co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { if (argdefs == NULL && co->co_argcount == nargs) { - return _PyFunction_FastCall(co, stack, nargs, globals); + return function_fastcall_impl(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); + return function_fastcall_impl(co, stack, Py_SIZE(argdefs), globals); } } @@ -5024,14 +5078,14 @@ PyObject * { /* Fast paths */ if (argdefs == NULL && co->co_argcount == nargs) { - return _PyFunction_FastCall(co, args, nargs, globals); + return function_fastcall_impl(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); + return function_fastcall_impl(co, args, Py_SIZE(argdefs), globals); } } diff -r e06af4027546 Python/modsupport.c --- a/Python/modsupport.c Mon Feb 06 07:15:57 2017 -0800 +++ b/Python/modsupport.c Tue Feb 07 02:09:45 2017 +0100 @@ -586,57 +586,6 @@ va_build_stack(PyObject **small_stack, P } -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) {