What is the article about?

Learn about the past and present of WebAssembly, how the great creation of making the Web more widely available has worked throughout the Web/Node.js life cycle, and why WASM is the future of the Web.

Throughout this article, you’ll learn about the WebAssembly native, AssemblyScript, and Emscripten compilers.

Finally, it looks into the future of WebAssembly, listing some exciting technology directions.

I have previously written articles that delve into the details of WebAssembly usage and debugging WebAssembly code in a browser. If you are interested, click on the link to read:

  • WebAssembly is debugged in the browser
  • Compile C/C++ programs into WebAssembly and then run them in a browser and Node.js

Why is WebAssembly needed?

The heel of dynamic languages

First let’s look at the JS code execution process:

This is the previous ChakraCore engine structure of Microsoft Edge. The JS engine of Microsoft Edge has switched to V8.

The overall process is:

  • Get the JS source code and hand it to Parser to generate the AST
  • ByteCode Compiler compiles the AST to ByteCode.
  • The ByteCode goes into a translator, which interprets the ByteCode line by line into Machine Code and then executes it

However, In fact, the Code we usually write can be optimized In many places. For example, if the same function is executed for many times, the Machine Code mark generated by this function can be optimized, and then packaged to JIT Compiler (just-in-time). When the function is executed next Time, It does not need to go through the parser-Compiler-interpreter process and can directly execute the prepared Machine Code, greatly improving the execution efficiency of the Code.

However, the above JIT optimization can only be used for statically typed variables, such as the function we want to optimize, which has only two parameters, each of which has a definite type. JavaScript is a dynamically typed language, which means that during the execution of a function, the type may change dynamically, and the parameters may become three. The type of the first parameter may change from object to array, which will cause the JIT to fail and require a re-run of parser-Compiler-interpreters-execuation, which are the two most time-consuming steps in the entire code execution process. This is also why the Web cannot execute some high performance applications, such as large games, video clips, etc. in the context of JavaScript.

Static language optimization

In fact, one of the main reasons why JS execution is slow is because of its dynamic language characteristics, which lead to JIT failure. Therefore, if we can introduce static features into JS, then we can maintain effective JIT, which is sure to speed up JS execution. At this time, ASM.js appeared.

Asm.js provides only two data types:

  • 32 – bit signed integer
  • 64 – bit signed floating point number

Other objects such as strings, bores, or objects are stored in memory as numeric values and are called via TypedArray. Integers and floating point numbers are represented as follows:

The ArrayBuffer object, TypedArray view, and DataView are an interface for JavaScript to manipulate binary data in the syntax of arrays, collectively referred to as binary arrays. Reference ArrayBuffer.

var a = 1; var x = a | 0; // x is a 32-bit integer. // y is a 64-bit floating point numberCopy the code

The function is written as follows:

function add(x, y) {
  x = x | 0;
  y = y | 0;
  return (x + y) | 0;
}
Copy the code

All of the above function parameters and return values require a declared type, which is a 32-bit integer.

In addition, asM.js does not provide garbage collection mechanism, and all memory operations are controlled by the developer. TypedArray reads and writes memory directly:

var buffer = new ArrayBuffer(32768); Var HEAP8 = new Int8Array(buffer); HEAP8 function compiledCode(PTR) {HEAP[PTR] = 12; return HEAP[ptr + 4]; }Copy the code

As you can see, ASM.js is a strict subset of JavaScript that requires variable types to be determined and immutable at run time, and removes JavaScript garbage collection mechanisms that require developers to manually manage memory. This allows the JS engine to do a lot of JIT optimizations based on asM.js code, and asM.js runs about 50% faster in browsers than native machine code.

new

However, no matter how statically ASM.js is made, it is still the domain of JavaScript to eliminate some time-consuming upper-level abstractions (garbage collection, etc.). Parser-compiler is also required for code execution, and these two processes are the most time-consuming in code execution.

For the sake of extreme performance, cutting-edge Web developers abandoned JavaScript and created an assembly language WebAssembly that can directly deal with Machine Code, directly eliminating parser-Compiler. At the same time, WebAssembly is a strongly typed static language, capable of maximum JIT optimization, making WebAssembly infinitely close to the speed of C/C++ and other native code.

Equivalent to the following process:

It can be executed without parser-Compiler, eliminates garbage collection, and WASM’s statically strongly typed language features allow for maximum JIT optimization.

WebAssembly que

To get a sense of where WebAssembly fits into the Web, use this diagram:

