Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
pycore_interpframe.h407 linesDownload Raw Back to internal
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 
codekingpro/portable-devtools · Team Ai