WebAssembly profile

While JavaScript, a dynamic language, can be hard to squeeze in some scenarios, WebAssembly is slowly coming into view as a breakthrough. So, what is WebAssembly?

WebAssembly (Wasm) is a stack virtual machine based binary instruction set designed as a portable compilation target for programming languages that can be deployed to both client and server Web applications.

To be more specific, WebAssembly is a assembler like low-level language (compiled into binary format) that runs in modern Web browsers (Web environments), runs at near-native performance, and provides portable compilation targets for high-level languages such as C/C++, C#, and Rust. So that they can run on the Web.

In fact, there is a lot of discussion about whether WebAssembly will replace JavaScript. In fact, Wasm is also designed to run with JavaScript, allowing the two to work together. Wasm can be called by JavaScript, into a JavaScript context, and can also invoke browser functions like a Web API. In a Web environment, WebAssembly will strictly adhere to the same origin policy and browser security policy. Having said that, we can see that one of the main purposes of WebAssembly and its original intent is to run on a Web environment, or it wouldn’t be called WebAssembly at all.

Docker founder Solomon Hykes once said:

If WASM+WASI existed in 2008, we wouldn’t have needed to created Docker. That’s how important it is. Webassembly on the server is the future of computing. A standardized system interface was the missing link. Let’s hope WASI is up to the task!

What oh? How can WebAssembly have anything to do with Docker? Isn’t Docker container technology? If you’re not familiar with WebAssembly, you might wonder, but WASM + WASI is actually quite a low-level technology, and we can’t just think of WebAssembly as writing a front-end in a back-end language. “Small ho, the pattern is small”. WebAssembly will be a very important technology in the future and is still evolving.

Not only can WebAssembly run in a browser, it can also run in non-Web environments, even though WebAssembly was originally designed for the Web. Non-web environments, i.e. servers, Internet of Things (IoT) devices, mobile applications, desktop applications, etc., are even embedded in a large application. Wasm can run in JavaScript virtual machines (such as Node.js) or not (some WASI Runtime implementations are covered later). In general, Wasm runs in a sandboxed execution environment (starting to sound a bit like Docker?). .

In addition to Wasm’s core specification, Wasm’s embedded interface specification has three types:

  • JavaScript API: Defines JavaScript classes and objects used to access WebAssembly from JavaScript
  • Web API: Defines extensions to the JavaScript API for Web API calls in browsers
  • WASI API: Defines a modular system interface to run WebAssembly outside of the Web

WASI is the standard for non-Web environments. WASI is the WebAssembly System Interface, which goes directly from the browser to the System call, which is why WebAssembly is so powerful.

WebAssembly instruction set

As mentioned earlier, WebAssembly (Wasm) is a binary instruction set based on a stacked virtual machine. When Wasm is used, it is compiled into binary and contains instruction sets. Because it is based on sandbox virtual environment, it ISA virtual instruction set architecture (v-isa). V-isa is based on stack machine model, and Wasm also chooses stack-based virtual machine model design.

When you write a Wasm instruction set, just like when you write an assembly, there’s a mnemonic, and in Wasm we have wat readable text; The instruction mnemonic text is eventually compiled into the Wasm binary module, corresponding to a file in the Wasm binary bytecode format.

WABT is a binary WebAssembly toolset. There are many tools available in it. Let’s use wat2WASM as an example.

Here is a WAT file:

(module
  (func (export "addTwo") (param i32 i32) (result i32)
    local.get 0
    local.get 1
    i32.add))
Copy the code

Can we guess what we’re doing with this code? Here we define a module that exposes an addTwo method that takes two integer arguments, adds them up, and returns. It’s that simple.

Next, we will compile it into wASM binary format. The compilation process log is as follows:

0000000: 0061 736d                                 ; WASM_BINARY_MAGIC
0000004: 0100 0000                                 ; WASM_BINARY_VERSION
; section "Type" (1)
0000008: 01                                        ; section code
0000009: 00                                        ; section size (guess)
000000a: 01                                        ; num types
; func type 0
000000b: 60                                        ; func
000000c: 02                                        ; num params
000000d: 7f                                        ; i32
000000e: 7f                                        ; i32
000000f: 01                                        ; num results
0000010: 7f                                        ; i32
0000009: 07                                        ; FIXUP section size
; section "Function" (3)
0000011: 03                                        ; section code
0000012: 00                                        ; section size (guess)
0000013: 01                                        ; num functions
0000014: 00                                        ; function 0 signature index
0000012: 02                                        ; FIXUP section size
; section "Export" (7)
0000015: 07                                        ; section code
0000016: 00                                        ; section size (guess)
0000017: 01                                        ; num exports
0000018: 06                                        ; string length
0000019: 6164 6454 776f                           addTwo  ; export name
000001f: 00                                        ; export kind
0000020: 00                                        ; export func index
0000016: 0a                                        ; FIXUP section size
; section "Code" (10)
0000021: 0a                                        ; section code
0000022: 00                                        ; section size (guess)
0000023: 01                                        ; num functions
; function body 0
0000024: 00                                        ; func body size (guess)
0000025: 00                                        ; local decl count
0000026: 20                                        ; local.get
0000027: 00                                        ; local index
0000028: 20                                        ; local.get
0000029: 01                                        ; local index
000002a: 6a                                        ; i32.add
000002b: 0b                                        ; end
0000024: 07                                        ; FIXUP func body size
0000022: 09                                        ; FIXUP section size
; section "name"
000002c: 00                                        ; section code
000002d: 00                                        ; section size (guess)
000002e: 04                                        ; string length
000002f: 6e61 6d65                                name  ; custom section name
0000033: 02                                        ; local name type
0000034: 00                                        ; subsection size (guess)
0000035: 01                                        ; num functions
0000036: 00                                        ; function index
0000037: 02                                        ; num locals
0000038: 00                                        ; local index
0000039: 00                                        ; string length
000003a: 01                                        ; local index
000003b: 00                                        ; string length
0000034: 07                                        ; FIXUP subsection size
000002d: 0e                                        ; FIXUP section size
Copy the code

Oh and clear? Why do you want to look at something like assembly? Why don’t you take a quick look at it, and let’s look at the compiled binary, how do we use it?

Let’s look at this JS code:

const wasmInstance = new WebAssembly.Instance(wasmModule, {});
const { addTwo } = wasmInstance.exports;

for (let i = 0; i < 10; i++) {
  console.log(addTwo(i, i));
}
Copy the code

In line 1, we get the module instance from Wasm, and in line 2 we get the addTwo method we wrote earlier. Then the next for loop uses this method directly, which is easy to understand. This code will print:

0, 2, 4, 6, 8, 10, 12, 14, 16, 18Copy the code

This is a simple loop output.

Ok, so we have an idea of how the Wasm instruction set is used interactively in a Web environment. So, do we have to write WAT above to use Wasm? (No, I can’t.) Instead of writing an assembly language, you usually write code in a high-level programming language like C/C++, Rust, Go, etc., and the compiler will automatically convert you to Wasm binary instructions.

I guess you get the idea that WebAssembly is technically not a new language, it is a compilation target Format, a standard specification, and WAT (WebAssembly Text Format) is an intermediate form for display in Text editors, browser developer tools, and so on. WAT was created only to enable humans to read and edit WebAssemblies, which are ultimately binary format. For example, if I now want to write a Go compiler that compiles the Go code into Wasm format, then the intermediate WAT format is very helpful to you as a low-level developer. So, WebAssembly is not a language, there is no WebAssembly compiler, you don’t need to install a Wasm compiler or anything like that.

For example, C/C++ programs are compiled into.wASM modules using Emscripten (based on LLVM) tools. To use the WASM module, we need an HTML file, a JS glue file to import the WASM module. Similarly, we use Go to develop Wasm module, also through the Go compiler (officially supported) to convert Wasm module, and then an HTML file, a JS glue file, read Wasm module, this form to achieve. WebAssembly does not currently have direct access to the DOM. So in order to use the Web API, the WebAssembly needs to call JavaScript, which then calls the Web API.

Currently, only the Wasm core specification has been released in version 1.0. The other specifications are still in draft form. Wasm is still young and has a long way to go, so we can keep an eye on future changes.

Write WebAssembly applications in Go

Now that we’re trying to write a simple WebAssembly application in Go, we can look at the Go Wiki for guidance. It’s actually quite easy to write Wasm in Go.

First we’ll write the wASM /main.go file:

package main

import "fmt"

func main() {
    fmt.Println("Hello, WebAssembly!")
}
Copy the code

A simple print is then compiled into a.wasm file with the following command:

GOOS=js GOARCH=wasm go build -o main.wasm
Copy the code

Copy Go official gave us the prepared glue JS file:

cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
Copy the code

Create an HTML file:

<html>
<head>
    <meta charset="utf-8"/>
    <script src="wasm_exec.js"></script>
    <script>
        const go = new Go();
        WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then((result) => {
            go.run(result.instance);
        });
    </script>
</head>
<body>
<h1>WebAssembly Demo</h1>
</body>
</html>
Copy the code

In HTML files we introduced compiled.wasm files and fixed WASm_exec.js files.

Let’s write a simple HTTP service to support our static files:

// A basic HTTP server. package main import ( "flag" "log" "net/http" ) var ( listen = flag.String("listen", ":2345", "listen address") dir = flag.String("dir", ".. /.. /assets", "directory to serve") ) // go run cmd/server/main.go -dir assets/ func main() { flag.Parse() log.Printf("listening on %q..." , *listen) err := http.ListenAndServe(*listen, http.FileServer(http.Dir(*dir))) log.Fatalln(err) }Copy the code

I put the static files into assets and the main files into CMD. The specific path can be changed according to your specific situation.

Run:

$ go run cmd/server/main.go -dir assets/
2021/03/08 23:46:36 listening on ":2345"...
Copy the code

Open the browser to 127.0.0.1:2345 and you can see the HTML is normal. Open the console and you can see the output Hello, WebAssembly! .

Ok, a simple Demo is done. I put the code in go-language-plus/code-example. From this example, you can get a sense of how WebAssembly works and how we can write WebAssembly applications. Next, ready to introduce WASI, WebAssembly Out of the Web!

——-

Interested can follow the public account: write a line of code to touch a fish, receive the latest tweets.