From 2cea8c29cf975a8ad7d8c3ff19d1e836c2d54707 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 10 Feb 2022 12:57:55 +0000 Subject: [PATCH] bpo-46532: Reduce number of memory writes to update call_shape.kwnames. (GH-31231) --- Python/ceval.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 7e19043c7aa..c3703a75ce0 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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)) {