Background: Start with JavaScript

JavaScript is dominant, no matter public or private projects, any organization, anywhere in the world. -GitHub Annual Report 2018

With the rapid development of JavaScript, it has become one of the most popular programming languages, which is driven by the development of the Web. However, as JavaScript is widely used, it also exposes many problems:

  • The syntax is too flexible to develop large Web projects;
  • Performance does not meet the requirements of some scenarios.

These two problems become the sword of Damocles over the head of JavaScript, threatening the wider application of JavaScript.

Brendan Eich never dreamed that JavaScript, which he had hastily designed in ten days, would be widely accepted and used by a large number of people around the world. One man digs a hole, another man fills it. Now that JavaScript has become the de facto standard for Web programming, these two burning questions are bound to be addressed.

MS, Google, Mozilla’s exploration

MS: TypeScript

The first problem was solved by MicroSoft, a well-known open-source software company.

MicroSoft built TypeScript with the lead architect of C# and Anders Hejlsberg, the founder of Delphi and Turbo Pascal.

TypeScript iS a strict superset of JavaScript that adds optional static typing and manipulates Prototype using object-oriented programming syntax that looks like class-based. So TypeScript can be understood this way:

MicroSoft has used TypeScript’s sharp weapon to build epic projects such as VSCode, and it seems that the first Damocles sword — “syntax is too flexible to develop large Web projects” — has been solved.

However, because TypeScript is still ultimately compiled into JavaScript and executed in the browser, the performance issues that plague JavaScript developers remain unresolved.

Google: V8

Back in 2008, Google launched its own JavaScript engine, V8, in an attempt to speed up JavaScript execution using JIT technology, and it did.

Thanks to the introduction of JIT, V8 has resulted in a tenfold increase in Web performance!

The image above shows Chrome’s V8 versus IE’s Chakra Benchmark results. Specific address point me

Now that performance has improved so much, have JavaScript’s much-maligned performance problems been solved? Why is Web performance still being challenged?

Single thread -> block

Most of the performance bottlenecks in Web applications are no longer due to JavaScript, but to the DOM. DOM and JavaScript are typically implemented separately in browsers. The following figure shows how DOM and JavaScript are implemented in different browsers:

Because Dom rendering and JavaScript engines are relatively independent, both modules access each other through interfaces. Due to the single-threaded nature of JavaScript, this access can only be simplex.

Think of the DOM and JavaScript as islands, connected by a bridge. Each time JavaScript accesses the DOM, it has to cross the bridge and pay a toll. The more times you access the DOM, the higher the toll, so it’s recommended to minimize the number of times you cross the bridge. I’ve been on a JavaScript island. To achieve this goal, you can use the Virtual Dom, Web Worker to achieve. I will not repeat it here.

JIT VS AOT is still inadequate in the face of heavy computing

As mentioned earlier, the V8 engine introduced JIT technology into JavaScript for the first time, dramatically increasing execution speed. So first we need to understand what JIT is, and AOT.

AOT: Ahead-of-Time compilation

It must be a strongly typed language. The binary file that can be executed by the CPU is generated directly before compilation. The CPU does not need to perform any compilation operations during execution.

JIT: Just-in-Time compilation

There is no compilation. Binary assembly code is generated according to the context and pumped into the CPU for execution. V8 optimizes JavaScript performance in this way by JIT execution, which can be optimized for code compilation, without having to translate into binary assembly code every time the code is run.

Because the dynamic language type of JavaScript cannot be changed, performance optimization can only be done in the form of a JIT.

To further JIT optimization and improve JavaScript performance, Mozilla has launched ASM.js.

Mozilla: asm. Js

Similar to TypeScript, ASM.js is also strongly typed JavaScript, but its syntax is a subset of JavaScript, specifically designed for JIT performance optimization.

A typical example of asM.js code is as follows:

As you can see, ASM.js uses bitwise or zero operations to declare x to be an integer. This ensures that the JIT generates binary code as quickly as possible during execution, eliminating the need to determine variable types based on context.

Mozilla provides a benchmark for asM.js:

asm.js To WebAssembly

Since Mozilla came up with ASM. js, Google, MicroSoft, and Apple all thought it was a good idea and banded together to build the WebAssembly ecosystem.

Unlike ASM.js, WebAssembly is a bytecode standard that relies on virtual machines to run in browsers as bytecodes.

Compilers like Emscripten can be relied on to compile strongly typed languages like C++/Golang/Rust/Kotlin into WebAssembly bytecodes (.wasm files). So a WebAssembly is not an Assembly, it just looks like Assembly. A typical. Wasm file looks like this:

