]> granicus.if.org Git - python/commitdiff
Argument Clinic: Use METH_FASTCALL for positionals
authorVictor Stinner <victor.stinner@gmail.com>
Tue, 17 Jan 2017 00:42:54 +0000 (01:42 +0100)
committerVictor Stinner <victor.stinner@gmail.com>
Tue, 17 Jan 2017 00:42:54 +0000 (01:42 +0100)
Issue #29286. Use METH_FASTCALL calling convention instead of METH_VARARGS to
parse position arguments. METH_FASTCALL is faster since it avoids the creation
of a temporary tuple to pass positional arguments.

Tools/clinic/clinic.py

index 4d84d4918e1947a5a2d09eeb501cd725741b72ec..7c4b388efe5bcf6715b6e399d42d28c8e33ef244 100755 (executable)
@@ -705,14 +705,14 @@ class CLanguage(Language):
             {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs)
             """)
 
-        parser_prototype_fastcall = normalize_snippet("""
+        parser_prototype_varargs = normalize_snippet("""
             static PyObject *
-            {c_basename}({self_type}{self_name}, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
+            {c_basename}({self_type}{self_name}, PyObject *args)
             """)
 
-        parser_prototype_varargs = normalize_snippet("""
+        parser_prototype_fastcall = normalize_snippet("""
             static PyObject *
-            {c_basename}({self_type}{self_name}, PyObject *args)
+            {c_basename}({self_type}{self_name}, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
             """)
 
         # parser_body_fields remembers the fields passed in to the
@@ -837,18 +837,36 @@ class CLanguage(Language):
                 """, indent=4))
 
         elif positional:
-            # positional-only, but no option groups
-            # we only need one call to PyArg_ParseTuple
+            if not new_or_init:
+                # positional-only, but no option groups
+                # we only need one call to _PyArg_ParseStack
 
-            flags = "METH_VARARGS"
-            parser_prototype = parser_prototype_varargs
+                flags = "METH_FASTCALL"
+                parser_prototype = parser_prototype_fastcall
 
-            parser_definition = parser_body(parser_prototype, normalize_snippet("""
-                if (!PyArg_ParseTuple(args, "{format_units}:{name}",
-                    {parse_arguments})) {{
-                    goto exit;
-                }}
-                """, indent=4))
+                parser_definition = parser_body(parser_prototype, normalize_snippet("""
+                    if (!_PyArg_ParseStack(args, nargs, "{format_units}:{name}",
+                        {parse_arguments})) {{
+                        goto exit;
+                    }}
+
+                    if ({self_type_check}!_PyArg_NoStackKeywords("{name}", kwnames)) {{
+                        goto exit;
+                    }}
+                    """, indent=4))
+            else:
+                # positional-only, but no option groups
+                # we only need one call to PyArg_ParseTuple
+
+                flags = "METH_VARARGS"
+                parser_prototype = parser_prototype_varargs
+
+                parser_definition = parser_body(parser_prototype, normalize_snippet("""
+                    if (!PyArg_ParseTuple(args, "{format_units}:{name}",
+                        {parse_arguments})) {{
+                        goto exit;
+                    }}
+                    """, indent=4))
 
         elif not new_or_init:
             flags = "METH_FASTCALL"