mirror of
https://github.com/python/cpython.git
synced 2025-07-19 17:25:54 +00:00
gh-106581: Split CALL_PY_EXACT_ARGS
into uops (#107760)
* Split `CALL_PY_EXACT_ARGS` into uops This is only the first step for doing `CALL` in Tier 2. The next step involves tracing into the called code object and back. After that we'll have to do the remaining `CALL` specialization. Finally we'll have to deal with `KW_NAMES`. Note: this moves setting `frame->return_offset` directly in front of `DISPATCH_INLINED()`, to make it easier to move it into `_PUSH_FRAME`.
This commit is contained in:
parent
665a4391e1
commit
dc8fdf5fd5
14 changed files with 412 additions and 116 deletions
28
Python/abstract_interp_cases.c.h
generated
28
Python/abstract_interp_cases.c.h
generated
|
@ -612,6 +612,30 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _CHECK_PEP_523: {
|
||||
break;
|
||||
}
|
||||
|
||||
case _CHECK_FUNCTION_EXACT_ARGS: {
|
||||
break;
|
||||
}
|
||||
|
||||
case _CHECK_STACK_SPACE: {
|
||||
break;
|
||||
}
|
||||
|
||||
case _INIT_CALL_PY_EXACT_ARGS: {
|
||||
STACK_SHRINK(oparg);
|
||||
STACK_SHRINK(1);
|
||||
PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
|
||||
break;
|
||||
}
|
||||
|
||||
case _PUSH_FRAME: {
|
||||
PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
|
||||
break;
|
||||
}
|
||||
|
||||
case CALL_NO_KW_TYPE_1: {
|
||||
STACK_SHRINK(oparg);
|
||||
STACK_SHRINK(1);
|
||||
|
@ -751,6 +775,10 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case SAVE_CURRENT_IP: {
|
||||
break;
|
||||
}
|
||||
|
||||
case EXIT_TRACE: {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -956,13 +956,13 @@ dummy_func(
|
|||
{
|
||||
PyGenObject *gen = (PyGenObject *)receiver;
|
||||
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
frame->return_offset = oparg;
|
||||
STACK_SHRINK(1);
|
||||
_PyFrame_StackPush(gen_frame, v);
|
||||
gen->gi_frame_state = FRAME_EXECUTING;
|
||||
gen->gi_exc_state.previous_item = tstate->exc_info;
|
||||
tstate->exc_info = &gen->gi_exc_state;
|
||||
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
|
||||
frame->return_offset = oparg;
|
||||
DISPATCH_INLINED(gen_frame);
|
||||
}
|
||||
if (Py_IsNone(v) && PyIter_Check(receiver)) {
|
||||
|
@ -995,13 +995,13 @@ dummy_func(
|
|||
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND);
|
||||
STAT_INC(SEND, hit);
|
||||
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
frame->return_offset = oparg;
|
||||
STACK_SHRINK(1);
|
||||
_PyFrame_StackPush(gen_frame, v);
|
||||
gen->gi_frame_state = FRAME_EXECUTING;
|
||||
gen->gi_exc_state.previous_item = tstate->exc_info;
|
||||
tstate->exc_info = &gen->gi_exc_state;
|
||||
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
|
||||
frame->return_offset = oparg;
|
||||
DISPATCH_INLINED(gen_frame);
|
||||
}
|
||||
|
||||
|
@ -2587,7 +2587,6 @@ dummy_func(
|
|||
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER);
|
||||
STAT_INC(FOR_ITER, hit);
|
||||
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
frame->return_offset = oparg;
|
||||
_PyFrame_StackPush(gen_frame, Py_None);
|
||||
gen->gi_frame_state = FRAME_EXECUTING;
|
||||
gen->gi_exc_state.previous_item = tstate->exc_info;
|
||||
|
@ -2595,6 +2594,7 @@ dummy_func(
|
|||
SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER);
|
||||
assert(next_instr[oparg].op.code == END_FOR ||
|
||||
next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
|
||||
frame->return_offset = oparg;
|
||||
DISPATCH_INLINED(gen_frame);
|
||||
}
|
||||
|
||||
|
@ -2949,32 +2949,72 @@ dummy_func(
|
|||
GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS);
|
||||
}
|
||||
|
||||
inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, callable, self_or_null, args[oparg] -- unused)) {
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
op(_CHECK_PEP_523, (--)) {
|
||||
DEOPT_IF(tstate->interp->eval_frame, CALL);
|
||||
}
|
||||
|
||||
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);
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
DEOPT_IF(code->co_argcount != oparg + (self_or_null != NULL), CALL);
|
||||
}
|
||||
|
||||
op(_CHECK_STACK_SPACE, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) {
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
|
||||
}
|
||||
|
||||
op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame: _PyInterpreterFrame*)) {
|
||||
int argcount = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
args--;
|
||||
argcount++;
|
||||
}
|
||||
DEOPT_IF(!PyFunction_Check(callable), CALL);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
DEOPT_IF(func->func_version != func_version, CALL);
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
DEOPT_IF(code->co_argcount != argcount, CALL);
|
||||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
|
||||
for (int i = 0; i < argcount; i++) {
|
||||
new_frame->localsplus[i] = args[i];
|
||||
}
|
||||
// Manipulate stack directly since we leave using DISPATCH_INLINED().
|
||||
STACK_SHRINK(oparg + 2);
|
||||
SKIP_OVER(INLINE_CACHE_ENTRIES_CALL);
|
||||
frame->return_offset = 0;
|
||||
DISPATCH_INLINED(new_frame);
|
||||
}
|
||||
|
||||
// The 'unused' output effect represents the return value
|
||||
// (which will be pushed when the frame returns).
|
||||
// It is needed so CALL_PY_EXACT_ARGS matches its family.
|
||||
op(_PUSH_FRAME, (new_frame: _PyInterpreterFrame* -- unused)) {
|
||||
// Write it out explicitly because it's subtly different.
|
||||
// Eventually this should be the only occurrence of this code.
|
||||
frame->return_offset = 0;
|
||||
assert(tstate->interp->eval_frame == NULL);
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
new_frame->previous = frame;
|
||||
CALL_STAT_INC(inlined_py_calls);
|
||||
#if TIER_ONE
|
||||
frame = cframe.current_frame = new_frame;
|
||||
goto start_frame;
|
||||
#endif
|
||||
#if TIER_TWO
|
||||
frame = tstate->cframe->current_frame = new_frame;
|
||||
ERROR_IF(_Py_EnterRecursivePy(tstate), exit_unwind);
|
||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||
ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive;
|
||||
#endif
|
||||
}
|
||||
|
||||
macro(CALL_PY_EXACT_ARGS) =
|
||||
unused/1 + // Skip over the counter
|
||||
_CHECK_PEP_523 +
|
||||
_CHECK_FUNCTION_EXACT_ARGS +
|
||||
_CHECK_STACK_SPACE +
|
||||
_INIT_CALL_PY_EXACT_ARGS +
|
||||
SAVE_IP + // Tier 2 only; special-cased oparg
|
||||
SAVE_CURRENT_IP + // Sets frame->prev_instr
|
||||
_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);
|
||||
|
@ -3735,6 +3775,16 @@ dummy_func(
|
|||
frame->prev_instr = ip_offset + oparg;
|
||||
}
|
||||
|
||||
op(SAVE_CURRENT_IP, (--)) {
|
||||
#if TIER_ONE
|
||||
frame->prev_instr = next_instr - 1;
|
||||
#endif
|
||||
#if TIER_TWO
|
||||
// Relies on a preceding SAVE_IP
|
||||
frame->prev_instr--;
|
||||
#endif
|
||||
}
|
||||
|
||||
op(EXIT_TRACE, (--)) {
|
||||
frame->prev_instr--; // Back up to just before destination
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
|
|
|
@ -602,11 +602,6 @@ int _Py_CheckRecursiveCallPy(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int _Py_EnterRecursivePy(PyThreadState *tstate) {
|
||||
return (tstate->py_recursion_remaining-- <= 0) &&
|
||||
_Py_CheckRecursiveCallPy(tstate);
|
||||
}
|
||||
|
||||
|
||||
static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) {
|
||||
tstate->py_recursion_remaining++;
|
||||
|
@ -770,6 +765,7 @@ resume_frame:
|
|||
#endif
|
||||
{
|
||||
|
||||
#define TIER_ONE 1
|
||||
#include "generated_cases.c.h"
|
||||
|
||||
/* INSTRUMENTED_LINE has to be here, rather than in bytecodes.c,
|
||||
|
|
|
@ -364,3 +364,8 @@ static const convertion_func_ptr CONVERSION_FUNCTIONS[4] = {
|
|||
#else
|
||||
#define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) _Py_atomic_load_relaxed(ATOMIC_VAL)
|
||||
#endif
|
||||
|
||||
static inline int _Py_EnterRecursivePy(PyThreadState *tstate) {
|
||||
return (tstate->py_recursion_remaining-- <= 0) &&
|
||||
_Py_CheckRecursiveCallPy(tstate);
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
|
|||
OBJECT_STAT_INC(optimization_uops_executed);
|
||||
switch (opcode) {
|
||||
|
||||
#define TIER_TWO 2
|
||||
#include "executor_cases.c.h"
|
||||
|
||||
default:
|
||||
|
@ -106,6 +107,7 @@ pop_3_error:
|
|||
pop_2_error:
|
||||
STACK_SHRINK(1);
|
||||
pop_1_error:
|
||||
pop_1_exit_unwind:
|
||||
STACK_SHRINK(1);
|
||||
error:
|
||||
// On ERROR_IF we return NULL as the frame.
|
||||
|
|
98
Python/executor_cases.c.h
generated
98
Python/executor_cases.c.h
generated
|
@ -103,7 +103,6 @@
|
|||
}
|
||||
|
||||
case TO_BOOL: {
|
||||
static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size");
|
||||
PyObject *value;
|
||||
PyObject *res;
|
||||
value = stack_pointer[-1];
|
||||
|
@ -363,7 +362,6 @@
|
|||
}
|
||||
|
||||
case BINARY_SUBSCR: {
|
||||
static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size");
|
||||
PyObject *sub;
|
||||
PyObject *container;
|
||||
PyObject *res;
|
||||
|
@ -557,7 +555,6 @@
|
|||
}
|
||||
|
||||
case STORE_SUBSCR: {
|
||||
static_assert(INLINE_CACHE_ENTRIES_STORE_SUBSCR == 1, "incorrect cache size");
|
||||
PyObject *sub;
|
||||
PyObject *container;
|
||||
PyObject *v;
|
||||
|
@ -862,7 +859,6 @@
|
|||
}
|
||||
|
||||
case UNPACK_SEQUENCE: {
|
||||
static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size");
|
||||
PyObject *seq;
|
||||
seq = stack_pointer[-1];
|
||||
#if ENABLE_SPECIALIZATION
|
||||
|
@ -950,7 +946,6 @@
|
|||
}
|
||||
|
||||
case STORE_ATTR: {
|
||||
static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size");
|
||||
PyObject *owner;
|
||||
PyObject *v;
|
||||
owner = stack_pointer[-1];
|
||||
|
@ -1061,7 +1056,6 @@
|
|||
}
|
||||
|
||||
case LOAD_GLOBAL: {
|
||||
static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size");
|
||||
PyObject *res;
|
||||
PyObject *null = NULL;
|
||||
#if ENABLE_SPECIALIZATION
|
||||
|
@ -1554,7 +1548,6 @@
|
|||
}
|
||||
|
||||
case LOAD_ATTR: {
|
||||
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
|
||||
PyObject *owner;
|
||||
PyObject *attr;
|
||||
PyObject *self_or_null = NULL;
|
||||
|
@ -1650,7 +1643,6 @@
|
|||
}
|
||||
|
||||
case COMPARE_OP: {
|
||||
static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size");
|
||||
PyObject *right;
|
||||
PyObject *left;
|
||||
PyObject *res;
|
||||
|
@ -2155,6 +2147,84 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _CHECK_PEP_523: {
|
||||
DEOPT_IF(tstate->interp->eval_frame, CALL);
|
||||
break;
|
||||
}
|
||||
|
||||
case _CHECK_FUNCTION_EXACT_ARGS: {
|
||||
PyObject *self_or_null;
|
||||
PyObject *callable;
|
||||
self_or_null = stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
uint32_t func_version = (uint32_t)operand;
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
DEOPT_IF(!PyFunction_Check(callable), CALL);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
DEOPT_IF(func->func_version != func_version, CALL);
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
DEOPT_IF(code->co_argcount != oparg + (self_or_null != NULL), CALL);
|
||||
break;
|
||||
}
|
||||
|
||||
case _CHECK_STACK_SPACE: {
|
||||
PyObject *callable;
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
|
||||
break;
|
||||
}
|
||||
|
||||
case _INIT_CALL_PY_EXACT_ARGS: {
|
||||
PyObject **args;
|
||||
PyObject *self_or_null;
|
||||
PyObject *callable;
|
||||
_PyInterpreterFrame *new_frame;
|
||||
args = stack_pointer - oparg;
|
||||
self_or_null = stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
int argcount = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
args--;
|
||||
argcount++;
|
||||
}
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
|
||||
for (int i = 0; i < argcount; i++) {
|
||||
new_frame->localsplus[i] = args[i];
|
||||
}
|
||||
STACK_SHRINK(oparg);
|
||||
STACK_SHRINK(1);
|
||||
stack_pointer[-1] = (PyObject *)new_frame;
|
||||
break;
|
||||
}
|
||||
|
||||
case _PUSH_FRAME: {
|
||||
_PyInterpreterFrame *new_frame;
|
||||
new_frame = (_PyInterpreterFrame *)stack_pointer[-1];
|
||||
STACK_SHRINK(1);
|
||||
// Write it out explicitly because it's subtly different.
|
||||
// Eventually this should be the only occurrence of this code.
|
||||
frame->return_offset = 0;
|
||||
assert(tstate->interp->eval_frame == NULL);
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
new_frame->previous = frame;
|
||||
CALL_STAT_INC(inlined_py_calls);
|
||||
#if TIER_ONE
|
||||
frame = cframe.current_frame = new_frame;
|
||||
goto start_frame;
|
||||
#endif
|
||||
#if TIER_TWO
|
||||
frame = tstate->cframe->current_frame = new_frame;
|
||||
if (_Py_EnterRecursivePy(tstate)) goto pop_1_exit_unwind;
|
||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||
ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case CALL_NO_KW_TYPE_1: {
|
||||
PyObject **args;
|
||||
PyObject *null;
|
||||
|
@ -2656,7 +2726,6 @@
|
|||
}
|
||||
|
||||
case BINARY_OP: {
|
||||
static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size");
|
||||
PyObject *rhs;
|
||||
PyObject *lhs;
|
||||
PyObject *res;
|
||||
|
@ -2726,6 +2795,17 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case SAVE_CURRENT_IP: {
|
||||
#if TIER_ONE
|
||||
frame->prev_instr = next_instr - 1;
|
||||
#endif
|
||||
#if TIER_TWO
|
||||
// Relies on a preceding SAVE_IP
|
||||
frame->prev_instr--;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case EXIT_TRACE: {
|
||||
frame->prev_instr--; // Back up to just before destination
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
|
|
99
Python/generated_cases.c.h
generated
99
Python/generated_cases.c.h
generated
|
@ -1191,13 +1191,13 @@
|
|||
{
|
||||
PyGenObject *gen = (PyGenObject *)receiver;
|
||||
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
frame->return_offset = oparg;
|
||||
STACK_SHRINK(1);
|
||||
_PyFrame_StackPush(gen_frame, v);
|
||||
gen->gi_frame_state = FRAME_EXECUTING;
|
||||
gen->gi_exc_state.previous_item = tstate->exc_info;
|
||||
tstate->exc_info = &gen->gi_exc_state;
|
||||
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
|
||||
frame->return_offset = oparg;
|
||||
DISPATCH_INLINED(gen_frame);
|
||||
}
|
||||
if (Py_IsNone(v) && PyIter_Check(receiver)) {
|
||||
|
@ -1237,13 +1237,13 @@
|
|||
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND);
|
||||
STAT_INC(SEND, hit);
|
||||
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
frame->return_offset = oparg;
|
||||
STACK_SHRINK(1);
|
||||
_PyFrame_StackPush(gen_frame, v);
|
||||
gen->gi_frame_state = FRAME_EXECUTING;
|
||||
gen->gi_exc_state.previous_item = tstate->exc_info;
|
||||
tstate->exc_info = &gen->gi_exc_state;
|
||||
SKIP_OVER(INLINE_CACHE_ENTRIES_SEND);
|
||||
frame->return_offset = oparg;
|
||||
DISPATCH_INLINED(gen_frame);
|
||||
}
|
||||
|
||||
|
@ -3343,7 +3343,6 @@
|
|||
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER);
|
||||
STAT_INC(FOR_ITER, hit);
|
||||
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
frame->return_offset = oparg;
|
||||
_PyFrame_StackPush(gen_frame, Py_None);
|
||||
gen->gi_frame_state = FRAME_EXECUTING;
|
||||
gen->gi_exc_state.previous_item = tstate->exc_info;
|
||||
|
@ -3351,6 +3350,7 @@
|
|||
SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER);
|
||||
assert(next_instr[oparg].op.code == END_FOR ||
|
||||
next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
|
||||
frame->return_offset = oparg;
|
||||
DISPATCH_INLINED(gen_frame);
|
||||
STACK_GROW(1);
|
||||
}
|
||||
|
@ -3764,38 +3764,83 @@
|
|||
|
||||
TARGET(CALL_PY_EXACT_ARGS) {
|
||||
PREDICTED(CALL_PY_EXACT_ARGS);
|
||||
PyObject **args;
|
||||
PyObject *self_or_null;
|
||||
PyObject *callable;
|
||||
PyObject **args;
|
||||
_PyInterpreterFrame *new_frame;
|
||||
// _CHECK_PEP_523
|
||||
{
|
||||
DEOPT_IF(tstate->interp->eval_frame, CALL);
|
||||
}
|
||||
// _CHECK_FUNCTION_EXACT_ARGS
|
||||
self_or_null = stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
{
|
||||
uint32_t func_version = read_u32(&next_instr[1].cache);
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
DEOPT_IF(!PyFunction_Check(callable), CALL);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
DEOPT_IF(func->func_version != func_version, CALL);
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
DEOPT_IF(code->co_argcount != oparg + (self_or_null != NULL), CALL);
|
||||
}
|
||||
// _CHECK_STACK_SPACE
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
{
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
|
||||
}
|
||||
// _INIT_CALL_PY_EXACT_ARGS
|
||||
args = stack_pointer - oparg;
|
||||
self_or_null = stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
uint32_t func_version = read_u32(&next_instr[1].cache);
|
||||
ASSERT_KWNAMES_IS_NULL();
|
||||
DEOPT_IF(tstate->interp->eval_frame, CALL);
|
||||
int argcount = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
args--;
|
||||
argcount++;
|
||||
{
|
||||
int argcount = oparg;
|
||||
if (self_or_null != NULL) {
|
||||
args--;
|
||||
argcount++;
|
||||
}
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
|
||||
for (int i = 0; i < argcount; i++) {
|
||||
new_frame->localsplus[i] = args[i];
|
||||
}
|
||||
}
|
||||
DEOPT_IF(!PyFunction_Check(callable), CALL);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
DEOPT_IF(func->func_version != func_version, CALL);
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
DEOPT_IF(code->co_argcount != argcount, CALL);
|
||||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, argcount);
|
||||
for (int i = 0; i < argcount; i++) {
|
||||
new_frame->localsplus[i] = args[i];
|
||||
// SAVE_CURRENT_IP
|
||||
next_instr += 3;
|
||||
{
|
||||
#if TIER_ONE
|
||||
frame->prev_instr = next_instr - 1;
|
||||
#endif
|
||||
#if TIER_TWO
|
||||
// Relies on a preceding SAVE_IP
|
||||
frame->prev_instr--;
|
||||
#endif
|
||||
}
|
||||
// Manipulate stack directly since we leave using DISPATCH_INLINED().
|
||||
STACK_SHRINK(oparg + 2);
|
||||
SKIP_OVER(INLINE_CACHE_ENTRIES_CALL);
|
||||
frame->return_offset = 0;
|
||||
DISPATCH_INLINED(new_frame);
|
||||
// _PUSH_FRAME
|
||||
STACK_SHRINK(oparg);
|
||||
STACK_SHRINK(1);
|
||||
STACK_SHRINK(2);
|
||||
{
|
||||
// Write it out explicitly because it's subtly different.
|
||||
// Eventually this should be the only occurrence of this code.
|
||||
frame->return_offset = 0;
|
||||
assert(tstate->interp->eval_frame == NULL);
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
new_frame->previous = frame;
|
||||
CALL_STAT_INC(inlined_py_calls);
|
||||
#if TIER_ONE
|
||||
frame = cframe.current_frame = new_frame;
|
||||
goto start_frame;
|
||||
#endif
|
||||
#if TIER_TWO
|
||||
frame = tstate->cframe->current_frame = new_frame;
|
||||
if (_Py_EnterRecursivePy(tstate)) goto pop_1_exit_unwind;
|
||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||
ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
TARGET(CALL_PY_WITH_DEFAULTS) {
|
||||
|
|
|
@ -606,6 +606,10 @@ pop_jump_if_bool:
|
|||
case OPARG_BOTTOM: // Second half of super-instr
|
||||
oparg = orig_oparg & 0xF;
|
||||
break;
|
||||
case OPARG_SAVE_IP: // op==SAVE_IP; oparg=next instr
|
||||
oparg = INSTR_IP(instr + offset, code);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"opcode=%d, oparg=%d; nuops=%d, i=%d; size=%d, offset=%d\n",
|
||||
|
@ -615,6 +619,11 @@ pop_jump_if_bool:
|
|||
Py_FatalError("garbled expansion");
|
||||
}
|
||||
ADD_TO_TRACE(expansion->uops[i].uop, oparg, operand);
|
||||
if (expansion->uops[i].uop == _PUSH_FRAME) {
|
||||
assert(i + 1 == nuops);
|
||||
ADD_TO_TRACE(SAVE_IP, 0, 0);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue