https://github.com/python/cpython/commit/5c44d7d99c470b4270b2f0e4841cf5a7f2499e15 commit: 5c44d7d99c470b4270b2f0e4841cf5a7f2499e15 branch: main author: Victor Stinner <vstin...@python.org> committer: vstinner <vstin...@python.org> date: 2025-03-19T18:17:44+01:00 summary:
gh-130931: Add pycore_interpframe.h internal header (#131249) Move _PyInterpreterFrame and associated functions to a new pycore_interpframe.h header. files: A Include/internal/pycore_interpframe.h M Include/internal/pycore_frame.h M Include/internal/pycore_genobject.h M Modules/_testexternalinspection.c M Objects/typeobject.c M Objects/typevarobject.c M Python/_warnings.c M Python/gc_free_threading.c M Python/legacy_tracing.c M Python/specialize.c M Python/tracemalloc.c diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 31a98723baf7bf..dde211c5eac015 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -1,3 +1,7 @@ +/* See InternalDocs/frames.md for an explanation of the frame stack + * including explanation of the PyFrameObject and _PyInterpreterFrame + * structs. */ + #ifndef Py_INTERNAL_FRAME_H #define Py_INTERNAL_FRAME_H #ifdef __cplusplus @@ -8,17 +12,8 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include <stdbool.h> -#include <stddef.h> // offsetof() -#include "pycore_code.h" // STATS -#include "pycore_stackref.h" // _PyStackRef -#include "pycore_stats.h" #include "pycore_typedefs.h" // _PyInterpreterFrame -/* See InternalDocs/frames.md for an explanation of the frame stack - * including explanation of the PyFrameObject and _PyInterpreterFrame - * structs. */ - struct _frame { PyObject_HEAD @@ -54,360 +49,6 @@ typedef enum _framestate { #define FRAME_STATE_SUSPENDED(S) ((S) == FRAME_SUSPENDED || (S) == FRAME_SUSPENDED_YIELD_FROM) #define FRAME_STATE_FINISHED(S) ((S) >= FRAME_COMPLETED) -enum _frameowner { - FRAME_OWNED_BY_THREAD = 0, - FRAME_OWNED_BY_GENERATOR = 1, - FRAME_OWNED_BY_FRAME_OBJECT = 2, - FRAME_OWNED_BY_INTERPRETER = 3, - FRAME_OWNED_BY_CSTACK = 4, -}; - -struct _PyInterpreterFrame { - _PyStackRef f_executable; /* Deferred or strong reference (code object or None) */ - struct _PyInterpreterFrame *previous; - _PyStackRef f_funcobj; /* Deferred or strong reference. Only valid if not on C stack */ - PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */ - PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */ - PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */ - PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */ - _Py_CODEUNIT *instr_ptr; /* Instruction currently executing (or about to begin) */ - _PyStackRef *stackpointer; -#ifdef Py_GIL_DISABLED - /* Index of thread-local bytecode containing instr_ptr. */ - int32_t tlbc_index; -#endif - uint16_t return_offset; /* Only relevant during a function call */ - char owner; -#ifdef Py_DEBUG - uint8_t visited:1; - uint8_t lltrace:7; -#else - uint8_t visited; -#endif - /* Locals and stack */ - _PyStackRef localsplus[1]; -}; - -#define _PyInterpreterFrame_LASTI(IF) \ - ((int)((IF)->instr_ptr - _PyFrame_GetBytecode((IF)))) - -static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) { - PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable); - assert(PyCode_Check(executable)); - return (PyCodeObject *)executable; -} - -static inline _Py_CODEUNIT * -_PyFrame_GetBytecode(_PyInterpreterFrame *f) -{ -#ifdef Py_GIL_DISABLED - PyCodeObject *co = _PyFrame_GetCode(f); - _PyCodeArray *tlbc = _PyCode_GetTLBCArray(co); - assert(f->tlbc_index >= 0 && f->tlbc_index < tlbc->size); - return (_Py_CODEUNIT *)tlbc->entries[f->tlbc_index]; -#else - return _PyCode_CODE(_PyFrame_GetCode(f)); -#endif -} - -static inline PyFunctionObject *_PyFrame_GetFunction(_PyInterpreterFrame *f) { - PyObject *func = PyStackRef_AsPyObjectBorrow(f->f_funcobj); - assert(PyFunction_Check(func)); - return (PyFunctionObject *)func; -} - -static inline _PyStackRef *_PyFrame_Stackbase(_PyInterpreterFrame *f) { - return (f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus); -} - -static inline _PyStackRef _PyFrame_StackPeek(_PyInterpreterFrame *f) { - assert(f->stackpointer > f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus); - assert(!PyStackRef_IsNull(f->stackpointer[-1])); - return f->stackpointer[-1]; -} - -static inline _PyStackRef _PyFrame_StackPop(_PyInterpreterFrame *f) { - assert(f->stackpointer > f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus); - f->stackpointer--; - return *f->stackpointer; -} - -static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, _PyStackRef value) { - *f->stackpointer = value; - f->stackpointer++; -} - -#define FRAME_SPECIALS_SIZE ((int)((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *))) - -static inline int -_PyFrame_NumSlotsForCodeObject(PyCodeObject *code) -{ - /* This function needs to remain in sync with the calculation of - * co_framesize in Tools/build/deepfreeze.py */ - assert(code->co_framesize >= FRAME_SPECIALS_SIZE); - return code->co_framesize - FRAME_SPECIALS_SIZE; -} - -static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest) -{ - dest->f_executable = PyStackRef_MakeHeapSafe(src->f_executable); - // Don't leave a dangling pointer to the old frame when creating generators - // and coroutines: - dest->previous = NULL; - dest->f_funcobj = PyStackRef_MakeHeapSafe(src->f_funcobj); - dest->f_globals = src->f_globals; - dest->f_builtins = src->f_builtins; - dest->f_locals = src->f_locals; - dest->frame_obj = src->frame_obj; - dest->instr_ptr = src->instr_ptr; -#ifdef Py_GIL_DISABLED - dest->tlbc_index = src->tlbc_index; -#endif - assert(src->stackpointer != NULL); - int stacktop = (int)(src->stackpointer - src->localsplus); - assert(stacktop >= 0); - dest->stackpointer = dest->localsplus + stacktop; - for (int i = 0; i < stacktop; i++) { - dest->localsplus[i] = PyStackRef_MakeHeapSafe(src->localsplus[i]); - } -} - -#ifdef Py_GIL_DISABLED -static inline void -_PyFrame_InitializeTLBC(PyThreadState *tstate, _PyInterpreterFrame *frame, - PyCodeObject *code) -{ - _Py_CODEUNIT *tlbc = _PyCode_GetTLBCFast(tstate, code); - if (tlbc == NULL) { - // No thread-local bytecode exists for this thread yet; use the main - // thread's copy, deferring thread-local bytecode creation to the - // execution of RESUME. - frame->instr_ptr = _PyCode_CODE(code); - frame->tlbc_index = 0; - } - else { - frame->instr_ptr = tlbc; - frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index; - } -} -#endif - -/* Consumes reference to func and locals. - Does not initialize frame->previous, which happens - when frame is linked into the frame stack. - */ -static inline void -_PyFrame_Initialize( - PyThreadState *tstate, _PyInterpreterFrame *frame, _PyStackRef func, - PyObject *locals, PyCodeObject *code, int null_locals_from, _PyInterpreterFrame *previous) -{ - frame->previous = previous; - frame->f_funcobj = func; - frame->f_executable = PyStackRef_FromPyObjectNew(code); - PyFunctionObject *func_obj = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(func); - frame->f_builtins = func_obj->func_builtins; - frame->f_globals = func_obj->func_globals; - frame->f_locals = locals; - frame->stackpointer = frame->localsplus + code->co_nlocalsplus; - frame->frame_obj = NULL; -#ifdef Py_GIL_DISABLED - _PyFrame_InitializeTLBC(tstate, frame, code); -#else - (void)tstate; - frame->instr_ptr = _PyCode_CODE(code); -#endif - frame->return_offset = 0; - frame->owner = FRAME_OWNED_BY_THREAD; - frame->visited = 0; -#ifdef Py_DEBUG - frame->lltrace = 0; -#endif - - for (int i = null_locals_from; i < code->co_nlocalsplus; i++) { - frame->localsplus[i] = PyStackRef_NULL; - } -} - -/* Gets the pointer to the locals array - * that precedes this frame. - */ -static inline _PyStackRef* -_PyFrame_GetLocalsArray(_PyInterpreterFrame *frame) -{ - return frame->localsplus; -} - -/* Fetches the stack pointer, and sets stackpointer to NULL. - Having stackpointer == NULL ensures that invalid - values are not visible to the cycle GC. */ -static inline _PyStackRef* -_PyFrame_GetStackPointer(_PyInterpreterFrame *frame) -{ - assert(frame->stackpointer != NULL); - _PyStackRef *sp = frame->stackpointer; - frame->stackpointer = NULL; - return sp; -} - -static inline void -_PyFrame_SetStackPointer(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer) -{ - assert(frame->stackpointer == NULL); - frame->stackpointer = stack_pointer; -} - -/* Determine whether a frame is incomplete. - * A frame is incomplete if it is part way through - * creating cell objects or a generator or coroutine. - * - * Frames on the frame stack are incomplete until the - * first RESUME instruction. - * Frames owned by a generator are always complete. - */ -static inline bool -_PyFrame_IsIncomplete(_PyInterpreterFrame *frame) -{ - if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { - return true; - } - return frame->owner != FRAME_OWNED_BY_GENERATOR && - frame->instr_ptr < _PyFrame_GetBytecode(frame) + - _PyFrame_GetCode(frame)->_co_firsttraceable; -} - -static inline _PyInterpreterFrame * -_PyFrame_GetFirstComplete(_PyInterpreterFrame *frame) -{ - while (frame && _PyFrame_IsIncomplete(frame)) { - frame = frame->previous; - } - return frame; -} - -static inline _PyInterpreterFrame * -_PyThreadState_GetFrame(PyThreadState *tstate) -{ - return _PyFrame_GetFirstComplete(tstate->current_frame); -} - -/* For use by _PyFrame_GetFrameObject - Do not call directly. */ -PyFrameObject * -_PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame); - -/* Gets the PyFrameObject for this frame, lazily - * creating it if necessary. - * Returns a borrowed reference */ -static inline PyFrameObject * -_PyFrame_GetFrameObject(_PyInterpreterFrame *frame) -{ - - assert(!_PyFrame_IsIncomplete(frame)); - PyFrameObject *res = frame->frame_obj; - if (res != NULL) { - return res; - } - return _PyFrame_MakeAndSetFrameObject(frame); -} - -void -_PyFrame_ClearLocals(_PyInterpreterFrame *frame); - -/* Clears all references in the frame. - * If take is non-zero, then the _PyInterpreterFrame frame - * may be transferred to the frame object it references - * instead of being cleared. Either way - * the caller no longer owns the references - * in the frame. - * take should be set to 1 for heap allocated - * frames like the ones in generators and coroutines. - */ -void -_PyFrame_ClearExceptCode(_PyInterpreterFrame * frame); - -int -_PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg); - -bool -_PyFrame_HasHiddenLocals(_PyInterpreterFrame *frame); - -PyObject * -_PyFrame_GetLocals(_PyInterpreterFrame *frame); - -static inline bool -_PyThreadState_HasStackSpace(PyThreadState *tstate, int size) -{ - assert( - (tstate->datastack_top == NULL && tstate->datastack_limit == NULL) - || - (tstate->datastack_top != NULL && tstate->datastack_limit != NULL) - ); - return tstate->datastack_top != NULL && - size < tstate->datastack_limit - tstate->datastack_top; -} - -extern _PyInterpreterFrame * -_PyThreadState_PushFrame(PyThreadState *tstate, size_t size); - -PyAPI_FUNC(void) _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame *frame); - -/* Pushes a frame without checking for space. - * Must be guarded by _PyThreadState_HasStackSpace() - * Consumes reference to func. */ -static inline _PyInterpreterFrame * -_PyFrame_PushUnchecked(PyThreadState *tstate, _PyStackRef func, int null_locals_from, _PyInterpreterFrame * previous) -{ - CALL_STAT_INC(frames_pushed); - PyFunctionObject *func_obj = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(func); - PyCodeObject *code = (PyCodeObject *)func_obj->func_code; - _PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)tstate->datastack_top; - tstate->datastack_top += code->co_framesize; - assert(tstate->datastack_top < tstate->datastack_limit); - _PyFrame_Initialize(tstate, new_frame, func, NULL, code, null_locals_from, - previous); - return new_frame; -} - -/* Pushes a trampoline frame without checking for space. - * Must be guarded by _PyThreadState_HasStackSpace() */ -static inline _PyInterpreterFrame * -_PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int stackdepth, _PyInterpreterFrame * previous) -{ - CALL_STAT_INC(frames_pushed); - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)tstate->datastack_top; - tstate->datastack_top += code->co_framesize; - assert(tstate->datastack_top < tstate->datastack_limit); - frame->previous = previous; - frame->f_funcobj = PyStackRef_None; - frame->f_executable = PyStackRef_FromPyObjectNew(code); -#ifdef Py_DEBUG - frame->f_builtins = NULL; - frame->f_globals = NULL; -#endif - frame->f_locals = NULL; - assert(stackdepth <= code->co_stacksize); - frame->stackpointer = frame->localsplus + code->co_nlocalsplus + stackdepth; - frame->frame_obj = NULL; -#ifdef Py_GIL_DISABLED - _PyFrame_InitializeTLBC(tstate, frame, code); -#else - frame->instr_ptr = _PyCode_CODE(code); -#endif - frame->owner = FRAME_OWNED_BY_THREAD; - frame->visited = 0; -#ifdef Py_DEBUG - frame->lltrace = 0; -#endif - frame->return_offset = 0; - return frame; -} - -PyAPI_FUNC(_PyInterpreterFrame *) -_PyEvalFramePushAndInit(PyThreadState *tstate, _PyStackRef func, - PyObject *locals, _PyStackRef const *args, - size_t argcount, PyObject *kwnames, - _PyInterpreterFrame *previous); - #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_genobject.h b/Include/internal/pycore_genobject.h index b0472c5b9ead36..e99ffcba64e66f 100644 --- a/Include/internal/pycore_genobject.h +++ b/Include/internal/pycore_genobject.h @@ -8,8 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_frame.h" -#include "pycore_typedefs.h" // _PyInterpreterFrame +#include "pycore_interpframe.h" // _PyInterpreterFrame /* _PyGenObject_HEAD defines the initial segment of generator diff --git a/Include/internal/pycore_interpframe.h b/Include/internal/pycore_interpframe.h new file mode 100644 index 00000000000000..93d3469ce75ec3 --- /dev/null +++ b/Include/internal/pycore_interpframe.h @@ -0,0 +1,379 @@ +/* See InternalDocs/frames.md for an explanation of the frame stack + * including explanation of the PyFrameObject and _PyInterpreterFrame + * structs. */ + +#ifndef Py_INTERNAL_INTERP_FRAME_H +#define Py_INTERNAL_INTERP_FRAME_H + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#include "pycore_code.h" // _PyCode_CODE() +#include "pycore_structs.h" // _PyStackRef +#include "pycore_stackref.h" // PyStackRef_AsPyObjectBorrow() +#include "pycore_typedefs.h" // _PyInterpreterFrame + + +#ifdef __cplusplus +extern "C" { +#endif + +enum _frameowner { + FRAME_OWNED_BY_THREAD = 0, + FRAME_OWNED_BY_GENERATOR = 1, + FRAME_OWNED_BY_FRAME_OBJECT = 2, + FRAME_OWNED_BY_INTERPRETER = 3, + FRAME_OWNED_BY_CSTACK = 4, +}; + +struct _PyInterpreterFrame { + _PyStackRef f_executable; /* Deferred or strong reference (code object or None) */ + struct _PyInterpreterFrame *previous; + _PyStackRef f_funcobj; /* Deferred or strong reference. Only valid if not on C stack */ + PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */ + PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */ + PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */ + PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */ + _Py_CODEUNIT *instr_ptr; /* Instruction currently executing (or about to begin) */ + _PyStackRef *stackpointer; +#ifdef Py_GIL_DISABLED + /* Index of thread-local bytecode containing instr_ptr. */ + int32_t tlbc_index; +#endif + uint16_t return_offset; /* Only relevant during a function call */ + char owner; +#ifdef Py_DEBUG + uint8_t visited:1; + uint8_t lltrace:7; +#else + uint8_t visited; +#endif + /* Locals and stack */ + _PyStackRef localsplus[1]; +}; + +#define _PyInterpreterFrame_LASTI(IF) \ + ((int)((IF)->instr_ptr - _PyFrame_GetBytecode((IF)))) + +static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) { + PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable); + assert(PyCode_Check(executable)); + return (PyCodeObject *)executable; +} + +static inline _Py_CODEUNIT * +_PyFrame_GetBytecode(_PyInterpreterFrame *f) +{ +#ifdef Py_GIL_DISABLED + PyCodeObject *co = _PyFrame_GetCode(f); + _PyCodeArray *tlbc = _PyCode_GetTLBCArray(co); + assert(f->tlbc_index >= 0 && f->tlbc_index < tlbc->size); + return (_Py_CODEUNIT *)tlbc->entries[f->tlbc_index]; +#else + return _PyCode_CODE(_PyFrame_GetCode(f)); +#endif +} + +static inline PyFunctionObject *_PyFrame_GetFunction(_PyInterpreterFrame *f) { + PyObject *func = PyStackRef_AsPyObjectBorrow(f->f_funcobj); + assert(PyFunction_Check(func)); + return (PyFunctionObject *)func; +} + +static inline _PyStackRef *_PyFrame_Stackbase(_PyInterpreterFrame *f) { + return (f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus); +} + +static inline _PyStackRef _PyFrame_StackPeek(_PyInterpreterFrame *f) { + assert(f->stackpointer > f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus); + assert(!PyStackRef_IsNull(f->stackpointer[-1])); + return f->stackpointer[-1]; +} + +static inline _PyStackRef _PyFrame_StackPop(_PyInterpreterFrame *f) { + assert(f->stackpointer > f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus); + f->stackpointer--; + return *f->stackpointer; +} + +static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, _PyStackRef value) { + *f->stackpointer = value; + f->stackpointer++; +} + +#define FRAME_SPECIALS_SIZE ((int)((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *))) + +static inline int +_PyFrame_NumSlotsForCodeObject(PyCodeObject *code) +{ + /* This function needs to remain in sync with the calculation of + * co_framesize in Tools/build/deepfreeze.py */ + assert(code->co_framesize >= FRAME_SPECIALS_SIZE); + return code->co_framesize - FRAME_SPECIALS_SIZE; +} + +static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest) +{ + dest->f_executable = PyStackRef_MakeHeapSafe(src->f_executable); + // Don't leave a dangling pointer to the old frame when creating generators + // and coroutines: + dest->previous = NULL; + dest->f_funcobj = PyStackRef_MakeHeapSafe(src->f_funcobj); + dest->f_globals = src->f_globals; + dest->f_builtins = src->f_builtins; + dest->f_locals = src->f_locals; + dest->frame_obj = src->frame_obj; + dest->instr_ptr = src->instr_ptr; +#ifdef Py_GIL_DISABLED + dest->tlbc_index = src->tlbc_index; +#endif + assert(src->stackpointer != NULL); + int stacktop = (int)(src->stackpointer - src->localsplus); + assert(stacktop >= 0); + dest->stackpointer = dest->localsplus + stacktop; + for (int i = 0; i < stacktop; i++) { + dest->localsplus[i] = PyStackRef_MakeHeapSafe(src->localsplus[i]); + } +} + +#ifdef Py_GIL_DISABLED +static inline void +_PyFrame_InitializeTLBC(PyThreadState *tstate, _PyInterpreterFrame *frame, + PyCodeObject *code) +{ + _Py_CODEUNIT *tlbc = _PyCode_GetTLBCFast(tstate, code); + if (tlbc == NULL) { + // No thread-local bytecode exists for this thread yet; use the main + // thread's copy, deferring thread-local bytecode creation to the + // execution of RESUME. + frame->instr_ptr = _PyCode_CODE(code); + frame->tlbc_index = 0; + } + else { + frame->instr_ptr = tlbc; + frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index; + } +} +#endif + +/* Consumes reference to func and locals. + Does not initialize frame->previous, which happens + when frame is linked into the frame stack. + */ +static inline void +_PyFrame_Initialize( + PyThreadState *tstate, _PyInterpreterFrame *frame, _PyStackRef func, + PyObject *locals, PyCodeObject *code, int null_locals_from, _PyInterpreterFrame *previous) +{ + frame->previous = previous; + frame->f_funcobj = func; + frame->f_executable = PyStackRef_FromPyObjectNew(code); + PyFunctionObject *func_obj = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(func); + frame->f_builtins = func_obj->func_builtins; + frame->f_globals = func_obj->func_globals; + frame->f_locals = locals; + frame->stackpointer = frame->localsplus + code->co_nlocalsplus; + frame->frame_obj = NULL; +#ifdef Py_GIL_DISABLED + _PyFrame_InitializeTLBC(tstate, frame, code); +#else + (void)tstate; + frame->instr_ptr = _PyCode_CODE(code); +#endif + frame->return_offset = 0; + frame->owner = FRAME_OWNED_BY_THREAD; + frame->visited = 0; +#ifdef Py_DEBUG + frame->lltrace = 0; +#endif + + for (int i = null_locals_from; i < code->co_nlocalsplus; i++) { + frame->localsplus[i] = PyStackRef_NULL; + } +} + +/* Gets the pointer to the locals array + * that precedes this frame. + */ +static inline _PyStackRef* +_PyFrame_GetLocalsArray(_PyInterpreterFrame *frame) +{ + return frame->localsplus; +} + +/* Fetches the stack pointer, and sets stackpointer to NULL. + Having stackpointer == NULL ensures that invalid + values are not visible to the cycle GC. */ +static inline _PyStackRef* +_PyFrame_GetStackPointer(_PyInterpreterFrame *frame) +{ + assert(frame->stackpointer != NULL); + _PyStackRef *sp = frame->stackpointer; + frame->stackpointer = NULL; + return sp; +} + +static inline void +_PyFrame_SetStackPointer(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer) +{ + assert(frame->stackpointer == NULL); + frame->stackpointer = stack_pointer; +} + +/* Determine whether a frame is incomplete. + * A frame is incomplete if it is part way through + * creating cell objects or a generator or coroutine. + * + * Frames on the frame stack are incomplete until the + * first RESUME instruction. + * Frames owned by a generator are always complete. + */ +static inline bool +_PyFrame_IsIncomplete(_PyInterpreterFrame *frame) +{ + if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { + return true; + } + return frame->owner != FRAME_OWNED_BY_GENERATOR && + frame->instr_ptr < _PyFrame_GetBytecode(frame) + + _PyFrame_GetCode(frame)->_co_firsttraceable; +} + +static inline _PyInterpreterFrame * +_PyFrame_GetFirstComplete(_PyInterpreterFrame *frame) +{ + while (frame && _PyFrame_IsIncomplete(frame)) { + frame = frame->previous; + } + return frame; +} + +static inline _PyInterpreterFrame * +_PyThreadState_GetFrame(PyThreadState *tstate) +{ + return _PyFrame_GetFirstComplete(tstate->current_frame); +} + +/* For use by _PyFrame_GetFrameObject + Do not call directly. */ +PyFrameObject * +_PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame); + +/* Gets the PyFrameObject for this frame, lazily + * creating it if necessary. + * Returns a borrowed reference */ +static inline PyFrameObject * +_PyFrame_GetFrameObject(_PyInterpreterFrame *frame) +{ + + assert(!_PyFrame_IsIncomplete(frame)); + PyFrameObject *res = frame->frame_obj; + if (res != NULL) { + return res; + } + return _PyFrame_MakeAndSetFrameObject(frame); +} + +void +_PyFrame_ClearLocals(_PyInterpreterFrame *frame); + +/* Clears all references in the frame. + * If take is non-zero, then the _PyInterpreterFrame frame + * may be transferred to the frame object it references + * instead of being cleared. Either way + * the caller no longer owns the references + * in the frame. + * take should be set to 1 for heap allocated + * frames like the ones in generators and coroutines. + */ +void +_PyFrame_ClearExceptCode(_PyInterpreterFrame * frame); + +int +_PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg); + +bool +_PyFrame_HasHiddenLocals(_PyInterpreterFrame *frame); + +PyObject * +_PyFrame_GetLocals(_PyInterpreterFrame *frame); + +static inline bool +_PyThreadState_HasStackSpace(PyThreadState *tstate, int size) +{ + assert( + (tstate->datastack_top == NULL && tstate->datastack_limit == NULL) + || + (tstate->datastack_top != NULL && tstate->datastack_limit != NULL) + ); + return tstate->datastack_top != NULL && + size < tstate->datastack_limit - tstate->datastack_top; +} + +extern _PyInterpreterFrame * +_PyThreadState_PushFrame(PyThreadState *tstate, size_t size); + +PyAPI_FUNC(void) _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame *frame); + +/* Pushes a frame without checking for space. + * Must be guarded by _PyThreadState_HasStackSpace() + * Consumes reference to func. */ +static inline _PyInterpreterFrame * +_PyFrame_PushUnchecked(PyThreadState *tstate, _PyStackRef func, int null_locals_from, _PyInterpreterFrame * previous) +{ + CALL_STAT_INC(frames_pushed); + PyFunctionObject *func_obj = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(func); + PyCodeObject *code = (PyCodeObject *)func_obj->func_code; + _PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)tstate->datastack_top; + tstate->datastack_top += code->co_framesize; + assert(tstate->datastack_top < tstate->datastack_limit); + _PyFrame_Initialize(tstate, new_frame, func, NULL, code, null_locals_from, + previous); + return new_frame; +} + +/* Pushes a trampoline frame without checking for space. + * Must be guarded by _PyThreadState_HasStackSpace() */ +static inline _PyInterpreterFrame * +_PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int stackdepth, _PyInterpreterFrame * previous) +{ + CALL_STAT_INC(frames_pushed); + _PyInterpreterFrame *frame = (_PyInterpreterFrame *)tstate->datastack_top; + tstate->datastack_top += code->co_framesize; + assert(tstate->datastack_top < tstate->datastack_limit); + frame->previous = previous; + frame->f_funcobj = PyStackRef_None; + frame->f_executable = PyStackRef_FromPyObjectNew(code); +#ifdef Py_DEBUG + frame->f_builtins = NULL; + frame->f_globals = NULL; +#endif + frame->f_locals = NULL; + assert(stackdepth <= code->co_stacksize); + frame->stackpointer = frame->localsplus + code->co_nlocalsplus + stackdepth; + frame->frame_obj = NULL; +#ifdef Py_GIL_DISABLED + _PyFrame_InitializeTLBC(tstate, frame, code); +#else + frame->instr_ptr = _PyCode_CODE(code); +#endif + frame->owner = FRAME_OWNED_BY_THREAD; + frame->visited = 0; +#ifdef Py_DEBUG + frame->lltrace = 0; +#endif + frame->return_offset = 0; + return frame; +} + +PyAPI_FUNC(_PyInterpreterFrame *) +_PyEvalFramePushAndInit(PyThreadState *tstate, _PyStackRef func, + PyObject *locals, _PyStackRef const *args, + size_t argcount, PyObject *kwnames, + _PyInterpreterFrame *previous); + +#ifdef __cplusplus +} +#endif +#endif // !Py_INTERNAL_INTERP_FRAME_H diff --git a/Modules/_testexternalinspection.c b/Modules/_testexternalinspection.c index fcb18aeef08c39..e90cfb9132b51d 100644 --- a/Modules/_testexternalinspection.c +++ b/Modules/_testexternalinspection.c @@ -52,7 +52,8 @@ #endif #include "Python.h" #include <internal/pycore_debug_offsets.h> // _Py_DebugOffsets -#include <internal/pycore_frame.h> // FRAME_OWNED_BY_CSTACK +#include <internal/pycore_frame.h> // FRAME_SUSPENDED_YIELD_FROM +#include <internal/pycore_interpframe.h> // FRAME_OWNED_BY_CSTACK #include <internal/pycore_stackref.h> // Py_TAG_BITS #ifndef HAVE_PROCESS_VM_READV diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 6bfcb7622e9adf..25153182f29487 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5,8 +5,8 @@ #include "pycore_call.h" // _PyObject_VectorcallTstate() #include "pycore_code.h" // CO_FAST_FREE #include "pycore_dict.h" // _PyDict_KeysSize() -#include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_function.h" // _PyFunction_GetVersionForCurrentState() +#include "pycore_interpframe.h" // _PyInterpreterFrame #include "pycore_lock.h" // _PySeqLock_* #include "pycore_long.h" // _PyLong_IsNegative(), _PyLong_GetOne() #include "pycore_memoryobject.h" // _PyMemoryView_FromBufferProc() diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 92d8a919ba51ce..6c199a52aa0ae6 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -1,10 +1,10 @@ // TypeVar, TypeVarTuple, ParamSpec, and TypeAlias #include "Python.h" -#include "pycore_frame.h" // _PyInterpreterFrame +#include "pycore_interpframe.h" // _PyInterpreterFrame #include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK, PyAnnotateFormat #include "pycore_typevarobject.h" -#include "pycore_unionobject.h" // _Py_union_type_or, _Py_union_from_tuple #include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString() +#include "pycore_unionobject.h" // _Py_union_type_or, _Py_union_from_tuple #include "structmember.h" /*[clinic input] diff --git a/Python/_warnings.c b/Python/_warnings.c index 72d6bf5b582aa5..64a6e1dea31fcd 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -1,5 +1,6 @@ #include "Python.h" #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION_MUT() +#include "pycore_frame.h" // PyFrameObject members #include "pycore_interp.h" // PyInterpreterState.warnings #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_pyerrors.h" // _PyErr_Occurred() diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 694f97d5c57334..36b6eca1eddfb3 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -2,20 +2,17 @@ #include "Python.h" #include "pycore_brc.h" // struct _brc_thread_state #include "pycore_ceval.h" // _Py_set_eval_breaker_bit() -#include "pycore_context.h" #include "pycore_dict.h" // _PyInlineValuesSize() +#include "pycore_frame.h" // FRAME_CLEARED #include "pycore_freelist.h" // _PyObject_ClearFreeLists() -#include "pycore_initconfig.h" +#include "pycore_initconfig.h" // _PyStatus_NO_MEMORY() #include "pycore_interp.h" // PyInterpreterState.gc -#include "pycore_object.h" #include "pycore_object_alloc.h" // _PyObject_MallocWithType() -#include "pycore_object_stack.h" -#include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_tstate.h" // _PyThreadStateImpl #include "pycore_weakref.h" // _PyWeakref_ClearRef() + #include "pydtrace.h" -#include "pycore_uniqueid.h" // _PyObject_MergeThreadLocalRefcounts() // enable the "mark alive" pass of GC diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index 0515e9bedeeacc..924e7e5ca01942 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -5,6 +5,7 @@ #include "Python.h" #include "pycore_audit.h" // _PySys_Audit() #include "pycore_ceval.h" // export _PyEval_SetProfile() +#include "pycore_frame.h" // PyFrameObject members #include "pycore_object.h" #include "opcode.h" diff --git a/Python/specialize.c b/Python/specialize.c index 4aa2fb9f7359f9..5634c601bc5da7 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -6,8 +6,8 @@ #include "pycore_critical_section.h" #include "pycore_descrobject.h" // _PyMethodWrapper_Type #include "pycore_dict.h" // DICT_KEYS_UNICODE -#include "pycore_frame.h" // FRAME_SPECIALS_SIZE #include "pycore_function.h" // _PyFunction_GetVersionForCurrentState() +#include "pycore_interpframe.h" // FRAME_SPECIALS_SIZE #include "pycore_list.h" // _PyListIterObject #include "pycore_long.h" // _PyLong_IsNonNegativeCompact() #include "pycore_moduleobject.h" diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c index 1ee040dde2262d..82e9c6f95e9cf4 100644 --- a/Python/tracemalloc.c +++ b/Python/tracemalloc.c @@ -3,14 +3,12 @@ #include "pycore_gc.h" // PyGC_Head #include "pycore_hashtable.h" // _Py_hashtable_t #include "pycore_initconfig.h" // _PyStatus_NO_MEMORY() +#include "pycore_interpframe.h" // _PyInterpreterFrame #include "pycore_lock.h" // PyMutex_LockFlags() #include "pycore_object.h" // _PyType_PreHeaderSize() #include "pycore_pymem.h" // _Py_tracemalloc_config #include "pycore_runtime.h" // _Py_ID() #include "pycore_traceback.h" // _Py_DumpASCII() -#include <pycore_frame.h> - -#include "frameobject.h" // _PyInterpreterFrame_GetLine #include <stdlib.h> // malloc() _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com