Skip to content

Memory

MIR locals, storage classes, frames, ownership modes, and raw-pointer discipline.

Updated View as Markdown

MIR separates a value’s semantic type, physical storage, and lifetime policy. Those three facts often correlate, but they are not interchangeable.

Locals

Each local records:

  • its resolved TypeRef;
  • an optional source name;
  • an RcMode;
  • a LocalStorage classification.

A local is a compiler value identity, not necessarily one memory slot. Its selected carrier can reside in a WebAssembly local within one continuation, receive a frame slot because it crosses suspension, or denote an arena-relative handle to bytes elsewhere.

Storage

LocalStorage has four states:

Storage Contract
Unset Layout inference has not stamped an authoritative choice
Scalar Value has a fixed size/alignment and fits a scalar carrier
Flex Local holds a four-byte arena-relative offset to allocated storage
InlineAggregate Fixed aggregate bytes live in a reserved frame region

Unset has conservative type-based fallbacks for early analysis, but it is not valid where final code generation requires an explicit layout decision.

Inline aggregates avoid a separate heap allocation for bounded, non-escaping values. Their primary local still uses the expected offset-shaped carrier so field operations can remain uniform, while InlineAggregateData reserves the actual frame bytes. Unsized or escaping data uses flex storage.

Frame layout

A suspending function’s frame begins with the runtime ABI header. Remaining slots are aligned and packed after it. Each slot records offset, size, alignment, type, and purpose.

Purposes include:

  • parameters and locals live across suspension;
  • state tags for confined continuation clusters;
  • spawn-arm state and inline subframes;
  • pointers to recursive child frames;
  • reusable staging space for wide transient values;
  • inline aggregate data;
  • persistent storage for boxed aggregate call results;
  • frame-resident cell contents.

The layout maps locals to primary slots and separately maps data regions such as inline aggregates and cells. These are not aliases by default. In particular, two inline aggregate data regions must not be merged merely because their pointer-shaped primary locals have non-overlapping apparent liveness.

The staging region follows a maximum, not sum, policy: sequential operations can reuse one region sized for the largest requirement. Persistent suspending results cannot use that shared region when two results may be live together.

Ownership

RcMode describes how an RC-relevant local participates in lifetime management:

Mode Meaning
Static Compile-time analysis inserts required clone/drop operations
Confined Crosses a single-resume boundary while remaining statically managed
Linear Ownership moves to at most one consumer; no clone/drop machinery
PinElided A proven frame-local reference needs no runtime pin
RawRef A short-lived absolute reference cannot cross an allocation barrier
InheritedExtract Extracted value inherits the container’s ownership rather than retaining
BorrowedExtract Extracted value is borrowed while the container remains owner

The last two may have identical load shapes to an ordinary field read. Their explicit mode prevents code generation from guessing whether an extraction must retain.

Ownership becomes operations in MIR: clone, retain, drop, shallow drop, in-place drop, and reuse. These are semantic operations even if a later pass elides or combines them. Code generation must not invent missing reference counting from type shape.

Arena-relative and absolute addresses

Stable heap and frame references normally use offsets relative to the current arena base. An arena can grow or relocate its backing memory, so an absolute address derived before an allocation barrier may become stale.

RawRef is permitted only when analysis proves all uses remain in one allocation-free span and die before the next barrier. The raw-pointer verifier is the backstop:

  • a derived absolute pointer cannot cross a memory-growth, host, allocation, or suspension barrier;
  • it cannot escape through a return, frame, closure, container, or unknown call;
  • consumers after a barrier must rematerialize from an arena-relative source.

Failure is diagnosed at the originating source range when available. Falling back from RawRef to the normal relative reference is always safe; keeping an unproven absolute address is not.

Runtime correspondence

MIR decides which values require frame or flex storage, but it does not implement the allocator. The runtime’s Memory section defines arena, flat, and TLSF allocation behavior. MIR’s obligation is to select the correct storage domain and emit explicit allocator and ownership primitives at the backend boundary.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close