mirror of https://github.com/python/cpython
bpo-46532: Reduce number of memory writes to update call_shape.kwnames. (GH-31231)
This commit is contained in:
parent
012e77eb5c
commit
2cea8c29cf
|
@ -1615,7 +1615,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
|
||||||
|
|
||||||
CFrame cframe;
|
CFrame cframe;
|
||||||
CallShape call_shape;
|
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.postcall_shrink = 0;
|
||||||
call_shape.total_args = 0;
|
call_shape.total_args = 0;
|
||||||
call_shape.callable = NULL; // Strong reference
|
call_shape.callable = NULL; // Strong reference
|
||||||
|
@ -4446,7 +4448,7 @@ handle_eval_breaker:
|
||||||
call_shape.postcall_shrink = 1;
|
call_shape.postcall_shrink = 1;
|
||||||
|
|
||||||
call_shape.total_args = oparg;
|
call_shape.total_args = oparg;
|
||||||
call_shape.kwnames = NULL;
|
assert(call_shape.kwnames == NULL);
|
||||||
#ifdef Py_STATS
|
#ifdef Py_STATS
|
||||||
extern int _PySpecialization_ClassifyCallable(PyObject *);
|
extern int _PySpecialization_ClassifyCallable(PyObject *);
|
||||||
_py_stats.opcode_stats[PRECALL_FUNCTION].specialization.failure++;
|
_py_stats.opcode_stats[PRECALL_FUNCTION].specialization.failure++;
|
||||||
|
@ -4490,12 +4492,11 @@ handle_eval_breaker:
|
||||||
call_shape.postcall_shrink = 2-is_method;
|
call_shape.postcall_shrink = 2-is_method;
|
||||||
|
|
||||||
call_shape.total_args = nargs;
|
call_shape.total_args = nargs;
|
||||||
call_shape.kwnames = NULL;
|
assert(call_shape.kwnames == NULL);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
TARGET(KW_NAMES) {
|
TARGET(KW_NAMES) {
|
||||||
assert(call_shape.kwnames == NULL);
|
|
||||||
assert(oparg < PyTuple_GET_SIZE(consts));
|
assert(oparg < PyTuple_GET_SIZE(consts));
|
||||||
call_shape.kwnames = GETITEM(consts, oparg);
|
call_shape.kwnames = GETITEM(consts, oparg);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
@ -4531,6 +4532,7 @@ handle_eval_breaker:
|
||||||
tstate, (PyFunctionObject *)function, locals,
|
tstate, (PyFunctionObject *)function, locals,
|
||||||
stack_pointer, positional_args, call_shape.kwnames
|
stack_pointer, positional_args, call_shape.kwnames
|
||||||
);
|
);
|
||||||
|
call_shape.kwnames = NULL;
|
||||||
STACK_SHRINK(call_shape.postcall_shrink);
|
STACK_SHRINK(call_shape.postcall_shrink);
|
||||||
// The frame has stolen all the arguments from the stack,
|
// The frame has stolen all the arguments from the stack,
|
||||||
// so there is no need to clean them up.
|
// so there is no need to clean them up.
|
||||||
|
@ -4556,6 +4558,7 @@ handle_eval_breaker:
|
||||||
positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
|
positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
|
||||||
call_shape.kwnames);
|
call_shape.kwnames);
|
||||||
}
|
}
|
||||||
|
call_shape.kwnames = NULL;
|
||||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
Py_DECREF(function);
|
Py_DECREF(function);
|
||||||
/* Clear the stack */
|
/* Clear the stack */
|
||||||
|
@ -4597,6 +4600,7 @@ handle_eval_breaker:
|
||||||
}
|
}
|
||||||
|
|
||||||
TARGET(CALL_PY_EXACT_ARGS) {
|
TARGET(CALL_PY_EXACT_ARGS) {
|
||||||
|
assert(call_shape.kwnames == NULL);
|
||||||
SpecializedCacheEntry *caches = GET_CACHE();
|
SpecializedCacheEntry *caches = GET_CACHE();
|
||||||
int argcount = call_shape.total_args;
|
int argcount = call_shape.total_args;
|
||||||
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
|
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
|
||||||
|
@ -4625,6 +4629,7 @@ handle_eval_breaker:
|
||||||
}
|
}
|
||||||
|
|
||||||
TARGET(CALL_PY_WITH_DEFAULTS) {
|
TARGET(CALL_PY_WITH_DEFAULTS) {
|
||||||
|
assert(call_shape.kwnames == NULL);
|
||||||
SpecializedCacheEntry *caches = GET_CACHE();
|
SpecializedCacheEntry *caches = GET_CACHE();
|
||||||
int argcount = call_shape.total_args;
|
int argcount = call_shape.total_args;
|
||||||
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
|
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
|
||||||
|
@ -4661,9 +4666,9 @@ handle_eval_breaker:
|
||||||
}
|
}
|
||||||
|
|
||||||
TARGET(CALL_NO_KW_TYPE_1) {
|
TARGET(CALL_NO_KW_TYPE_1) {
|
||||||
|
assert(call_shape.kwnames == NULL);
|
||||||
assert(cframe.use_tracing == 0);
|
assert(cframe.use_tracing == 0);
|
||||||
DEOPT_IF(call_shape.total_args != 1, CALL);
|
DEOPT_IF(call_shape.total_args != 1, CALL);
|
||||||
assert(call_shape.kwnames == NULL);
|
|
||||||
PyObject *obj = TOP();
|
PyObject *obj = TOP();
|
||||||
PyObject *callable = SECOND();
|
PyObject *callable = SECOND();
|
||||||
DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL);
|
DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL);
|
||||||
|
@ -4676,13 +4681,13 @@ handle_eval_breaker:
|
||||||
}
|
}
|
||||||
|
|
||||||
TARGET(CALL_NO_KW_STR_1) {
|
TARGET(CALL_NO_KW_STR_1) {
|
||||||
|
assert(call_shape.kwnames == NULL);
|
||||||
assert(cframe.use_tracing == 0);
|
assert(cframe.use_tracing == 0);
|
||||||
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
|
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
|
||||||
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
|
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
|
||||||
DEOPT_IF(call_shape.total_args != 1, CALL);
|
DEOPT_IF(call_shape.total_args != 1, CALL);
|
||||||
DEOPT_IF(tp != &PyUnicode_Type, CALL);
|
DEOPT_IF(tp != &PyUnicode_Type, CALL);
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
assert(call_shape.kwnames == NULL);
|
|
||||||
PyObject *arg = TOP();
|
PyObject *arg = TOP();
|
||||||
PyObject *res = PyObject_Str(arg);
|
PyObject *res = PyObject_Str(arg);
|
||||||
Py_DECREF(arg);
|
Py_DECREF(arg);
|
||||||
|
@ -4696,12 +4701,12 @@ handle_eval_breaker:
|
||||||
}
|
}
|
||||||
|
|
||||||
TARGET(CALL_NO_KW_TUPLE_1) {
|
TARGET(CALL_NO_KW_TUPLE_1) {
|
||||||
|
assert(call_shape.kwnames == NULL);
|
||||||
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
|
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
|
||||||
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
|
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
|
||||||
DEOPT_IF(call_shape.total_args != 1, CALL);
|
DEOPT_IF(call_shape.total_args != 1, CALL);
|
||||||
DEOPT_IF(tp != &PyTuple_Type, CALL);
|
DEOPT_IF(tp != &PyTuple_Type, CALL);
|
||||||
STAT_INC(CALL, hit);
|
STAT_INC(CALL, hit);
|
||||||
assert(call_shape.kwnames == NULL);
|
|
||||||
PyObject *arg = TOP();
|
PyObject *arg = TOP();
|
||||||
PyObject *res = PySequence_Tuple(arg);
|
PyObject *res = PySequence_Tuple(arg);
|
||||||
Py_DECREF(arg);
|
Py_DECREF(arg);
|
||||||
|
@ -4724,6 +4729,7 @@ handle_eval_breaker:
|
||||||
int nargs = call_shape.total_args - kwnames_len;
|
int nargs = call_shape.total_args - kwnames_len;
|
||||||
STACK_SHRINK(call_shape.total_args);
|
STACK_SHRINK(call_shape.total_args);
|
||||||
PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, nargs, call_shape.kwnames);
|
PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, nargs, call_shape.kwnames);
|
||||||
|
call_shape.kwnames = NULL;
|
||||||
/* Free the arguments. */
|
/* Free the arguments. */
|
||||||
for (int i = 0; i < call_shape.total_args; i++) {
|
for (int i = 0; i < call_shape.total_args; i++) {
|
||||||
Py_DECREF(stack_pointer[i]);
|
Py_DECREF(stack_pointer[i]);
|
||||||
|
@ -4833,6 +4839,7 @@ handle_eval_breaker:
|
||||||
call_shape.kwnames
|
call_shape.kwnames
|
||||||
);
|
);
|
||||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||||
|
call_shape.kwnames = NULL;
|
||||||
|
|
||||||
/* Free the arguments. */
|
/* Free the arguments. */
|
||||||
for (int i = 0; i < call_shape.total_args; i++) {
|
for (int i = 0; i < call_shape.total_args; i++) {
|
||||||
|
@ -5398,6 +5405,7 @@ unbound_local_error:
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
call_shape.kwnames = NULL;
|
||||||
/* Double-check exception status. */
|
/* Double-check exception status. */
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
if (!_PyErr_Occurred(tstate)) {
|
if (!_PyErr_Occurred(tstate)) {
|
||||||
|
|
Loading…
Reference in New Issue