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 acb105a7c1f] Lines: 49 49 100.0 %
Date: 2022-07-20 13:12:14 Functions: 13 13 100.0 %
Branches: 6 6 100.0 %

           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                 :            : };
      47                 :            : 
      48                 :            : typedef struct _PyInterpreterFrame {
      49                 :            :     /* "Specials" section */
      50                 :            :     PyFunctionObject *f_func; /* Strong reference */
      51                 :            :     PyObject *f_globals; /* Borrowed reference */
      52                 :            :     PyObject *f_builtins; /* Borrowed reference */
      53                 :            :     PyObject *f_locals; /* Strong reference, may be NULL */
      54                 :            :     PyCodeObject *f_code; /* Strong reference */
      55                 :            :     PyFrameObject *frame_obj; /* Strong reference, may be NULL */
      56                 :            :     /* Linkage section */
      57                 :            :     struct _PyInterpreterFrame *previous;
      58                 :            :     // NOTE: This is not necessarily the last instruction started in the given
      59                 :            :     // frame. Rather, it is the code unit *prior to* the *next* instruction. For
      60                 :            :     // example, it may be an inline CACHE entry, an instruction we just jumped
      61                 :            :     // over, or (in the case of a newly-created frame) a totally invalid value:
      62                 :            :     _Py_CODEUNIT *prev_instr;
      63                 :            :     int stacktop;     /* Offset of TOS from localsplus  */
      64                 :            :     bool is_entry;  // Whether this is the "root" frame for the current _PyCFrame.
      65                 :            :     char owner;
      66                 :            :     /* Locals and stack */
      67                 :            :     PyObject *localsplus[1];
      68                 :            : } _PyInterpreterFrame;
      69                 :            : 
      70                 :            : #define _PyInterpreterFrame_LASTI(IF) \
      71                 :            :     ((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code)))
      72                 :            : 
      73                 :    5973257 : static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) {
      74                 :    5973257 :     return f->localsplus + f->f_code->co_nlocalsplus;
      75                 :            : }
      76                 :            : 
      77                 :      14882 : static inline PyObject *_PyFrame_StackPeek(_PyInterpreterFrame *f) {
      78                 :            :     assert(f->stacktop > f->f_code->co_nlocalsplus);
      79                 :            :     assert(f->localsplus[f->stacktop-1] != NULL);
      80                 :      14882 :     return f->localsplus[f->stacktop-1];
      81                 :            : }
      82                 :            : 
      83                 :       1269 : static inline PyObject *_PyFrame_StackPop(_PyInterpreterFrame *f) {
      84                 :            :     assert(f->stacktop > f->f_code->co_nlocalsplus);
      85                 :       1269 :     f->stacktop--;
      86                 :       1269 :     return f->localsplus[f->stacktop];
      87                 :            : }
      88                 :            : 
      89                 :  260669836 : static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, PyObject *value) {
      90                 :  260669836 :     f->localsplus[f->stacktop] = value;
      91                 :  260669836 :     f->stacktop++;
      92                 :  260669836 : }
      93                 :            : 
      94                 :            : #define FRAME_SPECIALS_SIZE ((sizeof(_PyInterpreterFrame)-1)/sizeof(PyObject *))
      95                 :            : 
      96                 :            : void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest);
      97                 :            : 
      98                 :            : /* Consumes reference to func and locals */
      99                 :            : static inline void
     100                 :  269958431 : _PyFrame_InitializeSpecials(
     101                 :            :     _PyInterpreterFrame *frame, PyFunctionObject *func,
     102                 :            :     PyObject *locals, PyCodeObject *code)
     103                 :            : {
     104                 :  269958431 :     frame->f_func = func;
     105                 :  269958431 :     frame->f_code = (PyCodeObject *)Py_NewRef(code);
     106                 :  269958431 :     frame->f_builtins = func->func_builtins;
     107                 :  269958431 :     frame->f_globals = func->func_globals;
     108                 :  269958431 :     frame->f_locals = locals;
     109                 :  269958431 :     frame->stacktop = code->co_nlocalsplus;
     110                 :  269958431 :     frame->frame_obj = NULL;
     111                 :  269958431 :     frame->prev_instr = _PyCode_CODE(code) - 1;
     112                 :  269958431 :     frame->is_entry = false;
     113                 :  269958431 :     frame->owner = FRAME_OWNED_BY_THREAD;
     114                 :  269958431 : }
     115                 :            : 
     116                 :            : /* Gets the pointer to the locals array
     117                 :            :  * that precedes this frame.
     118                 :            :  */
     119                 :            : static inline PyObject**
     120                 :   21520229 : _PyFrame_GetLocalsArray(_PyInterpreterFrame *frame)
     121                 :            : {
     122                 :   21520229 :     return frame->localsplus;
     123                 :            : }
     124                 :            : 
     125                 :            : static inline PyObject**
     126                 :  537084082 : _PyFrame_GetStackPointer(_PyInterpreterFrame *frame)
     127                 :            : {
     128                 :  537084082 :     return frame->localsplus+frame->stacktop;
     129                 :            : }
     130                 :            : 
     131                 :            : static inline void
     132                 :  537083794 : _PyFrame_SetStackPointer(_PyInterpreterFrame *frame, PyObject **stack_pointer)
     133                 :            : {
     134                 :  537083794 :     frame->stacktop = (int)(stack_pointer - frame->localsplus);
     135                 :  537083794 : }
     136                 :            : 
     137                 :            : /* Determine whether a frame is incomplete.
     138                 :            :  * A frame is incomplete if it is part way through
     139                 :            :  * creating cell objects or a generator or coroutine.
     140                 :            :  *
     141                 :            :  * Frames on the frame stack are incomplete until the
     142                 :            :  * first RESUME instruction.
     143                 :            :  * Frames owned by a generator are always complete.
     144                 :            :  */
     145                 :            : static inline bool
     146                 :    1291588 : _PyFrame_IsIncomplete(_PyInterpreterFrame *frame)
     147                 :            : {
     148         [ +  + ]:    2571556 :     return frame->owner != FRAME_OWNED_BY_GENERATOR &&
     149         [ +  + ]:    1279968 :     frame->prev_instr < _PyCode_CODE(frame->f_code) + frame->f_code->_co_firsttraceable;
     150                 :            : }
     151                 :            : 
     152                 :            : /* For use by _PyFrame_GetFrameObject
     153                 :            :   Do not call directly. */
     154                 :            : PyFrameObject *
     155                 :            : _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame);
     156                 :            : 
     157                 :            : /* Gets the PyFrameObject for this frame, lazily
     158                 :            :  * creating it if necessary.
     159                 :            :  * Returns a borrowed referennce */
     160                 :            : static inline PyFrameObject *
     161                 :   14020927 : _PyFrame_GetFrameObject(_PyInterpreterFrame *frame)
     162                 :            : {
     163                 :            : 
     164                 :            :     assert(!_PyFrame_IsIncomplete(frame));
     165                 :   14020927 :     PyFrameObject *res =  frame->frame_obj;
     166         [ +  + ]:   14020927 :     if (res != NULL) {
     167                 :    8837186 :         return res;
     168                 :            :     }
     169                 :    5183741 :     return _PyFrame_MakeAndSetFrameObject(frame);
     170                 :            : }
     171                 :            : 
     172                 :            : /* Clears all references in the frame.
     173                 :            :  * If take is non-zero, then the _PyInterpreterFrame frame
     174                 :            :  * may be transferred to the frame object it references
     175                 :            :  * instead of being cleared. Either way
     176                 :            :  * the caller no longer owns the references
     177                 :            :  * in the frame.
     178                 :            :  * take should  be set to 1 for heap allocated
     179                 :            :  * frames like the ones in generators and coroutines.
     180                 :            :  */
     181                 :            : void
     182                 :            : _PyFrame_Clear(_PyInterpreterFrame * frame);
     183                 :            : 
     184                 :            : int
     185                 :            : _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg);
     186                 :            : 
     187                 :            : int
     188                 :            : _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame);
     189                 :            : 
     190                 :            : void
     191                 :            : _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear);
     192                 :            : 
     193                 :            : 
     194                 :            : static inline bool
     195                 :  150392152 : _PyThreadState_HasStackSpace(PyThreadState *tstate, int size)
     196                 :            : {
     197                 :  150392152 :     return tstate->datastack_top + size < tstate->datastack_limit;
     198                 :            : }
     199                 :            : 
     200                 :            : extern _PyInterpreterFrame *
     201                 :            : _PyThreadState_PushFrame(PyThreadState *tstate, size_t size);
     202                 :            : 
     203                 :            : void _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame *frame);
     204                 :            : 
     205                 :            : /* Pushes a frame without checking for space.
     206                 :            :  * Must be guarded by _PyThreadState_HasStackSpace()
     207                 :            :  * Consumes reference to func. */
     208                 :            : static inline _PyInterpreterFrame *
     209                 :  150388199 : _PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func)
     210                 :            : {
     211                 :            :     CALL_STAT_INC(frames_pushed);
     212                 :  150388199 :     PyCodeObject *code = (PyCodeObject *)func->func_code;
     213                 :  150388199 :     _PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)tstate->datastack_top;
     214                 :  150388199 :     tstate->datastack_top += code->co_framesize;
     215                 :            :     assert(tstate->datastack_top < tstate->datastack_limit);
     216                 :  150388199 :     _PyFrame_InitializeSpecials(new_frame, func, NULL, code);
     217                 :  150388199 :     return new_frame;
     218                 :            : }
     219                 :            : 
     220                 :            : int _PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame);
     221                 :            : 
     222                 :            : static inline
     223                 :   45071231 : PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame)
     224                 :            : {
     225                 :            :     assert(frame->owner == FRAME_OWNED_BY_GENERATOR);
     226                 :   45071231 :     size_t offset_in_gen = offsetof(PyGenObject, gi_iframe);
     227                 :   45071231 :     return (PyGenObject *)(((char *)frame) - offset_in_gen);
     228                 :            : }
     229                 :            : 
     230                 :            : #ifdef __cplusplus
     231                 :            : }
     232                 :            : #endif
     233                 :            : #endif /* !Py_INTERNAL_FRAME_H */

Generated by: LCOV version 1.14