JS 漫谈

Author:

ADoyle/蔡博文

(其实我没想好名字)

Free-Control Version

Live Version

起因

// strict & sloppy modes
function test1() {
  arguments[0] = 0;
}

// strict & sloppy modes
function test4() {
  var args = [].slice.call(arguments);
}

那些编译到 JS 的语言

  • CoffeeScript
  • TypeScript
  • ClojureScript
  • Google Web Toolkit (GWT), Java to JS
  • pyjamas, Python into JS
  • ......

asm.js

&
Emscripten

C/C++ => LLVM => asm.js

Define an asm.js module

function GeometricMean(stdlib, foreign, buffer) {
  "use asm";

  var exp = stdlib.Math.exp;
  var log = stdlib.Math.log;
  var values = new stdlib.Float64Array(buffer);

  function logSum(start, end) {
    start = start|0;
    end = end|0;

    var sum = 0.0, p = 0, q = 0;

    // asm.js forces byte addressing of the heap by requiring shifting by 3
    for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) {
      sum = sum + +log(values[p>>3]);
    }

    return +sum;
  }

  function geometricMean(start, end) {
    start = start|0;
    end = end|0;

    return +exp(+logSum(start, end) / +((end - start)|0));
  }

  return { geometricMean: geometricMean };
}
// 64k heap
var heap = new ArrayBuffer(0x10000);
// fill a region with input values
init(heap, START, END);
// produce exports object linked to AOT-compiled code
var fast = GeometricMean(window, null, heap);
// computes geometric mean of input values
fast.geometricMean(START, END);

Invoke the module

asm.js

  • LLVM bitcode to JS

  • AOT

    • 避免运行时类型检查

    • 基于 TypedArray 的虚拟 heap

  • ​显式定义整数与浮点数(强类型)

    • ​x | 0

  • 当 AOT 失败,可以退化到 JIT

Pros

Cons

  • 优化场景有限

    • 只限于整数、浮点数计算,二进制数组优化

  • 浏览器支持有限

http://caniuse.com/#feat=asmjs

Emscripten

LLVM to asm.js compiler

OpenGL to WebGL or HTML5 API

PNaCl

(Portable Native Client)

C/C++ => LLVM => PNaCl Bitcode

WebAssembly

asm.js enhanced = WebAssembly

C/C++ => LLVM => wasm

or

asm.js => wasm

54  movq rax,rsi        ;; Dead code.
57  movq rbx,[rbp-0x28]
61  testb rbx,0x1
64  jnz 189  (0x7f7b20fa2a7d)
70  shrq rbx,32
74  movq rdx,[rbp-0x30]
78  testb rdx,0x1
81  jnz 237  (0x7f7b20fa2aad)
87  shrq rdx,32
91  movq rcx,[rbp-0x18]
95  xchgq rax, rdx

A binary format for JS, all JS, not only asm.js.

It's not a bytecode,

it's a binary encoding of the AST that the parser calculates.

 

benefits:

  • the JS engine can skip the parsing step
  • it's much more compact than the JS original source

In s-expression (.wast)

(module
    (import $i1 "m" "import1")
    (import $i2 "import2" "")
    (func $main (call_import $i1))
    (start $main)
    (func $f (call_import $i2))
    (export "f" $f)
)

WebAssembly code is represented as an

Abstract Syntax Tree (AST)

Binary Encoding

Text Format

memory {
  temp: zero 4;
  scale: hex 02000000;
}

func ifelse(cond i32, a i32, b i32) i32 {
  storeI32(temp, 10);
  if (cond) {
    return a > b;
  } else {
    return a < b;
  }
}

export func main() i32 {
  storeI32(temp, 0);
  var i i32 = 0;
  done: while (i < 10) {
    i = i + 1;
    if (i >= 7) {
      break done;
    }
  }
  return (i + ifelse(0, 1, 2) * 2) * loadI32(temp) + loadI32(scale);
}

In wasm format (.wasm)

  • 设计一个可移植,体积小,加载快的二进制格式
  • 设计人类友好可读的文本格式
  • 多平台
    • Browser
    • Android
    • iOS
    • NodeJS
    • IoT
  • 优化解码和解析速度
  • 兼容性
    • 兼容现有的 web 平台
    • 与 JavaScript 在相同的语义领域下执行

实质

  • 基于现有的 JavaScript 引擎 + wasm 解析器
  • 服务端提前编译
  • 重点在优化代码解析效率 (decode + parse),
    而非代码执行效率 (execute)

意义

Q: 执行效率还是那么低,有意义吗?

Demo

如果你使用 chrome 浏览器,通过 chrome://flags/  开启 webassembly 选项

ArrayBuffer

&

TypedArray

WebGL

Three.js, Canvas, OpenGL ES...

SIMD

Single Instruction Multiple Data

var a = [1, 2, 3, 4];
var b = [5, 6, 7, 8];
var c = [];

c[0] = a[0] + b[0];
c[1] = a[1] + b[1];
c[2] = a[2] + b[2];
c[3] = a[3] + b[3];
c; // Array[6, 8, 10, 12]
var a = SIMD.Float32x4(1, 2, 3, 4);
var b = SIMD.Float32x4(5, 6, 7, 8);
// Float32x4[6, 8, 10, 12]
var c = SIMD.Float32x4.add(a,b);

SIMD

var a = [1, 2, 3, 4];
var b = [5, 6, 7, 8];
var c = [];

for (var i = 0; i < 4; i++) {
  if (a[i] < 3) {
    c[i] = a[i] * b[i];
  } else {
    c[i] = b[i] + a[i];
  }
}

console.log(c); // [5, 12, 10, 12]
var a = SIMD.Float32x4(1, 2, 3, 4);
var b = SIMD.Float32x4(5, 6, 7, 8);

var mask = SIMD.Float32x4.lessThan(a, SIMD.Float32x4.splat(3));
// Bool32x4[true, true, false, false]

var result = SIMD.Float32x4.select(
    mask, 
    SIMD.Float32x4.mul(a, b),
    SIMD.Float32x4.add(a, b)
);

console.log(result); // Float32x4[5, 12, 10, 12]

SIMD

嵌入式/物联网

  • duktape
    • embeddable Javascript engine with a focus on portability and compact footprint
  • Tessel

游戏引擎

JS 正在进化

  • Typescript
  • Web App
  • Hybrid App
  • Web Game
  • IoT

讲了那么多概念,你究竟想说什么?

asm.js
Emscripten

PNaCl

wasm

ArrayBuffer

TypedArray

WebGL

SIMD

IoT

WebGame Engine

JS is more universal

JavaScript maybe not 

But it's fun

the best

JS 漫谈

By ADoyle

JS 漫谈

No more update

  • 4,090