WebAssembly demo

1. What?


WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web.

A portable, small and fast-loading (binary) format, suitable for compiling to the Web

The main goal is to support high-performance applications in the Web environment. But the design does not rely on Web features, nor does it provide functions for Web features, and can also be used in other environments

A simple understanding is to define a compilation target format that can achieve near-native execution performance in any environment that supports this format. It is equivalent to allowing the expansion of native modules. In performance-critical scenarios, use other more suitable languages ​​(such as C++) to implement, and then compile to WebAssembly in advance, you can get a performance experience comparable to native

The design goals are divided into 2 aspects:

Fast, safe and portable semantics

Fast: execute with performance close to native code and utilize functions common to all modern hardware

Security: The code is verified and executed in a memory-safe sandbox environment to prevent data corruption or security violations

Well-defined: Fully and precise definition of legal procedures and their behavior, in a way that is easy to infer informal and formal

Independent of hardware: Compile on all modern architectures, desktop or mobile devices, and embedded systems

Independent of language: no bias towards any specific language, programming model or object model

Independent of the platform: can be embedded in the browser, run as a stand-alone VM, or integrated into other environments

Open: Programs can interact with their environment in a simple and universal way

Efficient and portable representation

Small and exquisite: Binary format is smaller than typical text or native code format, and can be transmitted quickly

Modularity: The program can be split into smaller parts, which can be transmitted, cached and used separately

Efficient: It can be decoded, verified and compiled quickly in a single pass (traversal), which is equivalent to real-time (JIT) or ahead of time (AOT) compilation

Streaming: Allows to start decoding, verification and compilation as early as possible before all the data is available

Parallel: allows decoding, verification and compilation to be split into multiple independent parallel tasks

Portability: No assumptions about architectures that are not widely supported on modern hardware

Major browsers (Chrome, Edge, Firefox, and WebKit) jointly promote the standardization process:


WebAssembly is currently being designed as an open standard by a W3C Community Group that includes representatives from all major browsers.

PS This thing is led by the browser manufacturers (the four of them stand together to do things, it is worth looking forward to), just by the way, open standards (not only for the Web environment), the motivation comes from the desire to further improve the JS runtime performance, in V8 After the introduction of JIT, it is impossible to further improve performance because of the limitations of JS language features (such as interpreted and weak types). Web capabilities are getting stronger and stronger, client JS is getting heavier and heavier, and the need to further improve JS execution performance is still there, so there is WebAssembly's salary

2. Wasm and wast
We know that WebAssembly defines a binary format, this format is wasm, for example:


0061 736d 0100 0000 0187 8080 8000 0160
027f 7f01 7f03 8280 8080 0001 0004 8480
8080 0001 7000 0005 8380 8080 0001 0001
0681 8080 8000 0007 9080 8080 0002 066d
656d 6f72 7902 0003 6763 6400 000a ab80
8080 0001 a580 8080 0001 017f 0240 2000
450d 0003 4020 0120 0022 026f 2100 2002
2101 2000 0d00 0b20 020f 0b20 010b 

The C code corresponding to this string of hexadecimal numbers is:


// 辗转相除法求最大公约数
int gcd(int m, int n) {
    if (m == 0) return n;
    return gcd(n % m, m);
}

The readability of wasm is equal to 0. In order to alleviate this problem, a text format with better readability is defined, called wast:


(module
 (table 0 anyfunc)
 (memory $0 1)
 (export "memory" (memory $0))
 (export "gcd" (func $gcd))
 (func $gcd (; 0 ;) (param $0 i32) (param $1 i32) (result i32)
  (local $2 i32)
  (block $label$0
   (br_if $label$0
    (i32.eqz
     (get_local $0)
    )
   )
   (loop $label$1
    (set_local $0
     (i32.rem_s
      (get_local $1)
      (tee_local $2
       (get_local $0)
      )
     )
    )
    (set_local $1
     (get_local $2)
    )
    (br_if $label$1
     (get_local $0)
    )
   )
   (return
    (get_local $2)
   )
  )
  (get_local $1)
 )
)

The parentheses are a bit Lisp-style, but at least they are readable, for example:

