diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2016-09-09 19:36:44 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2016-09-09 19:36:44 (GMT) |
commit | d8735720955557d8056bc1fca41ad1c3b48aa63c (patch) | |
tree | 87c04970bcbbd4ff7fd9b3c4ff5f138d98b7dc1e /Objects | |
parent | 84f6a8f725c0f7a06d5e77b283d6028bf854443c (diff) | |
download | cpython-d8735720955557d8056bc1fca41ad1c3b48aa63c.zip cpython-d8735720955557d8056bc1fca41ad1c3b48aa63c.tar.gz cpython-d8735720955557d8056bc1fca41ad1c3b48aa63c.tar.bz2 |
Add _PyObject_FastCallKeywords()
Issue #27830: Add _PyObject_FastCallKeywords(): avoid the creation of a
temporary dictionary for keyword arguments.
Other changes:
* Cleanup call_function() and fast_function() (ex: rename nk to nkwargs)
* Remove now useless do_call(), replaced with _PyObject_FastCallKeywords()
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/abstract.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index d876dc5..508fd82 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2366,6 +2366,74 @@ _PyObject_Call_Prepend(PyObject *func, return result; } +static PyObject * +_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, + PyObject *func) +{ + PyObject *kwdict; + Py_ssize_t i; + + kwdict = PyDict_New(); + if (kwdict == NULL) { + return NULL; + } + + for (i=0; i < nkwargs; i++) { + int err; + PyObject *key = PyTuple_GET_ITEM(kwnames, i); + PyObject *value = *values++; + + if (PyDict_GetItem(kwdict, key) != NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s%s got multiple values " + "for keyword argument '%U'", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + key); + Py_DECREF(kwdict); + return NULL; + } + + err = PyDict_SetItem(kwdict, key, value); + if (err) { + Py_DECREF(kwdict); + return NULL; + } + } + return kwdict; +} + +PyObject * +_PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, + PyObject *kwnames) +{ + PyObject *kwdict, *result; + Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + + assert(nargs >= 0); + assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); + assert((nargs == 0 && nkwargs == 0) || stack != NULL); + + if (PyFunction_Check(func)) { + /* Fast-path: avoid temporary tuple or dict */ + return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames); + } + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); + if (kwdict == NULL) { + return NULL; + } + } + else { + kwdict = NULL; + } + + result = _PyObject_FastCallDict(func, stack, nargs, kwdict); + Py_XDECREF(kwdict); + return result; +} + static PyObject* call_function_tail(PyObject *callable, PyObject *args) { |