Skip to content

Commit 2cea8c2

Browse files
authored
bpo-46532: Reduce number of memory writes to update call_shape.kwnames. (GH-31231)
1 parent 012e77e commit 2cea8c2

File tree

1 file changed

+15
-7
lines changed

1 file changed

+15
-7
lines changed

Python/ceval.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,7 +1615,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
16151615

16161616
CFrame cframe;
16171617
CallShape call_shape;
1618-
call_shape.kwnames = NULL; // Borrowed reference
1618+
call_shape.kwnames = NULL; // Borrowed reference. Reset by CALL instructions.
1619+
/* The following three values are always set by the PRECALL instructions.
1620+
They are set here to keep the compiler happy. */
16191621
call_shape.postcall_shrink = 0;
16201622
call_shape.total_args = 0;
16211623
call_shape.callable = NULL; // Strong reference
@@ -4446,7 +4448,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
44464448
call_shape.postcall_shrink = 1;
44474449

44484450
call_shape.total_args = oparg;
4449-
call_shape.kwnames = NULL;
4451+
assert(call_shape.kwnames == NULL);
44504452
#ifdef Py_STATS
44514453
extern int _PySpecialization_ClassifyCallable(PyObject *);
44524454
_py_stats.opcode_stats[PRECALL_FUNCTION].specialization.failure++;
@@ -4490,12 +4492,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
44904492
call_shape.postcall_shrink = 2-is_method;
44914493

44924494
call_shape.total_args = nargs;
4493-
call_shape.kwnames = NULL;
4495+
assert(call_shape.kwnames == NULL);
44944496
DISPATCH();
44954497
}
44964498

44974499
TARGET(KW_NAMES) {
4498-
assert(call_shape.kwnames == NULL);
44994500
assert(oparg < PyTuple_GET_SIZE(consts));
45004501
call_shape.kwnames = GETITEM(consts, oparg);
45014502
DISPATCH();
@@ -4531,6 +4532,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
45314532
tstate, (PyFunctionObject *)function, locals,
45324533
stack_pointer, positional_args, call_shape.kwnames
45334534
);
4535+
call_shape.kwnames = NULL;
45344536
STACK_SHRINK(call_shape.postcall_shrink);
45354537
// The frame has stolen all the arguments from the stack,
45364538
// so there is no need to clean them up.
@@ -4556,6 +4558,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
45564558
positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
45574559
call_shape.kwnames);
45584560
}
4561+
call_shape.kwnames = NULL;
45594562
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
45604563
Py_DECREF(function);
45614564
/* Clear the stack */
@@ -4597,6 +4600,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
45974600
}
45984601

45994602
TARGET(CALL_PY_EXACT_ARGS) {
4603+
assert(call_shape.kwnames == NULL);
46004604
SpecializedCacheEntry *caches = GET_CACHE();
46014605
int argcount = call_shape.total_args;
46024606
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
@@ -4625,6 +4629,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
46254629
}
46264630

46274631
TARGET(CALL_PY_WITH_DEFAULTS) {
4632+
assert(call_shape.kwnames == NULL);
46284633
SpecializedCacheEntry *caches = GET_CACHE();
46294634
int argcount = call_shape.total_args;
46304635
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
@@ -4661,9 +4666,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
46614666
}
46624667

46634668
TARGET(CALL_NO_KW_TYPE_1) {
4669+
assert(call_shape.kwnames == NULL);
46644670
assert(cframe.use_tracing == 0);
46654671
DEOPT_IF(call_shape.total_args != 1, CALL);
4666-
assert(call_shape.kwnames == NULL);
46674672
PyObject *obj = TOP();
46684673
PyObject *callable = SECOND();
46694674
DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL);
@@ -4676,13 +4681,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
46764681
}
46774682

46784683
TARGET(CALL_NO_KW_STR_1) {
4684+
assert(call_shape.kwnames == NULL);
46794685
assert(cframe.use_tracing == 0);
46804686
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
46814687
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
46824688
DEOPT_IF(call_shape.total_args != 1, CALL);
46834689
DEOPT_IF(tp != &PyUnicode_Type, CALL);
46844690
STAT_INC(CALL, hit);
4685-
assert(call_shape.kwnames == NULL);
46864691
PyObject *arg = TOP();
46874692
PyObject *res = PyObject_Str(arg);
46884693
Py_DECREF(arg);
@@ -4696,12 +4701,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
46964701
}
46974702

46984703
TARGET(CALL_NO_KW_TUPLE_1) {
4704+
assert(call_shape.kwnames == NULL);
46994705
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
47004706
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
47014707
DEOPT_IF(call_shape.total_args != 1, CALL);
47024708
DEOPT_IF(tp != &PyTuple_Type, CALL);
47034709
STAT_INC(CALL, hit);
4704-
assert(call_shape.kwnames == NULL);
47054710
PyObject *arg = TOP();
47064711
PyObject *res = PySequence_Tuple(arg);
47074712
Py_DECREF(arg);
@@ -4724,6 +4729,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
47244729
int nargs = call_shape.total_args - kwnames_len;
47254730
STACK_SHRINK(call_shape.total_args);
47264731
PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, nargs, call_shape.kwnames);
4732+
call_shape.kwnames = NULL;
47274733
/* Free the arguments. */
47284734
for (int i = 0; i < call_shape.total_args; i++) {
47294735
Py_DECREF(stack_pointer[i]);
@@ -4833,6 +4839,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
48334839
call_shape.kwnames
48344840
);
48354841
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
4842+
call_shape.kwnames = NULL;
48364843

48374844
/* Free the arguments. */
48384845
for (int i = 0; i < call_shape.total_args; i++) {
@@ -5398,6 +5405,7 @@ MISS_WITH_OPARG_COUNTER(STORE_SUBSCR)
53985405
}
53995406

54005407
error:
5408+
call_shape.kwnames = NULL;
54015409
/* Double-check exception status. */
54025410
#ifdef NDEBUG
54035411
if (!_PyErr_Occurred(tstate)) {

0 commit comments

Comments
 (0)