asm.js

Asm.js is a highly optimized subset of the JavaScript language. Optimization of JavaScript engine performance is achieved by avoiding certain mechanisms and patterns (mainly garbage collection and type determination) that are difficult to optimize for the JavaScript engine. In other words, while normal JavaScript code is type-loaded and garbage collected automatically, writing ASM.js style code means that the programmer needs to manage memory and determine data types.

Asm.js does not provide any additional syntax, as long as you write asM.js code, it is automatically recognized in JavaScript engines that support ASM.js optimization, allowing the engine to implement its own optimizations, and will work in engines that do not support ASM.js.

Hand-write asM.js examples

The first thing to solve is the problem of variable types in JavaScript

var a = 10;
var b = a;
Copy the code
var a = 10;
var b = a | 0;
Copy the code

The difference between the above two pieces of code is that the value type of b in the first piece of code is determined at run time, whereas b in the second piece of code is always treated as a 32-bit integer. The same and the limitation on the operation, such as (a + b) | 0 limit of two variables and operation for more efficient integer arithmetic. Running the above code in a JavaScript engine that supports ASM.js does low-level optimization.

The second problem to solve is memory allocation. As we all know, JavaScript does not provide an API for garbage collection. Most developers will think of setting unused variables to NULL in JavaScript, such as:

// Create an array of length 10000
var a = new Array(10000).fill('hello');

a = null;
Copy the code

For garbage collection, a = NULL simply tells the browser that the array of length 10000 is no longer referenced by any variable and can be reclaimed. The browser has its own idea of when to reclaim.

Memory allocation in ASM.js is different from this mechanism. It is controlled by the programmer himself. Use an ArrayBuffer to create a data buffer that can be stored and valued without the cost of memory allocation and garbage collection. ArrayBuffer can’t direct operation, but through type array object and DataView object (view), please refer to the specific usage MDN | ArrayBuffer, below is an example

// Create a 64K data buffer
var heap = new ArrayBuffer(0x10000);

// Use an array of 64-bit floating-point values to reference this buffer
var arr = new Float64Array( heap )

Copy the code

For a more complex example, use ASM.js-style code to write a function that computs the product of adjacent numbers between two numbers, stores it, and computs the sum

function ASM (heap) {

  var arr = new Int32Array(heap);

  function foo(x, y) {
    x = x | 0;
    y = y | 0;

    var i = 0;
    var p = 0;
    var sum = 0;
    for (i = x | 0; (i | 0) < (y | 0); p = (p + 8) | 0, i = (i + 1) | 0) {
      sum = (sum + i * (i + 1)) | 0;

      arr[p >> 3] = (i * (i + 1)) | 0;
    }

    return +sum;
  }

  return foo;
}

var heap = new ArrayBuffer(0x1000);

var foo = ASM(heap)

foo(0.1024) / / 357913600

Copy the code

Asm.js code is usually wrapped in a “module” mechanism, such that the memory area variables are private and cannot be changed externally. In the above code, ArrayBuffer is used to allocate memory, Int32Array is used to specify the data type, and each data is used with a special symbol to identify the data type. In engines that support ASM.js, these are signals that trigger optimization, while in engines that do not support ASM.js, These symbols are normal operators and do not affect the result.

Emscripten

In practice, it is not possible to write the ASM. js specification code by hand, which is extremely cumbersome and error-prone, so asM. js code is usually compiled from other languages, such as C/C++ code compiled into ASM. js using Emscripten.

Install Emscripten

$ git clone https://github.com/juj/emsdk.git
$ cd emsdk
$ ./emsdk install latest
$ ./emsdk activate latest
$ source ./emsdk_env.sh

Copy the code

Emscripten is very simple to compile and use

  1. Write a C++ program hello. Cc.
#include <iostream>

int main (a) {
  std: :cout << "Hello World" << std: :endl;
}
Copy the code
  1. Use the following command toC++Source code compiled intoasm.js.
emcc hello.cc
Copy the code

The output file a.ut.js is the JavaScript code for the ASM. js specification, which executes main by default.

WebAssembly

WebAssembly bytecode is a kind of machine code that is flattened out for different CPU architectures. WebAssembly bytecode cannot run directly on any CPU architecture, but it is very close to the machine code and can be translated into the machine code of the corresponding architecture very quickly. Therefore, WebAssembly runs at similar speed to the machine code. This sounds a lot like Java bytecode.

Before WebAssembly, browsers could only run.js code files. JavaScript was the only language for Web application development, but webAssembly-enabled browsers can now run.wasm code files.

WebAssembly is almost never written by hand. It is usually compiled from other languages. Currently, high-level languages that can compile WebAssembly include:

  • AssemblyScript: grammar andTypeScriptConsistent, low learning cost for the front-end, written for the front-endWebAssemblyThe best choice;
  • C ++: the official recommended way;
  • Rust: The syntax is complex and the learning cost is high, which may not be suitable for the front-end.
  • Kotlin: grammar andJava,JSSimilarly, language learning is cheap;
  • Golang: Grammar is easy and cheap to learn.

Hello world

Compile to WebAssembly using AssemblyScript, first install

yarn global add AssemblyScript/assemblyscript
Copy the code

Write the source code demo.ts

export function foo (x: i32) :i32 {
  return x * x;
}
Copy the code

Use ASC Demo. ts -o demo.wasm to compile the code and use js code fetch method to load the WASM module

fetch('./demo.wasm')
  .then(res= > {return res.arrayBuffer()})
  .then(WebAssembly.instantiate) // Compile to machine code for the current CPU architecture and instantiate it
  .then(module= > { // module is the WebAssembly module
    console.log(module.instance.exports.foo(100))})Copy the code

conclusion

Asm.js and WebAssembly are both underlying technologies for optimizing the performance of Web applications, and they are often compiled from other languages. Asm.js is a subset of JavaScript, so it works on browsers that don’t support asM.js optimization, and its file type is text; WebAssembly is a newer technology that provides a new API, doesn’t work on unsupported browsers, and its file type is binary bytecode. Although these two technologies are extremely improve the performance of web programs, but the general development will not use, only in intensive computing, graphics processing and other computing scenarios can play their huge advantages.

About the author: Ye MAO, Reed Science and technology Web front-end development engineer, representative works: Lipstick challenge network red small game, reed science and technology official website. Good at website construction, public account development, wechat small program development, small games, public account development, focus on front-end framework, server-side rendering, SEO technology, interaction design, image rendering, data analysis and other research.

Join us: [email protected] visit www.talkmoney.cn to learn more