diff -r be663c9a9e24 Include/abstract.h --- a/Include/abstract.h Thu Feb 09 23:49:50 2017 +0100 +++ b/Include/abstract.h Fri Feb 10 08:23:50 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 be663c9a9e24 Objects/abstract.c --- a/Objects/abstract.c Thu Feb 09 23:49:50 2017 +0100 +++ b/Objects/abstract.c Fri Feb 10 08:23:50 2017 +0900 @@ -2616,10 +2616,10 @@ static PyObject * } if (is_size_t) { - stack = _Py_VaBuildStack(small_stack, small_stack_len, format, va, &nargs); + stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, format, va, &nargs); } else { - stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, format, va, &nargs); + stack = _Py_VaBuildStack(small_stack, small_stack_len, format, va, &nargs); } if (stack == NULL) { return NULL; @@ -2687,6 +2687,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, ...) { @@ -2697,6 +2723,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; @@ -2720,6 +2753,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; @@ -2743,6 +2780,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; @@ -2766,6 +2810,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; @@ -2780,13 +2828,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) { @@ -2795,7 +2842,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) { @@ -2817,7 +2864,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 *); } @@ -2831,22 +2882,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); @@ -2858,19 +2910,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); @@ -2884,7 +2940,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 be663c9a9e24 Python/ceval.c --- a/Python/ceval.c Thu Feb 09 23:49:50 2017 +0100 +++ b/Python/ceval.c Fri Feb 10 08:23:50 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 */