Skip to content

Commit b900939

Browse files
committed
_PyFunction_FastCallDict() supports keyword args
Issue python#27809: * Rename _PyFunction_FastCall() to _PyFunction_FastCallDict() * Rename _PyCFunction_FastCall() to _PyCFunction_FastCallDict() * _PyFunction_FastCallDict() now supports keyword arguments
1 parent 559bb6a commit b900939

5 files changed

Lines changed: 51 additions & 20 deletions

File tree

Include/funcobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ PyAPI_FUNC(PyObject *) PyFunction_GetAnnotations(PyObject *);
5959
PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *);
6060

6161
#ifndef Py_LIMITED_API
62-
PyAPI_FUNC(PyObject *) _PyFunction_FastCall(
62+
PyAPI_FUNC(PyObject *) _PyFunction_FastCallDict(
6363
PyObject *func,
6464
PyObject **args, int nargs,
6565
PyObject *kwargs);

Include/methodobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *);
3838
PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *);
3939

4040
#ifndef Py_LIMITED_API
41-
PyAPI_FUNC(PyObject *) _PyCFunction_FastCall(PyObject *func,
41+
PyAPI_FUNC(PyObject *) _PyCFunction_FastCallDict(PyObject *func,
4242
PyObject **args, int nargs,
4343
PyObject *kwargs);
4444
#endif

Objects/abstract.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2255,7 +2255,8 @@ _PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs)
22552255
}
22562256

22572257
PyObject *
2258-
_PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs)
2258+
_PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs,
2259+
PyObject *kwargs)
22592260
{
22602261
ternaryfunc call;
22612262
PyObject *result = NULL;
@@ -2268,19 +2269,17 @@ _PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwa
22682269
assert(func != NULL);
22692270
assert(nargs >= 0);
22702271
assert(nargs == 0 || args != NULL);
2271-
/* issue #27128: support for keywords will come later:
2272-
_PyFunction_FastCall() doesn't support keyword arguments yet */
2273-
assert(kwargs == NULL);
2272+
assert(kwargs == NULL || PyDict_Check(kwargs));
22742273

22752274
if (Py_EnterRecursiveCall(" while calling a Python object")) {
22762275
return NULL;
22772276
}
22782277

22792278
if (PyFunction_Check(func)) {
2280-
result = _PyFunction_FastCall(func, args, nargs, kwargs);
2279+
result = _PyFunction_FastCallDict(func, args, nargs, kwargs);
22812280
}
22822281
else if (PyCFunction_Check(func)) {
2283-
result = _PyCFunction_FastCall(func, args, nargs, kwargs);
2282+
result = _PyCFunction_FastCallDict(func, args, nargs, kwargs);
22842283
}
22852284
else {
22862285
PyObject *tuple;

Objects/methodobject.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,16 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds)
146146
}
147147

148148
PyObject *
149-
_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, int nargs,
150-
PyObject *kwargs)
149+
_PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, int nargs,
150+
PyObject *kwargs)
151151
{
152152
PyCFunctionObject* func = (PyCFunctionObject*)func_obj;
153153
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
154154
PyObject *self = PyCFunction_GET_SELF(func);
155155
PyObject *result;
156156
int flags;
157157

158-
/* _PyCFunction_FastCall() must not be called with an exception set,
158+
/* _PyCFunction_FastCallDict() must not be called with an exception set,
159159
because it may clear it (directly or indirectly) and so the
160160
caller loses its exception */
161161
assert(!PyErr_Occurred());

Python/ceval.c

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4889,24 +4889,29 @@ fast_function(PyObject *func, PyObject **stack, int n, int nargs, int nk)
48894889
}
48904890

48914891
PyObject *
4892-
_PyFunction_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwargs)
4892+
_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs,
4893+
PyObject *kwargs)
48934894
{
48944895
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
48954896
PyObject *globals = PyFunction_GET_GLOBALS(func);
48964897
PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
48974898
PyObject *kwdefs, *closure, *name, *qualname;
4899+
PyObject *kwtuple, **k;
48984900
PyObject **d;
48994901
int nd;
4902+
Py_ssize_t nk;
4903+
PyObject *result;
49004904

49014905
PCALL(PCALL_FUNCTION);
49024906
PCALL(PCALL_FAST_FUNCTION);
49034907

4904-
/* issue #27128: support for keywords will come later */
4905-
assert(kwargs == NULL);
4908+
assert(kwargs == NULL || PyDict_Check(kwargs));
49064909

4907-
if (co->co_kwonlyargcount == 0 && kwargs == NULL &&
4910+
if (co->co_kwonlyargcount == 0 &&
4911+
(kwargs == NULL || PyDict_Size(kwargs) == 0) &&
49084912
co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
49094913
{
4914+
/* Fast paths */
49104915
if (argdefs == NULL && co->co_argcount == nargs) {
49114916
return _PyFunction_FastCallNoKw(co, args, nargs, globals);
49124917
}
@@ -4920,6 +4925,30 @@ _PyFunction_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwarg
49204925
}
49214926
}
49224927

4928+
if (kwargs != NULL) {
4929+
Py_ssize_t pos, i;
4930+
nk = PyDict_Size(kwargs);
4931+
4932+
kwtuple = PyTuple_New(2 * nk);
4933+
if (kwtuple == NULL) {
4934+
return NULL;
4935+
}
4936+
4937+
k = &PyTuple_GET_ITEM(kwtuple, 0);
4938+
pos = i = 0;
4939+
while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) {
4940+
Py_INCREF(k[i]);
4941+
Py_INCREF(k[i+1]);
4942+
i += 2;
4943+
}
4944+
nk = i / 2;
4945+
}
4946+
else {
4947+
kwtuple = NULL;
4948+
k = NULL;
4949+
nk = 0;
4950+
}
4951+
49234952
kwdefs = PyFunction_GET_KW_DEFAULTS(func);
49244953
closure = PyFunction_GET_CLOSURE(func);
49254954
name = ((PyFunctionObject *)func) -> func_name;
@@ -4933,11 +4962,14 @@ _PyFunction_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwarg
49334962
d = NULL;
49344963
nd = 0;
49354964
}
4936-
return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
4937-
args, nargs,
4938-
NULL, 0,
4939-
d, nd, kwdefs,
4940-
closure, name, qualname);
4965+
4966+
result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
4967+
args, nargs,
4968+
k, (int)nk,
4969+
d, nd, kwdefs,
4970+
closure, name, qualname);
4971+
Py_XDECREF(kwtuple);
4972+
return result;
49414973
}
49424974

49434975
static PyObject *

0 commit comments

Comments
 (0)