//! Differential fuzzing: random valid modules (built to give every pass //! work: duplicate functions and types, dead functions, dead stores, //! constant expressions, nested blocks, loops, tables) run under stitch //! before and after optimising. Every exported function is called with the //! same arguments; results, traps, memory and globals must match. Seeds are //! fixed, so a failure names a reproducible module (`FUZZ_SEED=n` runs one). //! Where stitch panics or disagrees, node (when installed) decides: stitch //! mishandles some valid local reuse patterns the optimiser produces. //! //! The strip test does what a web export does with a coverage run: it plays //! some exported functions, records which functions they entered, strips //! the units that were never entered (stubbing their call sites), runs all //! passes, and replays the same calls: they must behave the same. Every //! result is validated by stitch and, with node, by `WebAssembly.validate`. use makepad_stitch::{Engine, Linker, Module as StitchModule, Store, Val}; use makepad_wasm_strip::opt::{encode::encode, ir::*, units}; use makepad_wasm_strip::{wasm_optimize_checked, wasm_validate, OptimizeOptions}; use std::{path::PathBuf, process::Command}; struct Rng(u64); impl Rng { fn next(&mut self) -> u64 { self.0 ^= self.0 << 13; self.0 ^= self.0 >> 7; self.0 ^= self.0 << 17; self.0 } fn below(&mut self, n: usize) -> usize { (self.next() % n as u64) as usize } fn chance(&mut self, percent: u64) -> bool { self.next() % 100 < percent } fn i32(&mut self) -> i32 { match self.below(4) { 0 => self.below(4) as i32 - 1, 1 => self.next() as i32, 2 => [i32::MIN, i32::MAX, 0x7f, 0x80][self.below(4)], _ => self.below(300) as i32, } } } const TYS: [ValType; 4] = [ValType::I32, ValType::I64, ValType::F32, ValType::F64]; #[derive(Clone, Copy, PartialEq)] enum Label { Empty, Value, Loop, } struct FuncGen<'a> { rng: &'a mut Rng, module: &'a Module, /// Functions this one may call: those before it. callable: u32, locals: Vec, /// Loop counter locals, never touched by other code. counters: Vec, body: Vec, depth: u32, /// Open labels, innermost last: their result type, or `Loop` (never a /// branch target outside the counter's own, so loops stay bounded). labels: Vec