diff -r f507545ad22a Include/abstract.h --- a/Include/abstract.h Wed Feb 08 15:49:10 2017 +0100 +++ b/Include/abstract.h Thu Feb 09 00:58:13 2017 +0100 @@ -257,6 +257,12 @@ PyAPI_FUNC(PyObject *) _PyObject_Call_Pr PyObject *args, PyObject *kwargs); +PyAPI_FUNC(PyObject *) _PyObject_FastCall_Prepend( + PyObject *callable, + PyObject *obj, + PyObject **args, + Py_ssize_t nargs); + PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where); diff -r f507545ad22a Include/classobject.h --- a/Include/classobject.h Wed Feb 08 15:49:10 2017 +0100 +++ b/Include/classobject.h Thu Feb 09 00:58:13 2017 +0100 @@ -25,6 +25,11 @@ PyAPI_FUNC(PyObject *) PyMethod_New(PyOb PyAPI_FUNC(PyObject *) PyMethod_Function(PyObject *); PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *); +PyAPI_FUNC(PyObject *) _PyMethod_FastCall( + PyObject *method, + PyObject **args, + Py_ssize_t nargs); + /* Macros for direct access to these values. Type checks are *not* done, so use with care. */ #define PyMethod_GET_FUNCTION(meth) \ diff -r f507545ad22a Objects/abstract.c --- a/Objects/abstract.c Wed Feb 08 15:49:10 2017 +0100 +++ b/Objects/abstract.c Thu Feb 09 00:58:13 2017 +0100 @@ -2367,6 +2367,41 @@ PyObject * /* 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) { diff -r f507545ad22a Objects/classobject.c --- a/Objects/classobject.c Wed Feb 08 15:49:10 2017 +0100 +++ b/Objects/classobject.c Thu Feb 09 00:58:13 2017 +0100 @@ -317,6 +317,22 @@ method_call(PyObject *method, PyObject * return _PyObject_Call_Prepend(func, self, args, kwargs); } +PyObject * +_PyMethod_FastCall(PyObject *method, PyObject **args, Py_ssize_t nargs) +{ + PyObject *self, *func; + + self = PyMethod_GET_SELF(method); + if (self == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + func = PyMethod_GET_FUNCTION(method); + + return _PyObject_FastCall_Prepend(func, self, args, nargs); +} + static PyObject * method_descr_get(PyObject *meth, PyObject *obj, PyObject *cls) { diff -r f507545ad22a Objects/typeobject.c --- a/Objects/typeobject.c Wed Feb 08 15:49:10 2017 +0100 +++ b/Objects/typeobject.c Thu Feb 09 00:58:13 2017 +0100 @@ -1443,7 +1443,7 @@ static PyObject * call_method(PyObject *obj, _Py_Identifier *name, PyObject **args, Py_ssize_t nargs) { - PyObject *func, *retval; + PyObject *func, *result; func = lookup_maybe(obj, name); if (func == NULL) { @@ -1452,10 +1452,15 @@ call_method(PyObject *obj, _Py_Identifie return NULL; } - retval = _PyObject_FastCall(func, args, nargs); + if (Py_TYPE(func) == &PyMethod_Type) { + result = _PyMethod_FastCall(func, args, nargs); + } + else { + result = _PyObject_FastCall(func, args, nargs); + } Py_DECREF(func); - return retval; + return result; } /* Clone of call_method() that returns NotImplemented when the lookup fails. */