mirror of
https://github.com/python/cpython.git
synced 2025-08-23 02:04:56 +00:00
GH-118093: Specialize CALL_KW
(GH-123006)
This commit is contained in:
parent
e2f2dc708e
commit
c13e7d98fb
17 changed files with 1083 additions and 273 deletions
|
@ -4007,7 +4007,14 @@ dummy_func(
|
|||
_CALL_METHOD_DESCRIPTOR_FAST +
|
||||
_CHECK_PERIODIC;
|
||||
|
||||
inst(INSTRUMENTED_CALL_KW, ( -- )) {
|
||||
// Cache layout: counter/1, func_version/2
|
||||
family(CALL_KW, INLINE_CACHE_ENTRIES_CALL_KW) = {
|
||||
CALL_KW_BOUND_METHOD,
|
||||
CALL_KW_PY,
|
||||
CALL_KW_NON_PY,
|
||||
};
|
||||
|
||||
inst(INSTRUMENTED_CALL_KW, (counter/1, version/2 -- )) {
|
||||
int is_meth = !PyStackRef_IsNull(PEEK(oparg + 2));
|
||||
int total_args = oparg + is_meth;
|
||||
PyObject *function = PyStackRef_AsPyObjectBorrow(PEEK(oparg + 3));
|
||||
|
@ -4017,6 +4024,7 @@ dummy_func(
|
|||
tstate, PY_MONITORING_EVENT_CALL,
|
||||
frame, this_instr, function, arg);
|
||||
ERROR_IF(err, error);
|
||||
PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter);
|
||||
GO_TO_INSTRUCTION(CALL_KW);
|
||||
}
|
||||
|
||||
|
@ -4062,8 +4070,8 @@ dummy_func(
|
|||
if (new_frame == NULL) {
|
||||
ERROR_NO_POP();
|
||||
}
|
||||
assert(next_instr - this_instr == 1);
|
||||
frame->return_offset = 1;
|
||||
assert(next_instr - this_instr == 1 + INLINE_CACHE_ENTRIES_CALL_KW);
|
||||
frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL_KW;
|
||||
DISPATCH_INLINED(new_frame);
|
||||
}
|
||||
/* Callable is not a normal Python function */
|
||||
|
@ -4104,8 +4112,144 @@ dummy_func(
|
|||
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||
}
|
||||
|
||||
op(_PY_FRAME_KW, (callable, self_or_null, args[oparg], kwnames -- new_frame: _PyInterpreterFrame*)) {
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
PyObject *self_or_null_o = PyStackRef_AsPyObjectBorrow(self_or_null);
|
||||
|
||||
// oparg counts all of the args, but *not* self:
|
||||
int total_args = oparg;
|
||||
if (self_or_null_o != NULL) {
|
||||
args--;
|
||||
total_args++;
|
||||
}
|
||||
PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames);
|
||||
int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o);
|
||||
assert(Py_TYPE(callable_o) == &PyFunction_Type);
|
||||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
args, positional_args, kwnames_o
|
||||
);
|
||||
PyStackRef_CLOSE(kwnames);
|
||||
// The frame has stolen all the arguments from the stack,
|
||||
// so there is no need to clean them up.
|
||||
SYNC_SP();
|
||||
if (new_frame == NULL) {
|
||||
ERROR_NO_POP();
|
||||
}
|
||||
}
|
||||
|
||||
op(_CHECK_FUNCTION_VERSION_KW, (func_version/2, callable, self_or_null, unused[oparg], kwnames -- callable, self_or_null, unused[oparg], kwnames)) {
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
EXIT_IF(!PyFunction_Check(callable_o));
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
EXIT_IF(func->func_version != func_version);
|
||||
}
|
||||
|
||||
macro(CALL_KW_PY) =
|
||||
unused/1 + // Skip over the counter
|
||||
_CHECK_PEP_523 +
|
||||
_CHECK_FUNCTION_VERSION_KW +
|
||||
_PY_FRAME_KW +
|
||||
_SAVE_RETURN_OFFSET +
|
||||
_PUSH_FRAME;
|
||||
|
||||
op(_CHECK_METHOD_VERSION_KW, (func_version/2, callable, null, unused[oparg], kwnames -- callable, null, unused[oparg], kwnames)) {
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
|
||||
EXIT_IF(Py_TYPE(callable_o) != &PyMethod_Type);
|
||||
PyObject *func = ((PyMethodObject *)callable_o)->im_func;
|
||||
EXIT_IF(!PyFunction_Check(func));
|
||||
EXIT_IF(((PyFunctionObject *)func)->func_version != func_version);
|
||||
EXIT_IF(!PyStackRef_IsNull(null));
|
||||
}
|
||||
|
||||
op(_EXPAND_METHOD_KW, (callable, null, unused[oparg], kwnames -- method, self, unused[oparg], kwnames)) {
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
|
||||
assert(PyStackRef_IsNull(null));
|
||||
assert(Py_TYPE(callable_o) == &PyMethod_Type);
|
||||
self = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self);
|
||||
method = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func);
|
||||
assert(PyStackRef_FunctionCheck(method));
|
||||
PyStackRef_CLOSE(callable);
|
||||
}
|
||||
|
||||
macro(CALL_KW_BOUND_METHOD) =
|
||||
unused/1 + // Skip over the counter
|
||||
_CHECK_PEP_523 +
|
||||
_CHECK_METHOD_VERSION_KW +
|
||||
_EXPAND_METHOD_KW +
|
||||
flush + // so that self is in the argument array
|
||||
_PY_FRAME_KW +
|
||||
_SAVE_RETURN_OFFSET +
|
||||
_PUSH_FRAME;
|
||||
|
||||
specializing op(_SPECIALIZE_CALL_KW, (counter/1, callable, self_or_null, args[oparg], kwnames -- callable, self_or_null, args[oparg], kwnames)) {
|
||||
#if ENABLE_SPECIALIZATION
|
||||
if (ADAPTIVE_COUNTER_TRIGGERS(counter)) {
|
||||
next_instr = this_instr;
|
||||
_Py_Specialize_CallKw(callable, next_instr, oparg + !PyStackRef_IsNull(self_or_null));
|
||||
DISPATCH_SAME_OPARG();
|
||||
}
|
||||
STAT_INC(CALL, deferred);
|
||||
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
|
||||
#endif /* ENABLE_SPECIALIZATION */
|
||||
}
|
||||
|
||||
macro(CALL_KW) =
|
||||
_DO_CALL_KW +
|
||||
_SPECIALIZE_CALL_KW +
|
||||
unused/2 +
|
||||
_DO_CALL_KW;
|
||||
|
||||
op(_CHECK_IS_NOT_PY_CALLABLE_KW, (callable, unused, unused[oparg], kwnames -- callable, unused, unused[oparg], kwnames)) {
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
EXIT_IF(PyFunction_Check(callable_o));
|
||||
EXIT_IF(Py_TYPE(callable_o) == &PyMethod_Type);
|
||||
}
|
||||
|
||||
|
||||
op(_CALL_KW_NON_PY, (callable, self_or_null, args[oparg], kwnames -- res)) {
|
||||
#if TIER_ONE
|
||||
assert(opcode != INSTRUMENTED_CALL);
|
||||
#endif
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
PyObject *self_or_null_o = PyStackRef_AsPyObjectBorrow(self_or_null);
|
||||
|
||||
int total_args = oparg;
|
||||
if (self_or_null_o != NULL) {
|
||||
args--;
|
||||
total_args++;
|
||||
}
|
||||
/* Callable is not a normal Python function */
|
||||
STACKREFS_TO_PYOBJECTS(args, total_args, args_o);
|
||||
if (CONVERSION_FAILED(args_o)) {
|
||||
DECREF_INPUTS();
|
||||
ERROR_IF(true, error);
|
||||
}
|
||||
PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames);
|
||||
int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o);
|
||||
PyObject *res_o = PyObject_Vectorcall(
|
||||
callable_o, args_o,
|
||||
positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
|
||||
kwnames_o);
|
||||
PyStackRef_CLOSE(kwnames);
|
||||
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
|
||||
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||
PyStackRef_CLOSE(callable);
|
||||
for (int i = 0; i < total_args; i++) {
|
||||
PyStackRef_CLOSE(args[i]);
|
||||
}
|
||||
ERROR_IF(res_o == NULL, error);
|
||||
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||
}
|
||||
|
||||
macro(CALL_KW_NON_PY) =
|
||||
unused/1 + // Skip over the counter
|
||||
unused/2 +
|
||||
_CHECK_IS_NOT_PY_CALLABLE_KW +
|
||||
_CALL_KW_NON_PY +
|
||||
_CHECK_PERIODIC;
|
||||
|
||||
inst(INSTRUMENTED_CALL_FUNCTION_EX, ( -- )) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue