LCOV - code coverage report
Current view: top level - Include/internal - pycore_frame.h (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit 5e6661bce9] Lines: 55 60 91.7 %
Date: 2023-03-20 08:15:36 Functions: 14 16 87.5 %
Branches: 15 16 93.8 %

           Branch data     Line data    Source code
       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                 :            :     uint16_t yield_offset;
      64                 :            :     char owner;
      65                 :            :     /* Locals and stack */
      66                 :            :     PyObject *localsplus[1];
      67                 :            : } _PyInterpreterFrame;
      68                 :            : 
      69                 :            : #define _PyInterpreterFrame_LASTI(IF) \
      70                 :            :     ((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code)))
      71                 :            : 
      72                 :     107686 : static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) {
      73                 :     107686 :     return f->localsplus + f->f_code->co_nlocalsplus;
      74                 :            : }
      75                 :            : 
      76                 :          0 : static inline PyObject *_PyFrame_StackPeek(_PyInterpreterFrame *f) {
      77                 :            :     assert(f->stacktop > f->f_code->co_nlocalsplus);
      78                 :            :     assert(f->localsplus[f->stacktop-1] != NULL);
      79                 :          0 :     return f->localsplus[f->stacktop-1];
      80                 :            : }
      81                 :            : 
      82                 :          0 : static inline PyObject *_PyFrame_StackPop(_PyInterpreterFrame *f) {
      83                 :            :     assert(f->stacktop > f->f_code->co_nlocalsplus);
      84                 :          0 :     f->stacktop--;
      85                 :          0 :     return f->localsplus[f->stacktop];
      86                 :            : }
      87                 :            : 
      88                 :    4708097 : static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, PyObject *value) {
      89                 :    4708097 :     f->localsplus[f->stacktop] = value;
      90                 :    4708097 :     f->stacktop++;
      91                 :    4708097 : }
      92                 :            : 
      93                 :            : #define FRAME_SPECIALS_SIZE ((int)((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *)))
      94                 :            : 
      95                 :            : static inline int
      96                 :     122420 : _PyFrame_NumSlotsForCodeObject(PyCodeObject *code)
      97                 :            : {
      98                 :            :     /* This function needs to remain in sync with the calculation of
      99                 :            :      * co_framesize in Tools/build/deepfreeze.py */
     100                 :            :     assert(code->co_framesize >= FRAME_SPECIALS_SIZE);
     101                 :     122420 :     return code->co_framesize - FRAME_SPECIALS_SIZE;
     102                 :            : }
     103                 :            : 
     104                 :            : void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest);
     105                 :            : 
     106                 :            : /* Consumes reference to func and locals.
     107                 :            :    Does not initialize frame->previous, which happens
     108                 :            :    when frame is linked into the frame stack.
     109                 :            :  */
     110                 :            : static inline void
     111                 :    3608148 : _PyFrame_Initialize(
     112                 :            :     _PyInterpreterFrame *frame, PyFunctionObject *func,
     113                 :            :     PyObject *locals, PyCodeObject *code, int null_locals_from)
     114                 :            : {
     115                 :    3608148 :     frame->f_funcobj = (PyObject *)func;
     116                 :    3608148 :     frame->f_code = (PyCodeObject *)Py_NewRef(code);
     117                 :    3608148 :     frame->f_builtins = func->func_builtins;
     118                 :    3608148 :     frame->f_globals = func->func_globals;
     119                 :    3608148 :     frame->f_locals = locals;
     120                 :    3608148 :     frame->stacktop = code->co_nlocalsplus;
     121                 :    3608148 :     frame->frame_obj = NULL;
     122                 :    3608148 :     frame->prev_instr = _PyCode_CODE(code) - 1;
     123                 :    3608148 :     frame->yield_offset = 0;
     124                 :    3608148 :     frame->owner = FRAME_OWNED_BY_THREAD;
     125                 :            : 
     126         [ +  + ]:   14770178 :     for (int i = null_locals_from; i < code->co_nlocalsplus; i++) {
     127                 :   11162030 :         frame->localsplus[i] = NULL;
     128                 :            :     }
     129                 :    3608148 : }
     130                 :            : 
     131                 :            : /* Gets the pointer to the locals array
     132                 :            :  * that precedes this frame.
     133                 :            :  */
     134                 :            : static inline PyObject**
     135                 :      40191 : _PyFrame_GetLocalsArray(_PyInterpreterFrame *frame)
     136                 :            : {
     137                 :      40191 :     return frame->localsplus;
     138                 :            : }
     139                 :            : 
     140                 :            : static inline PyObject**
     141                 :    8316950 : _PyFrame_GetStackPointer(_PyInterpreterFrame *frame)
     142                 :            : {
     143                 :    8316950 :     return frame->localsplus+frame->stacktop;
     144                 :            : }
     145                 :            : 
     146                 :            : static inline void
     147                 :    6643440 : _PyFrame_SetStackPointer(_PyInterpreterFrame *frame, PyObject **stack_pointer)
     148                 :            : {
     149                 :    6643440 :     frame->stacktop = (int)(stack_pointer - frame->localsplus);
     150                 :    6643440 : }
     151                 :            : 
     152                 :            : /* Determine whether a frame is incomplete.
     153                 :            :  * A frame is incomplete if it is part way through
     154                 :            :  * creating cell objects or a generator or coroutine.
     155                 :            :  *
     156                 :            :  * Frames on the frame stack are incomplete until the
     157                 :            :  * first RESUME instruction.
     158                 :            :  * Frames owned by a generator are always complete.
     159                 :            :  */
     160                 :            : static inline bool
     161                 :     135181 : _PyFrame_IsIncomplete(_PyInterpreterFrame *frame)
     162                 :            : {
     163         [ +  + ]:     268369 :     return frame->owner != FRAME_OWNED_BY_GENERATOR &&
     164         [ +  + ]:     133188 :     frame->prev_instr < _PyCode_CODE(frame->f_code) + frame->f_code->_co_firsttraceable;
     165                 :            : }
     166                 :            : 
     167                 :            : static inline _PyInterpreterFrame *
     168                 :      23735 : _PyFrame_GetFirstComplete(_PyInterpreterFrame *frame)
     169                 :            : {
     170   [ +  +  +  + ]:      26489 :     while (frame && _PyFrame_IsIncomplete(frame)) {
     171                 :       2754 :         frame = frame->previous;
     172                 :            :     }
     173                 :      23735 :     return frame;
     174                 :            : }
     175                 :            : 
     176                 :            : static inline _PyInterpreterFrame *
     177                 :      20252 : _PyThreadState_GetFrame(PyThreadState *tstate)
     178                 :            : {
     179                 :      20252 :     return _PyFrame_GetFirstComplete(tstate->cframe->current_frame);
     180                 :            : }
     181                 :            : 
     182                 :            : /* For use by _PyFrame_GetFrameObject
     183                 :            :   Do not call directly. */
     184                 :            : PyFrameObject *
     185                 :            : _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame);
     186                 :            : 
     187                 :            : /* Gets the PyFrameObject for this frame, lazily
     188                 :            :  * creating it if necessary.
     189                 :            :  * Returns a borrowed referennce */
     190                 :            : static inline PyFrameObject *
     191                 :     108711 : _PyFrame_GetFrameObject(_PyInterpreterFrame *frame)
     192                 :            : {
     193                 :            : 
     194                 :            :     assert(!_PyFrame_IsIncomplete(frame));
     195                 :     108711 :     PyFrameObject *res =  frame->frame_obj;
     196         [ +  + ]:     108711 :     if (res != NULL) {
     197                 :       2128 :         return res;
     198                 :            :     }
     199                 :     106583 :     return _PyFrame_MakeAndSetFrameObject(frame);
     200                 :            : }
     201                 :            : 
     202                 :            : /* Clears all references in the frame.
     203                 :            :  * If take is non-zero, then the _PyInterpreterFrame frame
     204                 :            :  * may be transferred to the frame object it references
     205                 :            :  * instead of being cleared. Either way
     206                 :            :  * the caller no longer owns the references
     207                 :            :  * in the frame.
     208                 :            :  * take should  be set to 1 for heap allocated
     209                 :            :  * frames like the ones in generators and coroutines.
     210                 :            :  */
     211                 :            : void
     212                 :            : _PyFrame_ClearExceptCode(_PyInterpreterFrame * frame);
     213                 :            : 
     214                 :            : int
     215                 :            : _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg);
     216                 :            : 
     217                 :            : int
     218                 :            : _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame);
     219                 :            : 
     220                 :            : void
     221                 :            : _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear);
     222                 :            : 
     223                 :            : static inline bool
     224                 :    3608148 : _PyThreadState_HasStackSpace(PyThreadState *tstate, int size)
     225                 :            : {
     226                 :            :     assert(
     227                 :            :         (tstate->datastack_top == NULL && tstate->datastack_limit == NULL)
     228                 :            :         ||
     229                 :            :         (tstate->datastack_top != NULL && tstate->datastack_limit != NULL)
     230                 :            :     );
     231         [ +  + ]:    7216271 :     return tstate->datastack_top != NULL &&
     232         [ +  - ]:    3608123 :         size < tstate->datastack_limit - tstate->datastack_top;
     233                 :            : }
     234                 :            : 
     235                 :            : extern _PyInterpreterFrame *
     236                 :            : _PyThreadState_PushFrame(PyThreadState *tstate, size_t size);
     237                 :            : 
     238                 :            : void _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame *frame);
     239                 :            : 
     240                 :            : /* Pushes a frame without checking for space.
     241                 :            :  * Must be guarded by _PyThreadState_HasStackSpace()
     242                 :            :  * Consumes reference to func. */
     243                 :            : static inline _PyInterpreterFrame *
     244                 :    2183943 : _PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_locals_from)
     245                 :            : {
     246                 :            :     CALL_STAT_INC(frames_pushed);
     247                 :    2183943 :     PyCodeObject *code = (PyCodeObject *)func->func_code;
     248                 :    2183943 :     _PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)tstate->datastack_top;
     249                 :    2183943 :     tstate->datastack_top += code->co_framesize;
     250                 :            :     assert(tstate->datastack_top < tstate->datastack_limit);
     251                 :    2183943 :     _PyFrame_Initialize(new_frame, func, NULL, code, null_locals_from);
     252                 :    2183943 :     return new_frame;
     253                 :            : }
     254                 :            : 
     255                 :            : int _PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame);
     256                 :            : 
     257                 :            : static inline
     258                 :     551704 : PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame)
     259                 :            : {
     260                 :            :     assert(frame->owner == FRAME_OWNED_BY_GENERATOR);
     261                 :     551704 :     size_t offset_in_gen = offsetof(PyGenObject, gi_iframe);
     262                 :     551704 :     return (PyGenObject *)(((char *)frame) - offset_in_gen);
     263                 :            : }
     264                 :            : 
     265                 :            : #ifdef __cplusplus
     266                 :            : }
     267                 :            : #endif
     268                 :            : #endif /* !Py_INTERNAL_FRAME_H */

Generated by: LCOV version 1.14