From 3f1057a4b62d8c94ae77f34f950b74a45499b218 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 25 Aug 2016 01:04:14 +0200 Subject: [PATCH] method_call() and slot_tp_new() now uses fast call Issue #27841: Add _PyObject_Call_Prepend() helper function to prepend an argument to existing arguments to call a function. This helper uses fast calls. Modify method_call() and slot_tp_new() to use _PyObject_Call_Prepend(). --- Include/abstract.h | 4 ++++ Objects/abstract.c | 39 +++++++++++++++++++++++++++++++++++++++ Objects/classobject.c | 29 +++++++---------------------- Objects/typeobject.c | 23 +++++------------------ 4 files changed, 55 insertions(+), 40 deletions(-) diff --git a/Include/abstract.h b/Include/abstract.h index 474d7468e7d..ebad84b30e5 100644 --- a/Include/abstract.h +++ b/Include/abstract.h @@ -309,6 +309,10 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ Py_ssize_t nargs, Py_ssize_t nkwargs); + PyAPI_FUNC(PyObject *) _PyObject_Call_Prepend(PyObject *func, + PyObject *obj, PyObject *args, + PyObject *kwargs); + PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *func, PyObject *result, const char *where); diff --git a/Objects/abstract.c b/Objects/abstract.c index c41fe11e3a1..9e5405df0a9 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2388,6 +2388,45 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, return result; } +/* Positional arguments are obj followed args. */ +PyObject * +_PyObject_Call_Prepend(PyObject *func, + PyObject *obj, PyObject *args, PyObject *kwargs) +{ + PyObject *small_stack[8]; + PyObject **stack; + Py_ssize_t argcount; + PyObject *result; + + assert(PyTuple_Check(args)); + + argcount = PyTuple_GET_SIZE(args); + if (argcount + 1 <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { + stack = small_stack; + } + else { + stack = PyMem_Malloc((argcount + 1) * sizeof(PyObject *)); + if (stack == NULL) { + PyErr_NoMemory(); + return NULL; + } + } + + /* use borrowed references */ + stack[0] = obj; + Py_MEMCPY(&stack[1], + &PyTuple_GET_ITEM(args, 0), + argcount * sizeof(PyObject *)); + + result = _PyObject_FastCallDict(func, + stack, argcount + 1, + kwargs); + if (stack != small_stack) { + PyMem_Free(stack); + } + return result; +} + static PyObject* call_function_tail(PyObject *callable, PyObject *args) { diff --git a/Objects/classobject.c b/Objects/classobject.c index 5e8ac59df25..b0ed0230569 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -302,34 +302,19 @@ method_traverse(PyMethodObject *im, visitproc visit, void *arg) } static PyObject * -method_call(PyObject *func, PyObject *arg, PyObject *kw) +method_call(PyObject *method, PyObject *args, PyObject *kwargs) { - PyObject *self = PyMethod_GET_SELF(func); - PyObject *result; + PyObject *self, *func; - func = PyMethod_GET_FUNCTION(func); + self = PyMethod_GET_SELF(method); if (self == NULL) { PyErr_BadInternalCall(); return NULL; } - else { - Py_ssize_t argcount = PyTuple_Size(arg); - PyObject *newarg = PyTuple_New(argcount + 1); - int i; - if (newarg == NULL) - return NULL; - Py_INCREF(self); - PyTuple_SET_ITEM(newarg, 0, self); - for (i = 0; i < argcount; i++) { - PyObject *v = PyTuple_GET_ITEM(arg, i); - Py_XINCREF(v); - PyTuple_SET_ITEM(newarg, i+1, v); - } - arg = newarg; - } - result = PyObject_Call((PyObject *)func, arg, kw); - Py_DECREF(arg); - return result; + + func = PyMethod_GET_FUNCTION(method); + + return _PyObject_Call_Prepend(func, self, args, kwargs); } static PyObject * diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 63bfd667477..9b3d1533e93 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6356,29 +6356,16 @@ slot_tp_init(PyObject *self, PyObject *args, PyObject *kwds) static PyObject * slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - PyObject *func; - PyObject *newargs, *x; - Py_ssize_t i, n; + PyObject *func, *result; func = _PyObject_GetAttrId((PyObject *)type, &PyId___new__); - if (func == NULL) + if (func == NULL) { return NULL; - assert(PyTuple_Check(args)); - n = PyTuple_GET_SIZE(args); - newargs = PyTuple_New(n+1); - if (newargs == NULL) - return NULL; - Py_INCREF(type); - PyTuple_SET_ITEM(newargs, 0, (PyObject *)type); - for (i = 0; i < n; i++) { - x = PyTuple_GET_ITEM(args, i); - Py_INCREF(x); - PyTuple_SET_ITEM(newargs, i+1, x); } - x = PyObject_Call(func, newargs, kwds); - Py_DECREF(newargs); + + result = _PyObject_Call_Prepend(func, (PyObject *)type, args, kwds); Py_DECREF(func); - return x; + return result; } static void