// 导出了两个东西,分别叫`memory`和`gcd`
(export "memory" (memory $0))
(export "gcd" (func $gcd))
// 函数签名,接受2个int32类型参数,返回int32类型值
(func $gcd (; 0 ;) (param $0 i32) (param $1 i32) (result i32)
// 函数体...就不猜了

PSwast and wasm can be converted to each other, see WABT: The WebAssembly Binary Toolkit for details

In addition, you can see another text command in the Source panel of the browser:


func (param i32 i32) (result i32)
(local i32)
  block
    get_local 0
    i32.eqz
    br_if 0
    loop
      get_local 1
      get_local 0
      tee_local 2
      i32.rem_s
      set_local 0
      get_local 2
      set_local 1
      get_local 0
      br_if 0
    end
    get_local 2
    return
  end
  get_local 1
end

It looks very similar to wast, don’t know if there is a name, or it also belongs to wast? This is converted by the browser based on wasm

3. Trial play environment
environmental requirements:

C/C++ compilation environment Emscripten

A browser that supports WebAssembly (the latest Chrome supports it by default)


Does the online environment hurt? Demo environment: WebAssembly Explorer

COMPILE and DOWNLOAD can get wasm, it's easy to use

Note that the default is the C++ environment. If you want to use C, select C99 or C89 on the left, otherwise the function name will be corrupted, such as the wast of C++11:


(module
 (table 0 anyfunc)
 (memory $0 1)
 (export "memory" (memory $0))
 (export "_Z3gcdii" (func $_Z3gcdii))
 (func $_Z3gcdii (; 0 ;) (param $0 i32) (param $1 i32) (result i32)
  (local $2 i32)
  (block $label$0
   (br_if $label$0
    (i32.eqz
     (get_local $0)
    )
   )
   (loop $label$1
    (set_local $0
     (i32.rem_s
      (get_local $1)
      (tee_local $2
       (get_local $0)
      )
     )
    )
    (set_local $1
     (get_local $2)
    )
    (br_if $label$1
     (get_local $0)
    )
   )
   (return
    (get_local $2)
   )
  )
  (get_local $1)
 )
)

The function name has been compiled into _Z3gcdii. It is guessed that something like namespace is causing trouble. I am not familiar with C++. Use C obediently.

PS In addition to C/C++, other languages ​​can also play WebAssembly, such as Rust


Download platform SDK for local environment

Follow the installation steps

If nothing else, you can install it here, you can try emcc -v:


INFO:root:(Emscripten: Running sanity checks)
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.37.22
clang version 4.0.0  (emscripten 1.37.22 : 1.37.22)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: D:\emsdk-portable-64bit\clang\e1.37.22_64bit
INFO:root:(Emscripten: Running sanity checks)

You may encounter a DLL missing (MSVCP140.dll) error in the Windows environment. You can manually install the required C++ environment. For details, see MSVCP140.dll not found · Issue #5605 · kripken/emscripten

Then you can make a try (save the previous C code as a file gcd.c):

emcc ./c/gcd.c -Os -s WASM=1 -s SIDE_MODULE=1 -s BINARYEN_ASYNC_COMPILATION=0 -o ./output/gcd.wasm

PS For more usage, see Emscripten Tutorial

The content of gcd.wasm is as follows:


0061 736d 0100 0000 000c 0664 796c 696e
6b80 80c0 0200 010a 0260 027f 7f01 7f60
0000 0241 0403 656e 760a 6d65 6d6f 7279
4261 7365 037f 0003 656e 7606 6d65 6d6f
7279 0200 8002 0365 6e76 0574 6162 6c65
0170 0000 0365 6e76 0974 6162 6c65 4261
7365 037f 0003 0403 0001 0106 0b02 7f01
4100 0b7f 0141 000b 072b 0312 5f5f 706f
7374 5f69 6e73 7461 6e74 6961 7465 0002
0b72 756e 506f 7374 5365 7473 0001 045f
6763 6400 0009 0100 0a40 0327 0101 7f20
0004 4003 4020 0120 006f 2202 0440 2000
2101 2002 2100 0c01 0b0b 0520 0121 000b
2000 0b03 0001 0b12 0023 0024 0223 0241
8080 c002 6a24 0310 010b 

Note that the method name will be prefixed with an underscore (_) by default. In this example, the exported method name is _gcd. For details, see Interacting with code:


The keys passed into mergeInto generate functions that are prefixed by _. In other words myfunc: function() {}, becomes function _myfunc() {}, as all C methods in emscripten have a _ prefix. Keys starting with $ have the $ stripped and no underscore added.

The module interface used in JS should be underlined (I don’t know if there is a configuration item that can remove it)

Four. Try it


WebAssembly.compile(new Uint8Array(`
    0061 736d 0100 0000 0187 8080 8000 0160
    027f 7f01 7f03 8280 8080 0001 0004 8480
    8080 0001 7000 0005 8380 8080 0001 0001
    0681 8080 8000 0007 9080 8080 0002 066d
    656d 6f72 7902 0003 6763 6400 000a ab80
    8080 0001 a580 8080 0001 017f 0240 2000
    450d 0003 4020 0120 0022 026f 2100 2002
    2101 2000 0d00 0b20 020f 0b20 010b 
    `.match(/\S{2}/g).map(s => parseInt(s, 16))
)).then(module => {
    const instance = new WebAssembly.Instance(module);
    console.log(instance.exports);
    const { gcd } = instance.exports;
    console.log('gcd(328, 648)', gcd(328, 648));
});

The hexadecimal string comes from the online demo, which is consistent with the original wasm example. Just stick these things to Chrome's Console for execution. If everything is normal, you will get an error:


VM40:1 Uncaught (in promise) CompileError: WasmCompile: Wasm code generation disallowed in this context

This is because the default CSP (Content Security Policy) restrictions are easy to solve, just turn on the incognito mode (Ctrl/CMD + Shift + N)

Will get the output:


{memory: Memory, gcd: ƒ}
gcd(328, 648) 8

The first line is the export content of the module obtained by loading our WebAssembly, including a memory object and gcd method, and the output of the second line is the greatest common divisor calculated by calling the high-performance module

WebAssembly.compile and other related APIs can refer to:

JavaScript API-WebAssembly: Specification definition

WebAssembly-JavaScript | MDN: contains examples

In addition, the locally compiled version requires imports env (and the function name is prefixed with an underscore _):


WebAssembly.compile(new Uint8Array(`
    0061 736d 0100 0000 000c 0664 796c 696e
    6b80 80c0 0200 010a 0260 027f 7f01 7f60
    0000 0241 0403 656e 760a 6d65 6d6f 7279
    4261 7365 037f 0003 656e 7606 6d65 6d6f
    7279 0200 8002 0365 6e76 0574 6162 6c65
    0170 0000 0365 6e76 0974 6162 6c65 4261
    7365 037f 0003 0403 0001 0106 0b02 7f01
    4100 0b7f 0141 000b 072b 0312 5f5f 706f
    7374 5f69 6e73 7461 6e74 6961 7465 0002
    0b72 756e 506f 7374 5365 7473 0001 045f
    6763 6400 0009 0100 0a40 0327 0101 7f20
    0004 4003 4020 0120 006f 2202 0440 2000
    2101 2002 2100 0c01 0b0b 0520 0121 000b
    2000 0b03 0001 0b12 0023 0024 0223 0241
    8080 c002 6a24 0310 010b 
    `.match(/\S{2}/g).map(s => parseInt(s, 16))
)).then(module => {
    let imports = {
        env: {
            memoryBase: 0,
            memory: new WebAssembly.Memory({ initial: 256 }),
            tableBase: 0,
            table: new WebAssembly.Table({ initial: 0, element: 'anyfunc' })
        }
    };
    const instance = new WebAssembly.Instance(module, imports);
    console.log(instance.exports);
    // 注意下划线前缀
    const { _gcd } = instance.exports;
    console.log('gcd(328, 648)', _gcd(328, 648));
});

You can get similar output:


{__post_instantiate: ƒ, runPostSets: ƒ, _gcd: ƒ}
gcd(328, 648) 8

It should be that Emscripten has added some irrelevant things by default, which are functionally equivalent to our simplified version

V.
Advantages, disadvantages and application scenarios The
code size is small

About 300k (compressed) JavaScript logic is rewritten with WebAssembly, the volume is only about 90k

But using WebAssembly requires the introduction of a 50k-100k JavaScript class library as the infrastructure

Security is slightly improved

Although the WebAssembly text instructions corresponding to the source code are still unconcealed, the reverse cost is higher

Performance improvement

In theory, WebAssembly has close to native execution performance, because it skips the interpretation process, and the file size also has advantages in terms of transmission.

Of course, the premise is that in scenarios where the amount of business code is large and extreme performance is required, in repeated execution scenarios such as benchmarks, JIT is not much slower than AOT.

Disadvantages
currently limited capacity:

Only a few basic data types are supported (i32 / i64 / f32 / f64 / i8 / i16)

No direct access to DOM and other Web APIs

Unable to control GC

Application Scenario
WebAssembly defines a standard executable binary format for browsers, so that more developers can participate through a unified compilation mechanism to build a prosperous Web ecosystem. The vision is good, but there are some practical problems.

First of all, the original intention of WebAssembly is to "support high-performance applications in the Web environment". In order to break through the performance bottleneck, the possible application scenarios are:

Video decoding

Image Processing

3D/WebVR/AR visualization

Rendering engine

Physics engine

Compression/encryption algorithm

…Etc. scenes with a lot of computation

Of course, some support may also be built into the browser in the future, instead of using "extensions" or the like. But the real meaning of WebAssembly is to provide the ability to allow self-extension of high-performance "native" modules. After all, it may take a long time to wait for the browser to provide it and wait until the compatibility is acceptable. With this ability, No need to wait for the mainstream browsers on the market to support a certain native feature, you can do it yourself, and there is no compatibility difference. Conversely, a batch of popular community modules may emerge and gradually be adopted as browser native support, ecologically giving back to the Web environment

Reference
WebAssembly

WebAssembly in practice: How to write code: a great guide

How to comment on the latest WebAssembly bytecode technology in browsers?

WebAssembly: The silver bullet to solve JavaScript's chronic problems?

WebAssembly, the new era of the Web

Can WebAssembly be polyfilled?

wasm-arrays: WebAssembly array packaging library

Guess you like

Origin blog.51cto.com/15080030/2592698
Recommended