Giter Club home page Giter Club logo

go-ext-wasm's Introduction

Wasmer logo

Join the Wasmer Community Read our API documentation Go Report Card License

Wasmer is a Go library for executing WebAssembly binaries.

Install

To install the library, follow the classical:

$ CGO_ENABLED=1 go install github.com/wasmerio/go-ext-wasm/wasmer

The CGO_ENABLED part is very likely to be optional. 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. It contains function descriptions, short examples, long examples etc. Everything one need to start using Wasmer with Go!

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):

#[no_mangle]
pub extern fn sum(x: i32, y: i32) -> i32 {
    x + y
}

After compilation to WebAssembly, the wasmer/test/testdata/examples/simple.wasm binary file is generated. (Download it).

Then, we can execute it in 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:

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):

package main

// #include <stdlib.h>
//
// 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.

//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.
imports, _ := wasm.NewImports().Append("sum", sum, C.sum)

Finally, we use NewInstanceWithImports to inject the imports:

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

Read the memory

A WebAssembly instance has a linear memory. Let's see how to read it. Consider the following Rust program:

#[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.

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.

Development

The Go library is written in Go and Rust.

To build both parts, run the following commands:

$ just rust
$ just go

To build the Go part, run:

(Yes, you need just).

Testing

Once the library is build, run the following command:

$ just test

Benchmarks

We quickly compared Wasmer to Wagon and Life. The benchmarks are in benchmarks/. We run the n-body algorithm with N=100000. Here are the results:

Runtime Time (ms) Ratio (smaller is better)
Wasmer 42.06ms 1
Wagon 1812.15ms 43.1
Life 2136.46ms 50.8

What is WebAssembly?

Quoting the WebAssembly site:

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 available on a wide range of platforms.

About safety:

WebAssembly describes a memory-safe, sandboxed execution environment […].

License

The entire project is under the MIT License. Please read the LICENSE file.

go-ext-wasm's People

Contributors

bors[bot] avatar hywan avatar syrusakbary avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.