WebAssembly runtime -- Wasmtime

Wasmtime is made by bytecodealliance Small and efficient runtime for open source WebAssembly and WASI. It runs WebAssembly code outside the Web, both as a command-line utility and as a library embedded in larger applications.

Has the following characteristics:

  • Lightweight. Wasmtime is a standalone runtime for WebAssembly that can be extended according to your needs. It is suitable for tiny chips and can also use large servers. Wasmtime can also be embedded in almost any application.
  • quick. Wasmtime is built on an optimized Cranelift code generator to quickly generate high-quality machine code at runtime.
  • Configurable. Whether you need to precompile wasm ahead of time, generate code quickly with Lightbeam, or interpret it at runtime, Wasmtime has everything you need to execute wasm.
  • WASI. Wasmtime supports a rich set of API s for WASI standard Interact with the host environment.
  • standard. Wasmtime passed the official WebAssembly test suite, implemented wasm's official C API, and also implemented WebAssembly's proposals. Wasmtime developers have also been closely associated with the WebAssembly standard process.

Currently supported languages:

  • Rust - the ["https://crates.io/crates/wasmtime">wasmtime crate](https://zhuanlan.zhihu.com/p/224862650/%3C/code)
  • C - the f="https://bytecodealliance.github.io/wasmtime/c-api/">wasm.h, wasi.h, and wasmtime.h headers
  • Python - the ["https://pypi.org/project/wasmtime/">wasmtime PyPI package](https://zhuanlan.zhihu.com/p/224862650/%3C/code)
  • .NET - the ["https://www.nuget.org/packages/Wasmtime">Wasmtime NuGet package](https://zhuanlan.zhihu.com/p/224862650/%3C/code)
  • Go - the [wasmtime-go repository](https://zhuanlan.zhihu.com/p/224862650/ht%3C/code%3Etps://pkg.go.dev/github.com/bytecodealliance/wasmtime-go)

Install

Installing Wasmtime CLI on macos and linux is as easy as executing the following command:

$ curl https://wasmtime.dev/install.sh -sSf | bash

Windows or other operating system users, need to go to GitHub Releases download.
Since my operating system is centos, it may appear different from yours. After I execute the install script, I have the following output:

curl https://wasmtime.dev/install.sh -sSf | bash
  Installing latest version of Wasmtime (dev)
    Checking for existing Wasmtime installation
    Fetching archive for Linux, version dev
https://github.com/cranestation/wasmtime/releases/download/dev/wasmtime-dev-x86_64-linux.tar.xz
######################################################################## 100.0%
    Creating directory layout
  Extracting Wasmtime binaries
wasmtime-dev-x86_64-linux/
wasmtime-dev-x86_64-linux/wasmtime
wasmtime-dev-x86_64-linux/LICENSE
wasmtime-dev-x86_64-linux/README.md
     Editing user profile (/root/.bashrc)
Warning: Your profile (/root/.bashrc) already mentions Wasmtime and has not been changed.
    Finished installation. Open a new terminal to start using Wasmtime!

Then we check if wasmtime was successfully installed with the following:

# wasmtime
wasmtime 0.19.0
Wasmtime WebAssembly Runtime
USAGE:
    wasmtime <SUBCOMMAND>
FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information
SUBCOMMANDS:
    config      Controls Wasmtime configuration settings
    help        Prints this message or the help of the given subcommand(s)
    run         Runs a WebAssembly module
    wasm2obj    Translates a WebAssembly module to native object file
    wast        Runs a WebAssembly test script file
If a subcommand is not provided, the `run` subcommand will be used.
Usage examples:
Running a WebAssembly module with a start function:
  wasmtime example.wasm
Passing command line arguments to a WebAssembly module:
  wasmtime example.wasm arg1 arg2 arg3
Invoking a specific function (e.g. `add`) in a WebAssembly module:
  wasmtime example.wasm --invoke add 1 2

After the installation is complete, let's start with Hello world.

Demo

Wasmtime is available as a Go module. The following sections describe how to add Wasmtime to your project, with some examples of what can be done with WebAssembly modules.

Make sure you are using Go 1.12 or higher with module support.
First create a go module project:

$ mkdir hello-wasm
$ cd hello-wasm
$ go mod init hello-wasm

Then write main.go, the specific code is as follows:

package main
import (
    "fmt"
    "github.com/bytecodealliance/wasmtime-go"
)
func main() {
    engine := wasmtime.NewEngine()
    // Almost all operations in wasmtime require a contextual `store`
    // argument to share, so create that first
    store := wasmtime.NewStore(engine)
    // Compiling modules requires WebAssembly binary input, but the wasmtime
    // package also supports converting the WebAssembly text format to the
    // binary format.
    wasm, err := wasmtime.Wat2Wasm(`
      (module
        (import "" "hello" (func $hello))
        (func (export "run")
          (call $hello))
      )
    `)
    check(err)
    // Once we have our binary `wasm` we can compile that into a `*Module`
    // which represents compiled JIT code.
    module, err := wasmtime.NewModule(engine, wasm)
    check(err)
    // Our `hello.wat` file imports one item, so we create that function
    // here.
    item := wasmtime.WrapFunc(store, func() {
        fmt.Println("Hello from Go!")
    })
    // Next up we instantiate a module which is where we link in all our
    // imports. We've got one import so we pass that in here.
    instance, err := wasmtime.NewInstance(store, module, []*wasmtime.Extern{item.AsExtern()})
    check(err)
    // After we've instantiated we can lookup our `run` function and call
    // it.
    run := instance.GetExport("run").Func()
    _, err = run.Call()
    check(err)
}
func check(e error) {
    if e != nil {
        panic(e)
    }
}

Finally run:

$ go run main.go
Hello from Go!

Of course, when our wasm module code is relatively large, we can put the code in a file ending in .wat. Then use the NewModuleFromFile function to load the module code from the specified wat file.
E.g:
We create the following wasm text module that mainly exports a function for calculating the greatest common denominator of two numbers. Name it gcd.wat.

(module
  (func $gcd (param i32 i32) (result i32)
    (local i32)
    block  ;; label = @1
      block  ;; label = @2
        local.get 0
        br_if 0 (;@2;)
        local.get 1
        local.set 2
        br 1 (;@1;)
      end
      loop  ;; label = @2
        local.get 1
        local.get 0
        local.tee 2
        i32.rem_u
        local.set 0
        local.get 2
        local.set 1
        local.get 0
        br_if 0 (;@2;)
      end
    end
    local.get 2
  )
  (export "gcd" (func $gcd))
)

Then modify our main.go file as follows:

package main
import (
    "fmt"
    "github.com/bytecodealliance/wasmtime-go"
)
func main() {
    engine := wasmtime.NewEngine()
    store := wasmtime.NewStore(engine)
    module, err := wasmtime.NewModuleFromFile(engine, "gcd.wat")
    check(err)
    instance, err := wasmtime.NewInstance(store, module, []*wasmtime.Extern{})
    check(err)
    gcd := instance.GetExport("gcd").Func()
    val, err := gcd.Call(6, 27)
    fmt.Printf("gcd(6, 27) = %dn", val.(int32))
    check(err)
}
func check(e error) {
    if e != nil {
        panic(e)
    }
} 

Running main.go yields the following output:

$ go run main.go
gcd(6, 27) = 3

Epilogue

In fact, wasm's support for go is not particularly good. In future articles, we will create a wasm program in rust and execute it directly using something like wasmtime example.wasm .

Tags: Go WebAssembly

Posted by BraniffNET on Wed, 18 May 2022 18:57:47 +0300