Commit b9009391 authored by Victor Stinner's avatar Victor Stinner

_PyFunction_FastCallDict() supports keyword args

Issue #27809:

* Rename _PyFunction_FastCall() to _PyFunction_FastCallDict()
* Rename _PyCFunction_FastCall() to _PyCFunction_FastCallDict()
*  _PyFunction_FastCallDict() now supports keyword arguments
parent 559bb6a7
...@@ -59,7 +59,7 @@ PyAPI_FUNC(PyObject *) PyFunction_GetAnnotations(PyObject *); ...@@ -59,7 +59,7 @@ PyAPI_FUNC(PyObject *) PyFunction_GetAnnotations(PyObject *);
PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *); PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *);
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _PyFunction_FastCall( PyAPI_FUNC(PyObject *) _PyFunction_FastCallDict(
PyObject *func, PyObject *func,
PyObject **args, int nargs, PyObject **args, int nargs,
PyObject *kwargs); PyObject *kwargs);
......
...@@ -38,7 +38,7 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *); ...@@ -38,7 +38,7 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *);
PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *); PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *);
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _PyCFunction_FastCall(PyObject *func, PyAPI_FUNC(PyObject *) _PyCFunction_FastCallDict(PyObject *func,
PyObject **args, int nargs, PyObject **args, int nargs,
PyObject *kwargs); PyObject *kwargs);
#endif #endif
......
...@@ -2255,7 +2255,8 @@ _PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) ...@@ -2255,7 +2255,8 @@ _PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs)
} }
PyObject * PyObject *
_PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) _PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs,
PyObject *kwargs)
{ {
ternaryfunc call; ternaryfunc call;
PyObject *result = NULL; PyObject *result = NULL;
...@@ -2268,19 +2269,17 @@ _PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwa ...@@ -2268,19 +2269,17 @@ _PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwa
assert(func != NULL); assert(func != NULL);
assert(nargs >= 0); assert(nargs >= 0);
assert(nargs == 0 || args != NULL); assert(nargs == 0 || args != NULL);
/* issue #27128: support for keywords will come later: assert(kwargs == NULL || PyDict_Check(kwargs));
_PyFunction_FastCall() doesn't support keyword arguments yet */
assert(kwargs == NULL);
if (Py_EnterRecursiveCall(" while calling a Python object")) { if (Py_EnterRecursiveCall(" while calling a Python object")) {
return NULL; return NULL;
} }
if (PyFunction_Check(func)) { if (PyFunction_Check(func)) {
result = _PyFunction_FastCall(func, args, nargs, kwargs); result = _PyFunction_FastCallDict(func, args, nargs, kwargs);
} }
else if (PyCFunction_Check(func)) { else if (PyCFunction_Check(func)) {
result = _PyCFunction_FastCall(func, args, nargs, kwargs); result = _PyCFunction_FastCallDict(func, args, nargs, kwargs);
} }
else { else {
PyObject *tuple; PyObject *tuple;
......
...@@ -146,8 +146,8 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) ...@@ -146,8 +146,8 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds)
} }
PyObject * PyObject *
_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, int nargs, _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, int nargs,
PyObject *kwargs) PyObject *kwargs)
{ {
PyCFunctionObject* func = (PyCFunctionObject*)func_obj; PyCFunctionObject* func = (PyCFunctionObject*)func_obj;
PyCFunction meth = PyCFunction_GET_FUNCTION(func); PyCFunction meth = PyCFunction_GET_FUNCTION(func);
...@@ -155,7 +155,7 @@ _PyCFunction_FastCall(PyObject *func_obj, PyObject **args, int nargs, ...@@ -155,7 +155,7 @@ _PyCFunction_FastCall(PyObject *func_obj, PyObject **args, int nargs,
PyObject *result; PyObject *result;
int flags; int flags;
/* _PyCFunction_FastCall() must not be called with an exception set, /* _PyCFunction_FastCallDict() must not be called with an exception set,
because it may clear it (directly or indirectly) and so the because it may clear it (directly or indirectly) and so the
caller loses its exception */ caller loses its exception */
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
......
...@@ -4889,24 +4889,29 @@ fast_function(PyObject *func, PyObject **stack, int n, int nargs, int nk) ...@@ -4889,24 +4889,29 @@ fast_function(PyObject *func, PyObject **stack, int n, int nargs, int nk)
} }
PyObject * PyObject *
_PyFunction_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) _PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs,
PyObject *kwargs)
{ {
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
PyObject *globals = PyFunction_GET_GLOBALS(func); PyObject *globals = PyFunction_GET_GLOBALS(func);
PyObject *argdefs = PyFunction_GET_DEFAULTS(func); PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
PyObject *kwdefs, *closure, *name, *qualname; PyObject *kwdefs, *closure, *name, *qualname;
PyObject *kwtuple, **k;
PyObject **d; PyObject **d;
int nd; int nd;
Py_ssize_t nk;
PyObject *result;
PCALL(PCALL_FUNCTION); PCALL(PCALL_FUNCTION);
PCALL(PCALL_FAST_FUNCTION); PCALL(PCALL_FAST_FUNCTION);
/* issue #27128: support for keywords will come later */ assert(kwargs == NULL || PyDict_Check(kwargs));
assert(kwargs == NULL);
if (co->co_kwonlyargcount == 0 && kwargs == NULL && if (co->co_kwonlyargcount == 0 &&
(kwargs == NULL || PyDict_Size(kwargs) == 0) &&
co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
{ {
/* Fast paths */
if (argdefs == NULL && co->co_argcount == nargs) { if (argdefs == NULL && co->co_argcount == nargs) {
return _PyFunction_FastCallNoKw(co, args, nargs, globals); return _PyFunction_FastCallNoKw(co, args, nargs, globals);
} }
...@@ -4920,6 +4925,30 @@ _PyFunction_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwarg ...@@ -4920,6 +4925,30 @@ _PyFunction_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwarg
} }
} }
if (kwargs != NULL) {
Py_ssize_t pos, i;
nk = PyDict_Size(kwargs);
kwtuple = PyTuple_New(2 * nk);
if (kwtuple == NULL) {
return NULL;
}
k = &PyTuple_GET_ITEM(kwtuple, 0);
pos = i = 0;
while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) {
Py_INCREF(k[i]);
Py_INCREF(k[i+1]);
i += 2;
}
nk = i / 2;
}
else {
kwtuple = NULL;
k = NULL;
nk = 0;
}
kwdefs = PyFunction_GET_KW_DEFAULTS(func); kwdefs = PyFunction_GET_KW_DEFAULTS(func);
closure = PyFunction_GET_CLOSURE(func); closure = PyFunction_GET_CLOSURE(func);
name = ((PyFunctionObject *)func) -> func_name; name = ((PyFunctionObject *)func) -> func_name;
...@@ -4933,11 +4962,14 @@ _PyFunction_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwarg ...@@ -4933,11 +4962,14 @@ _PyFunction_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwarg
d = NULL; d = NULL;
nd = 0; nd = 0;
} }
return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
args, nargs, result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
NULL, 0, args, nargs,
d, nd, kwdefs, k, (int)nk,
closure, name, qualname); d, nd, kwdefs,
closure, name, qualname);
Py_XDECREF(kwtuple);
return result;
} }
static PyObject * static PyObject *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment