GH-128563: Add new frame owner type for interpreter entry frames (GH-129078)

Add new frame owner type for interpreter entry frames
This commit is contained in:
Mark Shannon 2025-01-21 10:15:02 +00:00 committed by GitHub
parent d3b1bb228c
commit f5b6356a11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 33 additions and 48 deletions

View file

@ -56,7 +56,8 @@ enum _frameowner {
FRAME_OWNED_BY_THREAD = 0, FRAME_OWNED_BY_THREAD = 0,
FRAME_OWNED_BY_GENERATOR = 1, FRAME_OWNED_BY_GENERATOR = 1,
FRAME_OWNED_BY_FRAME_OBJECT = 2, FRAME_OWNED_BY_FRAME_OBJECT = 2,
FRAME_OWNED_BY_CSTACK = 3, FRAME_OWNED_BY_INTERPRETER = 3,
FRAME_OWNED_BY_CSTACK = 4,
}; };
typedef struct _PyInterpreterFrame { typedef struct _PyInterpreterFrame {
@ -264,7 +265,7 @@ _PyFrame_SetStackPointer(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer)
static inline bool static inline bool
_PyFrame_IsIncomplete(_PyInterpreterFrame *frame) _PyFrame_IsIncomplete(_PyInterpreterFrame *frame)
{ {
if (frame->owner == FRAME_OWNED_BY_CSTACK) { if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) {
return true; return true;
} }
return frame->owner != FRAME_OWNED_BY_GENERATOR && return frame->owner != FRAME_OWNED_BY_GENERATOR &&

View file

@ -508,7 +508,7 @@ parse_frame_object(
return -1; return -1;
} }
if (owner == FRAME_OWNED_BY_CSTACK) { if (owner >= FRAME_OWNED_BY_INTERPRETER) {
return 0; return 0;
} }

View file

@ -2133,7 +2133,7 @@ _PyFrame_IsEntryFrame(PyFrameObject *frame)
assert(frame != NULL); assert(frame != NULL);
_PyInterpreterFrame *f = frame->f_frame; _PyInterpreterFrame *f = frame->f_frame;
assert(!_PyFrame_IsIncomplete(f)); assert(!_PyFrame_IsIncomplete(f));
return f->previous && f->previous->owner == FRAME_OWNED_BY_CSTACK; return f->previous && f->previous->owner == FRAME_OWNED_BY_INTERPRETER;
} }
PyCodeObject * PyCodeObject *

View file

