# go-ext-wasm
**Repository Path**: chenyiw/go-ext-wasm
## Basic Information
- **Project Name**: go-ext-wasm
- **Description**: Wasmer 是一个 Go 库,用来执行 WebAssembly 二进制程序
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 6
- **Created**: 2019-06-17
- **Last Updated**: 2024-11-22
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
Wasmer is a Go library for executing WebAssembly binaries.
# Install
To install the library, follow the classical:
```sh
$ go get github.com/wasmerio/go-ext-wasm/wasmer
```
To install the `go-wasmer` CLI, follow the classical:
```sh
$ go install github.com/wasmerio/go-ext-wasm/go-wasmer
```
`go install` will work on many macOS and Linux distributions. It will
not work on Windows yet, we are working on it.
# Documentation
[The documentation can be read online on godoc.org][documentation]. It
contains function descriptions, short examples, long examples
etc. Everything one need to start using Wasmer with Go!
Also, there is this article written for the announcement that
introduces the project: [Announcing the fastest WebAssembly runtime
for Go: wasmer][medium].
[documentation]: https://godoc.org/github.com/wasmerio/go-ext-wasm/wasmer
[medium]: https://medium.com/wasmer/announcing-the-fastest-webassembly-runtime-for-go-wasmer-19832d77c050
# Examples
## Basic example: Exported function
There is a toy program in `wasmer/test/testdata/examples/simple.rs`,
written in Rust (or any other language that compiles to WebAssembly):
```rust
#[no_mangle]
pub extern fn sum(x: i32, y: i32) -> i32 {
x + y
}
```
After compilation to WebAssembly, the
[`wasmer/test/testdata/examples/simple.wasm`](https://github.com/wasmerio/go-ext-wasm/blob/master/wasmer/test/testdata/examples/simple.wasm)
binary file is generated. ([Download
it](https://github.com/wasmerio/go-ext-wasm/raw/master/wasmer/test/testdata/examples/simple.wasm)).
Then, we can execute it in Go:
```go
package main
import (
"fmt"
wasm "github.com/wasmerio/go-ext-wasm/wasmer"
)
func main() {
// Reads the WebAssembly module as bytes.
bytes, _ := wasm.ReadBytes("simple.wasm")
// Instantiates the WebAssembly module.
instance, _ := wasm.NewInstance(bytes)
defer instance.Close()
// Gets the `sum` exported function from the WebAssembly instance.
sum := instance.Exports["sum"]
// Calls that exported function with Go standard values. The WebAssembly
// types are inferred and values are casted automatically.
result, _ := sum(5, 37)
fmt.Println(result) // 42!
}
```
## Imported function
A WebAssembly module can export functions, this is how to run a
WebAssembly function, like we did in the previous example with
`instance.Exports["sum"](1, 2)`. Nonetheless, a WebAssembly module can
depend on “extern functions”, then called imported functions. For
instance, let's consider the basic following Rust program:
```rust
extern {
fn sum(x: i32, y: i32) -> i32;
}
#[no_mangle]
pub extern fn add1(x: i32, y: i32) -> i32 {
unsafe { sum(x, y) + 1 }
}
```
In this case, the `add1` function is a WebAssembly exported function,
whilst the `sum` function is a WebAssembly imported function (the
WebAssembly instance needs to _import_ it to complete the
program). Good news: We can write the implementation of the `sum`
function directly in Go!
First, we need to declare the `sum` function signature in C inside a
Go comment (with the help of [cgo]):
```go
package main
// #include
//
// extern int32_t sum(void *context, int32_t x, int32_t y);
import "C"
```
Second, we declare the `sum` function implementation in Go. Notice the
`//export` which is the way cgo uses to map Go code to C code.
```go
//export sum
func sum(context unsafe.Pointer, x int32, y int32) int32 {
return x + y
}
```
Third, we use `NewImports` to create the WebAssembly imports. In this
code:
* `"sum"` is the imported function name,
* `sum` is the Go function pointer, and
* `C.sum` is the cgo function pointer.
```go
imports, _ := wasm.NewImports().Append("sum", sum, C.sum)
```
Finally, we use `NewInstanceWithImports` to inject the imports:
```go
bytes, _ := wasm.ReadBytes("imported_function.wasm")
instance, _ := wasm.NewInstanceWithImports(bytes, imports)
defer instance.Close()
// Gets and calls the `add1` exported function from the WebAssembly instance.
results, _ := instance.Exports["add1"](1, 2)
fmt.Println(result)
// add1(1, 2)
// = sum(1 + 2) + 1
// = 1 + 2 + 1
// = 4
// QED
```
[cgo]: https://golang.org/cmd/cgo/
## Read the memory
A WebAssembly instance has a linear memory. Let's see how to read
it. Consider the following Rust program:
```rust
#[no_mangle]
pub extern fn return_hello() -> *const u8 {
b"Hello, World!\0".as_ptr()
}
```
The `return_hello` function returns a pointer to a string. This string
is stored in the WebAssembly memory. Let's read it.
```go
bytes, _ := wasm.ReadBytes("memory.wasm")
instance, _ := wasm.NewInstance(bytes)
defer instance.Close()
// Calls the `return_hello` exported function.
// This function returns a pointer to a string.
result, _ := instance.Exports["return_hello"]()
// Gets the pointer value as an integer.
pointer := result.ToI32()
// Reads the memory.
memory := instance.Memory.Data()
fmt.Println(string(memory[pointer : pointer+13])) // Hello, World!
```
In this example, we already know the string length, and we use a slice
to read a portion of the memory directly. Notice that the string
terminates by a null byte, which means we could iterate over the
memory starting from `pointer` until a null byte is met; that's a
similar approach.
For a more complete example, see the [Greet Example][greet-example].
[greet-example]: https://godoc.org/github.com/wasmerio/go-ext-wasm/wasmer#example-package--Greet
# Development
The Go library is written in Go and Rust.
To build both parts, run the following commands:
```sh
$ just rust
$ just go
```
To build the Go part, run:
(Yes, you need [`just`]).
[`just`]: https://github.com/casey/just/
# Testing
Once the library is build, run the following command:
```sh
$ just test
```
# Benchmarks
We compared Wasmer to [Wagon][wagon] and [Life][life]. The benchmarks
are in `benchmarks/`. The computer that ran these benchmarks is a
MacBook Pro 15" from 2016, 2.9Ghz Core i7 with 16Gb of memory. Here
are the results in a table (the lower the ratio is, the better):
Benchmark |
Runtime |
Time (ms) |
Ratio |
N-Body |
Wasmer |
42.078 |
1× |
Wagon |
1841.950 |
44× |
Life |
1976.215 |
47× |
Fibonacci (recursive) |
Wasmer |
28.559 |
1× |
Wagon |
3238.050 |
113× |
Life |
3029.209 |
106× |
Pollard rho 128 |
Wasmer |
37.478 |
1× |
Wagon |
2165.563 |
58× |
Life |
2407.752 |
64× |
While both Life and Wagon provide on average the same speed, Wasmer is
on average 72 times faster.
Put on a graph, it looks like this (reminder: the lower, the better):

[wagon]: https://github.com/go-interpreter/wagon
[life]: https://github.com/perlin-network/life
# What is WebAssembly?
Quoting [the WebAssembly site](https://webassembly.org/):
> WebAssembly (abbreviated Wasm) is a binary instruction format for a
> stack-based virtual machine. Wasm is designed as a portable target
> for compilation of high-level languages like C/C++/Rust, enabling
> deployment on the web for client and server applications.
About speed:
> WebAssembly aims to execute at native speed by taking advantage of
> [common hardware
> capabilities](https://webassembly.org/docs/portability/#assumptions-for-efficient-execution)
> available on a wide range of platforms.
About safety:
> WebAssembly describes a memory-safe, sandboxed [execution
> environment](https://webassembly.org/docs/semantics/#linear-memory) […].
# License
The entire project is under the MIT License. Please read [the
`LICENSE` file][license].
[license]: https://github.com/wasmerio/wasmer/blob/master/LICENSE