Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/python3.14/internal/pycore_interpframe.h
1 #ifndef Py_INTERNAL_INTERP_FRAME_H 2 #define Py_INTERNAL_INTERP_FRAME_H 3 4 #ifndef Py_BUILD_CORE 5 # error "this header requires Py_BUILD_CORE define" 6 #endif 7 8 #include "pycore_code.h" // _PyCode_CODE() 9 #include "pycore_interpframe_structs.h" // _PyInterpreterFrame 10 #include "pycore_stackref.h" // PyStackRef_AsPyObjectBorrow() 11 #include "pycore_stats.h" // CALL_STAT_INC() 12 13 #ifdef __cplusplus 14 extern "C" { 15 #endif 16 17 #define _PyInterpreterFrame_LASTI(IF) \ 18 ((int)((IF)->instr_ptr - _PyFrame_GetBytecode((IF)))) 19 20 static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) { 21 assert(!PyStackRef_IsNull(f->f_executable)); 22 PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable); 23 assert(PyCode_Check(executable)); 24 return (PyCodeObject *)executable; 25 } 26 27 // Similar to _PyFrame_GetCode(), but return NULL if the frame is invalid or 28 // freed. Used by dump_frame() in Python/traceback.c. The function uses 29 // heuristics to detect freed memory, it's not 100% reliable. 30 static inline PyCodeObject* 31 _PyFrame_SafeGetCode(_PyInterpreterFrame *f) 32 { 33 // globals and builtins may be NULL on a legit frame, but it's unlikely. 34 // It's more likely that it's a sign of an invalid frame. 35 if (f->f_globals == NULL || f->f_builtins == NULL) { 36 return NULL; 37 } 38 39 if (PyStackRef_IsNull(f->f_executable)) { 40 return NULL; 41 } 42 void *ptr; 43 memcpy(&ptr, &f->f_executable, sizeof(f->f_executable)); 44 if (_PyMem_IsPtrFreed(ptr)) { 45 return NULL; 46 } 47 PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable); 48 if (_PyObject_IsFreed(executable)) { 49 return NULL; 50 } 51 if (!PyCode_Check(executable)) { 52 return NULL; 53 } 54 return (PyCodeObject *)executable; 55 } 56 57 static inline _Py_CODEUNIT * 58 _PyFrame_GetBytecode(_PyInterpreterFrame *f) 59 { 60 #ifdef Py_GIL_DISABLED 61 PyCodeObject *co = _PyFrame_GetCode(f); 62 _PyCodeArray *tlbc = _PyCode_GetTLBCArray(co); 63 assert(f->tlbc_index >= 0 && f->tlbc_index < tlbc->size); 64 return (_Py_CODEUNIT *)tlbc->entries[f->tlbc_index]; 65 #else 66 return _PyCode_CODE(_PyFrame_GetCode(f)); 67 #endif 68 } 69 70 // Similar to PyUnstable_InterpreterFrame_GetLasti(), but return NULL if the 71 // frame is invalid or freed. Used by dump_frame() in Python/traceback.c. The 72 // function uses heuristics to detect freed memory, it's not 100% reliable. 73 static inline int 74 _PyFrame_SafeGetLasti(struct _PyInterpreterFrame *f) 75 { 76 // Code based on _PyFrame_GetBytecode() but replace _PyFrame_GetCode() 77 // with _PyFrame_SafeGetCode(). 78 PyCodeObject *co = _PyFrame_SafeGetCode(f); 79 if (co == NULL) { 80 return -1; 81 } 82 83 _Py_CODEUNIT *bytecode; 84 #ifdef Py_GIL_DISABLED 85 _PyCodeArray *tlbc = _PyCode_GetTLBCArray(co); 86 assert(f->tlbc_index >= 0 && f->tlbc_index < tlbc->size); 87 bytecode = (_Py_CODEUNIT *)tlbc->entries[f->tlbc_index]; 88 #else 89 bytecode = _PyCode_CODE(co); 90 #endif 91 92 return (int)(f->instr_ptr - bytecode) * sizeof(_Py_CODEUNIT); 93 } 94 95 static inline PyFunctionObject *_PyFrame_GetFunction(_PyInterpreterFrame *f) { 96 PyObject *func = PyStackRef_AsPyObjectBorrow(f->f_funcobj); 97 assert(PyFunction_Check(func)); 98 return (PyFunctionObject *)func; 99 } 100 101 static inline _PyStackRef *_PyFrame_Stackbase(_PyInterpreterFrame *f) { 102 return (f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus); 103 } 104 105 static inline _PyStackRef _PyFrame_StackPeek(_PyInterpreterFrame *f) { 106 assert(f->stackpointer > f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus); 107 assert(!PyStackRef_IsNull(f->stackpointer[-1])); 108 return f->stackpointer[-1]; 109 } 110 111 static inline _PyStackRef _PyFrame_StackPop(_PyInterpreterFrame *f) { 112 assert(f->stackpointer > f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus); 113 f->stackpointer--; 114 return *f->stackpointer; 115 } 116 117 static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, _PyStackRef value) { 118 *f->stackpointer = value; 119 f->stackpointer++; 120 } 121 122 #define FRAME_SPECIALS_SIZE ((int)((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *))) 123 124 static inline int 125 _PyFrame_NumSlotsForCodeObject(PyCodeObject *code) 126 { 127 /* This function needs to remain in sync with the calculation of 128 * co_framesize in Tools/build/deepfreeze.py */ 129 assert(code->co_framesize >= FRAME_SPECIALS_SIZE); 130 return code->co_framesize - FRAME_SPECIALS_SIZE; 131 } 132 133 static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest) 134 { 135 dest->f_executable = PyStackRef_MakeHeapSafe(src->f_executable); 136 // Don't leave a dangling pointer to the old frame when creating generators 137 // and coroutines: 138 dest->previous = NULL; 139 dest->f_funcobj = PyStackRef_MakeHeapSafe(src->f_funcobj); 140 dest->f_globals = src->f_globals; 141 dest->f_builtins = src->f_builtins; 142 dest->f_locals = src->f_locals; 143 dest->frame_obj = src->frame_obj; 144 dest->instr_ptr = src->instr_ptr; 145 #ifdef Py_GIL_DISABLED 146 dest->tlbc_index = src->tlbc_index; 147 #endif 148 assert(src->stackpointer != NULL); 149 int stacktop = (int)(src->stackpointer - src->localsplus); 150 assert(stacktop >= 0); 151 dest->stackpointer = dest->localsplus + stacktop; 152 // visited is GC bookkeeping for the current stack walk, not frame state. 153 dest->visited = 0; 154 #ifdef Py_DEBUG 155 dest->lltrace = src->lltrace; 156 #endif 157 for (int i = 0; i < stacktop; i++) { 158 dest->localsplus[i] = PyStackRef_MakeHeapSafe(src->localsplus[i]); 159 } 160 } 161 162 #ifdef Py_GIL_DISABLED 163 static inline void 164 _PyFrame_InitializeTLBC(PyThreadState *tstate, _PyInterpreterFrame *frame, 165 PyCodeObject *code) 166 { 167 _Py_CODEUNIT *tlbc = _PyCode_GetTLBCFast(tstate, code); 168 if (tlbc == NULL) { 169 // No thread-local bytecode exists for this thread yet; use the main 170 // thread's copy, deferring thread-local bytecode creation to the 171 // execution of RESUME. 172 frame->instr_ptr = _PyCode_CODE(code); 173 frame->tlbc_index = 0; 174 } 175 else { 176 frame->instr_ptr = tlbc; 177 frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index; 178 } 179 } 180 #endif 181 182 /* Consumes reference to func and locals. 183 Does not initialize frame->previous, which happens 184 when frame is linked into the frame stack. 185 */ 186 static inline void 187 _PyFrame_Initialize( 188 PyThreadState *tstate, _PyInterpreterFrame *frame, _PyStackRef func, 189 PyObject *locals, PyCodeObject *code, int null_locals_from, _PyInterpreterFrame *previous) 190 { 191 frame->previous = previous; 192 frame->f_funcobj = func; 193 frame->f_executable = PyStackRef_FromPyObjectNew(code); 194 PyFunctionObject *func_obj = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(func); 195 frame->f_builtins = func_obj->func_builtins; 196 frame->f_globals = func_obj->func_globals; 197 frame->f_locals = locals; 198 frame->stackpointer = frame->localsplus + code->co_nlocalsplus; 199 frame->frame_obj = NULL; 200 #ifdef Py_GIL_DISABLED 201 _PyFrame_InitializeTLBC(tstate, frame, code); 202 #else 203 (void)tstate; 204 frame->instr_ptr = _PyCode_CODE(code); 205 #endif 206 frame->return_offset = 0; 207 frame->owner = FRAME_OWNED_BY_THREAD; 208 frame->visited = 0; 209 #ifdef Py_DEBUG 210 frame->lltrace = 0; 211 #endif 212 213 for (int i = null_locals_from; i < code->co_nlocalsplus; i++) { 214 frame->localsplus[i] = PyStackRef_NULL; 215 } 216 } 217 218 /* Gets the pointer to the locals array 219 * that precedes this frame. 220 */ 221 static inline _PyStackRef* 222 _PyFrame_GetLocalsArray(_PyInterpreterFrame *frame) 223 { 224 return frame->localsplus; 225 } 226 227 // Fetches the stack pointer, and (on debug builds) sets stackpointer to NULL. 228 // Having stackpointer == NULL makes it easier to catch missing stack pointer 229 // spills/restores (which could expose invalid values to the GC) using asserts. 230 static inline _PyStackRef* 231 _PyFrame_GetStackPointer(_PyInterpreterFrame *frame) 232 { 233 assert(frame->stackpointer != NULL); 234 _PyStackRef *sp = frame->stackpointer; 235 #ifndef NDEBUG 236 frame->stackpointer = NULL; 237 #endif 238 return sp; 239 } 240 241 static inline void 242 _PyFrame_SetStackPointer(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer) 243 { 244 assert(frame->stackpointer == NULL); 245 frame->stackpointer = stack_pointer; 246 } 247 248 /* Determine whether a frame is incomplete. 249 * A frame is incomplete if it is part way through 250 * creating cell objects or a generator or coroutine. 251 * 252 * Frames on the frame stack are incomplete until the 253 * first RESUME instruction. 254 * Frames owned by a generator are always complete. 255 * 256 * NOTE: We allow racy accesses to the instruction pointer 257 * from other threads for sys._current_frames() and similar APIs. 258 */ 259 static inline bool _Py_NO_SANITIZE_THREAD 260 _PyFrame_IsIncomplete(_PyInterpreterFrame *frame) 261 { 262 if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { 263 return true; 264 } 265 return frame->owner != FRAME_OWNED_BY_GENERATOR && 266 frame->instr_ptr < _PyFrame_GetBytecode(frame) + 267 _PyFrame_GetCode(frame)->_co_firsttraceable; 268 } 269 270 static inline _PyInterpreterFrame * 271 _PyFrame_GetFirstComplete(_PyInterpreterFrame *frame) 272 { 273 while (frame && _PyFrame_IsIncomplete(frame)) { 274 frame = frame->previous; 275 } 276 return frame; 277 } 278 279 static inline _PyInterpreterFrame * 280 _PyThreadState_GetFrame(PyThreadState *tstate) 281 { 282 return _PyFrame_GetFirstComplete(tstate->current_frame); 283 } 284 285 /* For use by _PyFrame_GetFrameObject 286 Do not call directly. */ 287 PyFrameObject * 288 _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame); 289 290 /* Gets the PyFrameObject for this frame, lazily 291 * creating it if necessary. 292 * Returns a borrowed reference */ 293 static inline PyFrameObject * 294 _PyFrame_GetFrameObject(_PyInterpreterFrame *frame) 295 { 296 297 assert(!_PyFrame_IsIncomplete(frame)); 298 PyFrameObject *res = frame->frame_obj; 299 if (res != NULL) { 300 return res; 301 } 302 return _PyFrame_MakeAndSetFrameObject(frame); 303 } 304 305 void 306 _PyFrame_ClearLocals(_PyInterpreterFrame *frame); 307 308 /* Clears all references in the frame. 309 * If take is non-zero, then the _PyInterpreterFrame frame 310 * may be transferred to the frame object it references 311 * instead of being cleared. Either way 312 * the caller no longer owns the references 313 * in the frame. 314 * take should be set to 1 for heap allocated 315 * frames like the ones in generators and coroutines. 316 */ 317 void 318 _PyFrame_ClearExceptCode(_PyInterpreterFrame * frame); 319 320 int 321 _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg); 322 323 bool 324 _PyFrame_HasHiddenLocals(_PyInterpreterFrame *frame); 325 326 PyObject * 327 _PyFrame_GetLocals(_PyInterpreterFrame *frame); 328 329 static inline bool 330 _PyThreadState_HasStackSpace(PyThreadState *tstate, int size) 331 { 332 assert( 333 (tstate->datastack_top == NULL && tstate->datastack_limit == NULL) 334 || 335 (tstate->datastack_top != NULL && tstate->datastack_limit != NULL) 336 ); 337 return tstate->datastack_top != NULL && 338 size < tstate->datastack_limit - tstate->datastack_top; 339 } 340 341 extern _PyInterpreterFrame * 342 _PyThreadState_PushFrame(PyThreadState *tstate, size_t size); 343 344 PyAPI_FUNC(void) _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame *frame); 345 346 /* Pushes a frame without checking for space. 347 * Must be guarded by _PyThreadState_HasStackSpace() 348 * Consumes reference to func. */ 349 static inline _PyInterpreterFrame * 350 _PyFrame_PushUnchecked(PyThreadState *tstate, _PyStackRef func, int null_locals_from, _PyInterpreterFrame * previous) 351 { 352 CALL_STAT_INC(frames_pushed); 353 PyFunctionObject *func_obj = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(func); 354 PyCodeObject *code = (PyCodeObject *)func_obj->func_code; 355 _PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)tstate->datastack_top; 356 tstate->datastack_top += code->co_framesize; 357 assert(tstate->datastack_top < tstate->datastack_limit); 358 _PyFrame_Initialize(tstate, new_frame, func, NULL, code, null_locals_from, 359 previous); 360 return new_frame; 361 } 362 363 /* Pushes a trampoline frame without checking for space. 364 * Must be guarded by _PyThreadState_HasStackSpace() */ 365 static inline _PyInterpreterFrame * 366 _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int stackdepth, _PyInterpreterFrame * previous) 367 { 368 CALL_STAT_INC(frames_pushed); 369 _PyInterpreterFrame *frame = (_PyInterpreterFrame *)tstate->datastack_top; 370 tstate->datastack_top += code->co_framesize; 371 assert(tstate->datastack_top < tstate->datastack_limit); 372 frame->previous = previous; 373 frame->f_funcobj = PyStackRef_None; 374 frame->f_executable = PyStackRef_FromPyObjectNew(code); 375 #ifdef Py_DEBUG 376 frame->f_builtins = NULL; 377 frame->f_globals = NULL; 378 #endif 379 frame->f_locals = NULL; 380 assert(stackdepth <= code->co_stacksize); 381 frame->stackpointer = frame->localsplus + code->co_nlocalsplus + stackdepth; 382 frame->frame_obj = NULL; 383 #ifdef Py_GIL_DISABLED 384 _PyFrame_InitializeTLBC(tstate, frame, code); 385 #else 386 frame->instr_ptr = _PyCode_CODE(code); 387 #endif 388 frame->owner = FRAME_OWNED_BY_THREAD; 389 frame->visited = 0; 390 #ifdef Py_DEBUG 391 frame->lltrace = 0; 392 #endif 393 frame->return_offset = 0; 394 return frame; 395 } 396 397 PyAPI_FUNC(_PyInterpreterFrame *) 398 _PyEvalFramePushAndInit(PyThreadState *tstate, _PyStackRef func, 399 PyObject *locals, _PyStackRef const *args, 400 size_t argcount, PyObject *kwnames, 401 _PyInterpreterFrame *previous); 402 403 #ifdef __cplusplus 404 } 405 #endif 406 #endif // !Py_INTERNAL_INTERP_FRAME_H