|  | 
| 1 | 1 | # The Tier 2 Interpreter | 
| 2 | 2 | 
 | 
| 3 |  | -Coming soon. | 
|  | 3 | +The [basic interpreter](interpreter.md), also referred to as the `tier 1` | 
|  | 4 | +interpreter, consists of a main loop that executes the bytecode instructions | 
|  | 5 | +generated by the [bytecode compiler](compiler.md) and their | 
|  | 6 | +[specializations](adaptive.md). Runtime optimization in tier 1 can only be | 
|  | 7 | +done for one instruction at a time. The `tier 2` interpreter is based on a | 
|  | 8 | +mechanism to replace an entire sequence of bytecode instructions, and this | 
|  | 9 | +enables optimizations that span multiple instructions. | 
|  | 10 | + | 
|  | 11 | +## The Optimizer and Executors | 
|  | 12 | + | 
|  | 13 | +The program begins running in tier 1, until a `JUMP_BACKWARD` instruction | 
|  | 14 | +determines that it is `hot` because the counter in its | 
|  | 15 | +[inline cache](interpreter.md#inline-cache-entries) indicates that is | 
|  | 16 | +executed more than some threshold number of times. It then calls the | 
|  | 17 | +function `_PyOptimizer_Optimize()` in | 
|  | 18 | +[`Python/optimizer.c`](../Python/optimizer.c), passing it the current | 
|  | 19 | +[frame](frames.md) and instruction pointer. `_PyOptimizer_Optimize()` | 
|  | 20 | +constructs an object of type | 
|  | 21 | +[`_PyExecutorObject`](Include/internal/pycore_optimizer.h) which implements | 
|  | 22 | +an optimized version of the instruction trace beginning at this jump. | 
|  | 23 | + | 
|  | 24 | +The optimizer determines where the trace ends, and the executor is set up | 
|  | 25 | +to either return to `tier 1` and resume execution, or transfer control | 
|  | 26 | +to another executor (see `_PyExitData` in Include/internal/pycore_optimizer.h). | 
|  | 27 | + | 
|  | 28 | +The executor is stored on the [`code object`](code_objects.md) of the frame, | 
|  | 29 | +in the `co_executors` field which is an array of executors. The start | 
|  | 30 | +instruction of the trace (the `JUMP_BACKWARD`) is replaced by an | 
|  | 31 | +`ENTER_EXECUTOR` instruction whose `oparg` is equal to the index of the | 
|  | 32 | +executor in `co_executors`. | 
|  | 33 | + | 
|  | 34 | +## The uop optimizer | 
|  | 35 | + | 
|  | 36 | +The optimizer that `_PyOptimizer_Optimize()` runs is configurable | 
|  | 37 | +via the `_Py_SetTier2Optimizer()` function (this is used in test | 
|  | 38 | +via `_testinternalcapi.set_optimizer()`.) | 
|  | 39 | + | 
|  | 40 | +The tier 2 optimizer, `_PyUOpOptimizer_Type`, is defined in | 
|  | 41 | +[`Python/optimizer.c`](../Python/optimizer.c). It translates | 
|  | 42 | +an instruction trace into a sequence of micro-ops by replacing | 
|  | 43 | +each bytecode by an equivalent sequence of micro-ops | 
|  | 44 | +(see `_PyOpcode_macro_expansion` in | 
|  | 45 | +[pycore_opcode_metadata.h](../Include/internal/pycore_opcode_metadata.h) | 
|  | 46 | +which is generated from [`Python/bytecodes.c`](../Python/bytecodes.c)). | 
|  | 47 | +The micro-op sequence is then optimized by | 
|  | 48 | +`_Py_uop_analyze_and_optimize` in | 
|  | 49 | +[`Python/optimizer_analysis.c`](../Python/optimizer_analysis.c). | 
|  | 50 | + | 
|  | 51 | +## Running a uop executor | 
|  | 52 | + | 
|  | 53 | +After a tier 1 `JUMP_BACKWARD` instruction invokes the uop optimizer | 
|  | 54 | +to create a tier 2 uop executor, it transfers control to this executor | 
|  | 55 | +via the `GOTO_TIER_TWO` macro, which jumps to `tier2_dispatch:` in | 
|  | 56 | +[`Python/ceval.c`](../Python/ceval.c), where there is a loops that | 
|  | 57 | +executes the micro-ops which are defined in | 
|  | 58 | +[`Python/executor_cases.c.h`](../Python/executor_cases.c.h). | 
|  | 59 | +This loop exits when an `_EXIT_TRACE` or `_DEOPT` uop is reached. | 
|  | 60 | + | 
|  | 61 | +## Invalidating Executors | 
|  | 62 | + | 
|  | 63 | +In addition to being stored on the code object, each executor is also | 
|  | 64 | +inserted into a list of all executors which is stored in the interpreter | 
|  | 65 | +state's `executor_list_head` field. This list is used when it is necessary | 
|  | 66 | +to invalidate executors because values that their construction depended | 
|  | 67 | +on may have changed. | 
0 commit comments