Skip to main content

Module bytecode

Module bytecode 

Source
Expand description

The fixed-width encoded form of the instructions.

ADR 0041 decides everything here: sixteen bytes, one opcode byte, one reserved flags byte that must be zero, three sixteen-bit fields that are always frame slots, and one sixty-four-bit payload that is everything else.

byte:  0        1        2   3     4   5     6   7     8 .. 15
       opcode   flags    a         b         c         payload
       u8       u8       u16       u16       u16       u64

§What this is for

Inst stays the compiler’s representation: it is what the lowering builds, what a listing prints, what a test asserts on, and what the debugger shows as lowered IR. This is the other half of issue #245’s split — a form that is verified once and then trusted, so that a dispatch loop can read an operand without asking whether it is in range.

Nothing executes one yet. This module is the encoder, the decoder, the verifier and the disassembly; running them is issue #245’s Phase 3.

§The layout is written and read by hand

An EncodedInst is [u8; 16] and every field goes in and comes out through the little-endian accessors below. There is no #[repr(C)] struct, no transmute and no bytemuck: issue #245 asks for the width and the byte order to be the format’s own promise rather than something inherited from what the Rust compiler happens to do with a declaration.

§It is 1:1 with the readable IR

Every Inst encodes to exactly one EncodedInst and back, so bytecode pc is IR pc. That is what keeps Function::spans, Local’s pc ranges and Table::targets meaning what they meant with no remapping, and it is why the disassembler is decode() plus crate::print rather than a second renderer. See disasm.

§Not a compatibility promise

ADR 0041 is explicit: this is an internal executable representation. There is no stable on-disk bytecode, no cross-version compatibility, no public ABI, and no opcode-number stability — the numbers below are positions in a generated table and move when the table does. verify() is nevertheless safe against arbitrary bytes, because a verifier that is only safe against its own encoder is not a verifier.

Re-exports§

pub use decode::decode;
pub use decode::Malformed;
pub use disasm::listing;
pub use encode::encode;
pub use encode::encode_function;
pub use encode::encode_program;
pub use encode::Encoded;
pub use encode::TooWide;
pub use op::Half;
pub use op::Op;
pub use op::Operand;
pub use op::Payload;
pub use verify::verify;
pub use verify::Fault;

Modules§

decode
Sixteen bytes back to Inst.
disasm
Reading encoded instructions back as text.
encode
Inst to sixteen bytes.
op
The hundred and one opcodes, and what each one makes of the four fields.
verify
The check that makes encoded bytes safe to execute without checking again.

Structs§

EncodedInst
One encoded instruction: sixteen bytes, little-endian.
Truncated
A byte sequence that is not a whole number of instructions.

Constants§

MAX_FRAME_WORDS
The most words one function’s frame may hold.

Functions§

instructions
Reads a run of bytes as instructions, refusing a partial one.