(root)/
Python-3.12.0/
Include/
internal/
pycore_flowgraph.h
       1  #ifndef Py_INTERNAL_CFG_H
       2  #define Py_INTERNAL_CFG_H
       3  #ifdef __cplusplus
       4  extern "C" {
       5  #endif
       6  
       7  #ifndef Py_BUILD_CORE
       8  #  error "this header requires Py_BUILD_CORE define"
       9  #endif
      10  
      11  #include "pycore_opcode_utils.h"
      12  #include "pycore_compile.h"
      13  
      14  
      15  typedef struct {
      16      int i_opcode;
      17      int i_oparg;
      18      _PyCompilerSrcLocation i_loc;
      19      struct _PyCfgBasicblock_ *i_target; /* target block (if jump instruction) */
      20      struct _PyCfgBasicblock_ *i_except; /* target block when exception is raised */
      21  } _PyCfgInstruction;
      22  
      23  typedef struct {
      24      int id;
      25  } _PyCfgJumpTargetLabel;
      26  
      27  
      28  typedef struct {
      29      struct _PyCfgBasicblock_ *handlers[CO_MAXBLOCKS+1];
      30      int depth;
      31  } _PyCfgExceptStack;
      32  
      33  typedef struct _PyCfgBasicblock_ {
      34      /* Each basicblock in a compilation unit is linked via b_list in the
      35         reverse order that the block are allocated.  b_list points to the next
      36         block in this list, not to be confused with b_next, which is next by
      37         control flow. */
      38      struct _PyCfgBasicblock_ *b_list;
      39      /* The label of this block if it is a jump target, -1 otherwise */
      40      _PyCfgJumpTargetLabel b_label;
      41      /* Exception stack at start of block, used by assembler to create the exception handling table */
      42      _PyCfgExceptStack *b_exceptstack;
      43      /* pointer to an array of instructions, initially NULL */
      44      _PyCfgInstruction *b_instr;
      45      /* If b_next is non-NULL, it is a pointer to the next
      46         block reached by normal control flow. */
      47      struct _PyCfgBasicblock_ *b_next;
      48      /* number of instructions used */
      49      int b_iused;
      50      /* length of instruction array (b_instr) */
      51      int b_ialloc;
      52      /* Used by add_checks_for_loads_of_unknown_variables */
      53      uint64_t b_unsafe_locals_mask;
      54      /* Number of predecessors that a block has. */
      55      int b_predecessors;
      56      /* depth of stack upon entry of block, computed by stackdepth() */
      57      int b_startdepth;
      58      /* instruction offset for block, computed by assemble_jump_offsets() */
      59      int b_offset;
      60      /* Basic block is an exception handler that preserves lasti */
      61      unsigned b_preserve_lasti : 1;
      62      /* Used by compiler passes to mark whether they have visited a basic block. */
      63      unsigned b_visited : 1;
      64      /* b_except_handler is used by the cold-detection algorithm to mark exception targets */
      65      unsigned b_except_handler : 1;
      66      /* b_cold is true if this block is not perf critical (like an exception handler) */
      67      unsigned b_cold : 1;
      68      /* b_warm is used by the cold-detection algorithm to mark blocks which are definitely not cold */
      69      unsigned b_warm : 1;
      70  } _PyCfgBasicblock;
      71  
      72  int _PyBasicblock_InsertInstruction(_PyCfgBasicblock *block, int pos, _PyCfgInstruction *instr);
      73  
      74  typedef struct cfg_builder_ {
      75      /* The entryblock, at which control flow begins. All blocks of the
      76         CFG are reachable through the b_next links */
      77      _PyCfgBasicblock *g_entryblock;
      78      /* Pointer to the most recently allocated block.  By following
      79         b_list links, you can reach all allocated blocks. */
      80      _PyCfgBasicblock *g_block_list;
      81      /* pointer to the block currently being constructed */
      82      _PyCfgBasicblock *g_curblock;
      83      /* label for the next instruction to be placed */
      84      _PyCfgJumpTargetLabel g_current_label;
      85  } _PyCfgBuilder;
      86  
      87  int _PyCfgBuilder_UseLabel(_PyCfgBuilder *g, _PyCfgJumpTargetLabel lbl);
      88  int _PyCfgBuilder_Addop(_PyCfgBuilder *g, int opcode, int oparg, _PyCompilerSrcLocation loc);
      89  
      90  int _PyCfgBuilder_Init(_PyCfgBuilder *g);
      91  void _PyCfgBuilder_Fini(_PyCfgBuilder *g);
      92  
      93  _PyCfgInstruction* _PyCfg_BasicblockLastInstr(const _PyCfgBasicblock *b);
      94  int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache,
      95                              int code_flags, int nlocals, int nparams, int firstlineno);
      96  int _PyCfg_Stackdepth(_PyCfgBasicblock *entryblock, int code_flags);
      97  void _PyCfg_ConvertPseudoOps(_PyCfgBasicblock *entryblock);
      98  int _PyCfg_ResolveJumps(_PyCfgBuilder *g);
      99  
     100  
     101  static inline int
     102  basicblock_nofallthrough(const _PyCfgBasicblock *b) {
     103      _PyCfgInstruction *last = _PyCfg_BasicblockLastInstr(b);
     104      return (last &&
     105              (IS_SCOPE_EXIT_OPCODE(last->i_opcode) ||
     106               IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)));
     107  }
     108  
     109  #define BB_NO_FALLTHROUGH(B) (basicblock_nofallthrough(B))
     110  #define BB_HAS_FALLTHROUGH(B) (!basicblock_nofallthrough(B))
     111  
     112  PyCodeObject *
     113  _PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *u, PyObject *const_cache,
     114                             PyObject *consts, int maxdepth, _PyCompile_InstructionSequence *instrs,
     115                             int nlocalsplus, int code_flags, PyObject *filename);
     116  
     117  #ifdef __cplusplus
     118  }
     119  #endif
     120  #endif /* !Py_INTERNAL_CFG_H */