1+ /* See InternalDocs/frames.md for an explanation of the frame stack
2+ * including explanation of the PyFrameObject and _PyInterpreterFrame
3+ * structs. */
4+
15#ifndef Py_INTERNAL_FRAME_H
26#define Py_INTERNAL_FRAME_H
37#ifdef __cplusplus
@@ -8,17 +12,8 @@ extern "C" {
812# error "this header requires Py_BUILD_CORE define"
913#endif
1014
11- #include <stdbool.h>
12- #include <stddef.h> // offsetof()
13- #include "pycore_code.h" // STATS
14- #include "pycore_stackref.h" // _PyStackRef
15- #include "pycore_stats.h"
1615#include "pycore_typedefs.h" // _PyInterpreterFrame
1716
18- /* See InternalDocs/frames.md for an explanation of the frame stack
19- * including explanation of the PyFrameObject and _PyInterpreterFrame
20- * structs. */
21-
2217
2318struct _frame {
2419 PyObject_HEAD
@@ -54,360 +49,6 @@ typedef enum _framestate {
5449#define FRAME_STATE_SUSPENDED (S ) ((S) == FRAME_SUSPENDED || (S) == FRAME_SUSPENDED_YIELD_FROM)
5550#define FRAME_STATE_FINISHED (S ) ((S) >= FRAME_COMPLETED)
5651
57- enum _frameowner {
58- FRAME_OWNED_BY_THREAD = 0 ,
59- FRAME_OWNED_BY_GENERATOR = 1 ,
60- FRAME_OWNED_BY_FRAME_OBJECT = 2 ,
61- FRAME_OWNED_BY_INTERPRETER = 3 ,
62- FRAME_OWNED_BY_CSTACK = 4 ,
63- };
64-
65- struct _PyInterpreterFrame {
66- _PyStackRef f_executable ; /* Deferred or strong reference (code object or None) */
67- struct _PyInterpreterFrame * previous ;
68- _PyStackRef f_funcobj ; /* Deferred or strong reference. Only valid if not on C stack */
69- PyObject * f_globals ; /* Borrowed reference. Only valid if not on C stack */
70- PyObject * f_builtins ; /* Borrowed reference. Only valid if not on C stack */
71- PyObject * f_locals ; /* Strong reference, may be NULL. Only valid if not on C stack */
72- PyFrameObject * frame_obj ; /* Strong reference, may be NULL. Only valid if not on C stack */
73- _Py_CODEUNIT * instr_ptr ; /* Instruction currently executing (or about to begin) */
74- _PyStackRef * stackpointer ;
75- #ifdef Py_GIL_DISABLED
76- /* Index of thread-local bytecode containing instr_ptr. */
77- int32_t tlbc_index ;
78- #endif
79- uint16_t return_offset ; /* Only relevant during a function call */
80- char owner ;
81- #ifdef Py_DEBUG
82- uint8_t visited :1 ;
83- uint8_t lltrace :7 ;
84- #else
85- uint8_t visited ;
86- #endif
87- /* Locals and stack */
88- _PyStackRef localsplus [1 ];
89- };
90-
91- #define _PyInterpreterFrame_LASTI (IF ) \
92- ((int)((IF)->instr_ptr - _PyFrame_GetBytecode((IF))))
93-
94- static inline PyCodeObject * _PyFrame_GetCode (_PyInterpreterFrame * f ) {
95- PyObject * executable = PyStackRef_AsPyObjectBorrow (f -> f_executable );
96- assert (PyCode_Check (executable ));
97- return (PyCodeObject * )executable ;
98- }
99-
100- static inline _Py_CODEUNIT *
101- _PyFrame_GetBytecode (_PyInterpreterFrame * f )
102- {
103- #ifdef Py_GIL_DISABLED
104- PyCodeObject * co = _PyFrame_GetCode (f );
105- _PyCodeArray * tlbc = _PyCode_GetTLBCArray (co );
106- assert (f -> tlbc_index >= 0 && f -> tlbc_index < tlbc -> size );
107- return (_Py_CODEUNIT * )tlbc -> entries [f -> tlbc_index ];
108- #else
109- return _PyCode_CODE (_PyFrame_GetCode (f ));
110- #endif
111- }
112-
113- static inline PyFunctionObject * _PyFrame_GetFunction (_PyInterpreterFrame * f ) {
114- PyObject * func = PyStackRef_AsPyObjectBorrow (f -> f_funcobj );
115- assert (PyFunction_Check (func ));
116- return (PyFunctionObject * )func ;
117- }
118-
119- static inline _PyStackRef * _PyFrame_Stackbase (_PyInterpreterFrame * f ) {
120- return (f -> localsplus + _PyFrame_GetCode (f )-> co_nlocalsplus );
121- }
122-
123- static inline _PyStackRef _PyFrame_StackPeek (_PyInterpreterFrame * f ) {
124- assert (f -> stackpointer > f -> localsplus + _PyFrame_GetCode (f )-> co_nlocalsplus );
125- assert (!PyStackRef_IsNull (f -> stackpointer [-1 ]));
126- return f -> stackpointer [-1 ];
127- }
128-
129- static inline _PyStackRef _PyFrame_StackPop (_PyInterpreterFrame * f ) {
130- assert (f -> stackpointer > f -> localsplus + _PyFrame_GetCode (f )-> co_nlocalsplus );
131- f -> stackpointer -- ;
132- return * f -> stackpointer ;
133- }
134-
135- static inline void _PyFrame_StackPush (_PyInterpreterFrame * f , _PyStackRef value ) {
136- * f -> stackpointer = value ;
137- f -> stackpointer ++ ;
138- }
139-
140- #define FRAME_SPECIALS_SIZE ((int)((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *)))
141-
142- static inline int
143- _PyFrame_NumSlotsForCodeObject (PyCodeObject * code )
144- {
145- /* This function needs to remain in sync with the calculation of
146- * co_framesize in Tools/build/deepfreeze.py */
147- assert (code -> co_framesize >= FRAME_SPECIALS_SIZE );
148- return code -> co_framesize - FRAME_SPECIALS_SIZE ;
149- }
150-
151- static inline void _PyFrame_Copy (_PyInterpreterFrame * src , _PyInterpreterFrame * dest )
152- {
153- dest -> f_executable = PyStackRef_MakeHeapSafe (src -> f_executable );
154- // Don't leave a dangling pointer to the old frame when creating generators
155- // and coroutines:
156- dest -> previous = NULL ;
157- dest -> f_funcobj = PyStackRef_MakeHeapSafe (src -> f_funcobj );
158- dest -> f_globals = src -> f_globals ;
159- dest -> f_builtins = src -> f_builtins ;
160- dest -> f_locals = src -> f_locals ;
161- dest -> frame_obj = src -> frame_obj ;
162- dest -> instr_ptr = src -> instr_ptr ;
163- #ifdef Py_GIL_DISABLED
164- dest -> tlbc_index = src -> tlbc_index ;
165- #endif
166- assert (src -> stackpointer != NULL );
167- int stacktop = (int )(src -> stackpointer - src -> localsplus );
168- assert (stacktop >= 0 );
169- dest -> stackpointer = dest -> localsplus + stacktop ;
170- for (int i = 0 ; i < stacktop ; i ++ ) {
171- dest -> localsplus [i ] = PyStackRef_MakeHeapSafe (src -> localsplus [i ]);
172- }
173- }
174-
175- #ifdef Py_GIL_DISABLED
176- static inline void
177- _PyFrame_InitializeTLBC (PyThreadState * tstate , _PyInterpreterFrame * frame ,
178- PyCodeObject * code )
179- {
180- _Py_CODEUNIT * tlbc = _PyCode_GetTLBCFast (tstate , code );
181- if (tlbc == NULL ) {
182- // No thread-local bytecode exists for this thread yet; use the main
183- // thread's copy, deferring thread-local bytecode creation to the
184- // execution of RESUME.
185- frame -> instr_ptr = _PyCode_CODE (code );
186- frame -> tlbc_index = 0 ;
187- }
188- else {
189- frame -> instr_ptr = tlbc ;
190- frame -> tlbc_index = ((_PyThreadStateImpl * )tstate )-> tlbc_index ;
191- }
192- }
193- #endif
194-
195- /* Consumes reference to func and locals.
196- Does not initialize frame->previous, which happens
197- when frame is linked into the frame stack.
198- */
199- static inline void
200- _PyFrame_Initialize (
201- PyThreadState * tstate , _PyInterpreterFrame * frame , _PyStackRef func ,
202- PyObject * locals , PyCodeObject * code , int null_locals_from , _PyInterpreterFrame * previous )
203- {
204- frame -> previous = previous ;
205- frame -> f_funcobj = func ;
206- frame -> f_executable = PyStackRef_FromPyObjectNew (code );
207- PyFunctionObject * func_obj = (PyFunctionObject * )PyStackRef_AsPyObjectBorrow (func );
208- frame -> f_builtins = func_obj -> func_builtins ;
209- frame -> f_globals = func_obj -> func_globals ;
210- frame -> f_locals = locals ;
211- frame -> stackpointer = frame -> localsplus + code -> co_nlocalsplus ;
212- frame -> frame_obj = NULL ;
213- #ifdef Py_GIL_DISABLED
214- _PyFrame_InitializeTLBC (tstate , frame , code );
215- #else
216- (void )tstate ;
217- frame -> instr_ptr = _PyCode_CODE (code );
218- #endif
219- frame -> return_offset = 0 ;
220- frame -> owner = FRAME_OWNED_BY_THREAD ;
221- frame -> visited = 0 ;
222- #ifdef Py_DEBUG
223- frame -> lltrace = 0 ;
224- #endif
225-
226- for (int i = null_locals_from ; i < code -> co_nlocalsplus ; i ++ ) {
227- frame -> localsplus [i ] = PyStackRef_NULL ;
228- }
229- }
230-
231- /* Gets the pointer to the locals array
232- * that precedes this frame.
233- */
234- static inline _PyStackRef *
235- _PyFrame_GetLocalsArray (_PyInterpreterFrame * frame )
236- {
237- return frame -> localsplus ;
238- }
239-
240- /* Fetches the stack pointer, and sets stackpointer to NULL.
241- Having stackpointer == NULL ensures that invalid
242- values are not visible to the cycle GC. */
243- static inline _PyStackRef *
244- _PyFrame_GetStackPointer (_PyInterpreterFrame * frame )
245- {
246- assert (frame -> stackpointer != NULL );
247- _PyStackRef * sp = frame -> stackpointer ;
248- frame -> stackpointer = NULL ;
249- return sp ;
250- }
251-
252- static inline void
253- _PyFrame_SetStackPointer (_PyInterpreterFrame * frame , _PyStackRef * stack_pointer )
254- {
255- assert (frame -> stackpointer == NULL );
256- frame -> stackpointer = stack_pointer ;
257- }
258-
259- /* Determine whether a frame is incomplete.
260- * A frame is incomplete if it is part way through
261- * creating cell objects or a generator or coroutine.
262- *
263- * Frames on the frame stack are incomplete until the
264- * first RESUME instruction.
265- * Frames owned by a generator are always complete.
266- */
267- static inline bool
268- _PyFrame_IsIncomplete (_PyInterpreterFrame * frame )
269- {
270- if (frame -> owner >= FRAME_OWNED_BY_INTERPRETER ) {
271- return true;
272- }
273- return frame -> owner != FRAME_OWNED_BY_GENERATOR &&
274- frame -> instr_ptr < _PyFrame_GetBytecode (frame ) +
275- _PyFrame_GetCode (frame )-> _co_firsttraceable ;
276- }
277-
278- static inline _PyInterpreterFrame *
279- _PyFrame_GetFirstComplete (_PyInterpreterFrame * frame )
280- {
281- while (frame && _PyFrame_IsIncomplete (frame )) {
282- frame = frame -> previous ;
283- }
284- return frame ;
285- }
286-
287- static inline _PyInterpreterFrame *
288- _PyThreadState_GetFrame (PyThreadState * tstate )
289- {
290- return _PyFrame_GetFirstComplete (tstate -> current_frame );
291- }
292-
293- /* For use by _PyFrame_GetFrameObject
294- Do not call directly. */
295- PyFrameObject *
296- _PyFrame_MakeAndSetFrameObject (_PyInterpreterFrame * frame );
297-
298- /* Gets the PyFrameObject for this frame, lazily
299- * creating it if necessary.
300- * Returns a borrowed reference */
301- static inline PyFrameObject *
302- _PyFrame_GetFrameObject (_PyInterpreterFrame * frame )
303- {
304-
305- assert (!_PyFrame_IsIncomplete (frame ));
306- PyFrameObject * res = frame -> frame_obj ;
307- if (res != NULL ) {
308- return res ;
309- }
310- return _PyFrame_MakeAndSetFrameObject (frame );
311- }
312-
313- void
314- _PyFrame_ClearLocals (_PyInterpreterFrame * frame );
315-
316- /* Clears all references in the frame.
317- * If take is non-zero, then the _PyInterpreterFrame frame
318- * may be transferred to the frame object it references
319- * instead of being cleared. Either way
320- * the caller no longer owns the references
321- * in the frame.
322- * take should be set to 1 for heap allocated
323- * frames like the ones in generators and coroutines.
324- */
325- void
326- _PyFrame_ClearExceptCode (_PyInterpreterFrame * frame );
327-
328- int
329- _PyFrame_Traverse (_PyInterpreterFrame * frame , visitproc visit , void * arg );
330-
331- bool
332- _PyFrame_HasHiddenLocals (_PyInterpreterFrame * frame );
333-
334- PyObject *
335- _PyFrame_GetLocals (_PyInterpreterFrame * frame );
336-
337- static inline bool
338- _PyThreadState_HasStackSpace (PyThreadState * tstate , int size )
339- {
340- assert (
341- (tstate -> datastack_top == NULL && tstate -> datastack_limit == NULL )
342- ||
343- (tstate -> datastack_top != NULL && tstate -> datastack_limit != NULL )
344- );
345- return tstate -> datastack_top != NULL &&
346- size < tstate -> datastack_limit - tstate -> datastack_top ;
347- }
348-
349- extern _PyInterpreterFrame *
350- _PyThreadState_PushFrame (PyThreadState * tstate , size_t size );
351-
352- PyAPI_FUNC (void ) _PyThreadState_PopFrame (PyThreadState * tstate , _PyInterpreterFrame * frame );
353-
354- /* Pushes a frame without checking for space.
355- * Must be guarded by _PyThreadState_HasStackSpace()
356- * Consumes reference to func. */
357- static inline _PyInterpreterFrame *
358- _PyFrame_PushUnchecked (PyThreadState * tstate , _PyStackRef func , int null_locals_from , _PyInterpreterFrame * previous )
359- {
360- CALL_STAT_INC (frames_pushed );
361- PyFunctionObject * func_obj = (PyFunctionObject * )PyStackRef_AsPyObjectBorrow (func );
362- PyCodeObject * code = (PyCodeObject * )func_obj -> func_code ;
363- _PyInterpreterFrame * new_frame = (_PyInterpreterFrame * )tstate -> datastack_top ;
364- tstate -> datastack_top += code -> co_framesize ;
365- assert (tstate -> datastack_top < tstate -> datastack_limit );
366- _PyFrame_Initialize (tstate , new_frame , func , NULL , code , null_locals_from ,
367- previous );
368- return new_frame ;
369- }
370-
371- /* Pushes a trampoline frame without checking for space.
372- * Must be guarded by _PyThreadState_HasStackSpace() */
373- static inline _PyInterpreterFrame *
374- _PyFrame_PushTrampolineUnchecked (PyThreadState * tstate , PyCodeObject * code , int stackdepth , _PyInterpreterFrame * previous )
375- {
376- CALL_STAT_INC (frames_pushed );
377- _PyInterpreterFrame * frame = (_PyInterpreterFrame * )tstate -> datastack_top ;
378- tstate -> datastack_top += code -> co_framesize ;
379- assert (tstate -> datastack_top < tstate -> datastack_limit );
380- frame -> previous = previous ;
381- frame -> f_funcobj = PyStackRef_None ;
382- frame -> f_executable = PyStackRef_FromPyObjectNew (code );
383- #ifdef Py_DEBUG
384- frame -> f_builtins = NULL ;
385- frame -> f_globals = NULL ;
386- #endif
387- frame -> f_locals = NULL ;
388- assert (stackdepth <= code -> co_stacksize );
389- frame -> stackpointer = frame -> localsplus + code -> co_nlocalsplus + stackdepth ;
390- frame -> frame_obj = NULL ;
391- #ifdef Py_GIL_DISABLED
392- _PyFrame_InitializeTLBC (tstate , frame , code );
393- #else
394- frame -> instr_ptr = _PyCode_CODE (code );
395- #endif
396- frame -> owner = FRAME_OWNED_BY_THREAD ;
397- frame -> visited = 0 ;
398- #ifdef Py_DEBUG
399- frame -> lltrace = 0 ;
400- #endif
401- frame -> return_offset = 0 ;
402- return frame ;
403- }
404-
405- PyAPI_FUNC (_PyInterpreterFrame * )
406- _PyEvalFramePushAndInit (PyThreadState * tstate , _PyStackRef func ,
407- PyObject * locals , _PyStackRef const * args ,
408- size_t argcount , PyObject * kwnames ,
409- _PyInterpreterFrame * previous );
410-
41152#ifdef __cplusplus
41253}
41354#endif
0 commit comments