diff -r 496e094f4734 -r 62fc65734b57 Include/abstract.h --- a/Include/abstract.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/abstract.h Thu Apr 21 16:32:06 2016 +0200 @@ -266,6 +266,12 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx PyAPI_FUNC(PyObject *) PyObject_Call(PyObject *callable_object, PyObject *args, PyObject *kw); + PyAPI_FUNC(PyObject *) _PyObject_FastCall(PyObject *callable_object, + PyObject **stack, + int na, int nk); + + PyAPI_FUNC(PyObject *) PyObject_CallNoArg(PyObject *callable_object); + #ifndef Py_LIMITED_API PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *func, PyObject *result, diff -r 496e094f4734 -r 62fc65734b57 Include/funcobject.h --- a/Include/funcobject.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/funcobject.h Thu Apr 21 16:32:06 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 -r 62fc65734b57 Include/modsupport.h --- a/Include/modsupport.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/modsupport.h Thu Apr 21 16:32:06 2016 +0200 @@ -44,6 +44,10 @@ PyAPI_FUNC(int) PyArg_VaParseTupleAndKey #endif PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list); +PyAPI_FUNC(PyObject**) Py_VaBuildStack(const char *format, va_list va, int *p_na); +PyAPI_FUNC(PyObject **) _Py_VaBuildStack_SizeT(const char *, va_list, int *); +PyAPI_FUNC(void) _Py_FreeStack(PyObject **stack, int na); + PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *); PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long); PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char *); diff -r 496e094f4734 -r 62fc65734b57 Include/object.h --- a/Include/object.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/object.h Thu Apr 21 16:32:06 2016 +0200 @@ -421,6 +421,8 @@ typedef struct _typeobject { destructor tp_finalize; + PyObject* (*tp_fastcall) (PyObject *self, PyObject **stack, int na, int nk); + #ifdef COUNT_ALLOCS /* these must be last and never explicitly initialized */ Py_ssize_t tp_allocs; diff -r 496e094f4734 -r 62fc65734b57 Lib/test/test_sys.py --- a/Lib/test/test_sys.py Thu Apr 21 00:23:08 2016 -0700 +++ b/Lib/test/test_sys.py Thu Apr 21 16:32:06 2016 +0200 @@ -1083,9 +1083,9 @@ class SizeofTest(unittest.TestCase): check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject - s = vsize('P2n15Pl4Pn9Pn11PIP') + s = vsize('P2n15Pl4Pn9Pn11PIPP') check(int, s) - s = vsize('P2n15Pl4Pn9Pn11PIP' # PyTypeObject + s = vsize('P2n15Pl4Pn9Pn11PIPP' # PyTypeObject '3P' # PyAsyncMethods '36P' # PyNumberMethods '3P' # PyMappingMethods diff -r 496e094f4734 -r 62fc65734b57 Modules/_operator.c --- a/Modules/_operator.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Modules/_operator.c Thu Apr 21 16:32:06 2016 +0200 @@ -455,13 +455,17 @@ itemgetter_traverse(itemgetterobject *ig } static PyObject * -itemgetter_call(itemgetterobject *ig, PyObject *args, PyObject *kw) +itemgetter_fastcall(PyObject *self, PyObject **stack, int na, int nk) { + itemgetterobject *ig = (itemgetterobject *)self; PyObject *obj, *result; Py_ssize_t i, nitems=ig->nitems; - if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &obj)) + if (na != 1 ||nk != 0) { + PyErr_SetNone(PyExc_TypeError); return NULL; + } + obj = stack[0]; if (nitems == 1) return PyObject_GetItem(obj, ig->item); @@ -486,6 +490,17 @@ itemgetter_call(itemgetterobject *ig, Py } static PyObject * +itemgetter_call(PyObject *self, PyObject *args, PyObject *kw) +{ + PyObject *obj; + + if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &obj)) + return NULL; + return itemgetter_fastcall(self, &obj, 1, 0); +} + + +static PyObject * itemgetter_repr(itemgetterobject *ig) { PyObject *repr; @@ -568,6 +583,16 @@ static PyTypeObject itemgetter_type = { 0, /* tp_alloc */ itemgetter_new, /* tp_new */ 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + itemgetter_fastcall, /* tp_fastcall */ }; diff -r 496e094f4734 -r 62fc65734b57 Objects/abstract.c --- a/Objects/abstract.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/abstract.c Thu Apr 21 16:32:06 2016 +0200 @@ -2174,101 +2174,199 @@ PyObject_Call(PyObject *func, PyObject * return _Py_CheckFunctionResult(func, result, NULL); } -static PyObject* -call_function_tail(PyObject *callable, PyObject *args) +PyObject * +_PyObject_FastCall(PyObject *func, PyObject **stack, int na, int nk) { - PyObject *retval; - + PyObject* (*fastcall) (PyObject *self, PyObject **stack, int na, int nk); + PyObject *args, *kwargs, *res; + Py_ssize_t i; + + assert(func != NULL); + if (na < 0 || nk < 0 || stack == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + fastcall = Py_TYPE(func)->tp_fastcall; + if (fastcall != NULL) { + return fastcall(func, stack, na, nk); + } + + if (PyFunction_Check(func)) { + /* FIXME: accept to pass NULL as stack? */ + return _PyFunction_FastCallStack(func, stack, na, nk); + } + + if (PyCFunction_Check(func)) { + PyCFunctionObject *cfunc = (PyCFunctionObject*)func; + int flags; + + flags = PyCFunction_GET_FLAGS(cfunc) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + + switch (flags) + { + case METH_NOARGS: + if (na == 0 && nk == 0) { + PyObject *self = PyCFunction_GET_SELF(cfunc); + PyCFunction meth = PyCFunction_GET_FUNCTION(cfunc); + return (*meth)(self, NULL); + } + break; + + case METH_O: + if (na == 1 && nk == 0) { + PyObject *self = PyCFunction_GET_SELF(cfunc); + PyCFunction meth = PyCFunction_GET_FUNCTION(cfunc); + PyObject *arg = stack[0]; + return (*meth)(self, arg); + } + break; + + default: + break; + } + } + + /* Slow-path: build a temporary tuple and maybe also a temporary dict */ + + args = PyTuple_New(na); if (args == NULL) return NULL; - if (!PyTuple_Check(args)) { - PyObject *a; - - a = PyTuple_New(1); - if (a == 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; } - PyTuple_SET_ITEM(a, 0, args); - args = a; + + for (i=0; i < nk; i++) { + PyObject *key = stack[na + i*2]; + PyObject *value = stack[na + i*2 + 1]; + + /* FIXME: reuse update_keyword_args() of ceval.c */ + if (PyDict_SetItem(kwargs, key, value) < 0) { + Py_DECREF(args); + Py_DECREF(kwargs); + return NULL; + } + } } - retval = PyObject_Call(callable, args, NULL); - + else { + kwargs = NULL; + } + + res = PyObject_Call(func, args, kwargs); Py_DECREF(args); - - return retval; + Py_XDECREF(kwargs); + return res; +} + +PyObject * +PyObject_CallNoArg(PyObject *func) +{ + /* FIXME: avoid this unused stack variable and allow NULL as stack */ + PyObject *stack[1]; + return _PyObject_FastCall(func, stack, 0, 0); } PyObject * PyObject_CallFunction(PyObject *callable, const char *format, ...) { va_list va; - PyObject *args; - - if (callable == NULL) + PyObject **stack; + int na; + PyObject *result; + + if (callable == NULL) { return null_error(); - - if (format && *format) { - va_start(va, format); - args = Py_VaBuildValue(format, va); - va_end(va); } - else - args = PyTuple_New(0); - if (args == NULL) + + if (!format || *format == '\0') { + return PyObject_CallNoArg(callable); + } + + va_start(va, format); + stack = Py_VaBuildStack(format, va, &na); + va_end(va); + + if (stack == NULL) { return NULL; - - return call_function_tail(callable, args); + } + + result = _PyObject_FastCall(callable, stack, na, 0); + _Py_FreeStack(stack, na); + return result; } PyObject * _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) { va_list va; - PyObject *args; + PyObject **stack; + int na; + PyObject *result; if (callable == NULL) return null_error(); - if (format && *format) { - va_start(va, format); - args = _Py_VaBuildValue_SizeT(format, va); - va_end(va); + if (!format || *format == '\0') { + return PyObject_CallNoArg(callable); } - else - args = PyTuple_New(0); - - return call_function_tail(callable, args); + + va_start(va, format); + stack = _Py_VaBuildStack_SizeT(format, va, &na); + va_end(va); + + if (stack == NULL) { + return NULL; + } + + result = _PyObject_FastCall(callable, stack, na, 0); + _Py_FreeStack(stack, na); + return result; } static PyObject* callmethod(PyObject* func, const char *format, va_list va, int is_size_t) { - PyObject *retval = NULL; - PyObject *args; + PyObject **stack; + int na; + PyObject *result; if (!PyCallable_Check(func)) { type_error("attribute of type '%.200s' is not callable", func); - goto exit; + Py_DECREF(func); + return NULL; } - if (format && *format) { - if (is_size_t) - args = _Py_VaBuildValue_SizeT(format, va); - else - args = Py_VaBuildValue(format, va); + if (!format || *format == '\0') { + result = PyObject_CallNoArg(func); + Py_DECREF(func); + return result; } - else - args = PyTuple_New(0); - - retval = call_function_tail(func, args); - - exit: - /* args gets consumed in call_function_tail */ - Py_XDECREF(func); - - return retval; + + if (is_size_t) { + stack = _Py_VaBuildStack_SizeT(format, va, &na); + } + else { + stack = Py_VaBuildStack(format, va, &na); + } + if (stack == NULL) { + return NULL; + } + + result = _PyObject_FastCall(func, stack, na, 0); + Py_DECREF(func); + _Py_FreeStack(stack, na); + return result; } PyObject * @@ -2353,104 +2451,130 @@ PyObject * return retval; } -static PyObject * -objargs_mktuple(va_list va) +Py_LOCAL_INLINE(Py_ssize_t) +objargs_count(va_list va) { - int i, n = 0; + Py_ssize_t na; va_list countva; - PyObject *result, *tmp; - - Py_VA_COPY(countva, va); - - while (((PyObject *)va_arg(countva, PyObject *)) != NULL) - ++n; - result = PyTuple_New(n); - if (result != NULL && n > 0) { - for (i = 0; i < n; ++i) { - tmp = (PyObject *)va_arg(va, PyObject *); - PyTuple_SET_ITEM(result, i, tmp); - Py_INCREF(tmp); - } + PyObject *obj; + + Py_VA_COPY(countva, va); + + na = 0; + while (1) { + obj = (PyObject *)va_arg(countva, PyObject *); + if (obj == NULL) + break; + na++; } - return result; + return na; +} + +Py_LOCAL_INLINE(void) +objargs_fill_stack(va_list va, int na, PyObject **stack) +{ + Py_ssize_t i; + PyObject *obj; + + for (i = 0; i < na; ++i) { + obj = (PyObject *)va_arg(va, PyObject *); + /* FIXME: does it matter to keep a strong reference? */ + Py_INCREF(obj); + stack[i] = obj; + } +} + +static void +objargs_clear_stack(PyObject **stack, int na) +{ + int i; + + for (i=0; i < na; i++) { + Py_DECREF(stack[i]); + } } PyObject * PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) { - PyObject *args, *tmp; + PyObject *func; va_list vargs; + Py_ssize_t na; + PyObject **stack; + PyObject *result; if (callable == NULL || name == NULL) return null_error(); - callable = PyObject_GetAttr(callable, name); - if (callable == NULL) + func = PyObject_GetAttr(callable, name); + if (func == NULL) { return NULL; + } /* count the args */ va_start(vargs, name); - args = objargs_mktuple(vargs); + na = objargs_count(vargs); + stack = alloca(sizeof(stack[0]) * na); + objargs_fill_stack(vargs, na, stack); va_end(vargs); - if (args == NULL) { - Py_DECREF(callable); - return NULL; - } - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); - Py_DECREF(callable); - - return tmp; + + result = _PyObject_FastCall(func, stack, na, 0); + Py_DECREF(func); + objargs_clear_stack(stack, na); + return result; } PyObject * _PyObject_CallMethodIdObjArgs(PyObject *callable, struct _Py_Identifier *name, ...) { - PyObject *args, *tmp; + PyObject *func; va_list vargs; + Py_ssize_t na; + PyObject **stack; + PyObject *result; if (callable == NULL || name == NULL) return null_error(); - callable = _PyObject_GetAttrId(callable, name); - if (callable == NULL) - return NULL; - - /* count the args */ - va_start(vargs, name); - args = objargs_mktuple(vargs); - va_end(vargs); - if (args == NULL) { - Py_DECREF(callable); + func = _PyObject_GetAttrId(callable, name); + if (func == NULL) { return NULL; } - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); - Py_DECREF(callable); - - return tmp; + + va_start(vargs, name); + na = objargs_count(vargs); + stack = alloca(sizeof(stack[0]) * na); + objargs_fill_stack(vargs, na, stack); + va_end(vargs); + + result = _PyObject_FastCall(func, stack, na, 0); + Py_DECREF(func); + objargs_clear_stack(stack, na); + return result; } PyObject * PyObject_CallFunctionObjArgs(PyObject *callable, ...) { - PyObject *args, *tmp; va_list vargs; - - if (callable == NULL) + Py_ssize_t na; + PyObject **stack; + PyObject *result; + + if (callable == NULL) { return null_error(); - - /* count the args */ + } + va_start(vargs, callable); - args = objargs_mktuple(vargs); + na = objargs_count(vargs); + stack = alloca(sizeof(stack[0]) * na); + objargs_fill_stack(vargs, na, stack); va_end(vargs); - if (args == NULL) - return NULL; - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); - - return tmp; + + result = _PyObject_FastCall(callable, stack, na, 0); + objargs_clear_stack(stack, na); + return result; } diff -r 496e094f4734 -r 62fc65734b57 Objects/descrobject.c --- a/Objects/descrobject.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/descrobject.c Thu Apr 21 16:32:06 2016 +0200 @@ -1372,9 +1372,6 @@ 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; if (obj == NULL || obj == Py_None) { @@ -1385,29 +1382,8 @@ 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; + + return _PyObject_FastCall(gs->prop_get, &obj, 1, 0); } static int diff -r 496e094f4734 -r 62fc65734b57 Python/ceval.c --- a/Python/ceval.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Python/ceval.c Thu Apr 21 16:32:06 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 ***, @@ -3044,7 +3043,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int Py_DECREF(mgr); if (enter == NULL) goto error; - res = PyObject_CallFunctionObjArgs(enter, NULL); + res = PyObject_CallNoArg(enter); Py_DECREF(enter); if (res == NULL) goto error; @@ -3075,7 +3074,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int Py_DECREF(mgr); if (enter == NULL) goto error; - res = PyObject_CallFunctionObjArgs(enter, NULL); + res = PyObject_CallNoArg(enter); Py_DECREF(enter); if (res == NULL) goto error; @@ -3114,6 +3113,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int gotos should still be resumed.) */ + PyObject *arg_stack[3]; PyObject *exit_func; PyObject *exc = TOP(), *val = Py_None, *tb = Py_None, *res; if (exc == Py_None) { @@ -3159,8 +3159,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int assert(block->b_type == EXCEPT_HANDLER); block->b_level--; } - /* XXX Not the fastest way to call it... */ - res = PyObject_CallFunctionObjArgs(exit_func, exc, val, tb, NULL); + arg_stack[0] = exc; + arg_stack[1] = val; + arg_stack[2] = tb; + res = _PyObject_FastCall(exit_func, arg_stack, 3, 0); Py_DECREF(exit_func); if (res == NULL) goto error; @@ -4034,7 +4036,8 @@ static PyObject * if (is_coro && coro_wrapper != NULL) { PyObject *wrapped; tstate->in_coroutine_wrapper = 1; - wrapped = PyObject_CallFunction(coro_wrapper, "N", gen); + wrapped = _PyObject_FastCall(coro_wrapper, &gen, 1, 0); + Py_DECREF(gen); tstate->in_coroutine_wrapper = 0; return wrapped; } @@ -4169,7 +4172,7 @@ do_raise(PyObject *exc, PyObject *cause) if (PyExceptionClass_Check(exc)) { type = exc; - value = PyObject_CallObject(exc, NULL); + value = PyObject_CallNoArg(exc); if (value == NULL) goto raise_error; if (!PyExceptionInstance_Check(value)) { @@ -4197,7 +4200,7 @@ do_raise(PyObject *exc, PyObject *cause) if (cause) { PyObject *fixed_cause; if (PyExceptionClass_Check(cause)) { - fixed_cause = PyObject_CallObject(cause, NULL); + fixed_cause = PyObject_CallNoArg(cause); if (fixed_cause == NULL) goto raise_error; Py_DECREF(cause); @@ -4585,17 +4588,23 @@ PyEval_CallObjectWithKeywords(PyObject * #endif if (arg == NULL) { + if (kw == NULL) { + return PyObject_CallNoArg(func); + } + arg = PyTuple_New(0); - if (arg == NULL) + if (arg == NULL) { return NULL; + } } else if (!PyTuple_Check(arg)) { PyErr_SetString(PyExc_TypeError, "argument list must be a tuple"); return NULL; } - else + else { Py_INCREF(arg); + } if (kw != NULL && !PyDict_Check(kw)) { PyErr_SetString(PyExc_TypeError, @@ -4691,8 +4700,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 +4757,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 +4776,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 +4788,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 +4797,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 +4810,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 +4822,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 +4837,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 +4853,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); } diff -r 496e094f4734 -r 62fc65734b57 Python/modsupport.c --- a/Python/modsupport.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Python/modsupport.c Thu Apr 21 16:32:06 2016 +0200 @@ -148,6 +148,75 @@ do_mklist(const char **p_format, va_list return v; } +void +_Py_FreeStack(PyObject **stack, int na) +{ + int i; + + for (i=0; i < na; i++) { + Py_DECREF(stack[i]); + } + PyMem_Free(stack); +} + + +static PyObject ** +do_mkstack(const char **p_format, va_list *p_va, int endchar, int n, int flags) +{ + PyObject **stack; + int i; + int itemfailed = 0; + if (n < 0) + return NULL; + if (n != 0) { + stack = PyMem_Malloc(n * sizeof(stack[0])); + } + else { + /* FIXME: fast-path for n=0 and/or n=1? */ + stack = PyMem_Malloc(1 * sizeof(stack[0])); + } + if (stack == NULL) { + PyErr_NoMemory(); + return NULL; + } + + /* Note that we can't bail immediately on error as this will leak + refcounts on any 'N' arguments. */ + for (i = 0; i < n; i++) { + PyObject *w; + + if (itemfailed) { + PyObject *exception, *value, *tb; + PyErr_Fetch(&exception, &value, &tb); + w = do_mkvalue(p_format, p_va, flags); + PyErr_Restore(exception, value, tb); + } + else { + w = do_mkvalue(p_format, p_va, flags); + } + if (w == NULL) { + itemfailed = 1; + Py_INCREF(Py_None); + w = Py_None; + } + stack[i] = w; + } + if (itemfailed) { + /* do_mkvalue() should have already set an error */ + _Py_FreeStack(stack, n); + return NULL; + } + if (**p_format != endchar) { + _Py_FreeStack(stack, n); + PyErr_SetString(PyExc_SystemError, + "Unmatched paren in format"); + return NULL; + } + if (endchar) + ++*p_format; + return stack; +} + static PyObject * do_mktuple(const char **p_format, va_list *p_va, int endchar, int n, int flags) { @@ -445,6 +514,129 @@ PyObject * return va_build_value(format, va, FLAG_SIZE_T); } +static const char* +format_strip_parenthesis(const char *format, char **p_copy) +{ + size_t len; + char *copy; + + *p_copy = NULL; + + /* FIXME: pass a flag to Py_VaBuildStack? */ + if (format[0] != '(') { + return format; + } + + len = strlen(format); + if (format[len-1] != ')') { + return format; + } + + /* Replace "(OO)" with "OO" */ + copy = PyMem_Malloc(len - 2 + 1); + if (copy == NULL) { + PyErr_NoMemory(); + return NULL; + } + Py_MEMCPY(copy, format + 1, len - 2); + copy[len-2] = '\0'; + + *p_copy = copy; + return copy; +} + +PyObject** +tuple_to_stack(PyObject *tuple, int *na) +{ + Py_ssize_t len = PyTuple_GET_SIZE(tuple); + Py_ssize_t i; + PyObject **stack; + + if (len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "too many parameters"); + return NULL; + } + + stack = PyMem_Malloc(len * sizeof(stack[0])); + if (stack == NULL) { + PyErr_NoMemory(); + return NULL; + } + + for (i=0; i < len; i++) { + PyObject *obj = PyTuple_GET_ITEM(tuple, i); + Py_INCREF(obj); + stack[i] = obj; + } + /* overflow tested below */ + *na = (int)len; + return stack; +} + +PyObject** +va_build_stack(const char *format, va_list va, int flags, int *p_na) +{ + const char *f; + int n; + va_list lva; + char *copy; + int stripped; + PyObject **stack; + + f = format_strip_parenthesis(format, ©); + if (f == NULL) { + return NULL; + } + stripped = (copy != NULL); + + n = countformat(f, '\0'); + + Py_VA_COPY(lva, va); + + if (n < 0) { + PyMem_Free(copy); + return NULL; + } + + stack = do_mkstack(&f, &lva, '\0', n, flags); + PyMem_Free(copy); + + if (stack == NULL) { + return NULL; + } + + /* if format isn't "(...)" and stack only contains one object which is a + tuple: unpack the tuple to a new stack */ + if (n == 1 && !stripped && PyTuple_Check(stack[0])) { + PyObject **stack2; + int n2; + + stack2 = tuple_to_stack(stack[0], &n2); + _Py_FreeStack(stack, n); + if (stack2 == NULL) { + return NULL; + } + + stack = stack2; + n = n2; + } + + *p_na = n; + return stack; +} + +PyObject** +Py_VaBuildStack(const char *format, va_list va, int *p_na) +{ + return va_build_stack(format, va, 0, p_na); +} + +PyObject** +_Py_VaBuildStack_SizeT(const char *format, va_list va, int *p_na) +{ + return va_build_stack(format, va, FLAG_SIZE_T, p_na); +} + static PyObject * va_build_value(const char *format, va_list va, int flags) { @@ -452,7 +644,7 @@ va_build_value(const char *format, va_li int n = countformat(f, '\0'); va_list lva; - Py_VA_COPY(lva, va); + Py_VA_COPY(lva, va); if (n < 0) return NULL;