codekingpro/portable-devtools
114k
1#ifndef Py_INTERNAL_INTERP_FRAME_H2#define Py_INTERNAL_INTERP_FRAME_H3 4#ifndef Py_BUILD_CORE5# error "this header requires Py_BUILD_CORE define"6#endif7 8#include "pycore_code.h" // _PyCode_CODE()9#include "pycore_interpframe_structs.h" // _PyInterpreterFrame10#include "pycore_stackref.h" // PyStackRef_AsPyObjectBorrow()11#include "pycore_stats.h" // CALL_STAT_INC()12 13#ifdef __cplusplus14extern "C" {15#endif16 17#define _PyInterpreterFrame_LASTI(IF) \18 ((int)((IF)->instr_ptr - _PyFrame_GetBytecode((IF))))19 20static 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 or28// freed. Used by dump_frame() in Python/traceback.c. The function uses29// heuristics to detect freed memory, it's not 100% reliable.30static 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 57static inline _Py_CODEUNIT *58_PyFrame_GetBytecode(_PyInterpreterFrame *f)59{60#ifdef Py_GIL_DISABLED61 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#else66 return _PyCode_CODE(_PyFrame_GetCode(f));67#endif68}69 70// Similar to PyUnstable_InterpreterFrame_GetLasti(), but return NULL if the71// frame is invalid or freed. Used by dump_frame() in Python/traceback.c. The72// function uses heuristics to detect freed memory, it's not 100% reliable.73static inline int74_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_DISABLED85 _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#else89 bytecode = _PyCode_CODE(co);90#endif91 92 return (int)(f->instr_ptr - bytecode) * sizeof(_Py_CODEUNIT);93}94 95static 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 101static inline _PyStackRef *_PyFrame_Stackbase(_PyInterpreterFrame *f) {102 return (f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus);103}104 105static 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 111static 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 117static 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 124static inline int125_PyFrame_NumSlotsForCodeObject(PyCodeObject *code)126{127 /* This function needs to remain in sync with the calculation of128 * 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 133static 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 generators137 // 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_DISABLED146 dest->tlbc_index = src->tlbc_index;147#endif148 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_DEBUG155 dest->lltrace = src->lltrace;156#endif157 for (int i = 0; i < stacktop; i++) {158 dest->localsplus[i] = PyStackRef_MakeHeapSafe(src->localsplus[i]);159 }160}161 162#ifdef Py_GIL_DISABLED163static inline void164_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 main170 // thread's copy, deferring thread-local bytecode creation to the171 // 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#endif181 182/* Consumes reference to func and locals.183 Does not initialize frame->previous, which happens184 when frame is linked into the frame stack.185 */186static inline void187_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_DISABLED201 _PyFrame_InitializeTLBC(tstate, frame, code);202#else203 (void)tstate;204 frame->instr_ptr = _PyCode_CODE(code);205#endif206 frame->return_offset = 0;207 frame->owner = FRAME_OWNED_BY_THREAD;208 frame->visited = 0;209#ifdef Py_DEBUG210 frame->lltrace = 0;211#endif212 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 array219 * that precedes this frame.220 */221static 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 pointer229// spills/restores (which could expose invalid values to the GC) using asserts.230static inline _PyStackRef*231_PyFrame_GetStackPointer(_PyInterpreterFrame *frame)232{233 assert(frame->stackpointer != NULL);234 _PyStackRef *sp = frame->stackpointer;235#ifndef NDEBUG236 frame->stackpointer = NULL;237#endif238 return sp;239}240 241static inline void242_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 through250 * creating cell objects or a generator or coroutine.251 *252 * Frames on the frame stack are incomplete until the253 * first RESUME instruction.254 * Frames owned by a generator are always complete.255 *256 * NOTE: We allow racy accesses to the instruction pointer257 * from other threads for sys._current_frames() and similar APIs.258 */259static inline bool _Py_NO_SANITIZE_THREAD260_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 270static inline _PyInterpreterFrame *271_PyFrame_GetFirstComplete(_PyInterpreterFrame *frame)272{273 while (frame && _PyFrame_IsIncomplete(frame)) {274 frame = frame->previous;275 }276 return frame;277}278 279static inline _PyInterpreterFrame *280_PyThreadState_GetFrame(PyThreadState *tstate)281{282 return _PyFrame_GetFirstComplete(tstate->current_frame);283}284 285/* For use by _PyFrame_GetFrameObject286 Do not call directly. */287PyFrameObject *288_PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame);289 290/* Gets the PyFrameObject for this frame, lazily291 * creating it if necessary.292 * Returns a borrowed reference */293static 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 305void306_PyFrame_ClearLocals(_PyInterpreterFrame *frame);307 308/* Clears all references in the frame.309 * If take is non-zero, then the _PyInterpreterFrame frame310 * may be transferred to the frame object it references311 * instead of being cleared. Either way312 * the caller no longer owns the references313 * in the frame.314 * take should be set to 1 for heap allocated315 * frames like the ones in generators and coroutines.316 */317void318_PyFrame_ClearExceptCode(_PyInterpreterFrame * frame);319 320int321_PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg);322 323bool324_PyFrame_HasHiddenLocals(_PyInterpreterFrame *frame);325 326PyObject *327_PyFrame_GetLocals(_PyInterpreterFrame *frame);328 329static inline bool330_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 341extern _PyInterpreterFrame *342_PyThreadState_PushFrame(PyThreadState *tstate, size_t size);343 344PyAPI_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. */349static 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() */365static 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_DEBUG376 frame->f_builtins = NULL;377 frame->f_globals = NULL;378#endif379 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_DISABLED384 _PyFrame_InitializeTLBC(tstate, frame, code);385#else386 frame->instr_ptr = _PyCode_CODE(code);387#endif388 frame->owner = FRAME_OWNED_BY_THREAD;389 frame->visited = 0;390#ifdef Py_DEBUG391 frame->lltrace = 0;392#endif393 frame->return_offset = 0;394 return frame;395}396 397PyAPI_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 __cplusplus404}405#endif406#endif // !Py_INTERNAL_INTERP_FRAME_H407 