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 */