wasmer

package
v2.2.3 Latest Latest
Warning

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

Go to latest
Published: Apr 8, 2022 License: Apache-2.0 Imports: 9 Imported by: 0

README

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:

# Enable cgo
$ export CGO_ENABLED=1; export CC=gcc;

$ go get github.com/wasmerio/go-ext-wasm/wasmer

It will work on many macOS and Linux distributions. It will not work on Windows yet, we are working on it.

If the pre-compiled shared libraries are not compatible with your system, try installing manually with the following command:

$ just build-runtime
$ just build
$ go install github.com/wasmerio/go-ext-wasm/wasmer

If you are a bazel user, add following to your WORKSPACE file

git_repository(
    name = "com_github_wasmerio_go_ext_wasm",
    remote = "https://github.com/wasmerio/go-ext-wasm",
    commit = "",
)

Documentation

The documentation can be read online on pkg.go.dev. 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.

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/wasmer-go/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().AppendFunction("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 build-runtime
$ just build

To build the Go part, run:

$ just build

(Yes, you need just).

Testing

Once the library is build, run the following command:

$ just tests

Benchmarks

We compared Wasmer to Wagon and 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
Wagon 1841.950 44×
Life 1976.215 47×
Fibonacci (recursive) Wasmer 28.559
Wagon 3238.050 113×
Life 3029.209 106×
Pollard rho 128 Wasmer 37.478
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):

Benchmark results

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.

Documentation

Overview

Package wasmer is a Go library to run WebAssembly binaries.

Index

Constants

View Source
const (
	// ImportExportKindFunction represents an import/export descriptor of kind function.
	ImportExportKindFunction = ImportExportKind(cWasmFunction)

	// ImportExportKindGlobal represents an import/export descriptor of kind global.
	ImportExportKindGlobal = ImportExportKind(cWasmGlobal)

	// ImportExportKindMemory represents an import/export descriptor of kind memory.
	ImportExportKindMemory = ImportExportKind(cWasmMemory)

	// ImportExportKindTable represents an import/export descriptor of kind table.
	ImportExportKindTable = ImportExportKind(cWasmTable)
)
View Source
const (
	// Unknown represents an unknown WASI version.
	Unknown = WasiVersion(cVersionUnknown)

	// Latest represents the latest WASI version.
	Latest = WasiVersion(cVersionSnapshot0)

	// Snapshot0 represents the `wasi_unstable` WASI version.
	Snapshot0 = WasiVersion(cVersionSnapshot0)

	// Snapshot1 represents the `wasi_snapshot1_preview` WASI version.
	Snapshot1 = WasiVersion(cVersionSnapshot1)
)

Variables

This section is empty.

Functions

func GetLastError

func GetLastError() (string, error)

GetLastError returns the last error message if any, otherwise returns an error.

func ReadBytes

func ReadBytes(filename string) ([]byte, error)

ReadBytes reads a `.wasm` file and returns its content as an array of bytes.

func Trap

func Trap(instanceContext *InstanceContext, errorMessage string) bool

@by taifu Trap stop executing the current instance

func Validate

func Validate(bytes []byte) bool

Validate validates a sequence of bytes that is supposed to represent a valid WebAssembly module.

Types

type ExportDescriptor

type ExportDescriptor struct {
	// The export name.
	Name string

	// The export kind/type.
	Kind ImportExportKind
}

ExportDescriptor represents an export descriptor of a WebAssembly module. It is different of an export of a WebAssembly instance. An export descriptor only has a name and a kind/type.

type ExportedFunctionError

type ExportedFunctionError struct {
	// contains filtered or unexported fields
}

ExportedFunctionError represents any kind of errors related to a WebAssembly exported function. It is returned by `Instance` functions only.

func NewExportedFunctionError

func NewExportedFunctionError(functionName string, message string) *ExportedFunctionError

NewExportedFunctionError constructs a new `ExportedFunctionError`, where `functionName` is the name of the exported function, and `message` is the error message. If the error message contains `%s`, then this parameter will be replaced by `functionName`.

func (*ExportedFunctionError) Error

func (error *ExportedFunctionError) Error() string

ExportedFunctionError is an actual error. The `Error` function returns the error message.

type Import

type Import interface{}

Import represents a WebAssembly instance imported function or memory. Imagine it is an union of `ImportFunction` and `ImportMemory`.

type ImportDescriptor

type ImportDescriptor struct {
	// The import name.
	Name string

	// The import namespace.
	Namespace string

	// The import kind/type.
	Kind ImportExportKind
}

ImportDescriptor represents an import descriptor of a WebAssembly module. It is different of an import of a WebAssembly instance. An import descriptor only has a name, a namespace, and a kind/type.

type ImportExportKind

type ImportExportKind int

ImportExportKind represents an import/export descriptor kind/type.

type ImportFunction

type ImportFunction struct {
	// contains filtered or unexported fields
}

ImportFunction represents a WebAssembly instance imported function.

type ImportMemory

type ImportMemory struct {
	// contains filtered or unexported fields
}

ImportMemory represents a WebAssembly instance imported memory.

type ImportObject

type ImportObject struct {
	// contains filtered or unexported fields
}

ImportObject owns a set of imports. It can be combined with a `Module` to create an `Instance`.

func NewDefaultWasiImportObject

func NewDefaultWasiImportObject() *ImportObject

NewDefaultWasiImportObject constructs a new `ImportObject` with WASI host imports.

To specify WASI program arguments, environment variables, preopened directories, and more, see `NewWasiImportObject`

func NewDefaultWasiImportObjectForVersion

func NewDefaultWasiImportObjectForVersion(version WasiVersion) *ImportObject

NewDefaultWasiImportObjectForVersion is similar to `NewDefaultWasiImportObject` but it specifies the WASI version.

func NewImportObject

func NewImportObject() *ImportObject

NewImportObject creates an empty `ImportObject`.

func NewWasiImportObject

func NewWasiImportObject(
	arguments []string,
	environmentVariables []string,
	preopenedDirs []string,
	mappedDirs []MapDirEntry,
) *ImportObject

NewWasiImportObject creates an `ImportObject` with the default WASI imports. Specify arguments (the first is the program name), environment variables ("envvar=value"), preopened directories (host file paths), and mapped directories (host file paths with an alias, see `MapDirEntry`)

func NewWasiImportObjectForVersion

func NewWasiImportObjectForVersion(
	version WasiVersion,
	arguments []string,
	environmentVariables []string,
	preopenedDirs []string,
	mappedDirs []MapDirEntry,
) *ImportObject

NewWasiImportObjectForVersion is similar to `NewWasiImportObject` but it specifies the WASI version.

func (*ImportObject) Close

func (importObject *ImportObject) Close()

Close frees the `ImportObject`

func (*ImportObject) Extend

func (importObject *ImportObject) Extend(imports Imports) error

Extend adds the given imports to the existing import object

func (*ImportObject) Imports

func (importObject *ImportObject) Imports() (*Imports, error)

Imports returns `*Imports` for a given `ImportObject`

type ImportObjectError

type ImportObjectError struct {
	// contains filtered or unexported fields
}

ImportObjectError represents errors related to `ImportObject`s.

func NewImportObjectError

func NewImportObjectError(message string) *ImportObjectError

NewImportObjectError constructs a new `ImportObjectError`

func (*ImportObjectError) Error

func (error *ImportObjectError) Error() string

ImportObjectError is an actual error. The `Error` function returns the error message.

type ImportedFunctionError

type ImportedFunctionError struct {
	// contains filtered or unexported fields
}

ImportedFunctionError represents any kind of errors related to a WebAssembly imported function. It is returned by `Import` or `Imports` functions only.

func NewImportedFunctionError

func NewImportedFunctionError(functionName string, message string) *ImportedFunctionError

NewImportedFunctionError constructs a new `ImportedFunctionError`, where `functionName` is the name of the imported function, and `message` is the error message. If the error message contains `%s`, then this parameter will be replaced by `functionName`.

func (*ImportedFunctionError) Error

func (error *ImportedFunctionError) Error() string

ImportedFunctionError is an actual error. The `Error` function returns the error message.

type Imports

type Imports struct {
	// contains filtered or unexported fields
}

Imports represents a set of imported functions for a WebAssembly instance.

func NewImports

func NewImports() *Imports

NewImports constructs a new empty `Imports`.

func (*Imports) Append

func (imports *Imports) Append(importName string, implementation interface{}, cgoPointer unsafe.Pointer) (*Imports, error)

Append adds a new imported function to the current set. Deprecated, please use AppendFunction instead.

func (*Imports) AppendFunction

func (imports *Imports) AppendFunction(importName string, implementation interface{}, cgoPointer unsafe.Pointer) (*Imports, error)

AppendFunction adds a new imported function to the current set.

func (*Imports) AppendMemory

func (imports *Imports) AppendMemory(importName string, memory *Memory) (*Imports, error)

AppendMemory adds a new imported memory to the current set.

func (*Imports) Close

func (imports *Imports) Close()

Close closes/frees all imports. For the moment, only imported functions must be freed. Imported memory must be freed manually by the owner.

func (*Imports) Namespace

func (imports *Imports) Namespace(namespace string) *Imports

Namespace changes the current namespace of the next imported functions.

type Instance

type Instance struct {

	// All functions exported by the WebAssembly instance, indexed
	// by their name as a string. An exported function is a
	// regular variadic Go closure. Arguments are untyped. Since
	// WebAssembly only supports: `i32`, `i64`, `f32` and `f64`
	// types, the accepted Go types are: `int8`, `uint8`, `int16`,
	// `uint16`, `int32`, `uint32`, `int64`, `int`, `uint`, `float32`
	// and `float64`. In addition to those types, the `Value` type
	// (from this project) is accepted. The conversion from a Go
	// value to a WebAssembly value is done automatically except for
	// the `Value` type (where type is coerced, that's the intent
	// here). The WebAssembly type is automatically inferred. Note
	// that the returned value is of kind `Value`, and not a
	// standard Go type.
	Exports map[string]func(...interface{}) (Value, error)

	// The exported memory of a WebAssembly instance.
	Memory *Memory
	// contains filtered or unexported fields
}

Instance represents a WebAssembly instance.

func NewInstance

func NewInstance(bytes []byte) (Instance, error)

NewInstance constructs a new `Instance` with no imports.

func NewInstanceWithImports

func NewInstanceWithImports(bytes []byte, imports *Imports) (Instance, error)

NewInstanceWithImports constructs a new `Instance` with imports.

func (*Instance) Close

func (instance *Instance) Close()

Close closes/frees an `Instance`.

func (*Instance) GetGasUsed

func (instance *Instance) GetGasUsed() uint64

GetGasUsed get gas

func (*Instance) HasMemory

func (instance *Instance) HasMemory() bool

HasMemory checks whether the instance has at least one exported memory.

func (*Instance) SetContextData

func (instance *Instance) SetContextData(data interface{})

SetContextData assigns a _data that can be used by all imported functions. Each imported function receives as its first argument an instance context (see `InstanceContext`). An instance context can hold any kind of _data, including _data that contain Go references such as slices, maps, or structs with reference types or pointers. It is important to understand that _data is global to the instance, and thus is shared by all imported functions.

func (*Instance) SetGasLimit

func (instance *Instance) SetGasLimit(value uint64)

SetGasLimit set gas limit

func (*Instance) SetGasUsed

func (instance *Instance) SetGasUsed(value uint64)

SetGasUsed set gas

type InstanceContext

type InstanceContext struct {
	// contains filtered or unexported fields
}

InstanceContext represents a way to access instance API from within an imported context.

func GetWasmerInstanceContext

func GetWasmerInstanceContext(instance *Instance) *InstanceContext

GetWasmerInstanceContext get instance context

func IntoInstanceContext

func IntoInstanceContext(instanceContext unsafe.Pointer) InstanceContext

IntoInstanceContext casts the first `context unsafe.Pointer` argument of an imported function into an `InstanceContext`.

func (*InstanceContext) Data

func (instanceContext *InstanceContext) Data() interface{}

Data returns the instance context _data as an `interface{}`. It's up to the user to assert the proper type.

func (*InstanceContext) Memory

func (instanceContext *InstanceContext) Memory() *Memory

Memory returns the current instance memory.

type InstanceError

type InstanceError struct {
	// contains filtered or unexported fields
}

InstanceError represents any kind of errors related to a WebAssembly instance. It is returned by `Instance` functions only.

func NewInstanceError

func NewInstanceError(message string) *InstanceError

NewInstanceError constructs a new `InstanceError`.

func (*InstanceError) Error

func (error *InstanceError) Error() string

`InstanceError` is an actual error. The `Error` function returns the error message.

type MapDirEntry

type MapDirEntry struct {
	// contains filtered or unexported fields
}

MapDirEntry is an entry that can be passed to `NewWasiImportObject`. Preopens a file for the WASI module but renames it to the given name

type Memory

type Memory struct {
	// contains filtered or unexported fields
}

Memory represents a WebAssembly memory. To read and write _data, please see the `Data` function. The memory can be owned or borrowed. It is only possible to create an owned memory from the user-land.

func NewMemory

func NewMemory(min, max uint32) (*Memory, error)

NewMemory instantiates a new owned WebAssembly memory, bound for imported memory.

func (*Memory) Close

func (memory *Memory) Close()

Close closes/frees memory allocated at the NewMemory at time.

func (*Memory) Data

func (memory *Memory) Data() []byte

Data returns a slice of bytes over the WebAssembly memory.

func (*Memory) Grow

func (memory *Memory) Grow(numberOfPages uint32) error

Grow the memory by a number of pages (65kb each).

func (*Memory) IsOwned

func (memory *Memory) IsOwned() bool

IsOwned checks whether the memory is owned, or borrowed.