@ -1090,7 +1090,7 @@ dummy_func(
} }
tier1 inst(INTERPRETER_EXIT, (retval --)) { tier1 inst(INTERPRETER_EXIT, (retval --)) {
assert(frame == &entry_frame); assert(frame->owner == FRAME_OWNED_BY_INTERPRETER);
assert(_PyFrame_IsIncomplete(frame)); assert(_PyFrame_IsIncomplete(frame));
/* Restore previous frame and return. */ /* Restore previous frame and return. */
tstate->current_frame = frame->previous; tstate->current_frame = frame->previous;
@ -1105,9 +1105,7 @@ dummy_func(
// retval is popped from the stack, but res // retval is popped from the stack, but res
// is pushed to a different frame, the callers' frame. // is pushed to a different frame, the callers' frame.
inst(RETURN_VALUE, (retval -- res)) { inst(RETURN_VALUE, (retval -- res)) {
#if TIER_ONE assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
assert(frame != &entry_frame);
#endif
_PyStackRef temp = retval; _PyStackRef temp = retval;
DEAD(retval); DEAD(retval);
SAVE_STACK(); SAVE_STACK();
@ -1205,7 +1203,7 @@ dummy_func(
PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver); PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver);
PyObject *retval_o; PyObject *retval_o;
assert(frame != &entry_frame); assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
if ((tstate->interp->eval_frame == NULL) && if ((tstate->interp->eval_frame == NULL) &&
(Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) && (Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) &&
((PyGenObject *)receiver_o)->gi_frame_state < FRAME_EXECUTING) ((PyGenObject *)receiver_o)->gi_frame_state < FRAME_EXECUTING)
@ -1278,9 +1276,7 @@ dummy_func(
// NOTE: It's important that YIELD_VALUE never raises an exception! // NOTE: It's important that YIELD_VALUE never raises an exception!
// The compiler treats any exception raised here as a failed close() // The compiler treats any exception raised here as a failed close()
// or throw() call. // or throw() call.
#if TIER_ONE assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
assert(frame != &entry_frame);
#endif
frame->instr_ptr++; frame->instr_ptr++;
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame);
assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1);

View file

@ -178,7 +178,7 @@ lltrace_instruction(_PyInterpreterFrame *frame,
int opcode, int opcode,
int oparg) int oparg)
{ {
if (frame->owner == FRAME_OWNED_BY_CSTACK) { if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) {
return; return;
} }
dump_stack(frame, stack_pointer); dump_stack(frame, stack_pointer);
@ -229,12 +229,12 @@ lltrace_resume_frame(_PyInterpreterFrame *frame)
} }
static int static int
maybe_lltrace_resume_frame(_PyInterpreterFrame *frame, _PyInterpreterFrame *skip_frame, PyObject *globals) maybe_lltrace_resume_frame(_PyInterpreterFrame *frame, PyObject *globals)
{ {
if (globals == NULL) { if (globals == NULL) {
return 0; return 0;
} }
if (frame == skip_frame) { if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) {
return 0; return 0;
} }
int r = PyDict_Contains(globals, &_Py_ID(__lltrace__)); int r = PyDict_Contains(globals, &_Py_ID(__lltrace__));
@ -818,7 +818,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
entry_frame.f_executable = PyStackRef_None; entry_frame.f_executable = PyStackRef_None;
entry_frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1; entry_frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1;
entry_frame.stackpointer = entry_frame.localsplus; entry_frame.stackpointer = entry_frame.localsplus;
entry_frame.owner = FRAME_OWNED_BY_CSTACK; entry_frame.owner = FRAME_OWNED_BY_INTERPRETER;
entry_frame.visited = 0; entry_frame.visited = 0;
entry_frame.return_offset = 0; entry_frame.return_offset = 0;
/* Push frame */ /* Push frame */
@ -880,7 +880,7 @@ resume_frame:
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
#ifdef LLTRACE #ifdef LLTRACE
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); lltrace = maybe_lltrace_resume_frame(frame, GLOBALS());
if (lltrace < 0) { if (lltrace < 0) {
goto exit_unwind; goto exit_unwind;
} }

View file

@ -89,7 +89,7 @@
#if LLTRACE #if LLTRACE
#define LLTRACE_RESUME_FRAME() \ #define LLTRACE_RESUME_FRAME() \
do { \ do { \
lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); \ lltrace = maybe_lltrace_resume_frame(frame, GLOBALS()); \
if (lltrace < 0) { \ if (lltrace < 0) { \
goto exit_unwind; \ goto exit_unwind; \
} \ } \
@ -238,7 +238,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
#endif #endif
#define WITHIN_STACK_BOUNDS() \ #define WITHIN_STACK_BOUNDS() \
(frame == &entry_frame || (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE())) (frame->owner == FRAME_OWNED_BY_INTERPRETER || (STACK_LEVEL() >= 0 && STACK_LEVEL() <= STACK_SIZE()))
/* Data access macros */ /* Data access macros */
#define FRAME_CO_CONSTS (_PyFrame_GetCode(frame)->co_consts) #define FRAME_CO_CONSTS (_PyFrame_GetCode(frame)->co_consts)

View file

@ -1441,9 +1441,7 @@
_PyStackRef retval; _PyStackRef retval;
_PyStackRef res; _PyStackRef res;
retval = stack_pointer[-1]; retval = stack_pointer[-1];
#if TIER_ONE assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
assert(frame != &entry_frame);
#endif
_PyStackRef temp = retval; _PyStackRef temp = retval;
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
@ -1579,9 +1577,7 @@
// NOTE: It's important that YIELD_VALUE never raises an exception! // NOTE: It's important that YIELD_VALUE never raises an exception!
// The compiler treats any exception raised here as a failed close() // The compiler treats any exception raised here as a failed close()
// or throw() call. // or throw() call.
#if TIER_ONE assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
assert(frame != &entry_frame);
#endif
frame->instr_ptr++; frame->instr_ptr++;
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame);
assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1);

View file

@ -48,7 +48,7 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame)
static void static void
take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
{ {
assert(frame->owner != FRAME_OWNED_BY_CSTACK); assert(frame->owner < FRAME_OWNED_BY_INTERPRETER);
assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
Py_ssize_t size = ((char*)frame->stackpointer) - (char *)frame; Py_ssize_t size = ((char*)frame->stackpointer) - (char *)frame;
memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size); memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size);
@ -69,7 +69,7 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
_PyInterpreterFrame *prev = _PyFrame_GetFirstComplete(frame->previous); _PyInterpreterFrame *prev = _PyFrame_GetFirstComplete(frame->previous);
frame->previous = NULL; frame->previous = NULL;
if (prev) { if (prev) {
assert(prev->owner != FRAME_OWNED_BY_CSTACK); assert(prev->owner < FRAME_OWNED_BY_INTERPRETER);
/* Link PyFrameObjects.f_back and remove link through _PyInterpreterFrame.previous */ /* Link PyFrameObjects.f_back and remove link through _PyInterpreterFrame.previous */
PyFrameObject *back = _PyFrame_GetFrameObject(prev); PyFrameObject *back = _PyFrame_GetFrameObject(prev);
if (back == NULL) { if (back == NULL) {

View file

@ -1476,7 +1476,7 @@ mark_stacks(PyInterpreterState *interp, PyGC_Head *visited, int visited_space, b
while (ts) { while (ts) {
_PyInterpreterFrame *frame = ts->current_frame; _PyInterpreterFrame *frame = ts->current_frame;
while (frame) { while (frame) {
if (frame->owner == FRAME_OWNED_BY_CSTACK) { if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) {
frame = frame->previous; frame = frame->previous;
continue; continue;
} }

View file

@ -5046,9 +5046,7 @@
// _RETURN_VALUE // _RETURN_VALUE
{ {
retval = val; retval = val;
#if TIER_ONE assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
assert(frame != &entry_frame);
#endif
_PyStackRef temp = retval; _PyStackRef temp = retval;
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
@ -5100,9 +5098,7 @@
// NOTE: It's important that YIELD_VALUE never raises an exception! // NOTE: It's important that YIELD_VALUE never raises an exception!
// The compiler treats any exception raised here as a failed close() // The compiler treats any exception raised here as a failed close()
// or throw() call. // or throw() call.
#if TIER_ONE assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
assert(frame != &entry_frame);
#endif
frame->instr_ptr++; frame->instr_ptr++;
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame);
assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1);
@ -5145,7 +5141,7 @@
INSTRUCTION_STATS(INTERPRETER_EXIT); INSTRUCTION_STATS(INTERPRETER_EXIT);
_PyStackRef retval; _PyStackRef retval;
retval = stack_pointer[-1]; retval = stack_pointer[-1];
assert(frame == &entry_frame); assert(frame->owner == FRAME_OWNED_BY_INTERPRETER);
assert(_PyFrame_IsIncomplete(frame)); assert(_PyFrame_IsIncomplete(frame));
/* Restore previous frame and return. */ /* Restore previous frame and return. */
tstate->current_frame = frame->previous; tstate->current_frame = frame->previous;
@ -7309,9 +7305,7 @@
_PyStackRef retval; _PyStackRef retval;
_PyStackRef res; _PyStackRef res;
retval = stack_pointer[-1]; retval = stack_pointer[-1];
#if TIER_ONE assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
assert(frame != &entry_frame);
#endif
_PyStackRef temp = retval; _PyStackRef temp = retval;
stack_pointer += -1; stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
@ -7364,7 +7358,7 @@
v = stack_pointer[-1]; v = stack_pointer[-1];
PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver); PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver);
PyObject *retval_o; PyObject *retval_o;
assert(frame != &entry_frame); assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
if ((tstate->interp->eval_frame == NULL) && if ((tstate->interp->eval_frame == NULL) &&
(Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) && (Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) &&
((PyGenObject *)receiver_o)->gi_frame_state < FRAME_EXECUTING) ((PyGenObject *)receiver_o)->gi_frame_state < FRAME_EXECUTING)
@ -8486,9 +8480,7 @@
// NOTE: It's important that YIELD_VALUE never raises an exception! // NOTE: It's important that YIELD_VALUE never raises an exception!
// The compiler treats any exception raised here as a failed close() // The compiler treats any exception raised here as a failed close()
// or throw() call. // or throw() call.
#if TIER_ONE assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
assert(frame != &entry_frame);
#endif
frame->instr_ptr++; frame->instr_ptr++;
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame);
assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1);

View file

@ -1946,7 +1946,7 @@ instrument_all_executing_code_objects(PyInterpreterState *interp) {
while (ts) { while (ts) {
_PyInterpreterFrame *frame = ts->current_frame; _PyInterpreterFrame *frame = ts->current_frame;
while (frame) { while (frame) {
if (frame->owner != FRAME_OWNED_BY_CSTACK) { if (frame->owner < FRAME_OWNED_BY_INTERPRETER) {
if (instrument_lock_held(_PyFrame_GetCode(frame), interp)) { if (instrument_lock_held(_PyFrame_GetCode(frame), interp)) {
return -1; return -1;
} }

View file

@ -890,7 +890,7 @@ done:
static void static void
dump_frame(int fd, _PyInterpreterFrame *frame) dump_frame(int fd, _PyInterpreterFrame *frame)
{ {
assert(frame->owner != FRAME_OWNED_BY_CSTACK); assert(frame->owner < FRAME_OWNED_BY_INTERPRETER);
PyCodeObject *code =_PyFrame_GetCode(frame); PyCodeObject *code =_PyFrame_GetCode(frame);
PUTS(fd, " File "); PUTS(fd, " File ");
@ -965,7 +965,7 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
unsigned int depth = 0; unsigned int depth = 0;
while (1) { while (1) {
if (frame->owner == FRAME_OWNED_BY_CSTACK) { if (frame->owner == FRAME_OWNED_BY_INTERPRETER) {
/* Trampoline frame */ /* Trampoline frame */
frame = frame->previous; frame = frame->previous;
if (frame == NULL) { if (frame == NULL) {
@ -973,7 +973,7 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
} }
/* Can't have more than one shim frame in a row */ /* Can't have more than one shim frame in a row */
assert(frame->owner != FRAME_OWNED_BY_CSTACK); assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
} }
if (MAX_FRAME_DEPTH <= depth) { if (MAX_FRAME_DEPTH <= depth) {

View file

@ -99,7 +99,7 @@ Py_TPFLAGS_BASE_EXC_SUBCLASS = (1 << 30)
Py_TPFLAGS_TYPE_SUBCLASS = (1 << 31) Py_TPFLAGS_TYPE_SUBCLASS = (1 << 31)
#From pycore_frame.h #From pycore_frame.h
FRAME_OWNED_BY_CSTACK = 3 FRAME_OWNED_BY_INTERPRETER = 3
MAX_OUTPUT_LEN=1024 MAX_OUTPUT_LEN=1024
@ -1113,7 +1113,7 @@ class PyFramePtr:
return int(instr_ptr - first_instr) return int(instr_ptr - first_instr)
def is_shim(self): def is_shim(self):
return self._f_special("owner", int) == FRAME_OWNED_BY_CSTACK return self._f_special("owner", int) == FRAME_OWNED_BY_INTERPRETER
def previous(self): def previous(self):
return self._f_special("previous", PyFramePtr) return self._f_special("previous", PyFramePtr)