single-pass amd64 + arm64
amd64 add eax, ecx arm64 add w0, w0, w1
Straight to machine code in one pass — Native runtime paths ship in CI on Linux/amd64, Linux/arm64, and Darwin/arm64.
A novel runtime that balances compile time, memory usage, and execution speed for a simply wonderful experience.
export function fib(n: i32): i64 { if (n < 2) return <i64>n return fib(n - 1) + fib(n - 2) }
;; fib — recursion across the call/return boundary (module (func $fib (export "fib") (param $n i32) (result i64) local.get $n i32.const 2 i32.lt_s (if (result i64) (then local.get $n i64.extend_i32_s ) (else local.get $n i32.const 1 i32.sub call $fib local.get $n i32.const 2 i32.sub call $fib i64.add ) ) ) )
; objdump -M intel · wago single-pass backend · 385 bytes 0: push rbp ; prologue 1: mov rbp,rsp 4: sub rsp,0x50 b: mov QWORD PTR [rbp-0x10],rsi 12: mov QWORD PTR [rbp-0x18],rdx 19: mov QWORD PTR [rbp-0x20],rcx 20: mov rax,QWORD PTR [rsi-0x48] ; stack-guard check 27: cmp rsp,rax 2a: jae 0x43 30: mov rsi,QWORD PTR [rbp-0x18] 37: mov DWORD PTR [rsi+0x0],0xd 41: leave 42: ret 43: mov rbx,QWORD PTR [rdi+0x0] ; load n 4a: mov rax,rbx 4d: cmp eax,0x2 ; n < 2 ? 50: jge 0x68 56: mov rax,rbx 59: movsxd rax,eax ; base case: (i64)n 5c: mov QWORD PTR [rbp-0x30],rax 63: jmp 0x159 ; jump to epilogue 68: mov rax,rbx 6b: sub eax,0x1 ; n - 1 6e: sub rsp,0x10 75: mov QWORD PTR [rsp+0x0],rax 7d: mov rdi,rsp 80: lea rcx,[rsp+0x8] 88: mov rsi,QWORD PTR [rbp-0x10] 8f: mov rdx,QWORD PTR [rbp-0x18] 96: mov QWORD PTR [rbp-0x28],rbx 9d: call 0x0 ; call fib(n-1) a2: mov rbx,QWORD PTR [rbp-0x28] a9: mov rax,QWORD PTR [rbp-0x18] b0: mov eax,DWORD PTR [rax+0x0] b6: test eax,eax b8: je 0xc7 be: add rsp,0x10 c5: leave c6: ret c7: mov rax,QWORD PTR [rsp+0x8] cf: add rsp,0x10 d6: mov rcx,rbx d9: sub ecx,0x2 ; n - 2 dc: mov QWORD PTR [rbp-0x30],rax e3: sub rsp,0x10 ea: mov QWORD PTR [rsp+0x0],rcx f2: mov rdi,rsp f5: lea rcx,[rsp+0x8] fd: mov rsi,QWORD PTR [rbp-0x10] 104: mov rdx,QWORD PTR [rbp-0x18] 10b: mov QWORD PTR [rbp-0x28],rbx 112: call 0x0 ; call fib(n-2) 117: mov rbx,QWORD PTR [rbp-0x28] 11e: mov rax,QWORD PTR [rbp-0x18] 125: mov eax,DWORD PTR [rax+0x0] 12b: test eax,eax 12d: je 0x13c 133: add rsp,0x10 13a: leave 13b: ret 13c: mov rax,QWORD PTR [rsp+0x8] 144: add rsp,0x10 14b: add rax,QWORD PTR [rbp-0x30] ; fib(n-1) + fib(n-2) 152: mov QWORD PTR [rbp-0x30],rax 159: mov rdi,QWORD PTR [rbp-0x20] ; write result 160: mov rax,QWORD PTR [rbp-0x30] 167: mov QWORD PTR [rdi+0x0],rax 16e: mov rsi,QWORD PTR [rbp-0x18] 175: mov DWORD PTR [rsi+0x0],0x0 17f: leave 180: ret ; return
// compile, instantiate & run wasm, no cgo mod, _ := wago.Compile(wasmBytes) inst, _ := wago.Instantiate(mod, nil) defer inst.Close() out, _ := inst.Invoke("fib", wago.I32(30)) fmt.Println(wago.AsI64(out[0])) // → 832040
It reads, checks, and compiles WebAssembly to native code — all in pure Go. No C, no cgo.
Compiles straight to native code for both architectures in milliseconds, with no warmup.
Full support for the WebAssembly 2.0 standard, on by default — SIMD, reference types, and the rest.
Fast and light: low latency, small memory, high throughput.
Your Go code and the wasm share one block of memory, a
plain []byte. No
copies.
Every export gets a typed Go wrapper, so calls stay type-safe and fast.
We run the full spec test suite and publish exactly what passes in SPECTEST.md. Nothing hidden.
wago tracks the official
WebAssembly/testsuite
file by file. The numbers here come straight from
the engine's own test run.
Add wago to your module and embed it, or drive the
engine straight from the CLI to run, compile, or
validate any .wasm.
[]byte
$ curl -fsSL https://install.wago.sh | sh
$ wago add.wasm 2 3 $ wago run --invoke=fib fib.wasm 30 $ wago run --wasi hello.wasm $ wago run --bounds=all fib.wasm 30 $ wago validate module.wasm $ wago version
The whole process, from spawn to exit, timed end-to-end across six real workloads. wago lands top-two on every one: it starts in milliseconds and runs native.
wago compiles straight to native in a single pass: no SSA, no IR, no optimizer, just the novel Valent-Block architecture. It still keeps pace with runtimes that run a full optimizing backend. Every stage, head-to-head with wazero.
Measured separately on each listed architecture; compare values within an architecture, not across machines. Numbers shift as the engine evolves — see the benchmark corpus & methodology.
One front end decodes and type-checks every module. Single-pass backends emit native amd64 and arm64 code in one pass; a planned typed IR would add an optimizing tier.
20 00 20 01 6amodule bytes
local.get 0 local.get 1 i32.addstructure
[i32 i32] → [i32] ✓type-checked
amd64 add eax, ecx arm64 add w0, w0, w1
Straight to machine code in one pass — Native runtime paths ship in CI on Linux/amd64, Linux/arm64, and Darwin/arm64.
%2 = add.i32 %0, %1
A target-agnostic IR feeds a second tier — dead-code elimination, constant folding, register allocation — and new backends for arm64, macOS and Windows, still no cgo.
Official and community Go modules add host interfaces, compiler features, and managed runtime services without expanding wago core. Follow each plugin's page for compatibility and stability details.
WASI Preview 1 host functions for stdio, args and environment, clocks, random data, and process exit.
Bounded, host-supervised WebAssembly workers with fixed-size mailboxes and lifecycle-safe teardown.
Portable v256 and v512 SIMD instructions with native AVX-512, AVX2, and NEON lowering.
Elastic, load-balanced, self-healing pools that distribute work across fleets of Wago workers.
Warm pools of clean WebAssembly instances for isolated, bounded, one-shot execution.
Capability-gated TCP, UDP, DNS, TLS, and related networking modules backed by bounded host policy.
Drop your email and we'll send one message the moment wago's public beta is live — no spam, unsubscribe anytime.
Apache-licensed and built in the open. Add it to your module in one command and call straight into native wasm, no cgo.