WebAssembly (also known as WASM) is a new language format that can run in the Web. It has the characteristics of small size, high performance and strong portability. It is similar to JavaScript in the Web at the bottom, and it is also the fourth language in the Web recognized by W3C.

There are several reasons why it is similar to JavaScript at the bottom:

  • Executed at the same level as JavaScript: JS Engine, such as Chrome’s V8
  • You can manipulate various Web apis just like JavaScript

WASM can also run in Node.js or other WASM Runtime.

WebAssembly text format

WASM is actually a bunch of binary formats that can be executed directly, but to make it easier to display in a text editor or developer tool, WASM also designs an “intermediate” text format, named wat or.wast for the extension, and then uses tools like WABT. Convert WASM in text format to executable code in binary format, with.wASM as an extended format.

Take a look at the module code in WASM text format:

(module
  (func $i (import "imports" "imported_func") (param i32))
  (func (export "exported_func")
    i32.const 42
    call $i
  )
)
Copy the code

The code logic is as follows:

  • A WASM module is defined first, and then from aimportsThe JS module imports a functionimported_func, and name it$i, receiving parametersi32
  • Then export a file namedexported_funcYou can import this function from a Web App, such as JS
  • And then the parametersi32Pass in 42 and call the function$i

We convert the above text format to binary via WABT:

  • Copy the above code to a new one namedsimple.watSave in the file
  • Compile transformations using WABT

When you have wABt installed, run the following command to compile:

wat2wasm simple.wat -o simple.wasm
Copy the code

The binary is converted to binary, but cannot be viewed in the text editor. To see the binary, we can add the -v option at compile time to print the content on the command line:

wat2wasm simple.wat -v
Copy the code

The following output is displayed:

As you can see, WebAssembly is code in binary format, and even though it provides a slightly more readable text format, it’s not really useful for actual coding, let alone development efficiency.

An attempt at WebAssembly as a programming language

Because the above binary and text formats are not suitable for coding, WASM is not a suitable language for normal development.

AssemblyScript, a variation of TypeScript that adds the WebAssembly type to JavaScript, It can be compiled into WebAssembly using Binaryen.

The WebAssembly types are roughly as follows:

  • I32, U32, I64, AND V128
  • Small integer: i8, u8, etc
  • Variable integer types: isize, usize, etc

AssemblyScript is statically compiled into a strongly typed WebAssembly binary in front of Binaryen, which is then handed over to the JS engine for execution, so while AssemblyScript brings a layer of abstraction, But the actual production code is still WebAssembly, keeping WebAssembly’s performance benefits. AssemblyScript is designed much like TypeScript, providing a set of built-in functions that directly manipulate WebAssembly and compiler features.

Built-in functions:

  • Static type checking:

    • function isInteger<T>(value? : T): ``bool
  • Practical functions:

    • function sizeof<T>(): usize
  • Operate WebAssembly:

    • Mathematical operations

      • function clz<T>(value: T): T
    • Memory operations

      • function load<T>(ptr: usize, immOffset? : usize): T
    • The control flow

      • function select<T>(ifTrue: T, ifFalse: T, condition: ``bool``): T
    • SIMD

    • Atomics

    • Inline instructions

Then build up a standard library based on this set of built-in functions.

The standard library:

  • Globals
  • Array
  • ArrayBuffer
  • DataView
  • Date
  • Error
  • Map
  • Math
  • Number
  • Set
  • String
  • Symbol
  • TypedArray

A typical Array is used as follows:

var arr = new Array<string>(10) // arr[0]; 😢 // initialize for (let I = 0; i < arr.length; ++i) { arr[i] = "" } arr[0]; // Works correctly 😊Copy the code

AssemblyScript adds typescript-like syntax to JavaScript, and then uses it to maintain static strong typing requirements such as C/C++. If not initialized, memory allocation will cause an error.

There are also some extension libraries, such as Node.js process, crypto, etc., JS Console, and some memory-related StaticArray, Heap, etc.

AssemblyScript builds almost all of the features that JavaScript has with its basic types, built-in libraries, standard libraries and extensions, while AssemblyScript provides a typescript-like syntax. It strictly follows the conventions of strongly typed static languages.

AssemblyScript implements the modules itself, such as exporting a module, because the ES module specification for WebAssembly is still in draft form:

// env.ts export declare function doSomething(foo: i32): void { /* ... Function body */}Copy the code

Import a module:

