The input is a Wasm module, and the output is a single Go source file, with no dependencies beyond the standard library.
To translate a Wasm module to Go use the following command:
wasm2go < input.wasm > output.go
The Go file forms a self contained package,
that exports a structure called Module,
and a New function to initialize it.
The methods of the Module structure are the Wasm module's exports,
whereas imports are interfaces New consumes.
We assume the input Wasm modules can be trusted. At a minimum, you should run Wasm modules through a verifier before attempting to convert an untrusted module.
The current target is a useful subset of Wasm produced by clang,
including the following features:
- bulk memory instructions and reference types;
- non-trapping float-to-int conversions;
- sign-extension instructions;
- multi-value results;
- 64-bit address space;
- extended constant expressions.
Generating human readable Go code is a non-goal:
- Wasm names must be mangled into Go identifiers;
- Wasm control flow is implemented with
gotoand labels; - Go's distinction between
boolandint32requires spurious control flow and type conversions; - Go's untyped numeric literals require explicit type conversions;
- Go's constant evaluator does not match Wasm semantics, requiring workarounds to avoid constant folding/propagation;
- float operations require type conversions to avoid being combined;
- float literals can't represent negative zero, infinities, or
NaN; - Go forbids unused variables/labels/etc.
Many of these introduce unnecessary verbosity, but they're necessary for semantic correctness.
Judge the output by the assembly generated by the Go compiler, not by how a human would read it.
For little endian CPUs,
you can generate faster code by using unsafe.
Despite the scary name, the generated code abides by the
rules of unsafe,
and all memory accesses are bounds checked.
To generate big/little endian Go code:
wasm2go -endian=big < input.wasm > output_big.go
wasm2go -endian=little < input.wasm > output_little.go
Both versions will be guarded by a build tag, so you can add both to your project.
The only other knob is whether to attempt to ensure float operations
canonicalize NaNs.
This is tested to work on both amd64 and arm64,
but is known to be broken on most other architectures.
Usage of wasm2go:
-endian string
endianness of the generated code (little or big)
-nanbox
whether to try to canonicalize NaNs
-nohead
disable the header comment (including build tags)
-nohost
disable generating interfaces for imports