Skip to content

Commit e5802d7

Browse files
committed
add jit
1 parent e040267 commit e5802d7

File tree

2 files changed

+53
-3
lines changed

2 files changed

+53
-3
lines changed

InternalDocs/README.md

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

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

41-
- [The Tier 2 Interpreter](tier2.md)
41+
- [The Tier 2 Interpreter and JIT](tier2.md)
4242

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

InternalDocs/tier2.md

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,12 @@ When tier 2 is enabled but the JIT is not (python was configured with
6060
[`--enable-experimental-jit=interpreter`](https://docs.python.org/dev/using/configure.html#cmdoption-enable-experimental-jit)),
6161
the executor jumps to `tier2_dispatch:` in
6262
[`Python/ceval.c`](../Python/ceval.c), where there is a loop that
63-
executes the micro-ops which are defined in
64-
[`Python/executor_cases.c.h`](../Python/executor_cases.c.h).
63+
executes the micro-ops. The micro-ops are are defined in
64+
[`Python/executor_cases.c.h`](../Python/executor_cases.c.h),
65+
which is generated by the build script
66+
[`Tools/cases_generator/tier2_generator.py`](../Tools/cases_generator/tier2_generator.py)
67+
from the bytecode definitions in
68+
[`Python/bytecodes.c`](../Python/bytecodes.c).
6569
This loop exits when an `_EXIT_TRACE` or `_DEOPT` uop is reached,
6670
and execution returns to teh tier 1 interpreter.
6771

@@ -72,3 +76,49 @@ inserted into a list of all executors which is stored in the interpreter
7276
state's `executor_list_head` field. This list is used when it is necessary
7377
to invalidate executors because values that their construction depended
7478
on may have changed.
79+
80+
## The JIT
81+
82+
When the jit is enabled (python was configured with
83+
[`--enable-experimental-jit`](https://docs.python.org/dev/using/configure.html#cmdoption-enable-experimental-jit),
84+
the uop executor's `jit_code` field is populated with a pointer to a compiled
85+
C function that implement the executor logic. This function's signature is
86+
defined by `jit_func` in [`pycore_jit.h`](Include/internal/pycore_jit.h).
87+
When the executor is invoked by `ENTER_EXECUTOR`, instead of jumping to
88+
the uop interpreter at `tier2_dispatch`, the executor runs the function
89+
that `jit_code` points to. This function returns the instruction pointer
90+
of the next Tier 1 instruction that needs to execute.
91+
92+
The generation of the jitted fuctions uses the copy-and-patch technique
93+
which is described in
94+
[Haoran Xu's article](https://sillycross.github.io/2023/05/12/2023-05-12/).
95+
At its core are statically generated `stencils` for the implementation
96+
of the micro ops, which are completed with runtime information while
97+
the jitted code is constructed for an executor by
98+
[`_PyJIT_Compile`](../Python/jit.c).
99+
100+
The stencils are generated under the build target `regen-jit` by the scripts
101+
in [`/Tools/jit`](/Tools/jit). This script reads
102+
[`Python/executor_cases.c.h`](../Python/executor_cases.c.h) (which is
103+
generated from [`Python/bytecodes.c`](../Python/bytecodes.c)). For
104+
each opcode, it constructs a `.c` file that contains a function for
105+
implementing this opcode, with some runtime information injected.
106+
This is done by replacing `CASE` by the bytecode definition in the
107+
template file [`Tools/jit/template.c`](../Tools/jit/template.c).
108+
109+
Each of the `.c` file is compiled by LLVM, to produce an object file
110+
that contains a function that executes the opcode. These compiled
111+
functions are used to generate the file
112+
[`jit_stencils.h`](../jit_stencils.h), which contains the functions
113+
that the JIT can use to emit code for each of the bytecodes.
114+
115+
For Python maintainers this means that changes to the bytecodes and
116+
their implementations do not require changes related to the JIT,
117+
because everything the JIT needs is automatically generated from
118+
[`Python/bytecodes.c`](../Python/bytecodes.c) at build time.
119+
120+
See Also:
121+
122+
* [Copy-and-Patch Compilation: A fast compilation algorithm for high-level languages and bytecode](https://arxiv.org/abs/2011.13127)
123+
124+
* [PyCon 2024: Building a JIT compiler for CPython](https://www.youtube.com/watch?v=kMO3Ju0QCDo)

0 commit comments

Comments
 (0)