import { doSomething } from "./env";
Copy the code

An example of a large block of code using a class:

class Animal<T> {
  static ONE: i32 = 1;
  static add(a: i32, b: i32): i32 { return a + b + Animal.ONE; }

  two: i16 = 2; // 6   instanceSub<T>(a: T, b: T): T { return a - b + <T>Animal.ONE; } // tsc does not allow this }

export function staticOne(): i32 {
  return Animal.ONE;
}

export function staticAdd(a: i32, b: i32): i32 {
  return Animal.add(a, b);
}

export function instanceTwo(): i32 {
  let animal = new Animal<i32>();
  return animal.two;
}

export function instanceSub(a: f32, b: f32): f32 {
  let animal = new Animal<f32>();
  return animal.instanceSub<f32>(a, b);
}
Copy the code

AssemblyScript opens the door to efficient coding with TS syntax, statically strongly typed specifications, and easy access to WebAssembly/ compiler apis. Compile it into a WASM binary using the Binaryen compiler, and then get the performance of WASM execution.

AssemblyScript has built a thriving ecosystem of applications thanks to its flexibility and performance. At present in the chain of blocks, build tools, editors, simulator, games, graphics editing tools, libraries, IoT, testing tools, etc, have a lot of use of AssemblyScript: www.assemblyscript.org/built-with-…

This is a backgammon game built using AssemblyScript.

A philosophy of genius: running C/C++ code in a browser

AssemblyScript has greatly improved WebAssembly’s shortcomings in efficient coding, but as a new programming language, its biggest disadvantages are ecology, developers and accumulation.

The designers of WebAssembly clearly designed it with all sorts of perfection in mind. Since WebAssembly is a binary format, it can be used as a compilation target for other languages. If you can build a compiler, Being able to compile an existing, mature language with a large number of developers and a powerful ecosystem into WebAssembly is like being able to directly reuse years of that language and use them to improve the WebAssembly ecosystem, running them on the Web and Node.js.

Fortunately, Emscripten already exists as an excellent compiler for C/C++.

Emscripten’s position in the development link can be visually illustrated by the following diagram:

Compile THE C/C++ code (Rust/Go, etc.) into WASM, then run the WASM runtime in the browser (or Node.js runtime) with JS glue code, such as ffmpeg. Emscripten compiler compiles to the Web for use, can directly transcode audio and video in the browser front end.

The JS “Gule” code above is necessary because if you want to compile C/C++ into WASM and execute it in the browser, you need to implement a Web API that maps to C/C++ related operations to ensure execution. This glue code currently contains some of the more popular C/C++ libraries. Such as SDL, OpenGL, OpenAL, and some POSIX apis.

The biggest use of WebAssembly today is this way of compiling C/C++ modules into WASM, with well-known examples of large libraries or applications such as Unreal Engine 4 and Unity.

Will WebAssembly replace JavaScript?

The answer is no.

Based on the above layers, the design of WASM can be summarized as follows:

  • Maximize the reuse of the existing underlying language ecosystem, such as C/C++ in game development, compiler design, etc
  • Near-native performance on the Web, Node.js, or other WASM Runtime, which allows browsers to run large games, image clips, and more
  • There is also maximum Web compatibility and security
  • AssemblyScript goes a step further in making it easy to write, write and debug if needed

So for good reason, WebAssembly fits better in this diagram:

WASM Bridges the ecosystem of various system programming languages, further complements the Web development ecosystem, and also provides performance supplement for JS, which is an important map missing in the development of Web up to now.

Rust Web Framework: github.com/yewstack/ye…

Explore Emscripten in depth

Address: github.com/emscripten-…

The following all the demo can be in the warehouse: code.byted.org/huangwei.fp… find

Star: 21.4 K

Maintenance: Active

Emscripten is an open source, cross-platform Compiler tool chain for compiling C/C++ into WebAssembly, consisting of LLVM, Binaryen, Closure Compiler, and other tools.

The core tool of Emscripten is Emscripten Compiler Frontend (EMCC), which is used to compile C/C++ code instead of some native compilers such as GCC or CLang.

In fact, in order for almost any portable C/C++ code base to be compiled into WebAssembly and executed on the Web or Node.js, Emscripten Runtime also provides a mapping of compliant C/C++ libraries and related apis to the Web/Node.js API, which exists in the compiled JS glue code.

The red part is the compilation of Emscripten, and the green part is the runtime support that Emscripten uses to make C/C++ code run:

Experience “Hello World” briefly

It is worth noting that the installation of webAssembly-related toolchains is almost always provided in source code, probably due to the habits of the C/C++ ecosystem.

To complete a simple C/C++ program running on the Web, we first need to install Emscripten’s SDK:

Git Clone HTTPS // github.com/emscripten-core/emsdk.git # go to the repository CD emsdk.git # go to the repository CD emsdk.git # We installed 1.39.18, /emsdk activate 1.39.18 # Add the corresponding environment variables to the system PATH source./emsdk_env.sh # Run the command to test whether the installation is successful  emcc -v #Copy the code

If the installation is successful, the following output is displayed after the preceding command is executed:

Emcc (Emscripten GCC /clang-like replacement + Linker emulating GNU LD) 1.39.18 Clang version 11.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 613 c4a87ba9bb39d1927402f4dd4c1ef1f9a02f7) Target: x86_64 - apple - darwin21.1.0 Thread model: posixCopy the code

Let’s prepare the initial code:

mkdir -r webassembly/hello_world
cd webassembly/hello_world && touch main.c
Copy the code

Add the following code to main.c:

#include <stdio.h> int main() { printf("hello, world! \n"); return 0; }Copy the code

Then use EMCC to compile the C code, switch to the webAssembly /hello_world directory on the command line, and run:

emcc main.c
Copy the code

This command outputs two files: a.ut.js and a.ut. wasm. The latter is the compiled WASM code, and the former is the JS glue code, which provides the WASM runtime.

You can use Node.js for quick tests:

node a.out.js
Copy the code

It prints “Hello, world!” , we successfully run the C/C++ code in node.js.

Let’s try running the code in a Web environment and modify the compiled code as follows:

emcc main.c -o main.html
Copy the code

The command above generates three files:

  • main.jsGlue code
  • main.wasmWASM code
  • main.htmlLoad the glue code to execute some of WASM’s logic

Emscripten generated code has certain rules, specific can consult: emscripten.org/docs/compil…

If you want to open this HTML in the browser, you need to start a local server, because the simple open through the file:// protocol access, mainstream browsers do not support XHR requests, only under the HTTP server, XHR requests, so we run the following command to open the website:

npx serve .
Copy the code

Open the web page, go to localhost:3000/main.html, you can see the following result:

There will also be printouts in the developer tools:

We managed to get C code running in Node.js and the browser!

On the future of WebAssembly

This article just lists some of the main application scenarios for WebAssembly today, including the high performance, lightweight, and cross-platform features of WebAssembly that allow you to run languages like C/C++ on the Web and desktop applications on the Web container.

But what this article didn’t cover was WASI, a standardized system interface for running WebAssembly on any system. As WebAssembly performance increases, WASI provides a perfectly viable way to run arbitrary code on any platform. Just like Docker does, but not limited to the operating system. As the founders of Docker put it:

“If WASM+WASI had been around in 2008, there would have been no need to create Docker. WASM on servers is the future of computing, the standardized system interface we’ve all been waiting for.

Another interesting thing is that WASM client development frameworks like Yew may become as popular in the future as React/Vue/Angular.

WASM’s package management tool, WAPM, may become the preferred way to share packages between frameworks in different languages thanks to the cross-platform nature of WASM.

At the same time, WebAssembly is mainly developed by W3C, and it is a project sponsored and jointly maintained by various manufacturers, including Microsoft, Google, Mozilla, etc. It is believed that WebAssembly will have a very promising future.

Refer to the link

  • www.ruanyifeng.com/blog/2017/0…
  • Pspdfkit.com/blog/2017/w…
  • Hacks.mozilla.org/2017/02/wha…
  • www.sitepoint.com/understandi…
  • www.cmake.org/download/
  • Developer.mozilla.org/en-US/docs/…
  • Research.mozilla.org/webassembly…
  • Itnext. IO/build – ffmpe…
  • Dev. To/alfg/ffmpeg…
  • Gist.github.com/rinthel/f4d…
  • Github.com/Kagami/ffmp…
  • Qdmana.com/2021/04/202…
  • Github.com/leandromore…
  • Ffmpeg.org/doxygen/4.1…

❤️/ Thanks for your support /

That is all the content of this sharing. I hope it will help you

Don’t forget to share, like and bookmark your favorite things

Welcome to the public number programmer bus, from byte, shrimp, zhaoyin three brothers, share programming experience, technical dry goods and career planning, help you to avoid detours into the factory.