makepad/libs/wasm_strip/examples/wasm_dump.rs
Admin 18824899e6 stitch: one wasm decoder and validator for the engine and the web export's optimiser -- stitch gets a public binary module: the whole binary format as plain data (every section, function bodies as typed instruction lists, Instr::decode for single instructions, decode_with_layout for where sections, bodies and data segments sit), covering MVP, multi-value, sign extension, saturating truncation, bulk memory, reference types, fixed and relaxed SIMD, threads, tail calls, multi-memory and extended constant expressions (memory64, exceptions and GC are decode errors). binary::validate checks a decoded module the way the spec's validation appendix does: an operand stack of possibly-unknown types and a control stack, instruction by instruction, block/loop/if parameters and results included. Module::new now decodes and validates through it and then refuses what the engine does not run (tail calls, atomics, shared memory, SIMD outside its f32x4 subset, v128 globals, extended constants) and modules beyond its limits, so the engine accepts exactly what it accepted before; the interpreter compiles from the decoded instructions. The old byte-level decoders and the visitor validator are gone.
wasm_strip: the optimiser decodes and validates with stitch; its own decoder and validator are deleted (the IR is stitch's binary module, the encoder stays here). After the passes, the encoded bytes are decoded and validated again and optimising fails when they do not validate, so an encoder bug cannot ship either. The size profile reads the module through the decoder's layout. film.wasm (Stage player) optimises to the same bytes as before, in 2.0 s.

Checked: stitch's own tests (testsuite 97, simd 11, ext_math 5) pass; cargo test --release -p makepad-wasm-strip (40 unit; spec: validator conformance on 147 core files plus the extended-const, multi-memory, relaxed-simd, tail-call and threads proposals, and the stitch suites after all passes; fuzz: 400 + 900 random modules behave the same before and after); cargo test --release -p makepad-script-math-aot -p makepad-script-compute pass; cargo check --release -p cargo-makepad clean; film.wasm output byte-identical to the previous decoder's.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 12:33:17 +02:00

30 lines
1.3 KiB
Rust

//! Prints a module's functions as decoded instructions: `wasm_dump <file.wasm> [func]`.
use makepad_wasm_strip::opt::ir::decode;
fn main() {
let args: Vec<String> = std::env::args().collect();
let module = decode(&std::fs::read(&args[1]).expect("read")).expect("decode");
let imported = module.num_imported_funcs() as usize;
let only: Option<usize> = args.get(2).map(|a| a.parse().expect("func index"));
println!("exports: {:?}", module.exports);
println!("types: {:?}", module.types);
println!("funcs: {:?}", module.funcs.iter().map(|f| f.ty).collect::<Vec<_>>());
println!("elems: {:?}", module.elems);
for (i, func) in module.funcs.iter().enumerate() {
let index = imported + i;
if only.map_or(false, |only| only != index) {
continue;
}
println!("func {index} type {:?} locals {:?}", module.types[func.ty as usize], func.locals);
let mut depth = 1;
for instr in &func.body {
if matches!(instr, makepad_wasm_strip::opt::ir::Instr::End | makepad_wasm_strip::opt::ir::Instr::Else) {
depth -= 1;
}
println!("{}{:?}", " ".repeat(depth), instr);
if instr.is_block_start() || matches!(instr, makepad_wasm_strip::opt::ir::Instr::Else) {
depth += 1;
}
}
}
}