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