Skip to content
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

Better document Direct/Indirect locations. #1538

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion ykrt/src/compile/jitc_yk/codegen/x64/deopt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,12 @@ pub(crate) extern "C" fn __yk_deopt(
VarLocation::ConstInt { bits: _, v } => v,
VarLocation::ConstFloat(f) => f.to_bits(),
VarLocation::ConstPtr(v) => u64::try_from(v).unwrap(),
VarLocation::Direct { .. } => {
VarLocation::Direct { frame_off, size } => {
// See comment below: this case never needs to do anything.
debug_assert_eq!(
*aotvar.get(0).unwrap(),
SMLocation::Direct(6, frame_off, u16::try_from(size).unwrap())
);
varidx += 1;
continue;
}
Expand Down
47 changes: 36 additions & 11 deletions yksmp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ impl Record {
}

/// Describes where live variables are stored at specific times during execution.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub enum Location {
/// The live variable is stored in a register. Note, that LLVM's stackmap only stores one
/// location per live variable, which is enough for reading them out. For deoptimisation
/// however, we need to restore live variables, and the compiler often puts them in multiple
/// places, e.g. during spilling. Thus the fields describe three different locations in total:
/// places, e.g. during spilling. Additional locations are recorded via a vector:
/// * `u16`: Dwarf register number
/// * `u16`: size of the value
/// * `Vec<u16>`: additional locations. >=0 is a DWARF register number. < 0 is a stack offset
Expand All @@ -59,18 +59,43 @@ pub enum Location {
/// FIXME: We may need more additional locations in the future, which however will require
/// rewriting the stackmap format (until now we managed to get by with two extra locations).
Register(u16, u16, Vec<i16>),
/// The live variable is a pointer into the stack. To avoid unnecessary spilling and
/// dereferencing LLVM just records the value as an (offset, register) pair where the register
/// is typically the base pointer:
/// * `u16`: Dwarf register number
/// The live variable lives on the stack, because it was either put there directly via an
/// `alloca` or it was spilled. The location is encoded as an offset relative to the base
/// pointer. To get the value, we first need to compute the pointer via `rbp - offset` and then
/// dereference it. For example, the following C-code is likely going to produce an indirect
/// variable:
/// ```
/// int x = 0;
/// control_point() // Live vars: [x]
/// printf("%p", &x); // Forces x to be stack allocated.
/// ```
///
/// The fields of an `Indirect` are:
/// * `u16`: Dwarf register number. This appears to be always RBP.
/// * `i32`: offset
/// * `u16`: size of the value
Direct(u16, i32, u16),
/// The live variable lives on the stack. Similar to the `Direct` location, it's recorded as an
/// (offset, register) pair where the register is typically the base pointer. However, to read
/// out the value the address described by the (offset, register) pair needs to be dereferenced
/// first.
Indirect(u16, i32, u16),
/// LLVM's stackmaps can use `Direct` locations to optimise an `Indirect` location, where the
/// value itself is a pointer to the stack. This avoids having to spill the variable to the
/// stack. For example, the following C-code is likely to produce a direct location if there
/// are no more free registers available:
/// ```
/// ...
/// int x = 0;
/// int* y = &x;
/// control_point() // Live vars: [x, y]
/// printf("%d %p", x, y);
/// ```
///
/// Instead of spilling `y` to the stack and recording it as an `Indirect` it can instead be
/// recorded as a `Direct` without spilling. This would lead to one `Indirect` and one `Direct`
/// location, where the offsets are the same:
/// x: Indirect(.., -8, 4)
/// y: Direct(.., -8, 8)
///
/// In order to get the value for `x` we compute the pointer and dereference it, whereas the
/// value for `y` is simply the computation of the pointer (`rbp - offset`).
Direct(u16, i32, u16),
/// The live variable is a constant and has been directly inlined into the stackmap.
Constant(u32),
/// The live variable is a large constant and was stored in a vector as part of a record. This
Expand Down
Loading