diff -r 496e094f4734 Include/abstract.h --- a/Include/abstract.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/abstract.h Thu Apr 21 10:53:10 2016 +0200 @@ -266,6 +266,10 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx PyAPI_FUNC(PyObject *) PyObject_Call(PyObject *callable_object, PyObject *args, PyObject *kw); + PyAPI_FUNC(PyObject *) _PyObject_CallStack(PyObject *callable_object, + PyObject **stack, + int na, int nk); + #ifndef Py_LIMITED_API PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *func, PyObject *result, diff -r 496e094f4734 Include/funcobject.h --- a/Include/funcobject.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/funcobject.h Thu Apr 21 10:53:10 2016 +0200 @@ -58,6 +58,12 @@ PyAPI_FUNC(int) PyFunction_SetClosure(Py PyAPI_FUNC(PyObject *) PyFunction_GetAnnotations(PyObject *); PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyFunction_FastCallStack( + PyObject *func, + PyObject **stack, + int na, + int nk); + /* Macros for direct access to these values. Type checks are *not* done, so use with care. */ #define PyFunction_GET_CODE(func) \ diff -r 496e094f4734 Objects/abstract.c --- a/Objects/abstract.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/abstract.c Thu Apr 21 10:53:10 2016 +0200 @@ -2174,6 +2174,75 @@ PyObject_Call(PyObject *func, PyObject * return _Py_CheckFunctionResult(func, result, NULL); } +PyObject * +_PyObject_CallStack(PyObject *callable_object, + PyObject **stack, int na, int nk) +{ + PyObject *args, *kwargs, *res; + Py_ssize_t i; + + assert(callable_object != NULL); + if (na < 0 || nk < 0 || stack == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + if (PyFunction_Check(callable_object)) { + return _PyFunction_FastCallStack(callable_object, stack, na, nk); + } + + if (PyCFunction_Check(callable_object)) { + PyCFunctionObject *func = (PyCFunctionObject*)callable_object; + if ((PyCFunction_GET_FLAGS(func) & METH_O) + && na == 1 + && nk == 0) + { + PyObject *self = PyCFunction_GET_SELF(func); + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *arg = stack[0]; + return (*meth)(self, arg); + } + } + + args = PyTuple_New(na); + if (args == NULL) + return NULL; + + for (i=0; i < na; i++) { + PyObject *item = stack[i]; + + Py_INCREF(item); + PyTuple_SET_ITEM(args, i, item); + } + + if (nk > 0) { + kwargs = PyDict_New(); + if (kwargs == NULL) { + Py_DECREF(args); + return NULL; + } + + for (i=0; i < nk; i++) { + PyObject *key = stack[na + i*2]; + PyObject *value = stack[na + i*2 + 1]; + + if (PyDict_SetItem(kwargs, key, value) < 0) { + Py_DECREF(args); + Py_DECREF(kwargs); + return NULL; + } + } + } + else { + kwargs = NULL; + } + + res = PyObject_Call(callable_object, args, kwargs); + Py_DECREF(args); + Py_XDECREF(kwargs); + return res; +} + static PyObject* call_function_tail(PyObject *callable, PyObject *args) { diff -r 496e094f4734 Objects/descrobject.c --- a/Objects/descrobject.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/descrobject.c Thu Apr 21 10:53:10 2016 +0200 @@ -1372,10 +1372,8 @@ property_dealloc(PyObject *self) static PyObject * property_descr_get(PyObject *self, PyObject *obj, PyObject *type) { - static PyObject * volatile cached_args = NULL; - PyObject *args; - PyObject *ret; propertyobject *gs = (propertyobject *)self; + PyObject *stack[1]; if (obj == NULL || obj == Py_None) { Py_INCREF(self); @@ -1385,29 +1383,9 @@ property_descr_get(PyObject *self, PyObj PyErr_SetString(PyExc_AttributeError, "unreadable attribute"); return NULL; } - args = cached_args; - if (!args || Py_REFCNT(args) != 1) { - Py_CLEAR(cached_args); - if (!(cached_args = args = PyTuple_New(1))) - return NULL; - } - Py_INCREF(args); - assert (Py_REFCNT(args) == 2); - Py_INCREF(obj); - PyTuple_SET_ITEM(args, 0, obj); - ret = PyObject_Call(gs->prop_get, args, NULL); - if (args == cached_args) { - if (Py_REFCNT(args) == 2) { - obj = PyTuple_GET_ITEM(args, 0); - PyTuple_SET_ITEM(args, 0, NULL); - Py_XDECREF(obj); - } - else { - Py_CLEAR(cached_args); - } - } - Py_DECREF(args); - return ret; + + stack[0] = obj; + return _PyObject_CallStack(gs->prop_get, stack, 1, 0); } static int diff -r 496e094f4734 Python/ceval.c --- a/Python/ceval.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Python/ceval.c Thu Apr 21 10:53:10 2016 +0200 @@ -113,7 +113,6 @@ static PyObject * call_function(PyObject #else static PyObject * call_function(PyObject ***, int); #endif -static PyObject * fast_function(PyObject *, PyObject ***, int, int, int); static PyObject * do_call(PyObject *, PyObject ***, int, int); static PyObject * ext_do_call(PyObject *, PyObject ***, int, int, int); static PyObject * update_keyword_args(PyObject *, int, PyObject ***, @@ -4691,8 +4690,7 @@ call_function(PyObject ***pp_stack, int { int na = oparg & 0xff; int nk = (oparg>>8) & 0xff; - int n = na + 2 * nk; - PyObject **pfunc = (*pp_stack) - n - 1; + PyObject **pfunc = (*pp_stack) - (na + 2 * nk) - 1; PyObject *func = *pfunc; PyObject *x, *w; @@ -4749,14 +4747,17 @@ call_function(PyObject ***pp_stack, int Py_INCREF(func); Py_SETREF(*pfunc, self); na++; - n++; } else Py_INCREF(func); READ_TIMESTAMP(*pintr0); - if (PyFunction_Check(func)) - x = fast_function(func, pp_stack, n, na, nk); - else + if (PyFunction_Check(func)) { + x = _PyFunction_FastCallStack(func, + *pp_stack - (na + 2 * nk), + na, nk); + } + else { x = do_call(func, pp_stack, na, nk); + } READ_TIMESTAMP(*pintr1); Py_DECREF(func); @@ -4765,7 +4766,7 @@ call_function(PyObject ***pp_stack, int /* Clear the stack of the function object. Also removes the arguments in case they weren't consumed already - (fast_function() and err_args() leave them on the stack). + (_PyFunction_FastCallStack() and err_args() leave them on the stack). */ while ((*pp_stack) > pfunc) { w = EXT_POP(*pp_stack); @@ -4777,7 +4778,7 @@ call_function(PyObject ***pp_stack, int return x; } -/* The fast_function() function optimize calls for which no argument +/* The _PyFunction_FastCallStack() function optimize calls for which no argument tuple is necessary; the objects are passed directly from the stack. For the simplest case -- a function that takes only positional arguments and is called with only positional arguments -- it @@ -4786,9 +4787,10 @@ call_function(PyObject ***pp_stack, int done before evaluating the frame. */ -static PyObject * -fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) +PyObject * +_PyFunction_FastCallStack(PyObject *func, PyObject **stack, int na, int nk) { + const int n = na + 2 * nk; PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); PyObject *globals = PyFunction_GET_GLOBALS(func); PyObject *argdefs = PyFunction_GET_DEFAULTS(func); @@ -4798,6 +4800,10 @@ fast_function(PyObject *func, PyObject * PyObject **d = NULL; int nd = 0; + assert(PyFunction_Check(func)); + assert(na >= 0); + assert(nk >= 0); + PCALL(PCALL_FUNCTION); PCALL(PCALL_FAST_FUNCTION); if (argdefs == NULL && co->co_argcount == n && @@ -4806,7 +4812,7 @@ fast_function(PyObject *func, PyObject * PyFrameObject *f; PyObject *retval = NULL; PyThreadState *tstate = PyThreadState_GET(); - PyObject **fastlocals, **stack; + PyObject **fastlocals; int i; PCALL(PCALL_FASTER_FUNCTION); @@ -4821,7 +4827,6 @@ fast_function(PyObject *func, PyObject * return NULL; fastlocals = f->f_localsplus; - stack = (*pp_stack) - n; for (i = 0; i < n; i++) { Py_INCREF(*stack); @@ -4838,8 +4843,8 @@ fast_function(PyObject *func, PyObject * nd = Py_SIZE(argdefs); } return _PyEval_EvalCodeWithName((PyObject*)co, globals, - (PyObject *)NULL, (*pp_stack)-n, na, - (*pp_stack)-2*nk, nk, d, nd, kwdefs, + (PyObject *)NULL, stack, na, + stack + na, nk, d, nd, kwdefs, PyFunction_GET_CLOSURE(func), name, qualname); }