diff -r 71876e4abce4 Include/abstract.h --- a/Include/abstract.h Thu Dec 15 12:40:53 2016 +0100 +++ b/Include/abstract.h Thu Dec 15 14:47:36 2016 +0100 @@ -312,7 +312,7 @@ PyAPI_FUNC(PyObject **) _PyStack_UnpackD overflow. The size is also chosen to allow using the small stack for most function calls of the Python standard library. On 64-bit CPU, it allocates 40 bytes on the stack. */ -#define _PY_FASTCALL_SMALL_STACK 5 +#define _PY_FASTCALL_SMALL_STACK 3 /* Call the callable object 'callable' with the "fast call" calling convention: args is a C array for positional arguments (nargs is the number of diff -r 71876e4abce4 Objects/abstract.c --- a/Objects/abstract.c Thu Dec 15 12:40:53 2016 +0100 +++ b/Objects/abstract.c Thu Dec 15 14:47:36 2016 +0100 @@ -2701,21 +2701,62 @@ PyObject * return retval; } -PyObject * -_PyObject_VaCallFunctionObjArgs(PyObject *callable, va_list vargs) +static PyObject* +#if defined(_MSC_VER) +__declspec(noinline) +#elif defined(__GNUC__) || defined(__clang__) +__attribute__((noinline)) +#endif +_PyObject_VaCallFunctionObjArgs_Stack(PyObject *callable, va_list vargs, + Py_ssize_t nargs) { - PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; + PyObject *stack[_PY_FASTCALL_SMALL_STACK]; + Py_ssize_t i; + + assert(1 <= nargs); /* _PyObject_CallNoArg() should be used for 0 arg */ + assert((size_t)nargs <= Py_ARRAY_LENGTH(stack)); + + for (i = 0; i < nargs; ++i) { + stack[i] = va_arg(vargs, PyObject *); + } + + return _PyObject_FastCall(callable, stack, nargs); +} + +static PyObject* +#if defined(_MSC_VER) +__declspec(noinline) +#elif defined(__GNUC__) || defined(__clang__) +__attribute__((noinline)) +#endif +_PyObject_VaCallFunctionObjArgs_Heap(PyObject *callable, va_list vargs, + Py_ssize_t nargs) +{ PyObject **stack; - Py_ssize_t nargs; + Py_ssize_t i; PyObject *result; - Py_ssize_t i; + + 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 *); + } + + result = _PyObject_FastCall(callable, stack, nargs); + PyMem_Free(stack); + return result; +} + +static Py_ssize_t +count_vargs(va_list vargs) +{ va_list countva; - - if (callable == NULL) { - return null_error(); - } - - /* Count the number of arguments */ + Py_ssize_t nargs; + va_copy(countva, vargs); nargs = 0; while (1) { @@ -2727,29 +2768,35 @@ PyObject * } va_end(countva); - /* Copy arguments */ - if (nargs <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { - stack = small_stack; + return nargs; +} + +Py_LOCAL_INLINE(PyObject *) +object_vacall(PyObject *callable, va_list vargs) +{ + Py_ssize_t nargs; + + if (callable == NULL) { + return null_error(); + } + + nargs = count_vargs(vargs); + + if (nargs == 0) { + return _PyObject_CallNoArg(callable); + } + else if (nargs <= _PY_FASTCALL_SMALL_STACK) { + return _PyObject_VaCallFunctionObjArgs_Stack(callable, vargs, nargs); } else { - stack = PyMem_Malloc(nargs * sizeof(stack[0])); - if (stack == NULL) { - PyErr_NoMemory(); - return NULL; - } + return _PyObject_VaCallFunctionObjArgs_Heap(callable, vargs, nargs); } - - 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_VaCallFunctionObjArgs(PyObject *callable, va_list vargs) +{ + return object_vacall(callable, vargs); } PyObject * @@ -2768,7 +2815,7 @@ PyObject_CallMethodObjArgs(PyObject *cal } va_start(vargs, name); - result = _PyObject_VaCallFunctionObjArgs(callable, vargs); + result = object_vacall(callable, vargs); va_end(vargs); Py_DECREF(callable); @@ -2792,7 +2839,7 @@ PyObject * } va_start(vargs, name); - result = _PyObject_VaCallFunctionObjArgs(callable, vargs); + result = object_vacall(callable, vargs); va_end(vargs); Py_DECREF(callable); @@ -2806,7 +2853,7 @@ PyObject_CallFunctionObjArgs(PyObject *c PyObject *result; va_start(vargs, callable); - result = _PyObject_VaCallFunctionObjArgs(callable, vargs); + result = object_vacall(callable, vargs); va_end(vargs); return result;