]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-46532: Reduce number of memory writes to update call_shape.kwnames. (GH-31231)
authorMark Shannon <mark@hotpy.org>
Thu, 10 Feb 2022 12:57:55 +0000 (12:57 +0000)
committerGitHub <noreply@github.com>
Thu, 10 Feb 2022 12:57:55 +0000 (12:57 +0000)
Python/ceval.c

index 7e19043c7aa64ef839a5d05b119feb454f1e2989..c3703a75ce0cac96039032bd71e9788f6364b7d3 100644 (file)
@@ -1615,7 +1615,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
 
     CFrame cframe;
     CallShape call_shape;
-    call_shape.kwnames = NULL; // Borrowed reference
+    call_shape.kwnames = NULL; // Borrowed reference. Reset by CALL instructions.
+    /* The following three values are always set by the PRECALL instructions.
+       They are set here to keep the compiler happy. */
     call_shape.postcall_shrink = 0;
     call_shape.total_args = 0;
     call_shape.callable = NULL; // Strong reference
@@ -4446,7 +4448,7 @@ handle_eval_breaker:
             call_shape.postcall_shrink = 1;
 
             call_shape.total_args = oparg;
-            call_shape.kwnames = NULL;
+            assert(call_shape.kwnames == NULL);
 #ifdef Py_STATS
             extern int _PySpecialization_ClassifyCallable(PyObject *);
             _py_stats.opcode_stats[PRECALL_FUNCTION].specialization.failure++;
@@ -4490,12 +4492,11 @@ handle_eval_breaker:
             call_shape.postcall_shrink = 2-is_method;
 
             call_shape.total_args = nargs;
-            call_shape.kwnames = NULL;
+            assert(call_shape.kwnames == NULL);
             DISPATCH();
         }
 
         TARGET(KW_NAMES) {
-            assert(call_shape.kwnames == NULL);
             assert(oparg < PyTuple_GET_SIZE(consts));
             call_shape.kwnames = GETITEM(consts, oparg);
             DISPATCH();
@@ -4531,6 +4532,7 @@ handle_eval_breaker:
                     tstate, (PyFunctionObject *)function, locals,
                     stack_pointer, positional_args, call_shape.kwnames
                 );
+                call_shape.kwnames = NULL;
                 STACK_SHRINK(call_shape.postcall_shrink);
                 // The frame has stolen all the arguments from the stack,
                 // so there is no need to clean them up.
@@ -4556,6 +4558,7 @@ handle_eval_breaker:
                     positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
                     call_shape.kwnames);
             }
+            call_shape.kwnames = NULL;
             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
             Py_DECREF(function);
             /* Clear the stack */
@@ -4597,6 +4600,7 @@ handle_eval_breaker:
         }
 
         TARGET(CALL_PY_EXACT_ARGS) {
+            assert(call_shape.kwnames == NULL);
             SpecializedCacheEntry *caches = GET_CACHE();
             int argcount = call_shape.total_args;
             DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
@@ -4625,6 +4629,7 @@ handle_eval_breaker:
         }
 
         TARGET(CALL_PY_WITH_DEFAULTS) {
+            assert(call_shape.kwnames == NULL);
             SpecializedCacheEntry *caches = GET_CACHE();
             int argcount = call_shape.total_args;
             DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
@@ -4661,9 +4666,9 @@ handle_eval_breaker:
         }
 
         TARGET(CALL_NO_KW_TYPE_1) {
+            assert(call_shape.kwnames == NULL);
             assert(cframe.use_tracing == 0);
             DEOPT_IF(call_shape.total_args != 1, CALL);
-            assert(call_shape.kwnames == NULL);
             PyObject *obj = TOP();
             PyObject *callable = SECOND();
             DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL);
@@ -4676,13 +4681,13 @@ handle_eval_breaker:
         }
 
         TARGET(CALL_NO_KW_STR_1) {
+            assert(call_shape.kwnames == NULL);
             assert(cframe.use_tracing == 0);
             DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
             PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
             DEOPT_IF(call_shape.total_args != 1, CALL);
             DEOPT_IF(tp != &PyUnicode_Type, CALL);
             STAT_INC(CALL, hit);
-            assert(call_shape.kwnames == NULL);
             PyObject *arg = TOP();
             PyObject *res = PyObject_Str(arg);
             Py_DECREF(arg);
@@ -4696,12 +4701,12 @@ handle_eval_breaker:
         }
 
         TARGET(CALL_NO_KW_TUPLE_1) {
+            assert(call_shape.kwnames == NULL);
             DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
             PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
             DEOPT_IF(call_shape.total_args != 1, CALL);
             DEOPT_IF(tp != &PyTuple_Type, CALL);
             STAT_INC(CALL, hit);
-            assert(call_shape.kwnames == NULL);
             PyObject *arg = TOP();
             PyObject *res = PySequence_Tuple(arg);
             Py_DECREF(arg);
@@ -4724,6 +4729,7 @@ handle_eval_breaker:
             int nargs = call_shape.total_args - kwnames_len;
             STACK_SHRINK(call_shape.total_args);
             PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, nargs, call_shape.kwnames);
+            call_shape.kwnames = NULL;
             /* Free the arguments. */
             for (int i = 0; i < call_shape.total_args; i++) {
                 Py_DECREF(stack_pointer[i]);
@@ -4833,6 +4839,7 @@ handle_eval_breaker:
                 call_shape.kwnames
             );
             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
+            call_shape.kwnames = NULL;
 
             /* Free the arguments. */
             for (int i = 0; i < call_shape.total_args; i++) {
@@ -5398,6 +5405,7 @@ unbound_local_error:
         }
 
 error:
+        call_shape.kwnames = NULL;
         /* Double-check exception status. */
 #ifdef NDEBUG
         if (!_PyErr_Occurred(tstate)) {