mirror of
https://github.com/python/cpython.git
synced 2025-08-23 02:04:56 +00:00
GH-105848: Replace KW_NAMES + CALL with LOAD_CONST + CALL_KW (GH-109300)
This commit is contained in:
parent
987b4bc087
commit
22e65eecaa
22 changed files with 719 additions and 508 deletions
|
@ -74,7 +74,6 @@ dummy_func(
|
|||
unsigned int oparg,
|
||||
_Py_CODEUNIT *next_instr,
|
||||
PyObject **stack_pointer,
|
||||
PyObject *kwnames,
|
||||
int throwflag,
|
||||
PyObject *args[]
|
||||
)
|
||||
|
@ -2854,12 +2853,6 @@ dummy_func(
|
|||
self = owner;
|
||||
}
|
||||
|
||||
inst(KW_NAMES, (--)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS));
|
||||
kwnames = GETITEM(FRAME_CO_CONSTS, oparg);
|
||||
}
|
||||
|
||||
inst(INSTRUMENTED_CALL, ( -- )) {
|
||||
int is_meth = PEEK(oparg + 1) != NULL;
|
||||
int total_args = oparg + is_meth;
|
||||
|
@ -2876,36 +2869,31 @@ dummy_func(
|
|||
}
|
||||
|
||||
// Cache layout: counter/1, func_version/2
|
||||
// Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members!
|
||||
// CALL_INTRINSIC_1/2, CALL_KW, and CALL_FUNCTION_EX aren't members!
|
||||
family(CALL, INLINE_CACHE_ENTRIES_CALL) = {
|
||||
CALL_BOUND_METHOD_EXACT_ARGS,
|
||||
CALL_PY_EXACT_ARGS,
|
||||
CALL_PY_WITH_DEFAULTS,
|
||||
CALL_NO_KW_TYPE_1,
|
||||
CALL_NO_KW_STR_1,
|
||||
CALL_NO_KW_TUPLE_1,
|
||||
CALL_TYPE_1,
|
||||
CALL_STR_1,
|
||||
CALL_TUPLE_1,
|
||||
CALL_BUILTIN_CLASS,
|
||||
CALL_NO_KW_BUILTIN_O,
|
||||
CALL_NO_KW_BUILTIN_FAST,
|
||||
CALL_BUILTIN_O,
|
||||
CALL_BUILTIN_FAST,
|
||||
CALL_BUILTIN_FAST_WITH_KEYWORDS,
|
||||
CALL_NO_KW_LEN,
|
||||
CALL_NO_KW_ISINSTANCE,
|
||||
CALL_NO_KW_LIST_APPEND,
|
||||
CALL_NO_KW_METHOD_DESCRIPTOR_O,
|
||||
CALL_LEN,
|
||||
CALL_ISINSTANCE,
|
||||
CALL_LIST_APPEND,
|
||||
CALL_METHOD_DESCRIPTOR_O,
|
||||
CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS,
|
||||
CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS,
|
||||
CALL_NO_KW_METHOD_DESCRIPTOR_FAST,
|
||||
CALL_NO_KW_ALLOC_AND_ENTER_INIT,
|
||||
CALL_METHOD_DESCRIPTOR_NOARGS,
|
||||
CALL_METHOD_DESCRIPTOR_FAST,
|
||||
CALL_ALLOC_AND_ENTER_INIT,
|
||||
};
|
||||
|
||||
// On entry, the stack is either
|
||||
// [NULL, callable, arg1, arg2, ...]
|
||||
// or
|
||||
// [method, self, arg1, arg2, ...]
|
||||
// (Some args may be keywords, see KW_NAMES, which sets 'kwnames'.)
|
||||
// On exit, the stack is [result].
|
||||
// When calling Python, inline the call using DISPATCH_INLINED().
|
||||
inst(CALL, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
// oparg counts all of the args, but *not* self:
|
||||
int total_args = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
args--;
|
||||
|
@ -2915,7 +2903,7 @@ dummy_func(
|
|||
_PyCallCache *cache = (_PyCallCache *)next_instr;
|
||||
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
|
||||
next_instr--;
|
||||
_Py_Specialize_Call(callable, next_instr, total_args, kwnames);
|
||||
_Py_Specialize_Call(callable, next_instr, total_args);
|
||||
DISPATCH_SAME_OPARG();
|
||||
}
|
||||
STAT_INC(CALL, deferred);
|
||||
|
@ -2931,7 +2919,6 @@ dummy_func(
|
|||
Py_DECREF(callable);
|
||||
callable = method;
|
||||
}
|
||||
int positional_args = total_args - KWNAMES_LEN();
|
||||
// Check if the call can be inlined or not
|
||||
if (Py_TYPE(callable) == &PyFunction_Type &&
|
||||
tstate->interp->eval_frame == NULL &&
|
||||
|
@ -2941,9 +2928,8 @@ dummy_func(
|
|||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)callable, locals,
|
||||
args, positional_args, kwnames
|
||||
args, total_args, NULL
|
||||
);
|
||||
kwnames = NULL;
|
||||
// Manipulate stack directly since we leave using DISPATCH_INLINED().
|
||||
STACK_SHRINK(oparg + 2);
|
||||
// The frame has stolen all the arguments from the stack,
|
||||
|
@ -2958,8 +2944,8 @@ dummy_func(
|
|||
/* Callable is not a normal Python function */
|
||||
res = PyObject_Vectorcall(
|
||||
callable, args,
|
||||
positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
|
||||
kwnames);
|
||||
total_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
|
||||
NULL);
|
||||
if (opcode == INSTRUMENTED_CALL) {
|
||||
PyObject *arg = total_args == 0 ?
|
||||
&_PyInstrumentation_MISSING : args[0];
|
||||
|
@ -2977,7 +2963,6 @@ dummy_func(
|
|||
}
|
||||
}
|
||||
}
|
||||
kwnames = NULL;
|
||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||
Py_DECREF(callable);
|
||||
for (int i = 0; i < total_args; i++) {
|
||||
|
@ -3006,7 +2991,6 @@ dummy_func(
|
|||
}
|
||||
|
||||
op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
DEOPT_IF(!PyFunction_Check(callable), CALL);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
DEOPT_IF(func->func_version != func_version, CALL);
|
||||
|
@ -3081,7 +3065,6 @@ dummy_func(
|
|||
_PUSH_FRAME;
|
||||
|
||||
inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, callable, self_or_null, args[oparg] -- unused)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
DEOPT_IF(tstate->interp->eval_frame, CALL);
|
||||
int argcount = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
|
@ -3116,8 +3099,7 @@ dummy_func(
|
|||
DISPATCH_INLINED(new_frame);
|
||||
}
|
||||
|
||||
inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
inst(CALL_TYPE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) {
|
||||
assert(oparg == 1);
|
||||
DEOPT_IF(null != NULL, CALL);
|
||||
PyObject *obj = args[0];
|
||||
|
@ -3128,8 +3110,7 @@ dummy_func(
|
|||
Py_DECREF(&PyType_Type); // I.e., callable
|
||||
}
|
||||
|
||||
inst(CALL_NO_KW_STR_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
inst(CALL_STR_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) {
|
||||
assert(oparg == 1);
|
||||
DEOPT_IF(null != NULL, CALL);
|
||||
DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL);
|
||||
|
@ -3142,8 +3123,7 @@ dummy_func(
|
|||
CHECK_EVAL_BREAKER();
|
||||
}
|
||||
|
||||
inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
inst(CALL_TUPLE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) {
|
||||
assert(oparg == 1);
|
||||
DEOPT_IF(null != NULL, CALL);
|
||||
DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL);
|
||||
|
@ -3156,13 +3136,12 @@ dummy_func(
|
|||
CHECK_EVAL_BREAKER();
|
||||
}
|
||||
|
||||
inst(CALL_NO_KW_ALLOC_AND_ENTER_INIT, (unused/1, unused/2, callable, null, args[oparg] -- unused)) {
|
||||
inst(CALL_ALLOC_AND_ENTER_INIT, (unused/1, unused/2, callable, null, args[oparg] -- unused)) {
|
||||
/* This instruction does the following:
|
||||
* 1. Creates the object (by calling ``object.__new__``)
|
||||
* 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``)
|
||||
* 3. Pushes the frame for ``__init__`` to the frame stack
|
||||
* */
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
_PyCallCache *cache = (_PyCallCache *)next_instr;
|
||||
DEOPT_IF(null != NULL, CALL);
|
||||
DEOPT_IF(!PyType_Check(callable), CALL);
|
||||
|
@ -3225,14 +3204,11 @@ dummy_func(
|
|||
args--;
|
||||
total_args++;
|
||||
}
|
||||
int kwnames_len = KWNAMES_LEN();
|
||||
DEOPT_IF(!PyType_Check(callable), CALL);
|
||||
PyTypeObject *tp = (PyTypeObject *)callable;
|
||||
DEOPT_IF(tp->tp_vectorcall == NULL, CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
res = tp->tp_vectorcall((PyObject *)tp, args,
|
||||
total_args - kwnames_len, kwnames);
|
||||
kwnames = NULL;
|
||||
res = tp->tp_vectorcall((PyObject *)tp, args, total_args, NULL);
|
||||
/* Free the arguments. */
|
||||
for (int i = 0; i < total_args; i++) {
|
||||
Py_DECREF(args[i]);
|
||||
|
@ -3242,9 +3218,8 @@ dummy_func(
|
|||
CHECK_EVAL_BREAKER();
|
||||
}
|
||||
|
||||
inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
inst(CALL_BUILTIN_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
/* Builtin METH_O functions */
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
int total_args = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
args--;
|
||||
|
@ -3271,9 +3246,8 @@ dummy_func(
|
|||
CHECK_EVAL_BREAKER();
|
||||
}
|
||||
|
||||
inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
inst(CALL_BUILTIN_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
/* Builtin METH_FASTCALL functions, without keywords */
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
int total_args = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
args--;
|
||||
|
@ -3319,14 +3293,8 @@ dummy_func(
|
|||
_PyCFunctionFastWithKeywords cfunc =
|
||||
(_PyCFunctionFastWithKeywords)(void(*)(void))
|
||||
PyCFunction_GET_FUNCTION(callable);
|
||||
res = cfunc(
|
||||
PyCFunction_GET_SELF(callable),
|
||||
args,
|
||||
total_args - KWNAMES_LEN(),
|
||||
kwnames
|
||||
);
|
||||
res = cfunc(PyCFunction_GET_SELF(callable), args, total_args, NULL);
|
||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||
kwnames = NULL;
|
||||
|
||||
/* Free the arguments. */
|
||||
for (int i = 0; i < total_args; i++) {
|
||||
|
@ -3337,8 +3305,7 @@ dummy_func(
|
|||
CHECK_EVAL_BREAKER();
|
||||
}
|
||||
|
||||
inst(CALL_NO_KW_LEN, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
inst(CALL_LEN, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
/* len(o) */
|
||||
int total_args = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
|
@ -3362,8 +3329,7 @@ dummy_func(
|
|||
ERROR_IF(res == NULL, error);
|
||||
}
|
||||
|
||||
inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
inst(CALL_ISINSTANCE, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
/* isinstance(o, o2) */
|
||||
int total_args = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
|
@ -3390,8 +3356,7 @@ dummy_func(
|
|||
}
|
||||
|
||||
// This is secretly a super-instruction
|
||||
inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, callable, self, args[oparg] -- unused)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
inst(CALL_LIST_APPEND, (unused/1, unused/2, callable, self, args[oparg] -- unused)) {
|
||||
assert(oparg == 1);
|
||||
PyInterpreterState *interp = tstate->interp;
|
||||
DEOPT_IF(callable != interp->callable_cache.list_append, CALL);
|
||||
|
@ -3410,8 +3375,7 @@ dummy_func(
|
|||
DISPATCH();
|
||||
}
|
||||
|
||||
inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
inst(CALL_METHOD_DESCRIPTOR_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
int total_args = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
args--;
|
||||
|
@ -3459,9 +3423,8 @@ dummy_func(
|
|||
int nargs = total_args - 1;
|
||||
_PyCFunctionFastWithKeywords cfunc =
|
||||
(_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
|
||||
res = cfunc(self, args + 1, nargs - KWNAMES_LEN(), kwnames);
|
||||
res = cfunc(self, args + 1, nargs, NULL);
|
||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||
kwnames = NULL;
|
||||
|
||||
/* Free the arguments. */
|
||||
for (int i = 0; i < total_args; i++) {
|
||||
|
@ -3472,8 +3435,7 @@ dummy_func(
|
|||
CHECK_EVAL_BREAKER();
|
||||
}
|
||||
|
||||
inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
inst(CALL_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
assert(oparg == 0 || oparg == 1);
|
||||
int total_args = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
|
@ -3503,8 +3465,7 @@ dummy_func(
|
|||
CHECK_EVAL_BREAKER();
|
||||
}
|
||||
|
||||
inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
inst(CALL_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) {
|
||||
int total_args = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
args--;
|
||||
|
@ -3532,6 +3493,91 @@ dummy_func(
|
|||
CHECK_EVAL_BREAKER();
|
||||
}
|
||||
|
||||
inst(INSTRUMENTED_CALL_KW, ( -- )) {
|
||||
int is_meth = PEEK(oparg + 2) != NULL;
|
||||
int total_args = oparg + is_meth;
|
||||
PyObject *function = PEEK(oparg + 3);
|
||||
PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING
|
||||
: PEEK(total_args + 1);
|
||||
int err = _Py_call_instrumentation_2args(
|
||||
tstate, PY_MONITORING_EVENT_CALL,
|
||||
frame, next_instr - 1, function, arg);
|
||||
ERROR_IF(err, error);
|
||||
GO_TO_INSTRUCTION(CALL_KW);
|
||||
}
|
||||
|
||||
inst(CALL_KW, (callable, self_or_null, args[oparg], kwnames -- res)) {
|
||||
// oparg counts all of the args, but *not* self:
|
||||
int total_args = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
args--;
|
||||
total_args++;
|
||||
}
|
||||
if (self_or_null == NULL && Py_TYPE(callable) == &PyMethod_Type) {
|
||||
args--;
|
||||
total_args++;
|
||||
PyObject *self = ((PyMethodObject *)callable)->im_self;
|
||||
args[0] = Py_NewRef(self);
|
||||
PyObject *method = ((PyMethodObject *)callable)->im_func;
|
||||
args[-1] = Py_NewRef(method);
|
||||
Py_DECREF(callable);
|
||||
callable = method;
|
||||
}
|
||||
int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames);
|
||||
// Check if the call can be inlined or not
|
||||
if (Py_TYPE(callable) == &PyFunction_Type &&
|
||||
tstate->interp->eval_frame == NULL &&
|
||||
((PyFunctionObject *)callable)->vectorcall == _PyFunction_Vectorcall)
|
||||
{
|
||||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)callable, locals,
|
||||
args, positional_args, kwnames
|
||||
);
|
||||
Py_DECREF(kwnames);
|
||||
// Manipulate stack directly since we leave using DISPATCH_INLINED().
|
||||
STACK_SHRINK(oparg + 3);
|
||||
// The frame has stolen all the arguments from the stack,
|
||||
// so there is no need to clean them up.
|
||||
if (new_frame == NULL) {
|
||||
goto error;
|
||||
}
|
||||
frame->return_offset = 0;
|
||||
DISPATCH_INLINED(new_frame);
|
||||
}
|
||||
/* Callable is not a normal Python function */
|
||||
res = PyObject_Vectorcall(
|
||||
callable, args,
|
||||
positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
|
||||
kwnames);
|
||||
if (opcode == INSTRUMENTED_CALL_KW) {
|
||||
PyObject *arg = total_args == 0 ?
|
||||
&_PyInstrumentation_MISSING : args[0];
|
||||
if (res == NULL) {
|
||||
_Py_call_instrumentation_exc2(
|
||||
tstate, PY_MONITORING_EVENT_C_RAISE,
|
||||
frame, next_instr-1, callable, arg);
|
||||
}
|
||||
else {
|
||||
int err = _Py_call_instrumentation_2args(
|
||||
tstate, PY_MONITORING_EVENT_C_RETURN,
|
||||
frame, next_instr-1, callable, arg);
|
||||
if (err < 0) {
|
||||
Py_CLEAR(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_DECREF(kwnames);
|
||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||
Py_DECREF(callable);
|
||||
for (int i = 0; i < total_args; i++) {
|
||||
Py_DECREF(args[i]);
|
||||
}
|
||||
ERROR_IF(res == NULL, error);
|
||||
CHECK_EVAL_BREAKER();
|
||||
}
|
||||
|
||||
inst(INSTRUMENTED_CALL_FUNCTION_EX, ( -- )) {
|
||||
GO_TO_INSTRUCTION(CALL_FUNCTION_EX);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue