]> granicus.if.org Git - python/commitdiff
_PyFunction_FastCallDict() supports keyword args
authorVictor Stinner <victor.stinner@gmail.com>
Mon, 22 Aug 2016 21:15:44 +0000 (23:15 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Mon, 22 Aug 2016 21:15:44 +0000 (23:15 +0200)
Issue #27809:

* Rename _PyFunction_FastCall() to _PyFunction_FastCallDict()
* Rename _PyCFunction_FastCall() to _PyCFunction_FastCallDict()
*  _PyFunction_FastCallDict() now supports keyword arguments

Include/funcobject.h
Include/methodobject.h
Objects/abstract.c
Objects/methodobject.c
Python/ceval.c

index 908944d44f0ff74d28d253dfb9c831520e05851b..24602e6a51024bc1f72e58dee97b9cff8474a922 100644 (file)
@@ -59,7 +59,7 @@ PyAPI_FUNC(PyObject *) PyFunction_GetAnnotations(PyObject *);
 PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *);
 
 #ifndef Py_LIMITED_API
-PyAPI_FUNC(PyObject *) _PyFunction_FastCall(
+PyAPI_FUNC(PyObject *) _PyFunction_FastCallDict(
     PyObject *func,
     PyObject **args, int nargs,
     PyObject *kwargs);
index 8dec00a8f5319bb2909f6ab6fb2d85ba5c57bd3d..107a65025710484b148cc288e15660746f8fc750 100644 (file)
@@ -38,7 +38,7 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *);
 PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *);
 
 #ifndef Py_LIMITED_API
-PyAPI_FUNC(PyObject *) _PyCFunction_FastCall(PyObject *func,
+PyAPI_FUNC(PyObject *) _PyCFunction_FastCallDict(PyObject *func,
     PyObject **args, int nargs,
     PyObject *kwargs);
 #endif
index 2ce7f327e92195cd5fd5b6ae27bca1834254c617..0e67693fcf8e6470a9fd2a7298fb22be0bc41bde 100644 (file)
@@ -2255,7 +2255,8 @@ _PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs)
 }
 
 PyObject *
-_PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs)
+_PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs,
+                       PyObject *kwargs)
 {
     ternaryfunc call;
     PyObject *result = NULL;
@@ -2268,19 +2269,17 @@ _PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwa
     assert(func != NULL);
     assert(nargs >= 0);
     assert(nargs == 0 || args != NULL);
-    /* issue #27128: support for keywords will come later:
-       _PyFunction_FastCall() doesn't support keyword arguments yet */
-    assert(kwargs == NULL);
+    assert(kwargs == NULL || PyDict_Check(kwargs));
 
     if (Py_EnterRecursiveCall(" while calling a Python object")) {
         return NULL;
     }
 
     if (PyFunction_Check(func)) {
-        result = _PyFunction_FastCall(func, args, nargs, kwargs);
+        result = _PyFunction_FastCallDict(func, args, nargs, kwargs);
     }
     else if (PyCFunction_Check(func)) {
-        result = _PyCFunction_FastCall(func, args, nargs, kwargs);
+        result = _PyCFunction_FastCallDict(func, args, nargs, kwargs);
     }
     else {
         PyObject *tuple;
index 0e26232194cb32e0990d2a2f9ca557233ce37693..edb2fc013c44f30af88158ceb2338281855cd258 100644 (file)
@@ -146,8 +146,8 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds)
 }
 
 PyObject *
-_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, int nargs,
-                      PyObject *kwargs)
+_PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, int nargs,
+                          PyObject *kwargs)
 {
     PyCFunctionObject* func = (PyCFunctionObject*)func_obj;
     PyCFunction meth = PyCFunction_GET_FUNCTION(func);
@@ -155,7 +155,7 @@ _PyCFunction_FastCall(PyObject *func_obj, PyObject **args, int nargs,
     PyObject *result;
     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
        caller loses its exception */
     assert(!PyErr_Occurred());
index 96380bca96cdddc7eb4cfc2bd0921141a98cafae..d656fab3ee45f69c2a8923626368dfe1ab2a89db 100644 (file)
@@ -4889,24 +4889,29 @@ fast_function(PyObject *func, PyObject **stack, int n, int nargs, int nk)
 }
 
 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);
     PyObject *globals = PyFunction_GET_GLOBALS(func);
     PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
     PyObject *kwdefs, *closure, *name, *qualname;
+    PyObject *kwtuple, **k;
     PyObject **d;
     int nd;
+    Py_ssize_t nk;
+    PyObject *result;
 
     PCALL(PCALL_FUNCTION);
     PCALL(PCALL_FAST_FUNCTION);
 
-    /* issue #27128: support for keywords will come later */
-    assert(kwargs == NULL);
+    assert(kwargs == NULL || PyDict_Check(kwargs));
 
-    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))
     {
+        /* Fast paths */
         if (argdefs == NULL && co->co_argcount == nargs) {
             return _PyFunction_FastCallNoKw(co, args, nargs, globals);
         }
@@ -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);
     closure = PyFunction_GET_CLOSURE(func);
     name = ((PyFunctionObject *)func) -> func_name;
@@ -4933,11 +4962,14 @@ _PyFunction_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwarg
         d = NULL;
         nd = 0;
     }
-    return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
-                                     args, nargs,
-                                    NULL, 0,
-                                    d, nd, kwdefs,
-                                    closure, name, qualname);
+
+    result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
+                                      args, nargs,
+                                      k, (int)nk,
+                                      d, nd, kwdefs,
+                                      closure, name, qualname);
+    Py_XDECREF(kwtuple);
+    return result;
 }
 
 static PyObject *