diff -r 31342913fb1e Objects/abstract.c --- a/Objects/abstract.c Thu Feb 09 02:01:37 2017 +0100 +++ b/Objects/abstract.c Thu Feb 09 21:17:13 2017 +0900 @@ -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 31342913fb1e Objects/typeobject.c --- a/Objects/typeobject.c Thu Feb 09 02:01:37 2017 +0100 +++ b/Objects/typeobject.c Thu Feb 09 21:17:13 2017 +0900 @@ -1439,22 +1439,48 @@ PyObject * instead of PyObject_GetAttrString(). This uses the same convention as lookup_method to cache the interned name string object. */ +extern PyObject* +_PyObject_FastCall_Prepend( + PyObject *callable, + PyObject *obj, + PyObject **args, + Py_ssize_t nargs); + static PyObject * call_method(PyObject *obj, _Py_Identifier *name, PyObject **args, Py_ssize_t nargs) { - PyObject *func, *retval; - - func = lookup_maybe(obj, name); - if (func == NULL) { - if (!PyErr_Occurred()) - PyErr_SetObject(PyExc_AttributeError, name->object); + PyObject *descr = _PyType_LookupId(Py_TYPE(obj), name); + if (descr == NULL) { + PyErr_SetObject(PyExc_AttributeError, name->object); return NULL; } - retval = _PyObject_FastCall(func, args, nargs); + // Fast path for calling Python method. + // Calling special method implemented in Python is most common use case + // of call_method(). + if (PyFunction_Check(descr)) { + return _PyObject_FastCall_Prepend(descr, obj, args, nargs); + } + + PyObject *func; + descrgetfunc f = Py_TYPE(descr)->tp_descr_get; + + if (f == NULL) { + Py_INCREF(descr); + func = descr; + } + else { + func = f(descr, obj, (PyObject *)(Py_TYPE(obj))); + if (func == NULL) { + if (!PyErr_Occurred()) + PyErr_SetObject(PyExc_AttributeError, name->object); + return NULL; + } + } + + PyObject *retval = _PyObject_FastCall(func, args, nargs); Py_DECREF(func); - return retval; }