-
-
Notifications
You must be signed in to change notification settings - Fork 32.9k
gh-119786: Edit InternalDocs/frames.md
, Python/vm-state.md
, Python/tier2_engine.md
#124450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 8 commits
60b1689
fbf47e4
3aaa70c
1a6df69
944d1ab
0c2489f
c7cdfb5
be38623
26d5559
52225eb
ba8f39a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,24 +3,25 @@ | |
## Definition of Tiers | ||
|
||
- **Tier 1** is the classic Python bytecode interpreter. | ||
This includes the specializing adaptive interpreter described in [PEP 659](https://peps.python.org/pep-0659/) and introduced in Python 3.11. | ||
This includes the specializing [adaptive interpreter](adaptive.md). | ||
- **Tier 2**, also known as the micro-instruction ("uop") interpreter, is a new interpreter with a different instruction format. | ||
Eclips4 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
It will be introduced in Python 3.13, and also forms the basis for a JIT using copy-and-patch technology that is likely to be introduced at the same time (but, unlike the Tier 2 interpreter, hasn't landed in the main branch yet). | ||
It was introduced in Python 3.13, and also forms the basis for a JIT using copy-and-patch technology. See [Tier 2](tier2_engine.md) for more information. | ||
|
||
|
||
# Frame state | ||
Eclips4 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Almost all interpreter state is nominally stored in the frame structure. | ||
A pointer to the current frame is held in `frame`. It contains: | ||
A pointer to the current frame is held in `frame`, for more information about what `frame` contains see [Frames](frames.md): | ||
Eclips4 marked this conversation as resolved.
Show resolved
Hide resolved
Eclips4 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CC @markshannon I can't comment on lines that haven't changed, so this is for a number of comments on vm-state.md. L 21: The interpreters share an implementation of what? The frame? Caches the depth - is this stack depth? L 40: Add a link to exception_handling.md. L45: Not sure what you mean here: "The implementation of jumps within a single Tier 2 superblock/trace is just that, an implementation." L51: "within the superblock" is repeated twice. I think it might be worth moving the contents of the "Thread state and interpreter state" section to the beginning, as a high level overview of the components of the state, and then drill into the parts. The "Tier 2 IR format" section doesn't seem to belong to the vm-state topic at all. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Both tier 1 and tier 2 use the same canonical in-memory representation. Tier 2 might store some values temporarily in registers, but that should be invisible to other code. The reason this is noteworthy is that other VMs, e.g. HotSpot can have different frame layouts for the compiler and interpreter. |
||
# Thread state and interpreter state | ||
|
||
- **local variables** (a.k.a. "fast locals") | ||
Eclips4 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- **evaluation stack** (tacked onto the end of the locals) | ||
- **stack top** (an integer giving the top of the evaluation stack) | ||
- **instruction pointer** | ||
- **code object**, which holds things like the array of instructions, lists of constants and names referenced by certain instructions, the exception handling table, and the table that translates instruction offsets to line numbers | ||
- **return offset**, only relevant during calls, telling the interpreter where to return | ||
Another important piece of VM state is the **thread state**, held in `tstate`. | ||
Eclips4 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
The current frame pointer, `frame`, is always equal to `tstate->current_frame`. | ||
The thread state also holds the exception state (`tstate->exc_info`) and the recursion counters (`tstate->c_recursion_remaining` and `tstate->py_recursion_remaining`). | ||
|
||
There are some other fields in the frame structure of less importance; notably frames are linked together in a singly-linked list via the `previous` pointer, pointing from callee to caller. | ||
The frame also holds a pointer to the current function, globals, builtins, and the locals converted to dict (used to support the `locals()` built-in). | ||
The thread state is also used to access the **interpreter state** (`tstate->interp`), which is important since the "eval breaker" flags are stored there (`tstate->interp->ceval.eval_breaker`, an "atomic" variable), as well as the "PEP 523 function" (`tstate->interp->eval_frame`). | ||
The interpreter state also holds the optimizer state (`optimizer` and some counters). | ||
Note that the eval breaker may be moved to the thread state soon as part of the multicore (PEP 703) work. | ||
|
||
## Fast locals and evaluation stack | ||
|
||
|
@@ -47,7 +48,7 @@ The Tier 2 instruction pointer is strictly internal to the Tier 2 interpreter, s | |
|
||
## Unwinding | ||
|
||
Unwinding uses exception tables to find the next point at which normal execution can occur, or fail if there are no exception handlers. | ||
Unwinding uses exception tables to find the next point at which normal execution can occur, or fail if there are no exception handlers. For more information on what exception tables are, see [exception handling](exception_handling.md). | ||
During unwinding both the stack and the instruction pointer should be in their canonical, in-memory representation. | ||
|
||
## Jumps in bytecode | ||
|
@@ -68,23 +69,3 @@ Patching exits should be fairly straightforward in the interpreter. | |
It will be more complex in the JIT. | ||
|
||
(We might also consider deoptimizations as a separate jump type.) | ||
|
||
# Thread state and interpreter state | ||
|
||
Another important piece of VM state is the **thread state**, held in `tstate`. | ||
The current frame pointer, `frame`, is always equal to `tstate->current_frame`. | ||
The thread state also holds the exception state (`tstate->exc_info`) and the recursion counters (`tstate->c_recursion_remaining` and `tstate->py_recursion_remaining`). | ||
|
||
The thread state is also used to access the **interpreter state** (`tstate->interp`), which is important since the "eval breaker" flags are stored there (`tstate->interp->ceval.eval_breaker`, an "atomic" variable), as well as the "PEP 523 function" (`tstate->interp->eval_frame`). | ||
The interpreter state also holds the optimizer state (`optimizer` and some counters). | ||
Note that the eval breaker may be moved to the thread state soon as part of the multicore (PEP 703) work. | ||
|
||
# Tier 2 IR format | ||
|
||
The tier 2 IR (Internal Representation) format is also the basis for the Tier 2 interpreter (though the two formats may eventually differ). This format is also used as the input to the machine code generator (the JIT compiler). | ||
|
||
Tier 2 IR entries are all the same size; there is no equivalent to `EXTENDED_ARG` or trailing inline cache entries. Each instruction is a struct with the following fields (all integers of varying sizes): | ||
|
||
- **opcode**: Sometimes the same as a Tier 1 opcode, sometimes a separate micro opcode. Tier 2 opcodes are 9 bits (as opposed to Tier 1 opcodes, which fit in 8 bits). By convention, Tier 2 opcode names start with `_`. | ||
- **oparg**: The argument. Usually the same as the Tier 1 oparg after expansion of `EXTENDED_ARG` prefixes. Up to 32 bits. | ||
- **operand**: An additional argument, Typically the value of *one* cache item from the Tier 1 inline cache, up to 64 bits. | ||
Eclips4 marked this conversation as resolved.
Show resolved
Hide resolved
|
Uh oh!
There was an error while loading. Please reload this page.