00000000: 0061 736d 0100 0000 0108 0260 017f 0060 .asm....... `... ` 00000010: 0000 0215 0203 656e 7603 6d65 6d02 0001 ...... env.mem... 00000020: 026a 7303 6c6f 6700 0003 0201 0107 0b01 .js.log......... 00000030: 0765 7861 6d70 6c65 0001 0a23 0121 0041 .example... #.! .A 00000040: 0042 c8ca b1e3 f68d c8ab ef00 3703 0041 .B.......... 7.. A 00000050: 0841 f2d8 918b 0236 0200 4100 1000 0b .A..... 6.. A....Copy the code

In actual combat

Environment builder: Compile Emscripten

This time it is compiled into a WebAssembly file using the official recommended CPP language and executed in a browser. The first step is to set up the Emscripten environment. Emscripten is used to convert CPP files into WASM bytecode files.

The conventional construction process is very tedious:

1. Make sure CMake, Xcode, Python 2.7.x 2clonehttps://github.com/juj/emsdk.git, 3. / emsdk install - build = Release SDK - incoming - 64 - bit binaryen - master - 64 - bit wait for about an hour... To switch versions, recompile is required.Copy the code

However, some good people have come up with a quick way to start your WebAssembly journey with a Docker image. Just take the following steps:

Docker pull trzeci/emscripten:latest 3,alias emcc='Docker run -- rm -v $(PWD):/ src-u emscripten trzeci/emscripten emccCopy the code

Compile CPP MD5 functions into WASM

First you need to find a CPP code to calculate MD5:

[email protected]:codenoid/md5-cpp.git

Use the EMSCRIPTEN_KEEPALIVE macro in emscripten.h to ensure that the EMCC compiler does not optimize the function when it is compiled because it is not called.

Here uint8_t* is implicitly typed to char*

Compile CPP files into WASM files using EMCC:

emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='[" cwrap "]' md5. CCopy the code
  • -O3: specifies the optimization level. O3 is the highest optimization level

  • -s WASM=1: Generates WASM code instead of ASM.js code

  • -s EXTRA_EXPORTED_RUNTIME_METHODS= ‘[” cwrap “]’ : Uses the cwrap function to reference exported functions in JavaScript

Finally, two files a.ut.js and a.ut.wasm are generated. These are the glue files for WASM and JavaScript interaction and the WebAssembly bytecode files.

Calculate MD5 and print the result:

Two things to note here:

  • A. ut.js will fetch wASM files automatically. Because there is a cross-domain situation when obtaining WASM files, you can use http-server to create a local server.
  • CPP variable types and JavaScript variable types need to be converted, and the conversion is automatically performed by glue code. The specific conversion rules are as follows:

benchmark

Since WebAssembly is all about improving performance, benchmark is a must. Encrypt the “IVWeb” short character 100,000 times. Benchmark results are as follows:

You can see that WebAssembly has approximately a 39% increase in computational performance compared to pure JavaScript, which is a far cry from the common 100%+ performance improvement. Why is that?

I benchmark the 2M long text, and the result is as follows:

This one is a bigger one. What accounts for such a big gap? I suspect there are two reasons:

  1. After 100,000 times of “IVWeb” short character encryption, JIT optimization intervention, no need to compile every time, JavasScript performance has been greatly improved.
  2. If the ivWeb short character is encrypted 100,000 times, the glue code is executed many times, which slows down the performance.

In view of the above two guesses, a group of benchmark was made to encrypt “IVWeb” 5000000 times

You can see that the performance gap between WebAssembly and pure JavaScript is very close, confirming my suspicions.

This time I have uploaded the Benchmark code to GitHub repository:

[email protected]:PeacefulLion/wasm-benchmark.git

revelation

Given the power of V8, you don’t need WebAssembly for 90% of applications.

Implications: How to improve JS code performance?

  1. Provide default types when declaring variables to speed UP JIT intervention
  2. Do not easily change the type of a variable
  3. Does Node.js have JIT preheating like JAVA?

Summary and Prospect

WebAssembly isn’t perfect yet. But thread support, exception handling, garbage collection, tail-call optimization, etc., are already on WebAssembly’s to-do list.

In the future, WebAssembly can be used to:

  • Extended browser-side visual and Audio processing capabilities (H.265)
  • High-performance Web applications based on WebAssembly (encryption, gaming, mining?)

Webpack4 already supports importing wASM files.

In the future, it will be possible for WebAssemblies to reference directly through HTML tags, such as:

<script src="./wa.wasm"></script>;Copy the code

Or it can be referenced via JavaScript ES6 modules, such as:

import xxx from './wa.wasm'; ;Copy the code

Resource sharing

WAPM

A WebAssembly package manager

WasmExplorer

Online transfer from CPP to WASM

Refer to the article

WebAssembly status and practice

Web side H.265 player development and decryption

Quietly lift the veil of secrecy around WebAssembly


Pay attention to [IVWEB community] public number to get the latest weekly articles, leading to the top of life!