std/inst
std/inst
Section titled “std/inst”std/wasm/inst — control-flow, constant, and variable instruction encoders for the WebAssembly Core 1.0 binary format. Spec: https://webassembly.github.io/spec/core/binary/instructions.html Third slice of Phase 1 of docs/TOOLCHAIN-SELF-HOSTING.md. After leb128 (variable-length ints) and encode (module container, sections, functypes), this slice handles the instruction subset needed to assemble a function body: - constants (i32 / i64 / f32 / f64) - parametric: drop, select - variable: local.get/set/tee, global.get/set - control: unreachable, nop, block, loop, if/else, end, br, br_if, return, call, call_indirect - code-section helpers: put_function_body, put_locals_* Arithmetic, comparison, memory, and conversion instructions (the bulk of the opcode space) are deferred to a later slice — each one is a single function (opcode byte + maybe an immediate) so they’re cheap to add, but together they bloat this PR more than is useful for review. Same shape as the rest of std/wasm: every encoder takes a u8[] and appends. The block / loop / if forms emit only the start of the construct (opcode + blocktype); the caller appends the body and calls inst_end to close it. That matches the stream-y nature of wasm function bodies and avoids a tree- shaped intermediate.
blocktype_empty
Section titled “blocktype_empty”pub function blocktype_empty(): u8put_blocktype_typeidx
Section titled “put_blocktype_typeidx”pub function put_blocktype_typeidx(buf: u8[], idx: i32): u8[]inst_i32_const
Section titled “inst_i32_const”pub function inst_i32_const(buf: u8[], v: i32): u8[]inst_i64_const
Section titled “inst_i64_const”pub function inst_i64_const(buf: u8[], v: i64): u8[]inst_f32_const
Section titled “inst_f32_const”pub function inst_f32_const(buf: u8[], bits: u32): u8[]f32.const carries the IEEE-754 bit pattern as a fixed 4-byte
little-endian u32 — no leb. The caller is responsible for
having the bits in u32 form (float.bits-equivalent); this
encoder just lays the bytes down.
inst_f64_const
Section titled “inst_f64_const”pub function inst_f64_const(buf: u8[], bits: u64): u8[]f64.const carries an 8-byte little-endian u64 of the bit pattern, same shape as f32 but doubled.
inst_drop
Section titled “inst_drop”pub function inst_drop(buf: u8[]): u8[]inst_select
Section titled “inst_select”pub function inst_select(buf: u8[]): u8[]inst_local_get
Section titled “inst_local_get”pub function inst_local_get(buf: u8[], idx: u32): u8[]inst_local_set
Section titled “inst_local_set”pub function inst_local_set(buf: u8[], idx: u32): u8[]inst_local_tee
Section titled “inst_local_tee”pub function inst_local_tee(buf: u8[], idx: u32): u8[]inst_global_get
Section titled “inst_global_get”pub function inst_global_get(buf: u8[], idx: u32): u8[]inst_global_set
Section titled “inst_global_set”pub function inst_global_set(buf: u8[], idx: u32): u8[]inst_unreachable
Section titled “inst_unreachable”pub function inst_unreachable(buf: u8[]): u8[]inst_nop
Section titled “inst_nop”pub function inst_nop(buf: u8[]): u8[]inst_block_start
Section titled “inst_block_start”pub function inst_block_start(buf: u8[], blocktype: u8): u8[]inst_block_start appends block + the blocktype byte. The
caller fills the body, then calls inst_end to write 0x0B.
blocktype is either blocktype_empty() (0x40) or one of the
encode.valtype_* bytes — anything that fits in a single byte.
For typeidx-encoded blocktypes, the caller composes
0x02 + sleb_i32(idx) manually using put_blocktype_typeidx.
inst_loop_start
Section titled “inst_loop_start”pub function inst_loop_start(buf: u8[], blocktype: u8): u8[]inst_if_start
Section titled “inst_if_start”pub function inst_if_start(buf: u8[], blocktype: u8): u8[]inst_else
Section titled “inst_else”pub function inst_else(buf: u8[]): u8[]inst_end
Section titled “inst_end”pub function inst_end(buf: u8[]): u8[]inst_br
Section titled “inst_br”pub function inst_br(buf: u8[], labelidx: u32): u8[]inst_br_if
Section titled “inst_br_if”pub function inst_br_if(buf: u8[], labelidx: u32): u8[]inst_return
Section titled “inst_return”pub function inst_return(buf: u8[]): u8[]inst_call
Section titled “inst_call”pub function inst_call(buf: u8[], funcidx: u32): u8[]inst_call_indirect
Section titled “inst_call_indirect”pub function inst_call_indirect(buf: u8[], typeidx: u32, tableidx: u32): u8[]call_indirect carries both a type index (the expected signature) and a table index (0 in MVP, but the encoding reserves the slot for the multi-table proposal). Stack shape at the call site: … args, callee_index.
put_locals_empty
Section titled “put_locals_empty”pub function put_locals_empty(buf: u8[]): u8[]put_locals_empty — locals_vec of length 0: a single uleb(0).
put_locals_one_group
Section titled “put_locals_one_group”pub function put_locals_one_group(buf: u8[], count: u32, vt: u8): u8[]put_locals_one_group — count locals of a single valtype.
Emits uleb(1) + uleb(count) + valtype byte. Covers the
“function needs N i32 spill slots” case the existing wasm
backend hits most often.
put_function_body
Section titled “put_function_body”pub function put_function_body(buf: u8[], locals_bytes: u8[], body_bytes: u8[]): u8[]put_function_body wraps a fully-assembled function body — locals_bytes (produced by one of the put_locals_* helpers) + body_bytes (the instruction sequence, NOT including the final 0x0B — this helper appends it) — with the size prefix the code section expects.