mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
GH-128563: Move some labels, to simplify implementing tailcalling interpreter. (GH-129525)
This commit is contained in:
parent
9ba281d871
commit
54f74b80ae
5 changed files with 89 additions and 54 deletions
|
@ -5303,14 +5303,40 @@ dummy_func(
|
||||||
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
|
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
goto resume_with_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
label(resume_with_error) {
|
|
||||||
next_instr = frame->instr_ptr;
|
next_instr = frame->instr_ptr;
|
||||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label(start_frame) {
|
||||||
|
if (_Py_EnterRecursivePy(tstate)) {
|
||||||
|
goto exit_unwind;
|
||||||
|
}
|
||||||
|
next_instr = frame->instr_ptr;
|
||||||
|
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||||
|
|
||||||
|
#ifdef LLTRACE
|
||||||
|
{
|
||||||
|
int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS());
|
||||||
|
frame->lltrace = lltrace;
|
||||||
|
if (lltrace < 0) {
|
||||||
|
goto exit_unwind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Py_DEBUG
|
||||||
|
/* _PyEval_EvalFrameDefault() must not be called with an exception set,
|
||||||
|
because it can clear it (directly or indirectly) and so the
|
||||||
|
caller loses its exception */
|
||||||
|
assert(!_PyErr_Occurred(tstate));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// END BYTECODES //
|
// END BYTECODES //
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5320,7 +5346,6 @@ dummy_func(
|
||||||
exit_unwind:
|
exit_unwind:
|
||||||
handle_eval_breaker:
|
handle_eval_breaker:
|
||||||
resume_frame:
|
resume_frame:
|
||||||
resume_with_error:
|
|
||||||
start_frame:
|
start_frame:
|
||||||
unbound_local_error:
|
unbound_local_error:
|
||||||
;
|
;
|
||||||
|
|
|
@ -792,6 +792,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Local "register" variables.
|
||||||
|
* These are cached values from the frame and code object. */
|
||||||
|
_Py_CODEUNIT *next_instr;
|
||||||
|
_PyStackRef *stack_pointer;
|
||||||
|
|
||||||
#if defined(Py_DEBUG) && !defined(Py_STACKREF_DEBUG)
|
#if defined(Py_DEBUG) && !defined(Py_STACKREF_DEBUG)
|
||||||
/* Set these to invalid but identifiable values for debugging. */
|
/* Set these to invalid but identifiable values for debugging. */
|
||||||
entry_frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0};
|
entry_frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0};
|
||||||
|
@ -819,67 +824,36 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
|
||||||
/* support for generator.throw() */
|
/* support for generator.throw() */
|
||||||
if (throwflag) {
|
if (throwflag) {
|
||||||
if (_Py_EnterRecursivePy(tstate)) {
|
if (_Py_EnterRecursivePy(tstate)) {
|
||||||
goto exit_unwind;
|
goto early_exit;
|
||||||
}
|
}
|
||||||
/* Because this avoids the RESUME,
|
|
||||||
* we need to update instrumentation */
|
|
||||||
#ifdef Py_GIL_DISABLED
|
#ifdef Py_GIL_DISABLED
|
||||||
/* Load thread-local bytecode */
|
/* Load thread-local bytecode */
|
||||||
if (frame->tlbc_index != ((_PyThreadStateImpl *)tstate)->tlbc_index) {
|
if (frame->tlbc_index != ((_PyThreadStateImpl *)tstate)->tlbc_index) {
|
||||||
_Py_CODEUNIT *bytecode =
|
_Py_CODEUNIT *bytecode =
|
||||||
_PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame));
|
_PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame));
|
||||||
if (bytecode == NULL) {
|
if (bytecode == NULL) {
|
||||||
goto exit_unwind;
|
goto early_exit;
|
||||||
}
|
}
|
||||||
ptrdiff_t off = frame->instr_ptr - _PyFrame_GetBytecode(frame);
|
ptrdiff_t off = frame->instr_ptr - _PyFrame_GetBytecode(frame);
|
||||||
frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index;
|
frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index;
|
||||||
frame->instr_ptr = bytecode + off;
|
frame->instr_ptr = bytecode + off;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
/* Because this avoids the RESUME, we need to update instrumentation */
|
||||||
_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
|
_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
|
||||||
monitor_throw(tstate, frame, frame->instr_ptr);
|
next_instr = frame->instr_ptr;
|
||||||
/* TO DO -- Monitor throw entry. */
|
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||||
goto resume_with_error;
|
monitor_throw(tstate, frame, next_instr);
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Local "register" variables.
|
|
||||||
* These are cached values from the frame and code object. */
|
|
||||||
_Py_CODEUNIT *next_instr;
|
|
||||||
_PyStackRef *stack_pointer;
|
|
||||||
|
|
||||||
#if defined(_Py_TIER2) && !defined(_Py_JIT)
|
#if defined(_Py_TIER2) && !defined(_Py_JIT)
|
||||||
/* Tier 2 interpreter state */
|
/* Tier 2 interpreter state */
|
||||||
_PyExecutorObject *current_executor = NULL;
|
_PyExecutorObject *current_executor = NULL;
|
||||||
const _PyUOpInstruction *next_uop = NULL;
|
const _PyUOpInstruction *next_uop = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
start_frame:
|
goto start_frame;
|
||||||
if (_Py_EnterRecursivePy(tstate)) {
|
|
||||||
goto exit_unwind;
|
|
||||||
}
|
|
||||||
|
|
||||||
next_instr = frame->instr_ptr;
|
|
||||||
resume_frame:
|
|
||||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
|
||||||
|
|
||||||
#ifdef LLTRACE
|
|
||||||
{
|
|
||||||
int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS());
|
|
||||||
frame->lltrace = lltrace;
|
|
||||||
if (lltrace < 0) {
|
|
||||||
goto exit_unwind;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Py_DEBUG
|
|
||||||
/* _PyEval_EvalFrameDefault() must not be called with an exception set,
|
|
||||||
because it can clear it (directly or indirectly) and so the
|
|
||||||
caller loses its exception */
|
|
||||||
assert(!_PyErr_Occurred(tstate));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DISPATCH();
|
|
||||||
|
|
||||||
#include "generated_cases.c.h"
|
#include "generated_cases.c.h"
|
||||||
|
|
||||||
|
@ -983,10 +957,10 @@ error_tier_two:
|
||||||
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
|
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
|
||||||
assert(next_uop[-1].format == UOP_FORMAT_TARGET);
|
assert(next_uop[-1].format == UOP_FORMAT_TARGET);
|
||||||
frame->return_offset = 0; // Don't leave this random
|
frame->return_offset = 0; // Don't leave this random
|
||||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
|
||||||
Py_DECREF(current_executor);
|
Py_DECREF(current_executor);
|
||||||
tstate->previous_executor = NULL;
|
tstate->previous_executor = NULL;
|
||||||
goto resume_with_error;
|
next_instr = frame->instr_ptr;
|
||||||
|
goto error;
|
||||||
|
|
||||||
jump_to_jump_target:
|
jump_to_jump_target:
|
||||||
assert(next_uop[-1].format == UOP_FORMAT_JUMP);
|
assert(next_uop[-1].format == UOP_FORMAT_JUMP);
|
||||||
|
@ -1018,6 +992,20 @@ goto_to_tier1:
|
||||||
|
|
||||||
#endif // _Py_TIER2
|
#endif // _Py_TIER2
|
||||||
|
|
||||||
|
early_exit:
|
||||||
|
assert(_PyErr_Occurred(tstate));
|
||||||
|
_Py_LeaveRecursiveCallPy(tstate);
|
||||||
|
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
|
||||||
|
// GH-99729: We need to unlink the frame *before* clearing it:
|
||||||
|
_PyInterpreterFrame *dying = frame;
|
||||||
|
frame = tstate->current_frame = dying->previous;
|
||||||
|
_PyEval_FrameClearAndPop(tstate, dying);
|
||||||
|
frame->return_offset = 0;
|
||||||
|
assert(frame->owner == FRAME_OWNED_BY_INTERPRETER);
|
||||||
|
/* Restore previous frame and exit */
|
||||||
|
tstate->current_frame = frame->previous;
|
||||||
|
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
|
|
|
@ -381,7 +381,9 @@ do { \
|
||||||
tstate->previous_executor = NULL; \
|
tstate->previous_executor = NULL; \
|
||||||
frame = tstate->current_frame; \
|
frame = tstate->current_frame; \
|
||||||
if (next_instr == NULL) { \
|
if (next_instr == NULL) { \
|
||||||
goto resume_with_error; \
|
next_instr = frame->instr_ptr; \
|
||||||
|
stack_pointer = _PyFrame_GetStackPointer(frame); \
|
||||||
|
goto error; \
|
||||||
} \
|
} \
|
||||||
stack_pointer = _PyFrame_GetStackPointer(frame); \
|
stack_pointer = _PyFrame_GetStackPointer(frame); \
|
||||||
DISPATCH(); \
|
DISPATCH(); \
|
||||||
|
|
32
Python/generated_cases.c.h
generated
32
Python/generated_cases.c.h
generated
|
@ -8703,15 +8703,37 @@
|
||||||
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
|
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
goto resume_with_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
resume_with_error:
|
|
||||||
{
|
|
||||||
next_instr = frame->instr_ptr;
|
next_instr = frame->instr_ptr;
|
||||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start_frame:
|
||||||
|
{
|
||||||
|
if (_Py_EnterRecursivePy(tstate)) {
|
||||||
|
goto exit_unwind;
|
||||||
|
}
|
||||||
|
next_instr = frame->instr_ptr;
|
||||||
|
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||||
|
#ifdef LLTRACE
|
||||||
|
{
|
||||||
|
int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS());
|
||||||
|
frame->lltrace = lltrace;
|
||||||
|
if (lltrace < 0) {
|
||||||
|
goto exit_unwind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Py_DEBUG
|
||||||
|
/* _PyEval_EvalFrameDefault() must not be called with an exception set,
|
||||||
|
because it can clear it (directly or indirectly) and so the
|
||||||
|
caller loses its exception */
|
||||||
|
assert(!_PyErr_Occurred(tstate));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
/* END LABELS */
|
/* END LABELS */
|
||||||
#undef TIER_ONE
|
#undef TIER_ONE
|
||||||
|
|
|
@ -511,7 +511,6 @@ def has_error_with_pop(op: parser.InstDef) -> bool:
|
||||||
variable_used(op, "ERROR_IF")
|
variable_used(op, "ERROR_IF")
|
||||||
or variable_used(op, "pop_1_error")
|
or variable_used(op, "pop_1_error")
|
||||||
or variable_used(op, "exception_unwind")
|
or variable_used(op, "exception_unwind")
|
||||||
or variable_used(op, "resume_with_error")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -520,7 +519,6 @@ def has_error_without_pop(op: parser.InstDef) -> bool:
|
||||||
variable_used(op, "ERROR_NO_POP")
|
variable_used(op, "ERROR_NO_POP")
|
||||||
or variable_used(op, "pop_1_error")
|
or variable_used(op, "pop_1_error")
|
||||||
or variable_used(op, "exception_unwind")
|
or variable_used(op, "exception_unwind")
|
||||||
or variable_used(op, "resume_with_error")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue