(root)/
Python-3.12.0/
Include/
internal/
pycore_frame.h
       1  #ifndef Py_INTERNAL_FRAME_H
       2  #define Py_INTERNAL_FRAME_H
       3  #ifdef __cplusplus
       4  extern "C" {
       5  #endif
       6  
       7  #include <stdbool.h>
       8  #include <stddef.h>
       9  #include "pycore_code.h"         // STATS
      10  
      11  /* See Objects/frame_layout.md for an explanation of the frame stack
      12   * including explanation of the PyFrameObject and _PyInterpreterFrame
      13   * structs. */
      14  
      15  
      16  struct _frame {
      17      PyObject_HEAD
      18      PyFrameObject *f_back;      /* previous frame, or NULL */
      19      struct _PyInterpreterFrame *f_frame; /* points to the frame data */
      20      PyObject *f_trace;          /* Trace function */
      21      int f_lineno;               /* Current line number. Only valid if non-zero */
      22      char f_trace_lines;         /* Emit per-line trace events? */
      23      char f_trace_opcodes;       /* Emit per-opcode trace events? */
      24      char f_fast_as_locals;      /* Have the fast locals of this frame been converted to a dict? */
      25      /* The frame data, if this frame object owns the frame */
      26      PyObject *_f_frame_data[1];
      27  };
      28  
      29  extern PyFrameObject* _PyFrame_New_NoTrack(PyCodeObject *code);
      30  
      31  
      32  /* other API */
      33  
      34  typedef enum _framestate {
      35      FRAME_CREATED = -2,
      36      FRAME_SUSPENDED = -1,
      37      FRAME_EXECUTING = 0,
      38      FRAME_COMPLETED = 1,
      39      FRAME_CLEARED = 4
      40  } PyFrameState;
      41  
      42  enum _frameowner {
      43      FRAME_OWNED_BY_THREAD = 0,
      44      FRAME_OWNED_BY_GENERATOR = 1,
      45      FRAME_OWNED_BY_FRAME_OBJECT = 2,
      46      FRAME_OWNED_BY_CSTACK = 3,
      47  };
      48  
      49  typedef struct _PyInterpreterFrame {
      50      PyCodeObject *f_code; /* Strong reference */
      51      struct _PyInterpreterFrame *previous;
      52      PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */
      53      PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */
      54      PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */
      55      PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */
      56      PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */
      57      // NOTE: This is not necessarily the last instruction started in the given
      58      // frame. Rather, it is the code unit *prior to* the *next* instruction. For
      59      // example, it may be an inline CACHE entry, an instruction we just jumped
      60      // over, or (in the case of a newly-created frame) a totally invalid value:
      61      _Py_CODEUNIT *prev_instr;
      62      int stacktop;  /* Offset of TOS from localsplus  */
      63      /* The return_offset determines where a `RETURN` should go in the caller,
      64       * relative to `prev_instr`.
      65       * It is only meaningful to the callee,
      66       * so it needs to be set in any CALL (to a Python function)
      67       * or SEND (to a coroutine or generator).
      68       * If there is no callee, then it is meaningless. */
      69      uint16_t return_offset;
      70      char owner;
      71      /* Locals and stack */
      72      PyObject *localsplus[1];
      73  } _PyInterpreterFrame;
      74  
      75  #define _PyInterpreterFrame_LASTI(IF) \
      76      ((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code)))
      77  
      78  static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) {
      79      return f->localsplus + f->f_code->co_nlocalsplus;
      80  }
      81  
      82  static inline PyObject *_PyFrame_StackPeek(_PyInterpreterFrame *f) {
      83      assert(f->stacktop > f->f_code->co_nlocalsplus);
      84      assert(f->localsplus[f->stacktop-1] != NULL);
      85      return f->localsplus[f->stacktop-1];
      86  }
      87  
      88  static inline PyObject *_PyFrame_StackPop(_PyInterpreterFrame *f) {
      89      assert(f->stacktop > f->f_code->co_nlocalsplus);
      90      f->stacktop--;
      91      return f->localsplus[f->stacktop];
      92  }
      93  
      94  static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, PyObject *value) {
      95      f->localsplus[f->stacktop] = value;
      96      f->stacktop++;
      97  }
      98  
      99  #define FRAME_SPECIALS_SIZE ((int)((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *)))
     100  
     101  static inline int
     102  _PyFrame_NumSlotsForCodeObject(PyCodeObject *code)
     103  {
     104      /* This function needs to remain in sync with the calculation of
     105       * co_framesize in Tools/build/deepfreeze.py */
     106      assert(code->co_framesize >= FRAME_SPECIALS_SIZE);
     107      return code->co_framesize - FRAME_SPECIALS_SIZE;
     108  }
     109  
     110  void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest);
     111  
     112  /* Consumes reference to func and locals.
     113     Does not initialize frame->previous, which happens
     114     when frame is linked into the frame stack.
     115   */
     116  static inline void
     117  _PyFrame_Initialize(
     118      _PyInterpreterFrame *frame, PyFunctionObject *func,
     119      PyObject *locals, PyCodeObject *code, int null_locals_from)
     120  {
     121      frame->f_funcobj = (PyObject *)func;
     122      frame->f_code = (PyCodeObject *)Py_NewRef(code);
     123      frame->f_builtins = func->func_builtins;
     124      frame->f_globals = func->func_globals;
     125      frame->f_locals = locals;
     126      frame->stacktop = code->co_nlocalsplus;
     127      frame->frame_obj = NULL;
     128      frame->prev_instr = _PyCode_CODE(code) - 1;
     129      frame->return_offset = 0;
     130      frame->owner = FRAME_OWNED_BY_THREAD;
     131  
     132      for (int i = null_locals_from; i < code->co_nlocalsplus; i++) {
     133          frame->localsplus[i] = NULL;
     134      }
     135  }
     136  
     137  /* Gets the pointer to the locals array
     138   * that precedes this frame.
     139   */
     140  static inline PyObject**
     141  _PyFrame_GetLocalsArray(_PyInterpreterFrame *frame)
     142  {
     143      return frame->localsplus;
     144  }
     145  
     146  /* Fetches the stack pointer, and sets stacktop to -1.
     147     Having stacktop <= 0 ensures that invalid
     148     values are not visible to the cycle GC.
     149     We choose -1 rather than 0 to assist debugging. */
     150  static inline PyObject**
     151  _PyFrame_GetStackPointer(_PyInterpreterFrame *frame)
     152  {
     153      PyObject **sp = frame->localsplus + frame->stacktop;
     154      frame->stacktop = -1;
     155      return sp;
     156  }
     157  
     158  static inline void
     159  _PyFrame_SetStackPointer(_PyInterpreterFrame *frame, PyObject **stack_pointer)
     160  {
     161      frame->stacktop = (int)(stack_pointer - frame->localsplus);
     162  }
     163  
     164  /* Determine whether a frame is incomplete.
     165   * A frame is incomplete if it is part way through
     166   * creating cell objects or a generator or coroutine.
     167   *
     168   * Frames on the frame stack are incomplete until the
     169   * first RESUME instruction.
     170   * Frames owned by a generator are always complete.
     171   */
     172  static inline bool
     173  _PyFrame_IsIncomplete(_PyInterpreterFrame *frame)
     174  {
     175      return frame->owner != FRAME_OWNED_BY_GENERATOR &&
     176      frame->prev_instr < _PyCode_CODE(frame->f_code) + frame->f_code->_co_firsttraceable;
     177  }
     178  
     179  static inline _PyInterpreterFrame *
     180  _PyFrame_GetFirstComplete(_PyInterpreterFrame *frame)
     181  {
     182      while (frame && _PyFrame_IsIncomplete(frame)) {
     183          frame = frame->previous;
     184      }
     185      return frame;
     186  }
     187  
     188  static inline _PyInterpreterFrame *
     189  _PyThreadState_GetFrame(PyThreadState *tstate)
     190  {
     191      return _PyFrame_GetFirstComplete(tstate->cframe->current_frame);
     192  }
     193  
     194  /* For use by _PyFrame_GetFrameObject
     195    Do not call directly. */
     196  PyFrameObject *
     197  _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame);
     198  
     199  /* Gets the PyFrameObject for this frame, lazily
     200   * creating it if necessary.
     201   * Returns a borrowed referennce */
     202  static inline PyFrameObject *
     203  _PyFrame_GetFrameObject(_PyInterpreterFrame *frame)
     204  {
     205  
     206      assert(!_PyFrame_IsIncomplete(frame));
     207      PyFrameObject *res =  frame->frame_obj;
     208      if (res != NULL) {
     209          return res;
     210      }
     211      return _PyFrame_MakeAndSetFrameObject(frame);
     212  }
     213  
     214  /* Clears all references in the frame.
     215   * If take is non-zero, then the _PyInterpreterFrame frame
     216   * may be transferred to the frame object it references
     217   * instead of being cleared. Either way
     218   * the caller no longer owns the references
     219   * in the frame.
     220   * take should  be set to 1 for heap allocated
     221   * frames like the ones in generators and coroutines.
     222   */
     223  void
     224  _PyFrame_ClearExceptCode(_PyInterpreterFrame * frame);
     225  
     226  int
     227  _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg);
     228  
     229  PyObject *
     230  _PyFrame_GetLocals(_PyInterpreterFrame *frame, int include_hidden);
     231  
     232  int
     233  _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame);
     234  
     235  void
     236  _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear);
     237  
     238  static inline bool
     239  _PyThreadState_HasStackSpace(PyThreadState *tstate, int size)
     240  {
     241      assert(
     242          (tstate->datastack_top == NULL && tstate->datastack_limit == NULL)
     243          ||
     244          (tstate->datastack_top != NULL && tstate->datastack_limit != NULL)
     245      );
     246      return tstate->datastack_top != NULL &&
     247          size < tstate->datastack_limit - tstate->datastack_top;
     248  }
     249  
     250  extern _PyInterpreterFrame *
     251  _PyThreadState_PushFrame(PyThreadState *tstate, size_t size);
     252  
     253  void _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame *frame);
     254  
     255  /* Pushes a frame without checking for space.
     256   * Must be guarded by _PyThreadState_HasStackSpace()
     257   * Consumes reference to func. */
     258  static inline _PyInterpreterFrame *
     259  _PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_locals_from)
     260  {
     261      CALL_STAT_INC(frames_pushed);
     262      PyCodeObject *code = (PyCodeObject *)func->func_code;
     263      _PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)tstate->datastack_top;
     264      tstate->datastack_top += code->co_framesize;
     265      assert(tstate->datastack_top < tstate->datastack_limit);
     266      _PyFrame_Initialize(new_frame, func, NULL, code, null_locals_from);
     267      return new_frame;
     268  }
     269  
     270  static inline
     271  PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame)
     272  {
     273      assert(frame->owner == FRAME_OWNED_BY_GENERATOR);
     274      size_t offset_in_gen = offsetof(PyGenObject, gi_iframe);
     275      return (PyGenObject *)(((char *)frame) - offset_in_gen);
     276  }
     277  
     278  #ifdef __cplusplus
     279  }
     280  #endif
     281  #endif /* !Py_INTERNAL_FRAME_H */