What Is New in Python1
What Is New in Python1
What Is New in Python1
When CPython is configured and built using the --enable-experimental-jit option, a just-in-time (JIT)
compiler is added which may speed up some Python programs. On Windows,
use PCbuild/build.bat --experimental-jit to enable the JIT or --experimental-jit-interpreter to enable
the Tier 2 interpreter. Build requirements and further supporting information are contained
at Tools/jit/README.md.
The --enable-experimental-jit option takes these (optional) values, defaulting to yes if --enable-
experimental-jit is present without the optional value.
yes: Enable the JIT. To disable the JIT at runtime, pass the environment
variable PYTHON_JIT=0.
yes-off: Build the JIT but disable it by default. To enable the JIT at runtime, pass the
environment variable PYTHON_JIT=1.
interpreter: Enable the Tier 2 interpreter but disable the JIT. The interpreter can be disabled
by running with PYTHON_JIT=0.
We start with specialized Tier 1 bytecode. See What’s new in 3.11 for details.
When the Tier 1 bytecode gets hot enough, it gets translated to a new purely internal
intermediate representation (IR), called the Tier 2 IR, and sometimes referred to as micro-ops
(“uops”).
The Tier 2 IR uses the same stack-based virtual machine as Tier 1, but the instruction format
is better suited to translation to machine code.
We have several optimization passes for Tier 2 IR, which are applied before it is interpreted
or translated to machine code.
There is a Tier 2 interpreter, but it is mostly intended for debugging the earlier stages of the
optimization pipeline. The Tier 2 interpreter can be enabled by configuring Python with --
enable-experimental-jit=interpreter.
When the JIT is enabled, the optimized Tier 2 IR is translated to machine code, which is then
executed.
The machine code translation process uses a technique called copy-and-patch. It has no
runtime dependencies, but there is a new build-time dependency on LLVM.
See also
PEP 744
(JIT by Brandt Bucher, inspired by a paper by Haoran Xu and Fredrik Kjolstad. Tier 2 IR by Mark
Shannon and Guido van Rossum. Tier 2 optimizer by Ken Jin.)
This change to the semantics of locals() in optimized scopes also affects the default behavior of code
execution functions that implicitly target locals() if no explicit namespace is provided (such
as exec() and eval()). In previous versions, whether or not changes could be accessed by
calling locals() after calling the code execution function was implementation-dependent. In CPython
specifically, such code would typically appear to work as desired, but could sometimes fail in
optimized scopes based on other code (including debuggers and code execution tracing tools)
potentially resetting the shared snapshot in that scope. Now, the code will always run against an
independent snapshot of the local variables in optimized scopes, and hence the changes will never
be visible in subsequent calls to locals(). To access the changes made in these cases, an explicit
namespace reference must now be passed to the relevant function. Alternatively, it may make sense
to update affected code to use a higher level code execution API that returns the resulting code
execution namespace (e.g. runpy.run_path() when executing Python files from disk).
To ensure debuggers and similar tools can reliably update local variables in scopes affected by this
change, FrameType.f_locals now returns a write-through proxy to the frame’s local and locally
referenced nonlocal variables in these scopes, rather than returning an inconsistently updated
shared dict instance with undefined runtime semantics.
See PEP 667 for more details, including related C API changes and deprecations. Porting notes are
also provided below for the affected Python APIs and C APIs.
(PEP and implementation contributed by Mark Shannon and Tian Gao in gh-74929. Documentation
updates provided by Guido van Rossum and Alyssa Coghlan.)