A Rust library and code-generation tool that compiles WebAssembly modules into native Rust code. The output is a set of Rust traits and free functions that implement the module's semantics, with no interpreter loop at runtime.
Repository: https://github.com/portal-co/wars2
Given a .wasm binary, wars (the compiler crate) reads the module and emits Rust token streams (via proc_macro2 / quote) that:
- Define a trait named after the module containing one method per exported function.
- Define a
*Datastruct that holds the module's state: linear memories, globals, and tables. - Implement all exported functions as free Rust functions that operate on a user-supplied context type.
- Wire up imports by delegating to methods the caller must implement on the context.
The generated code uses trampolining (portal-pc-tramp) to avoid stack overflows on recursive wasm programs, and represents all values either as primitive Rust types (u32, u64, f32, f64) or as wars_rt::func::Value<C> for reference types.
The compiler. Takes OptsCore (wasm bytes, a name, flags, optional plugins) and produces a TokenStream.
Two backends are available via Cargo features:
wasmparser(WasmparserBackend) — a single-pass backend that walks the binary withwasmparserdirectly. Intended to replace the waffle pipeline for common cases. Described in code as "fast, dependency-light."waffle(LegacyPortalWaffleBackend) — an older backend built on theportal-pc-waffleIR. It applies a relooper pass and an "unswitch" transform (convertingselect-terminator blocks into chains of conditional branches before handing the CFG torelooper) before emitting code.
Both backends share code in src/shared.rs for name mangling, type rendering, and function-signature helpers.
Generation flags (bitflags):
ASYNC— emit async-compatible signatures usingwars_rt::func::unsync.LEGACY— legacy ABI mode.NEW_ABI— opt into an updated calling convention (0x100).
A Plugin trait lets callers intercept import resolution and inject custom code at the pre/post generation hooks.
The runtime support library used by generated code. It is no_std + alloc-compatible.
Key pieces:
Memorytrait — abstraction over linear memory (read/write/size/grow). Implementations provided forVec<u8>,Box<dyn Memory>, andArc<Mutex<T>>. An optionalic-stable-structuresfeature adds an implementation backed by Internet Computer stable memory.func::Value<C>— the runtime value type for reference values, covering i32/i64/f32/f64, function references (FunRefas anArc<dyn Fn>), external references, null, and (with thedumpsterfeature) GC-managed structs.func::Df<A,B,C>— type alias for a reference-counted, type-erased function reference.CtxSpectrait — marker trait that context types implement to declare theirExternRefandErrorassociated types.- Integer/float intrinsics — wrapping arithmetic, shifts, comparisons, and load/store helpers generated via macros, exported as top-level free functions for use by generated code.
gcmodule (featuredumpster) — GC support using thedumpstercycle-collecting GC, withGcCore<R>,Field<R>(const/mutable), and newtypesStruct,Array,Const,Mut.wrlmodule — adapter layer towasm_runtime_layer, translating betweenwars_rt's value types andwasm_runtime_layer::Value.wasixmodule — currently empty (stub).
A tiny helper crate used by the waffle backend. Given a waffle::FunctionBody, it builds the CFG, filters to dominance-reachable blocks, and calls relooper::reloop to produce a structured ShapedBlock<Block> tree. Panics with a diagnostic if relooper fails.
Integration test crate. The build script (build.rs) constructs a simple wasm module in-memory using wasm-encoder (with functions: add, sub, calladd, getglobal, setglobal, loadi32, storei32), then runs both backends to generate Rust code, writes the output to OUT_DIR, and formats it with prettyplease. The generated modules are included via include! and exercised in tests/integration.rs.
- Version 0.9.0-alpha.1 across all workspace crates. The project has had several previous release tags (v0.7.x, v0.8.x).
- The wasmparser backend is described in comments as a replacement for the waffle pipeline, suggesting the waffle backend is in a transitional / legacy state.
- Several items are commented out or stubbed:
wasixmodule is nearly empty,HOST_MEMORYandWASIXflags exist but are commented out, someTODOcomments remain (e.g.,Field::Muttraversal ingc.rs). - The
wrlmodule (wasm_runtime_layer bridge) is present but its dependency is commented out inCargo.toml(# wasm_runtime_layer = "0.4.0"), suggesting it is not currently wired up. - License: CC0-1.0.
portal-pc-waffle/portal-pc-waffle-ir— a fork of thewafflewasm IR, sourced fromhttps://github.com/portal-co/waffle-.git.relooper0.1.0 — converts arbitrary CFGs into structured control flow.portal-pc-tramp0.3.0 — trampolining to avoid stack overflows in generated recursive functions.dumpster1.0.0 (optional) — cycle-collecting GC used for wasm GC support.wasmparser0.240.0 — used by the new backend and the tester.wasm-encoder0.240.0 — used by the tester to construct test wasm binaries.
cargo build
cargo test -p testerThe tester crate requires both the waffle and wasmparser features on the wars dependency (declared in its Cargo.toml).