]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-47127: Specialize calls for fastcall c methods with keywords (GH-32125)
authorKumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
Sun, 27 Mar 2022 19:53:25 +0000 (01:23 +0530)
committerGitHub <noreply@github.com>
Sun, 27 Mar 2022 19:53:25 +0000 (03:53 +0800)
* add PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS

Include/opcode.h
Lib/opcode.py
Misc/NEWS.d/next/Core and Builtins/2022-03-26-12-21-53.bpo-47127.Mh86RB.rst [new file with mode: 0644]
Python/ceval.c
Python/opcode_targets.h
Python/specialize.c

index dfc7b72e3cdc687aa7429e85790ed7d10e33a59b..0ce7c158bbd58879f163d324626a1f543e8947c9 100644 (file)
@@ -157,32 +157,33 @@ extern "C" {
 #define PRECALL_BOUND_METHOD                    62
 #define PRECALL_BUILTIN_CLASS                   63
 #define PRECALL_BUILTIN_FAST_WITH_KEYWORDS      64
-#define PRECALL_NO_KW_BUILTIN_FAST              65
-#define PRECALL_NO_KW_BUILTIN_O                 66
-#define PRECALL_NO_KW_ISINSTANCE                67
-#define PRECALL_NO_KW_LEN                       72
-#define PRECALL_NO_KW_LIST_APPEND               73
-#define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST    76
-#define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS  77
-#define PRECALL_NO_KW_METHOD_DESCRIPTOR_O       78
-#define PRECALL_NO_KW_STR_1                     79
-#define PRECALL_NO_KW_TUPLE_1                   80
-#define PRECALL_NO_KW_TYPE_1                    81
-#define PRECALL_PYFUNC                         140
-#define RESUME_QUICK                           141
-#define STORE_ATTR_ADAPTIVE                    143
-#define STORE_ATTR_INSTANCE_VALUE              150
-#define STORE_ATTR_SLOT                        153
-#define STORE_ATTR_WITH_HINT                   154
-#define STORE_FAST__LOAD_FAST                  158
-#define STORE_FAST__STORE_FAST                 159
-#define STORE_SUBSCR_ADAPTIVE                  161
-#define STORE_SUBSCR_DICT                      167
-#define STORE_SUBSCR_LIST_INT                  168
-#define UNPACK_SEQUENCE_ADAPTIVE               169
-#define UNPACK_SEQUENCE_LIST                   170
-#define UNPACK_SEQUENCE_TUPLE                  173
-#define UNPACK_SEQUENCE_TWO_TUPLE              174
+#define PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS  65
+#define PRECALL_NO_KW_BUILTIN_FAST              66
+#define PRECALL_NO_KW_BUILTIN_O                 67
+#define PRECALL_NO_KW_ISINSTANCE                72
+#define PRECALL_NO_KW_LEN                       73
+#define PRECALL_NO_KW_LIST_APPEND               76
+#define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST    77
+#define PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS  78
+#define PRECALL_NO_KW_METHOD_DESCRIPTOR_O       79
+#define PRECALL_NO_KW_STR_1                     80
+#define PRECALL_NO_KW_TUPLE_1                   81
+#define PRECALL_NO_KW_TYPE_1                   140
+#define PRECALL_PYFUNC                         141
+#define RESUME_QUICK                           143
+#define STORE_ATTR_ADAPTIVE                    150
+#define STORE_ATTR_INSTANCE_VALUE              153
+#define STORE_ATTR_SLOT                        154
+#define STORE_ATTR_WITH_HINT                   158
+#define STORE_FAST__LOAD_FAST                  159
+#define STORE_FAST__STORE_FAST                 161
+#define STORE_SUBSCR_ADAPTIVE                  167
+#define STORE_SUBSCR_DICT                      168
+#define STORE_SUBSCR_LIST_INT                  169
+#define UNPACK_SEQUENCE_ADAPTIVE               170
+#define UNPACK_SEQUENCE_LIST                   173
+#define UNPACK_SEQUENCE_TUPLE                  174
+#define UNPACK_SEQUENCE_TWO_TUPLE              175
 #define DO_TRACING                             255
 
 extern const uint8_t _PyOpcode_Caches[256];
@@ -347,6 +348,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
     [PRECALL_BOUND_METHOD] = PRECALL,
     [PRECALL_BUILTIN_CLASS] = PRECALL,
     [PRECALL_BUILTIN_FAST_WITH_KEYWORDS] = PRECALL,
+    [PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = PRECALL,
     [PRECALL_NO_KW_BUILTIN_FAST] = PRECALL,
     [PRECALL_NO_KW_BUILTIN_O] = PRECALL,
     [PRECALL_NO_KW_ISINSTANCE] = PRECALL,
index 7a52c13579af7c175d1bd480555c149710f33664..0b463d3f183aadd0f7b502abbd558f18d1c2f50a 100644 (file)
@@ -294,6 +294,7 @@ _specializations = {
         "PRECALL_BOUND_METHOD",
         "PRECALL_BUILTIN_CLASS",
         "PRECALL_BUILTIN_FAST_WITH_KEYWORDS",
+        "PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS",
         "PRECALL_NO_KW_BUILTIN_FAST",
         "PRECALL_NO_KW_BUILTIN_O",
         "PRECALL_NO_KW_ISINSTANCE",
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-26-12-21-53.bpo-47127.Mh86RB.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-26-12-21-53.bpo-47127.Mh86RB.rst
new file mode 100644 (file)
index 0000000..c4ec977
--- /dev/null
@@ -0,0 +1 @@
+Speed up calls to c functions with keyword arguments by 25% with specialization. Patch by Kumar Aditya.
index 4824b192f4e48b9cc9a7d41f7beddef0cfa0256a..8b59f4233a7b23f7fd487357fc4a568f5f3459e0 100644 (file)
@@ -5090,6 +5090,38 @@ handle_eval_breaker:
             DISPATCH();
         }
 
+        TARGET(PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) {
+            int is_meth = is_method(stack_pointer, oparg);
+            int total_args = oparg + is_meth;
+            PyObject *callable = PEEK(total_args + 1);
+            DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), PRECALL);
+            PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
+            DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), PRECALL);
+            STAT_INC(PRECALL, hit);
+            SKIP_CALL();
+            int nargs = total_args-1;
+            STACK_SHRINK(nargs);
+            _PyCFunctionFastWithKeywords cfunc = (_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
+            PyObject *self = TOP();
+            PyObject *res = cfunc(self, stack_pointer, nargs - KWNAMES_LEN(), call_shape.kwnames);
+            assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
+            call_shape.kwnames = NULL;
+
+            /* Free the arguments. */
+            for (int i = 0; i < nargs; i++) {
+                Py_DECREF(stack_pointer[i]);
+            }
+            Py_DECREF(self);
+            STACK_SHRINK(2-is_meth);
+            SET_TOP(res);
+            Py_DECREF(callable);
+            if (res == NULL) {
+                goto error;
+            }
+            CHECK_EVAL_BREAKER();
+            DISPATCH();
+        }
+
         TARGET(PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) {
             assert(call_shape.kwnames == NULL);
             assert(oparg == 0 || oparg == 1);
index 2aa6471abf99a14e9fce7fc217ee12f267baec9a..dbcacee7e02055f9acac358f8936c10567230079 100644 (file)
@@ -64,23 +64,23 @@ static void *opcode_targets[256] = {
     &&TARGET_PRECALL_BOUND_METHOD,
     &&TARGET_PRECALL_BUILTIN_CLASS,
     &&TARGET_PRECALL_BUILTIN_FAST_WITH_KEYWORDS,
+    &&TARGET_PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS,
     &&TARGET_PRECALL_NO_KW_BUILTIN_FAST,
     &&TARGET_PRECALL_NO_KW_BUILTIN_O,
-    &&TARGET_PRECALL_NO_KW_ISINSTANCE,
     &&TARGET_GET_ITER,
     &&TARGET_GET_YIELD_FROM_ITER,
     &&TARGET_PRINT_EXPR,
     &&TARGET_LOAD_BUILD_CLASS,
+    &&TARGET_PRECALL_NO_KW_ISINSTANCE,
     &&TARGET_PRECALL_NO_KW_LEN,
-    &&TARGET_PRECALL_NO_KW_LIST_APPEND,
     &&TARGET_LOAD_ASSERTION_ERROR,
     &&TARGET_RETURN_GENERATOR,
+    &&TARGET_PRECALL_NO_KW_LIST_APPEND,
     &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST,
     &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS,
     &&TARGET_PRECALL_NO_KW_METHOD_DESCRIPTOR_O,
     &&TARGET_PRECALL_NO_KW_STR_1,
     &&TARGET_PRECALL_NO_KW_TUPLE_1,
-    &&TARGET_PRECALL_NO_KW_TYPE_1,
     &&TARGET_LIST_TO_TUPLE,
     &&TARGET_RETURN_VALUE,
     &&TARGET_IMPORT_STAR,
@@ -139,39 +139,40 @@ static void *opcode_targets[256] = {
     &&TARGET_LOAD_DEREF,
     &&TARGET_STORE_DEREF,
     &&TARGET_DELETE_DEREF,
+    &&TARGET_PRECALL_NO_KW_TYPE_1,
     &&TARGET_PRECALL_PYFUNC,
-    &&TARGET_RESUME_QUICK,
     &&TARGET_CALL_FUNCTION_EX,
-    &&TARGET_STORE_ATTR_ADAPTIVE,
+    &&TARGET_RESUME_QUICK,
     &&TARGET_EXTENDED_ARG,
     &&TARGET_LIST_APPEND,
     &&TARGET_SET_ADD,
     &&TARGET_MAP_ADD,
     &&TARGET_LOAD_CLASSDEREF,
     &&TARGET_COPY_FREE_VARS,
-    &&TARGET_STORE_ATTR_INSTANCE_VALUE,
+    &&TARGET_STORE_ATTR_ADAPTIVE,
     &&TARGET_RESUME,
     &&TARGET_MATCH_CLASS,
+    &&TARGET_STORE_ATTR_INSTANCE_VALUE,
     &&TARGET_STORE_ATTR_SLOT,
-    &&TARGET_STORE_ATTR_WITH_HINT,
     &&TARGET_FORMAT_VALUE,
     &&TARGET_BUILD_CONST_KEY_MAP,
     &&TARGET_BUILD_STRING,
+    &&TARGET_STORE_ATTR_WITH_HINT,
     &&TARGET_STORE_FAST__LOAD_FAST,
-    &&TARGET_STORE_FAST__STORE_FAST,
     &&TARGET_LOAD_METHOD,
-    &&TARGET_STORE_SUBSCR_ADAPTIVE,
+    &&TARGET_STORE_FAST__STORE_FAST,
     &&TARGET_LIST_EXTEND,
     &&TARGET_SET_UPDATE,
     &&TARGET_DICT_MERGE,
     &&TARGET_DICT_UPDATE,
     &&TARGET_PRECALL,
+    &&TARGET_STORE_SUBSCR_ADAPTIVE,
     &&TARGET_STORE_SUBSCR_DICT,
     &&TARGET_STORE_SUBSCR_LIST_INT,
     &&TARGET_UNPACK_SEQUENCE_ADAPTIVE,
-    &&TARGET_UNPACK_SEQUENCE_LIST,
     &&TARGET_CALL,
     &&TARGET_KW_NAMES,
+    &&TARGET_UNPACK_SEQUENCE_LIST,
     &&TARGET_UNPACK_SEQUENCE_TUPLE,
     &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
     &&_unknown_opcode,
@@ -253,6 +254,5 @@ static void *opcode_targets[256] = {
     &&_unknown_opcode,
     &&_unknown_opcode,
     &&_unknown_opcode,
-    &&_unknown_opcode,
     &&TARGET_DO_TRACING
 };
index 720bc7f241586b7075ec19ab2e253074022569e9..5839d7629466d629bf01bdade19018337548e1e9 100644 (file)
@@ -1446,6 +1446,10 @@ specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr,
             _Py_SET_OPCODE(*instr, PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST);
             return 0;
         }
+        case METH_FASTCALL|METH_KEYWORDS: {
+            _Py_SET_OPCODE(*instr, PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS);
+            return 0;
+        }
     }
     SPECIALIZATION_FAIL(PRECALL, builtin_call_fail_kind(descr->d_method->ml_flags));
     return -1;