Skip to main content

DebugLocalMeta

Struct DebugLocalMeta 

Source
#[repr(C)]
pub struct DebugLocalMeta { pub source_name: *const u8, pub name_len: u32, pub symbol_id: u32, pub descriptor: *const TypeDescriptor, pub type_id: u32, pub kind: u8, pub span_start: u32, pub span_end: u32, pub callee_name: *const u8, pub callee_name_len: u32, pub slot_kind: DebugSlotKind, }
Expand description

One local’s metadata at frame construction: the source name (ptr + len), the compiler-assigned symbol id, the local’s static type descriptor, the full static Type id, the user-vs-temp classification, the source span, and what its value slot’s word means. Flattened for FFI.

Fields§

§source_name: *const u8§name_len: u32§symbol_id: u32§descriptor: *const TypeDescriptor

The local’s static type descriptor (§9.3). The backend embeds the 'static TypeDescriptor resolved from the MIR local’s Type.

§type_id: u32

The full static Type id (praxis_typeck::Type(u32) handle). Lets the debugger reconstruct the exact local type (incl. collection element types / record shapes) the runtime descriptor alone loses.

§kind: u8

The debugger classification: LOCAL_KIND_USER (a binding the programmer wrote) or LOCAL_KIND_TEMP (a compiler intermediate). The split is structural, not a name convention.

§span_start: u32

The local’s source span [start, end) (byte offsets into program source) for debugger provenance. User locals carry their binding’s span; temps carry the expression they materialize (rendered as @ "expr"). (0, 0) means “no span” (the return slot, span-less captures).

§span_end: u32§callee_name: *const u8

The function a direct call defines this local from (a 'static embedded string), or null with a zero callee_name_len for every local that is not one.

It is what places a caller frame’s line: a frame below the innermost is stopped in a call, and the call is the one whose callee is the frame above it. Static, because it is a fact about the program — the live slots cannot answer it, since a loop leaves an earlier pass’s value in the call’s temp.

Null for a CallIndirect: a closure’s target is a value, and the name this would hold does not exist until the call runs.

§callee_name_len: u32§slot_kind: DebugSlotKind

What this local’s value slot holds (ADR-120 part 2). DebugSlotKind::Reference for every local whose box the compiler kept; a scalar kind for a temp whose box the block-local forwarding deleted and whose payload the definition stores raw.

A real enum, not the u8 its neighbours kind and type_id are, because nothing outside Rust ever writes this struct: #[repr(C)] is here so crate::crash_snapshot reads a stable layout, and generated code only ever stores the address of the enclosing FunctionDebugMeta. So there is no bit pattern to validate and no “unknown tag” case to decide what to do with — which is one fewer place the answer could be Reference by accident.

Implementations§

Source§

impl DebugLocalMeta

Source

pub unsafe fn read(&self, word: Option<GcRef>) -> Option<DebugValue>

Decode one value slot’s word under this local’s slot_kind.

The only place a slot word becomes something typed, and therefore the only place the reference/scalar question is asked. None is “nothing has been written here yet”; DebugValue::Reclaimed is the third state, a reference slot whose object the collector took after it was written.

§The zero word, and the one thing a scalar slot cannot say

A claim zeroes its run, so an all-zero word is “no value yet” — which for a DebugSlotKind::Reference slot is exact, because a GcRef is NonNull and can never be zero (F18, the niche this module’s header describes).

For a scalar slot it cannot be exact — 2^64 payloads do not fit in 2^64 words beside an “unwritten” state — so exactly one payload per kind reads back as <uninit>. Which one is DebugSlotKind::store_bias’s choice: three kinds lose nothing, Float loses one NaN, and Int loses i64::MIN. The direction of the error is the safe one — a slot under-reports a value it holds and never reports a value it does not. an_int_slot_holding_i64_min_reads_as_uninit_and_zero_does_not pins both halves.

§Safety

word must be the current content of a live value slot belonging to a frame whose metadata is this one — that is, values[i] paired with locals[i] of the same FunctionDebugMeta. Pairing a word with another local’s metadata is exactly the mistake this function exists to make impossible to write by hand, and the two callers (DebugFrameStackHeader::clear_reclaimed and crash_snapshot::copy_stack) both zip the two arrays.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.