makepad/libs/wasm_strip/examples
Admin 9054bba68d wasm_strip units: table entries are pruned by a liveness mark -- a function is live when it is exported or the start function, a live function calls it, or live code or the data it reaches names its table slot: an i32.const that is not an operand of arithmetic, a comparison, a branch or a load address; the method slots of a vtable ([drop fn or 0, size, align, method...]) at an address live code or the data it reaches names, up to the next vtable header (code that loads a method from a known vtable names an address inside it); the first words of another named static (a thread local's key) up to the next address anything named before the strip. Every other entry points at a trapping stub of its type and dead-code elimination drops the function. Counting every word of live data named almost every slot (small numbers in the data) and a cycle (a closure's vtable named by the function that only that closure reaches) kept dead widgets alive. OptimizeOptions.prune_exported_table prunes a table the module exports for a host that only grows it (the film's kernel linker); data::DataLive::of_code leaves dead code's anchors out. Examples: wasm_units modules --prune-exported-table, wasm_units report (per unit: code bytes and functions a coverage run entered, matched by demangled name), wasm_why --root (the call chain from a function back to the table slot or export that keeps it). Checked: cargo test --release -p makepad-wasm-strip --lib (42) and --test fuzz stripped (OPT2's stripped_modules_replay_the_same); counter collect-run strip pixel-identical in headless Chrome incl. two clicks; the P(DOOM) film with its analysis census (42 of 119 script modules used): optimised 18.65 MB / 3.799 MB br -> 18.05 MB / 3.733 MB br, widgets_core code 993 -> 882 KB, plays the full 156 s in the safety gate the same as the unstripped build.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 13:45:53 +02:00
..
wasm_dump.rs 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. 2026-10-01 12:33:17 +02:00
wasm_opt.rs wasm_strip: panics become traps, with a symbol file to read them back -- OptimizeOptions.panic_trap (off by default): every call LLVM follows with unreachable (a function that never returns: panic, panic_fmt, failed unwrap/expect, bounds and slice checks, allocation failure) becomes a plain unreachable, and the instructions computing its arguments go with it when nothing they do survives a trap (stack values, locals, loads, arithmetic); the panic functions, their formatting and messages are then dead for the passes after. A panic traps without printing. OptimizeOptions.symbols puts the symbol file in OptimizeReport.symbols: F <index> <name> for every function of the output and, with panic_trap, P <code offset> <index> <callee> | <message> | <file:line:col> per trap, the offset being the one a browser's wasm stack frame shows; the message and location come from the constant arguments of the site (a &str, a format string's first piece, a core::panic::Location). The sites carry a marker constant through the passes, taken out last; functions equal once it is out are merged then (merge::run_mapped says where each went), so the symbol file costs 1.2 KB of the 19.96 MB output. Names now go at the very end when only the symbol file needs them (pass reports leave them out). stitch: binary::body_offsets gives each instruction's offset in a function body entry. wasm_opt takes --panic-trap and --symbols <file>. 2026-10-01 12:53:29 +02:00
wasm_profile.rs wasm_strip: our own wasm optimiser and a per-crate size profiler -- wasm_optimize decodes the linked module into an IR, runs size passes (custom sections and names out, dead functions/globals/data, peephole, local renumbering by use, identical-function merging, type/import compaction, ordering for compression), and re-validates after every pass: a pass whose output does not validate is undone and named in the report, so the result is always a valid module. The validator covers SIMD incl. relaxed SIMD, bulk memory, atomics, reference types, multi-value, tail calls and multi-memory (memory64, exceptions and GC are refused at decode). wasm_size_profile groups code and data by crate/module path through its own Rust v0/legacy demangler (text, JSON, before/after diff). Examples: wasm_opt, wasm_profile, wasm_dump. No Binaryen, no new runtime dependencies. hello_world (threaded, LTO, build-std): 9.82 MB raw / 2.81 MB brotli -> 7.61 / 2.59 MB, about 1 s. Checked: cargo test --release -p makepad-wasm-strip (40 unit; spec: 147 core .wast files plus the threads/relaxed-simd/tail-call/multi-memory/extended-const proposals accepted/refused as specified, every module of the 105 suites stitch runs still passes its assertions after all passes except table_grow (a stitch panic); fuzz: 550 random modules, results/traps/globals/memory identical, node settling what stitch cannot). 2026-10-01 11:12:10 +02:00
wasm_units.rs wasm_strip units: table entries are pruned by a liveness mark -- a function is live when it is exported or the start function, a live function calls it, or live code or the data it reaches names its table slot: an i32.const that is not an operand of arithmetic, a comparison, a branch or a load address; the method slots of a vtable ([drop fn or 0, size, align, method...]) at an address live code or the data it reaches names, up to the next vtable header (code that loads a method from a known vtable names an address inside it); the first words of another named static (a thread local's key) up to the next address anything named before the strip. Every other entry points at a trapping stub of its type and dead-code elimination drops the function. Counting every word of live data named almost every slot (small numbers in the data) and a cycle (a closure's vtable named by the function that only that closure reaches) kept dead widgets alive. OptimizeOptions.prune_exported_table prunes a table the module exports for a host that only grows it (the film's kernel linker); data::DataLive::of_code leaves dead code's anchors out. Examples: wasm_units modules --prune-exported-table, wasm_units report (per unit: code bytes and functions a coverage run entered, matched by demangled name), wasm_why --root (the call chain from a function back to the table slot or export that keeps it). Checked: cargo test --release -p makepad-wasm-strip --lib (42) and --test fuzz stripped (OPT2's stripped_modules_replay_the_same); counter collect-run strip pixel-identical in headless Chrome incl. two clicks; the P(DOOM) film with its analysis census (42 of 119 script modules used): optimised 18.65 MB / 3.799 MB br -> 18.05 MB / 3.733 MB br, widgets_core code 993 -> 882 KB, plays the full 156 s in the safety gate the same as the unstripped build. 2026-10-01 13:45:53 +02:00
wasm_why.rs wasm_strip units: table entries are pruned by a liveness mark -- a function is live when it is exported or the start function, a live function calls it, or live code or the data it reaches names its table slot: an i32.const that is not an operand of arithmetic, a comparison, a branch or a load address; the method slots of a vtable ([drop fn or 0, size, align, method...]) at an address live code or the data it reaches names, up to the next vtable header (code that loads a method from a known vtable names an address inside it); the first words of another named static (a thread local's key) up to the next address anything named before the strip. Every other entry points at a trapping stub of its type and dead-code elimination drops the function. Counting every word of live data named almost every slot (small numbers in the data) and a cycle (a closure's vtable named by the function that only that closure reaches) kept dead widgets alive. OptimizeOptions.prune_exported_table prunes a table the module exports for a host that only grows it (the film's kernel linker); data::DataLive::of_code leaves dead code's anchors out. Examples: wasm_units modules --prune-exported-table, wasm_units report (per unit: code bytes and functions a coverage run entered, matched by demangled name), wasm_why --root (the call chain from a function back to the table slot or export that keeps it). Checked: cargo test --release -p makepad-wasm-strip --lib (42) and --test fuzz stripped (OPT2's stripped_modules_replay_the_same); counter collect-run strip pixel-identical in headless Chrome incl. two clicks; the P(DOOM) film with its analysis census (42 of 119 script modules used): optimised 18.65 MB / 3.799 MB br -> 18.05 MB / 3.733 MB br, widgets_core code 993 -> 882 KB, plays the full 156 s in the safety gate the same as the unstripped build. 2026-10-01 13:45:53 +02:00