mirror of
https://github.com/python/cpython.git
synced 2025-07-17 16:25:18 +00:00
GH-118095: Handle RETURN_GENERATOR
in tier 2 (GH-118180)
This commit is contained in:
parent
10bb90ed49
commit
f180b31e76
16 changed files with 143 additions and 81 deletions
|
@ -837,12 +837,7 @@ dummy_func(
|
|||
_PyFrame_StackPush(frame, retval);
|
||||
LOAD_SP();
|
||||
LOAD_IP(frame->return_offset);
|
||||
#if LLTRACE && TIER_ONE
|
||||
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
|
||||
if (lltrace < 0) {
|
||||
goto exit_unwind;
|
||||
}
|
||||
#endif
|
||||
LLTRACE_RESUME_FRAME();
|
||||
}
|
||||
|
||||
macro(RETURN_VALUE) =
|
||||
|
@ -3186,12 +3181,7 @@ dummy_func(
|
|||
tstate->py_recursion_remaining--;
|
||||
LOAD_SP();
|
||||
LOAD_IP(0);
|
||||
#if LLTRACE && TIER_ONE
|
||||
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
|
||||
if (lltrace < 0) {
|
||||
goto exit_unwind;
|
||||
}
|
||||
#endif
|
||||
LLTRACE_RESUME_FRAME();
|
||||
}
|
||||
|
||||
macro(CALL_BOUND_METHOD_EXACT_ARGS) =
|
||||
|
@ -3877,7 +3867,7 @@ dummy_func(
|
|||
}
|
||||
}
|
||||
|
||||
tier1 inst(RETURN_GENERATOR, (--)) {
|
||||
inst(RETURN_GENERATOR, (-- res)) {
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
|
||||
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
|
||||
|
@ -3887,19 +3877,19 @@ dummy_func(
|
|||
assert(EMPTY());
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
frame->instr_ptr = next_instr;
|
||||
frame->instr_ptr++;
|
||||
_PyFrame_Copy(frame, gen_frame);
|
||||
assert(frame->frame_obj == NULL);
|
||||
gen->gi_frame_state = FRAME_CREATED;
|
||||
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
|
||||
_Py_LeaveRecursiveCallPy(tstate);
|
||||
assert(frame != &entry_frame);
|
||||
res = (PyObject *)gen;
|
||||
_PyInterpreterFrame *prev = frame->previous;
|
||||
_PyThreadState_PopFrame(tstate, frame);
|
||||
frame = tstate->current_frame = prev;
|
||||
_PyFrame_StackPush(frame, (PyObject *)gen);
|
||||
LOAD_IP(frame->return_offset);
|
||||
goto resume_frame;
|
||||
LOAD_SP();
|
||||
LLTRACE_RESUME_FRAME();
|
||||
}
|
||||
|
||||
inst(BUILD_SLICE, (start, stop, step if (oparg == 3) -- slice)) {
|
||||
|
|
|
@ -86,6 +86,18 @@
|
|||
#define PRE_DISPATCH_GOTO() ((void)0)
|
||||
#endif
|
||||
|
||||
#if LLTRACE
|
||||
#define LLTRACE_RESUME_FRAME() \
|
||||
do { \
|
||||
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); \
|
||||
if (lltrace < 0) { \
|
||||
goto exit_unwind; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define LLTRACE_RESUME_FRAME() ((void)0)
|
||||
#endif
|
||||
|
||||
#ifdef Py_GIL_DISABLED
|
||||
#define QSBR_QUIESCENT_STATE(tstate) _Py_qsbr_quiescent_state(((_PyThreadStateImpl *)tstate)->qsbr)
|
||||
#else
|
||||
|
|
43
Python/executor_cases.c.h
generated
43
Python/executor_cases.c.h
generated
|
@ -988,12 +988,7 @@
|
|||
_PyFrame_StackPush(frame, retval);
|
||||
LOAD_SP();
|
||||
LOAD_IP(frame->return_offset);
|
||||
#if LLTRACE && TIER_ONE
|
||||
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
|
||||
if (lltrace < 0) {
|
||||
goto exit_unwind;
|
||||
}
|
||||
#endif
|
||||
LLTRACE_RESUME_FRAME();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3213,12 +3208,7 @@
|
|||
tstate->py_recursion_remaining--;
|
||||
LOAD_SP();
|
||||
LOAD_IP(0);
|
||||
#if LLTRACE && TIER_ONE
|
||||
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
|
||||
if (lltrace < 0) {
|
||||
goto exit_unwind;
|
||||
}
|
||||
#endif
|
||||
LLTRACE_RESUME_FRAME();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3833,6 +3823,35 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _RETURN_GENERATOR: {
|
||||
PyObject *res;
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
|
||||
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
|
||||
if (gen == NULL) {
|
||||
JUMP_TO_ERROR();
|
||||
}
|
||||
assert(EMPTY());
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
frame->instr_ptr++;
|
||||
_PyFrame_Copy(frame, gen_frame);
|
||||
assert(frame->frame_obj == NULL);
|
||||
gen->gi_frame_state = FRAME_CREATED;
|
||||
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
|
||||
_Py_LeaveRecursiveCallPy(tstate);
|
||||
res = (PyObject *)gen;
|
||||
_PyInterpreterFrame *prev = frame->previous;
|
||||
_PyThreadState_PopFrame(tstate, frame);
|
||||
frame = tstate->current_frame = prev;
|
||||
LOAD_IP(frame->return_offset);
|
||||
LOAD_SP();
|
||||
LLTRACE_RESUME_FRAME();
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case _BUILD_SLICE: {
|
||||
PyObject *step = NULL;
|
||||
PyObject *stop;
|
||||
|
|
|
@ -53,18 +53,6 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame)
|
|||
return f;
|
||||
}
|
||||
|
||||
void
|
||||
_PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest)
|
||||
{
|
||||
assert(src->stacktop >= _PyFrame_GetCode(src)->co_nlocalsplus);
|
||||
Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src;
|
||||
memcpy(dest, src, size);
|
||||
// Don't leave a dangling pointer to the old frame when creating generators
|
||||
// and coroutines:
|
||||
dest->previous = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
|
||||
{
|
||||
|
|
40
Python/generated_cases.c.h
generated
40
Python/generated_cases.c.h
generated
|
@ -997,12 +997,7 @@
|
|||
tstate->py_recursion_remaining--;
|
||||
LOAD_SP();
|
||||
LOAD_IP(0);
|
||||
#if LLTRACE && TIER_ONE
|
||||
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
|
||||
if (lltrace < 0) {
|
||||
goto exit_unwind;
|
||||
}
|
||||
#endif
|
||||
LLTRACE_RESUME_FRAME();
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
|
@ -1786,12 +1781,7 @@
|
|||
tstate->py_recursion_remaining--;
|
||||
LOAD_SP();
|
||||
LOAD_IP(0);
|
||||
#if LLTRACE && TIER_ONE
|
||||
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
|
||||
if (lltrace < 0) {
|
||||
goto exit_unwind;
|
||||
}
|
||||
#endif
|
||||
LLTRACE_RESUME_FRAME();
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
|
@ -4992,12 +4982,7 @@
|
|||
_PyFrame_StackPush(frame, retval);
|
||||
LOAD_SP();
|
||||
LOAD_IP(frame->return_offset);
|
||||
#if LLTRACE && TIER_ONE
|
||||
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
|
||||
if (lltrace < 0) {
|
||||
goto exit_unwind;
|
||||
}
|
||||
#endif
|
||||
LLTRACE_RESUME_FRAME();
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
|
@ -5006,6 +4991,7 @@
|
|||
frame->instr_ptr = next_instr;
|
||||
next_instr += 1;
|
||||
INSTRUCTION_STATS(RETURN_GENERATOR);
|
||||
PyObject *res;
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
|
||||
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
|
||||
|
@ -5015,19 +5001,22 @@
|
|||
assert(EMPTY());
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
frame->instr_ptr = next_instr;
|
||||
frame->instr_ptr++;
|
||||
_PyFrame_Copy(frame, gen_frame);
|
||||
assert(frame->frame_obj == NULL);
|
||||
gen->gi_frame_state = FRAME_CREATED;
|
||||
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
|
||||
_Py_LeaveRecursiveCallPy(tstate);
|
||||
assert(frame != &entry_frame);
|
||||
res = (PyObject *)gen;
|
||||
_PyInterpreterFrame *prev = frame->previous;
|
||||
_PyThreadState_PopFrame(tstate, frame);
|
||||
frame = tstate->current_frame = prev;
|
||||
_PyFrame_StackPush(frame, (PyObject *)gen);
|
||||
LOAD_IP(frame->return_offset);
|
||||
goto resume_frame;
|
||||
LOAD_SP();
|
||||
LLTRACE_RESUME_FRAME();
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(RETURN_VALUE) {
|
||||
|
@ -5050,12 +5039,7 @@
|
|||
_PyFrame_StackPush(frame, retval);
|
||||
LOAD_SP();
|
||||
LOAD_IP(frame->return_offset);
|
||||
#if LLTRACE && TIER_ONE
|
||||
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS());
|
||||
if (lltrace < 0) {
|
||||
goto exit_unwind;
|
||||
}
|
||||
#endif
|
||||
LLTRACE_RESUME_FRAME();
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
|
|
|
@ -697,7 +697,8 @@ top: // Jump here after _PUSH_FRAME or likely branches
|
|||
// Reserve space for nuops (+ _SET_IP + _EXIT_TRACE)
|
||||
int nuops = expansion->nuops;
|
||||
RESERVE(nuops + 1); /* One extra for exit */
|
||||
if (expansion->uops[nuops-1].uop == _POP_FRAME) {
|
||||
int16_t last_op = expansion->uops[nuops-1].uop;
|
||||
if (last_op == _POP_FRAME || last_op == _RETURN_GENERATOR) {
|
||||
// Check for trace stack underflow now:
|
||||
// We can't bail e.g. in the middle of
|
||||
// LOAD_CONST + _POP_FRAME.
|
||||
|
@ -756,7 +757,7 @@ top: // Jump here after _PUSH_FRAME or likely branches
|
|||
Py_FatalError("garbled expansion");
|
||||
}
|
||||
|
||||
if (uop == _POP_FRAME) {
|
||||
if (uop == _POP_FRAME || uop == _RETURN_GENERATOR) {
|
||||
TRACE_STACK_POP();
|
||||
/* Set the operand to the function or code object returned to,
|
||||
* to assist optimization passes. (See _PUSH_FRAME below.)
|
||||
|
|
|
@ -369,7 +369,7 @@ eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit)
|
|||
static PyCodeObject *
|
||||
get_code(_PyUOpInstruction *op)
|
||||
{
|
||||
assert(op->opcode == _PUSH_FRAME || op->opcode == _POP_FRAME);
|
||||
assert(op->opcode == _PUSH_FRAME || op->opcode == _POP_FRAME || op->opcode == _RETURN_GENERATOR);
|
||||
PyCodeObject *co = NULL;
|
||||
uint64_t operand = op->operand;
|
||||
if (operand == 0) {
|
||||
|
|
|
@ -651,6 +651,28 @@ dummy_func(void) {
|
|||
}
|
||||
}
|
||||
|
||||
op(_RETURN_GENERATOR, ( -- res)) {
|
||||
SYNC_SP();
|
||||
ctx->frame->stack_pointer = stack_pointer;
|
||||
frame_pop(ctx);
|
||||
stack_pointer = ctx->frame->stack_pointer;
|
||||
OUT_OF_SPACE_IF_NULL(res = sym_new_unknown(ctx));
|
||||
|
||||
/* Stack space handling */
|
||||
assert(corresponding_check_stack == NULL);
|
||||
assert(co != NULL);
|
||||
int framesize = co->co_framesize;
|
||||
assert(framesize > 0);
|
||||
assert(framesize <= curr_space);
|
||||
curr_space -= framesize;
|
||||
|
||||
co = get_code(this_instr);
|
||||
if (co == NULL) {
|
||||
// might be impossible, but bailing is still safe
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
op(_CHECK_STACK_SPACE, ( --)) {
|
||||
assert(corresponding_check_stack == NULL);
|
||||
corresponding_check_stack = this_instr;
|
||||
|
|
23
Python/optimizer_cases.c.h
generated
23
Python/optimizer_cases.c.h
generated
|
@ -1840,6 +1840,29 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _RETURN_GENERATOR: {
|
||||
_Py_UopsSymbol *res;
|
||||
ctx->frame->stack_pointer = stack_pointer;
|
||||
frame_pop(ctx);
|
||||
stack_pointer = ctx->frame->stack_pointer;
|
||||
OUT_OF_SPACE_IF_NULL(res = sym_new_unknown(ctx));
|
||||
/* Stack space handling */
|
||||
assert(corresponding_check_stack == NULL);
|
||||
assert(co != NULL);
|
||||
int framesize = co->co_framesize;
|
||||
assert(framesize > 0);
|
||||
assert(framesize <= curr_space);
|
||||
curr_space -= framesize;
|
||||
co = get_code(this_instr);
|
||||
if (co == NULL) {
|
||||
// might be impossible, but bailing is still safe
|
||||
goto done;
|
||||
}
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case _BUILD_SLICE: {
|
||||
_Py_UopsSymbol *slice;
|
||||
slice = sym_new_not_null(ctx);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue