Announcing the fastest WebAssembly runtime for Go: wasmer
https://medium.com/wasmer/announcing-the-fastest-webassembly-runtime-for-go-wasmer-19832d77c050
Ivan EnderlinMay 30
Announcing the fastest WebAssembly runtime for Go: wasmer

WebAssembly is a portable binary format. That means the same file can run anywhere.
To uphold this bold statement, each language, platform and system must be able to run WebAssembly — as fast and safely as possible.
Wasmer is a WebAssembly runtime written in Rust. It goes without saying that the runtime can be used in any Rust application. We have also successfully embedded the runtime in other languages:
- Using C and C++ bindings
- In PHP, using
[php-ext-wasm](https://github.com/wasmerio/php-ext-wasm)
- In Python, using
[python-ext-wasm](https://github.com/wasmerio/python-ext-wasm)
— wasmer package on PyPI - In Ruby, using
[ruby-ext-wasm](https://github.com/wasmerio/ruby-ext-wasm)
— wasmer gem on RubyGems - It is now time to hang around Go ?!
We are super happy to announce github.com/wasmerio/go-ext-wasm/wasmer
, a Go library to run WebAssembly binaries, fast.
wasmerio/go-ext-wasm
_??️ Go library to run WebAssembly binaries. Contribute to wasmerio/go-ext-wasm development by creating an account on…_github.com
Calling a WebAssembly function from Go
First, let’s install wasmer
in your go environment (with cgo support).
- export CGO_ENABLED=1; export CC=gcc; go install github.com/wasmerio/go-ext-wasm/wasmer
Let’s jump immediately into some examples.github.com/wasmerio/go-ext-wasm/wasmer
is a regular Go library. The installation is automated with import "github.com/wasmerio/go-ext-wasm/wasmer"
.
Let’s get our hands dirty. We will write a program that compiles to WebAssembly easily, using Rust for instance:
After compilation to WebAssembly, we get a file like this one, named simple.wasm
.
The following Go program executes the sum
function by passing 5
and 37
as arguments:
Great! We have successfully executed a WebAssembly file inside Go.
Note: Go values passed to the WebAssembly exported function are automatically cast to WebAssembly values. Types are inferred and casting is done automatically. Thus, a WebAssembly function acts as any regular Go function.
WebAssembly calling Go funtions
A WebAssembly module exports some functions, so that they can be called from the outside world. This is the entry point to execute WebAssembly.
Nonetheless, a WebAssembly module can also have imported functions. Let’s consider the following Rust program:
sum
function implementation is in another language. Download the WebAssembly file hereThe exported function add1
calls the sum
function. Its implementation is absent, only its signature is defined. This is an “extern function”, and for WebAssembly, this is an imported function, because its implementation must be imported.
Let’s implement the sum
function in Go! To do so, need to use cgo:
- The
sum
function signature is defined in C (see the comment aboveimport "C"
), - The
sum
implementation is defined in Go. Notice the//export
which is the way cgo uses to map Go code to C code, NewImports
is an API used to create WebAssembly imports. In this code"sum"
is the WebAssembly imported function name,sum
is the Go function pointer, andC.sum
is the cgo function pointer,- Finally,
NewInstanceWithImports
is the constructor to use to instantiate the WebAssembly module with imports. That’s it.
Let’s see the complete program:
Reading the memory
A WebAssembly instance has a linear memory. Let’s see how to read it. Consider the following Rust program:
The return_hello
function returns a pointer to a string. The string terminates by a null byte, à la C. Let’s jump on the Go side:
The return_hello
function returns a pointer as an i32
value. We get its value by calling ToI32
. Then, we fetch the memory data with instance.Memory.Data()
.
This function returns a slice over the WebAssembly instance memory. It can be used as any regular Go slice.
Fortunately for us, we already know the length of the string we want to read, so memory[pointer : pointer+13]
is enough to read the bytes, that are then cast to a string. Et voilà !
You can read the Greet Example to see a more advanced usage of the memory API.
Benchmarks
So far, github.com/wasmerio/go-ext-wasm/wasmer
has a nice API, but …is it fast?
Contrary to PHP or Ruby, there are already existing runtimes in the Go world to execute WebAssembly. The main candidates are:
- Life, from Perlin Network, a WebAssembly interpreter
- Wagon, from Go Interpreter, a WebAssembly interpreter and toolkit.
In our blog post about the PHP extension, we have used the n-body algorithm to benchmark the performance. Life provides more benchmarks: the Fibonacci algorithm (the recursive version), the Pollard’s rho algorithm, and the Snappy Compress operation. The latter works successfully with github.com/wasmerio/go-ext-wasm/wasmer
but not with Life or Wagon. We have removed it from the benchmark suites. Benchmark sources are online.
We use Life 20190521143330–57f3819c2df0, and Wagon 0.4.0, i.e. the latest versions to date.
The benchmark numbers represent the average result for 10 runs each. The computer that ran these benchmarks is a MacBook Pro 15” from 2016, 2.9Ghz Core i7 with 16Gb of memory.
Results are grouped by benchmark algorithm on the X axis. The Y axis represents the time used to run the algorithm, expressed in milliseconds. The lower, the better.

While both Life and Wagon provide on average the same speed, Wasmer (github.com/wasmerio/go-ext/wasmer
) is on average 72 times faster ?.
It is important to know that Wasmer comes with 3 backends: Singlepass, Cranelift, and LLVM. The default backend that is used by the Go library is Cranelift (learn more about Cranelift). Using LLVM will provide performance close to native, but we decided to start with Cranelift as it offers the best tradeoff between compilation-time and execution-time (learn more about the different backends, when to use them, pros and cons etc.).
Conclusion
[github.com/wasmerio/go-ext-wasm/wasmer](https://github.com/wasmerio/go-ext-wasm)
is a new Go library to execute WebAssembly binaries. It embeds the Wasmer runtime. The first version supports all the required API for the most common usages.
The current benchmarks (a mix from our benchmark suites and from Life suites) show that Wasmer is — on average — 72 times faster than Life and Wagon, the two major existing WebAssembly runtimes in the Go world.
If you want to follow the development, take a look at @wasmerio and @mnt_io on Twitter, or @wasmer"">@wasmer@webassembly.social on Mastodon. And of course, everything is open source at https://github.com/wasmerio/go-ext-wasm.
wasmerio/go-ext-wasm
_??️ Go library to run WebAssembly binaries. Contribute to wasmerio/go-ext-wasm development by creating an account on…_github.com
Thank you for your time, we can’t wait to see what you build with us!
ft_update_time2019-06-02 19:31