wasm2go

command module
v0.0.0-...-a067e70 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 4, 2026 License: MIT Imports: 21 Imported by: 0

README

A Wasm to Go translator

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 exported functions, whereas imports are interfaces New consumes. The module may also export its global variables (as fields). And if it imports a memory, you can provide your own allocator.

Only a subset of the Wasm specification will be supported, as the goal is to translate specific Wasm modules to Go.

For example, we don't need to implement SIMD, as we can ask (e.g.) LLVM not to emit it.

We also 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.

This includes most Wasm 1.0 features, with the following exceptions:

  • export aliasing (exporting the same function/global under different names);
  • export conflicts (after the trivial name mangling we apply);
  • importing tables or globals.

It also supports a subset of Wasm 2.0 features:

  • bulk memory operations and reference types;
  • nontrapping float-to-int conversions;
  • sign-extension operators;
  • multi-values.

The goal is not to produce particularly readable Go code:

  • because Go makes a distinction between statements and expresions, we use a stack-to-register approach to translate Wasm to Go;
  • Wasm control flow is implemented with goto and labels;
  • the distinction in Go between bool and int32 requires spurious control flow and type conversions;
  • Go's untyped numeric literals require explicit type conversions;
  • float operations require type conversions to avoid being combined;
  • float literals can't represent negative zero, infinities, or NaN, often requiring Float64frombits;
  • 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, we can generate much 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 make sure float operations canonicalize NaNs.

Usage of wasm2go:
  -endian string
        endianness of the generated code (big or little)
  -nanbox
        whether to canonicalize NaNs (default true)

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
br
f32
f64
fac
i32
i64
if
nop

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL