Go WebAssembly

What is WebAssembly

The following is the definition given by Mozilla on MDN:

WebAssembly (abbreviation: Wasm) is a new way of coding that runs in modern web browsers - it is a low-level assembly-like language with a compact binary format that can run with near-native performance and provides a compilation target for languages such as C/C++ so that they can run on the Web. It is also designed to coexist with JavaScript, allowing the two to work together.

Wasm’s official website picks out the highlights itself as

  • Is a binary instruction format for stack-based virtual machines.
  • Is designed to be a portable compilation target for programming languages.
  • Ability to deploy client and server applications on the web.

New coding approach that can be run in a browser. Can run with near-native performance. Can be cross-language, e.g. C/C++; can coexist with JavaScript.

Looks like a nice new toy that can run cross-platform.

Developed by which

The earliest WebAssembly 1.0 was based on a feature set implementation of asm.js (a strict subset of Javascript, statically typed, eliminating the garbage collection mechanism, etc.). WebAssembly 2.0 was then further extended and developed based on new standards.

The WebAssembly development teams are from Mozilla, Google, Microsoft, and Apple, representing the four major web browsers Firefox, Chrome, Microsoft Edge, and Safari.

WebAssembly development team

Some important timelines:

  • 2015 WebAssembly was first released, with a demo of Angry Bots for Unity in the four major browsers mentioned above.
  • March 2017, first release of WebAssembly MVP version, end of preview version and official release, which can be understood as 1.0.
  • In February 2018, the WebAssembly Working Group (WWG) released three public working drafts of the core specification, JavaScript interface, and Web API.
  • In 2019, Chrome 75 is released with WebAssembly threads enabled by default.
  • In June 2022, the release of WebAssembly 2.0 begins.

Several large companies sent people together to make this, it’s relatively new and has only started to be supported more in recent years. Currently still in WebAssembly 2.0, still in the development phase.

1.0 and 2.0 difference one

Intuitively, the biggest differences between 1.0 and 2.0 are:

  • The main goal of 1.0 is to be able to run WebAssembly in all major browsers. 96% of installed browsers support WebAssembly (version 1.0) according to Unity as of October 2022, essentially achieving full coverage.
  • WebAssembly has a second lease on life (2.0): the ability to aggregate and integrate languages with each other through the modular system interface of WASI (WebAssembly System Interfac), an intermediate product called .wasm.

From WebAssembly 2.0 onwards, the boundaries are bigger and the goal is entirely portable and secure high-level languages. It is expected to be used in browsers, programming languages, and systems.

It has the feel of a JVM:

WebAssembly 2.0

Go Quick Start

After we get a quick background on WebAssembly. Let’s get down to business and see how Go’s WebAssembly is doing and how it’s being used.

Go currently has two ways to use WebAssembly, the first is to use the syscall/js standard library, which barely supports WebAssembly 1.0.

The code is as follows:

1
2
3
4
5
6
7
8
package main

import "syscall/js"

func main() {
    alert := js.Global().Get("alert")
    alert.Invoke("Hello")
}

Compile command:

1
$ GOOS=js GOARCH=wasm go build -o jianyu.wasm

Then just use the corresponding WebAssembly call in JS.

The second way is to use the open source library tinygo-org/tinygo, which is based on LLM and supports WebAssembly 1.0/2.0 (WASM/WASI).

Install tinygo with brew.

1
2
$ brew tap tinygo-org/tools
$ brew install tinygo

If the installation is successful, execute tinygo version and you will see the version information.

The Go wasm code is as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import (
    figure "github.com/common-nighthawk/go-figure"
)

//export HelloWorld
func HelloWorld() {
    myFigure := figure.NewFigure("Hello World", "", true)
    myFigure.Print()
}

func main() {}

Compile command:

1
tinygo build -o module.wasm -target wasi .

After a successful run, the module.wasm binary will be compiled in the corresponding directory and can be used by other platforms and languages.

If you want to call the generated .wasm in Go or other languages, you need to find the corresponding WASI-compliant libraries and rules.

Here is the code for Go wasmer-go to call .wasm:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import (
    "fmt"
    "io/ioutil"

    wasmer "github.com/wasmerio/wasmer-go/wasmer"
)

func main() {
    wasmBytes, _ := ioutil.ReadFile("module.wasm")

    store := wasmer.NewStore(wasmer.NewEngine())
    module, _ := wasmer.NewModule(store, wasmBytes)

    wasiEnv, _ := wasmer.NewWasiStateBuilder("wasi-program").
        // Choose according to your actual situation
        // Argument("--foo").
        // Environment("ABC", "DEF").
        // MapDirectory("./", ".").
        Finalize()
    importObject, err := wasiEnv.GenerateImportObject(store, module)
    check(err)

    instance, err := wasmer.NewInstance(module, importObject)
    check(err)

    start, err := instance.Exports.GetWasiStartFunction()
    check(err)
    start()

    HelloWorld, err := instance.Exports.GetFunction("HelloWorld")
    check(err)
    result, _ := HelloWorld()
    fmt.Println(result)
}

func check(e error) {
    if e != nil {
        panic(e)
    }
}

It will output Hello World when run successfully.

The Go standard library syscall/js only supports WebAssembly 1.0 and can only be used in JS-related scenarios, not integrated with other languages.

Among them, tinygo implements WASI and integrates with other platform languages using WASI as a standard interface. However, tinygo does not support all Go syntax features, see Go language features for details.

Note in particular that the level of support for WebAssembly (WASI) varies from language to language.

Other Application Scenarios

Another important factor that makes WebAssembly hot is that it can be integrated and used on a variety of cloud-native components, further extending the scenario.

WebAssembly on Cloud Native Components

For example, on Envoy and Istio, custom filters can be easily integrated into Envoy using wasm, enabling enhancements to the Envoy agent.

Summary

This article provides background on WebAssembly, does a quick hands-on, explores extension scenarios, and more. Although WebAssembly is a new wheel, it is also claimed to be able to integrate and be integrated with WASI.

But in reality, the level of support for WebAssembly varies from language to language. Go’s official standard library is not well maintained, and WASI issues are not moving forward.