Skip to content

Commit 98ae83b

Browse files
committed
add content to tier2
1 parent 2a4bc06 commit 98ae83b

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

InternalDocs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Program Execution
3737

3838
- [The Specializing Interpreter](adaptive.md)
3939

40-
- [The Tier 2 Interpreter (coming soon)](tier2.md)
40+
- [The Tier 2 Interpreter](tier2.md)
4141

4242
- [Garbage Collector Design](garbage_collector.md)
4343

InternalDocs/tier2.md

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,67 @@
11
# The Tier 2 Interpreter
22

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

Comments
 (0)