func (*Memory) Length

func (memory *Memory) Length() uint32

Length calculates the memory length (in bytes).

type MemoryError

type MemoryError struct {
	// contains filtered or unexported fields
}

MemoryError represents any kind of errors related to a WebAssembly memory. It is returned by `Memory` functions only.

func NewMemoryError

func NewMemoryError(message string) *MemoryError

NewMemoryError constructs a new `MemoryError`.

func (*MemoryError) Error

func (error *MemoryError) Error() string

`MemoryError` is an actual error. The `Error` function returns the error message.

type Module

type Module struct {
	Exports []ExportDescriptor
	Imports []ImportDescriptor
	// contains filtered or unexported fields
}

Module represents a WebAssembly module.

func Compile

func Compile(bytes []byte) (Module, error)

Compile compiles a WebAssembly module from bytes.

func DeserializeModule

func DeserializeModule(serializedModuleBytes []byte) (Module, error)

DeserializeModule deserializes a sequence of bytes into a module. Ideally, those bytes must come from `Module.Serialize`.

func (*Module) Close

func (module *Module) Close()

Close closes/frees a `Module`.

func (*Module) Instantiate

func (module *Module) Instantiate() (Instance, error)

Instantiate creates a new instance of the WebAssembly module.

func (*Module) InstantiateWithImportObject

func (module *Module) InstantiateWithImportObject(importObject *ImportObject) (Instance, error)

InstantiateWithImportObject creates a new instance of a WebAssembly module with an `ImportObject`

func (*Module) InstantiateWithImports

func (module *Module) InstantiateWithImports(imports *Imports) (Instance, error)

InstantiateWithImports creates a new instance with imports of the WebAssembly module.

func (*Module) Serialize

func (module *Module) Serialize() ([]byte, error)

Serialize serializes the current module into a sequence of bytes. Those bytes can be deserialized into a module with `DeserializeModule`.

type ModuleError

type ModuleError struct {
	// contains filtered or unexported fields
}

ModuleError represents any kind of errors related to a WebAssembly module.

func NewModuleError

func NewModuleError(message string) *ModuleError

NewModuleError constructs a new `ModuleError`.

func (*ModuleError) Error

func (error *ModuleError) Error() string

`ModuleError` is an actual error. The `Error` function returns the error message.

type Value

type Value struct {
	// contains filtered or unexported fields
}

Value represents a WebAssembly value of a particular type.

func F32

func F32(value float32) Value

F32 constructs a WebAssembly value of type `f32`.

func F64

func F64(value float64) Value

F64 constructs a WebAssembly value of type `f64`.

func I32

func I32(value int32) Value

I32 constructs a WebAssembly value of type `i32`.

func I64

func I64(value int64) Value

I64 constructs a WebAssembly value of type `i64`.

func (Value) GetType

func (value Value) GetType() ValueType

GetType gets the type of the WebAssembly value.

func (Value) String

func (value Value) String() string

String formats the WebAssembly value as a Go string.

func (Value) ToF32

func (value Value) ToF32() float32

ToF32 reads the WebAssembly value bits as a `float32`. The WebAssembly value type is ignored.

func (Value) ToF64

func (value Value) ToF64() float64

ToF64 reads the WebAssembly value bits as a `float64`. The WebAssembly value type is ignored.

func (Value) ToI32

func (value Value) ToI32() int32

ToI32 reads the WebAssembly value bits as an `int32`. The WebAssembly value type is ignored.

func (Value) ToI64

func (value Value) ToI64() int64

ToI64 reads the WebAssembly value bits as an `int64`. The WebAssembly value type is ignored.

func (Value) ToVoid

func (value Value) ToVoid() interface{}

ToVoid reads the WebAssembly value bits as a `nil`. The WebAssembly value type is ignored.

type ValueType

type ValueType int

ValueType represents the `Value` type.

const (
	// TypeI32 represents the WebAssembly `i32` type.
	TypeI32 ValueType = iota

	// TypeI64 represents the WebAssembly `i64` type.
	TypeI64

	// TypeF32 represents the WebAssembly `f32` type.
	TypeF32

	// TypeF64 represents the WebAssembly `f64` type.
	TypeF64

	// TypeVoid represents nothing.
	// WebAssembly doesn't have “void” type, but it is introduced
	// here to represent the returned value of a WebAssembly exported
	// function that returns nothing.
	TypeVoid
)

type WasiVersion

type WasiVersion uint

WasiVersion represents the WASI version.

func WasiGetVersion

func WasiGetVersion(module Module) WasiVersion

WasiGetVersion returns the WASI version of a module if any, other `Unknown` is returned.

Jump to

Keyboard shortcuts

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