pub struct Function {Show 14 fields
pub module: Arc<str>,
pub name: Arc<str>,
pub params: Vec<LayoutId>,
pub reprs: Vec<Repr>,
pub refs: RefMap,
pub returns: LayoutId,
pub captures: Vec<Capture>,
pub code: Vec<Inst>,
pub spans: Vec<Span>,
pub locals: Vec<Local>,
pub inlined: Vec<Inlined>,
pub span: Span,
pub is_async: bool,
pub stub: bool,
}Expand description
One lowered function.
Fields§
§module: Arc<str>The module and name the source declared, for diagnostics and for
Program::function_named.
name: Arc<str>§params: Vec<LayoutId>The layout of each parameter, in declaration order.
Parameters occupy the frame from slot 0 onward, each taking the words
its layout says: a (Int, Point, Int) list occupies slots 0, 1–2 and
3. Declaration order, not a permutation into type groups — ADR 0034’s
“a mixed list such as (Int, String, Int) is not permuted into type
regions”. There are no type regions to permute into.
reprs: Vec<Repr>What each slot of the frame holds. reprs.len() is the frame size.
A slot’s Repr is fixed for the whole function; that is what makes
Function::refs correct at every program counter. A slot may be
reused by a later value of the same Repr, and a reference slot is
cleared to null at its last use, so the static map costs no retention
beyond a value’s live range.
refs: RefMapWhich slots are references, derived from Function::reprs.
returns: LayoutIdThe layout of what the function answers.
Inst::Return names the base slot of the answer in the callee’s
frame and the caller’s Inst::Call names the base slot of the
destination location in its own; the machine copies this many words
between them.
captures: Vec<Capture>The values the enclosing body handed this function, if it is a lambda. Empty for a declared function.
code: Vec<Inst>§spans: Vec<Span>The source span of each instruction, parallel to Function::code.
A parallel array rather than a field of Inst: a span is read when
a run fails or a trace is written, and never in the dispatch loop, so
it should not be in the cache line the loop is reading.
locals: Vec<Local>What the source called the values in the frame, and where each name meant which slot.
In declaration order, which is the order the shadowing rule reads
them in; see Local. Not parallel to anything — a function binds as
many names as it binds — and empty is a legal answer for a body that
binds none.
inlined: Vec<Inlined>The bodies this function holds that were written somewhere else.
lower::inline expands a call to a small leaf where it is made, and
the frame that call would have pushed then does not exist. Nothing
downstream can tell: a run of instructions in the middle of this
function is another function, and every reader that walks frames —
an error’s chain, a backtrace, a profile — sees one frame where there
were two.
So the expansion writes down what it removed. This is that record, and
it is Local’s shape for Local’s reason: a slot number is not an
answer to “what did the source call this”, and a program counter is not
an answer to “whose instruction is this”.
In the order the expansions were made, which is program-counter order,
and ranges nest rather than overlap. A reader takes the last range
that contains the pc, which is the innermost body — the same rule
Function::local_at follows, for the same reason.
span: SpanWhere the declaration itself is, for a diagnostic that is about the function rather than about one of its instructions.
is_async: boolWhether the body is a task’s: async fn, or the lambda a spawn
was handed.
stub: boolWhether this is a stand-in the lowering left for a declaration it
did not lower a body for. See lower::stub, and Function::is_stub.
Implementations§
Source§impl Function
impl Function
Sourcepub fn frame_size(&self) -> u32
pub fn frame_size(&self) -> u32
How many words a call to this function occupies on the stack.
Sourcepub fn param_slot(&self, at: usize, layouts: &[Layout]) -> Slot
pub fn param_slot(&self, at: usize, layouts: &[Layout]) -> Slot
The first slot of parameter at, which is the widths of the ones
before it.
Sourcepub fn param_words(&self, layouts: &[Layout]) -> u32
pub fn param_words(&self, layouts: &[Layout]) -> u32
How many slots the parameters occupy in total.
Sourcepub fn span_at(&self, pc: usize) -> Span
pub fn span_at(&self, pc: usize) -> Span
The span of the instruction at pc, or the declaration’s own.
Sourcepub fn local_at(&self, name: &str, pc: Pc) -> Option<&Local>
pub fn local_at(&self, name: &str, pc: Pc) -> Option<&Local>
Which slot name denotes at pc, if the source bound it there.
The last match wins, because a shadowing declaration is recorded
beside the one it shadows rather than in place of it: see Local.
Sourcepub fn inlined_at(&self, pc: Pc) -> impl Iterator<Item = &Inlined> + '_
pub fn inlined_at(&self, pc: Pc) -> impl Iterator<Item = &Inlined> + '_
The expanded bodies pc is inside, innermost last.
A reader that wants one frame’s worth of context wants the last of them; a reader rebuilding a chain wants all of them, innermost first, which is this reversed. Ranges nest, so “contains the pc” and “in the order they were made” is enough to order them: an inner expansion is always written after the outer one it sits in.
Sourcepub fn is_stub(&self) -> bool
pub fn is_stub(&self) -> bool
Whether this is a stand-in rather than a lowered body.
A stub has no body to stop at: its one instruction is a Return
written at the declaration’s own span, and it has no parameters and
no names, because there was no boundary and no scope to bind them
from. A tool that resolves a source location or a breakpoint against
a program — a debugger walking Function::locals, a stack trace
reading Function::span_at — has to skip a stub rather than answer
out of it, or it answers a question about a function that was never
written.
It answers true for all three kinds lower::stub’s doc comment
describes, because stub is the one place any of them is built and
this reads back exactly what it recorded. But a program that actually
runs — the output of lower_roots or
lower_entry once a lowering finishes without
error — can only hold two of the three: the declaration a slice left
out, and a generic declaration whose instantiations carry the real
code beside it. The third kind, a declaration this lowering reported
a gap about, belongs to a lowering that never got handed back — a gap
is an error, so the program it would have been part of does not exist
for a caller of this method to ask about.
This is a stored fact rather than a test of the four fields above,
because a shape a stub happens to have is not a shape only a stub
has. lower::stub’s own construction is the only place that knows
why the instruction, span, and empty lists are what they are;
asking a shape test to recover that intent at a distance means the
day a real body of one instruction is ever written at its
declaration’s own span, the test is wrong and nothing says so.
Recording the fact the lowering already has costs one field;
re-deriving it costs a convention two crates now have to keep in
sync by hand.