diff -r e5cd74868dfc Include/abstract.h --- a/Include/abstract.h Fri Feb 10 00:41:06 2017 +0100 +++ b/Include/abstract.h Fri Feb 10 11:47:37 2017 +0900 @@ -311,6 +311,10 @@ PyAPI_FUNC(PyObject *) PyObject_CallMeth PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, const char *format, ...); + +/* Like PyObject_GenericGetAttr(), but may return unbound instance method. */ +PyAPI_FUNC(int) _PyObject_GetMethod(PyObject *obj, PyObject *name, + PyObject **method); #endif /* !Py_LIMITED_API */ PyAPI_FUNC(PyObject *) _PyObject_CallFunction_SizeT(PyObject *callable, diff -r e5cd74868dfc Objects/abstract.c --- a/Objects/abstract.c Fri Feb 10 00:41:06 2017 +0100 +++ b/Objects/abstract.c Fri Feb 10 11:47:37 2017 +0900 @@ -2332,6 +2332,9 @@ PyObject * else if (PyCFunction_Check(callable)) { return _PyCFunction_FastCallDict(callable, args, nargs, kwargs); } + else if (Py_TYPE(callable) == &PyMethodDescr_Type) { + return _PyMethodDescr_FastCallKeywords(callable, args, nargs, kwargs); + } else { PyObject *argstuple, *result; ternaryfunc call; @@ -2689,6 +2692,32 @@ callmethod(PyObject* callable, const cha return _PyObject_CallFunctionVa(callable, format, va, is_size_t); } +// Helper function for PyObject_CallMetho[Id]() when no arguments. +// try to skip temporal method object and argument allocation. +static PyObject* +callmethod_noarg(PyObject *obj, PyObject *name) +{ + if (!name) { // caller can pass _PyUnicode_FromId() directly + return NULL; + } + + PyObject *callable = NULL, *retval; + int unbound = _PyObject_GetMethod(obj, name, &callable); + if (callable == NULL) { + return NULL; + } + + if (unbound) { + retval = _PyObject_FastCall(callable, &obj, 1); + } + else { + retval = _PyObject_CallNoArg(callable); + } + + Py_DECREF(callable); + return retval; +} + PyObject * PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) { @@ -2699,6 +2728,13 @@ PyObject_CallMethod(PyObject *obj, const return null_error(); } + if (!format || !*format) { + PyObject *nameobj = PyUnicode_FromString(name); + retval = callmethod_noarg(obj, nameobj); + Py_XDECREF(nameobj); + return retval; + } + callable = PyObject_GetAttrString(obj, name); if (callable == NULL) return NULL; @@ -2722,6 +2758,10 @@ PyObject * return null_error(); } + if (!format || !*format) { + return callmethod_noarg(obj, _PyUnicode_FromId(name)); + } + callable = _PyObject_GetAttrId(obj, name); if (callable == NULL) return NULL; @@ -2745,6 +2785,13 @@ PyObject * return null_error(); } + if (!format || !*format) { + PyObject *nameobj = PyUnicode_FromString(name); + retval = callmethod_noarg(obj, nameobj); + Py_XDECREF(nameobj); + return retval; + } + callable = PyObject_GetAttrString(obj, name); if (callable == NULL) return NULL; @@ -2768,6 +2815,10 @@ PyObject * return null_error(); } + if (!format || !*format) { + return callmethod_noarg(obj, _PyUnicode_FromId(name)); + } + callable = _PyObject_GetAttrId(obj, name); if (callable == NULL) { return NULL; @@ -2782,13 +2833,12 @@ PyObject * } static PyObject * -object_vacall(PyObject *callable, va_list vargs) +object_vacall(PyObject *callable, PyObject *self, 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) { @@ -2797,7 +2847,7 @@ object_vacall(PyObject *callable, va_lis /* Count the number of arguments */ va_copy(countva, vargs); - nargs = 0; + nargs = (self != NULL); while (1) { PyObject *arg = va_arg(countva, PyObject *); if (arg == NULL) { @@ -2819,7 +2869,11 @@ object_vacall(PyObject *callable, va_lis } } - for (i = 0; i < nargs; ++i) { + Py_ssize_t i = 0; + if (self != NULL) { + stack[i++] = self; + } + for (; i < nargs; ++i) { stack[i] = va_arg(vargs, PyObject *); } @@ -2833,22 +2887,23 @@ object_vacall(PyObject *callable, va_lis } PyObject * -PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) +PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...) { va_list vargs; PyObject *result; - if (callable == NULL || name == NULL) { + if (obj == NULL || name == NULL) { return null_error(); } - callable = PyObject_GetAttr(callable, name); + PyObject *callable = NULL; + int unbound = _PyObject_GetMethod(obj, name, &callable); if (callable == NULL) { return NULL; } va_start(vargs, name); - result = object_vacall(callable, vargs); + result = object_vacall(callable, unbound ? obj : NULL, vargs); va_end(vargs); Py_DECREF(callable); @@ -2860,19 +2915,23 @@ PyObject * struct _Py_Identifier *name, ...) { va_list vargs; - PyObject *callable, *result; + PyObject *callable = NULL, *result; if (obj == NULL || name == NULL) { return null_error(); } - callable = _PyObject_GetAttrId(obj, name); + PyObject *nameobj = _PyUnicode_FromId(name); // borrowed + if (nameobj == NULL) { + return NULL; + } + int unbound = _PyObject_GetMethod( obj, nameobj, &callable); if (callable == NULL) { return NULL; } va_start(vargs, name); - result = object_vacall(callable, vargs); + result = object_vacall(callable, unbound ? obj : NULL, vargs); va_end(vargs); Py_DECREF(callable); @@ -2886,7 +2945,7 @@ PyObject_CallFunctionObjArgs(PyObject *c PyObject *result; va_start(vargs, callable); - result = object_vacall(callable, vargs); + result = object_vacall(callable, NULL, vargs); va_end(vargs); return result; diff -r e5cd74868dfc Python/ceval.c --- a/Python/ceval.c Fri Feb 10 00:41:06 2017 +0100 +++ b/Python/ceval.c Fri Feb 10 11:47:37 2017 +0900 @@ -30,9 +30,6 @@ #define CHECKEXC 1 /* Double-check exception checking */ #endif -/* Private API for the LOAD_METHOD opcode. */ -extern int _PyObject_GetMethod(PyObject *, PyObject *, PyObject **); - typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *); /* Forward declarations */