Compiling C/C++
to JavaScript

GDC 2013

Alon Zakai - Mozilla

Why JavaScript?

1. Because it's there

JavaScript is the only standards-based language in all web browsers

2. And it can be fast

Despite JavaScript's dynamic nature, modern JavaScript VMs are quite speedy, and even more so with asm.js as we saw in the demos before!

Why Compile to JavaScript?

1. Reuse existing code


C/C++  =>  LLVM  =>  Emscripten  =>  JavaScript


Automatically convert to JavaScript, no need for time-consuming manual rewrites

2. Speed

Compiled code can be faster than handwritten JavaScript (!)

Modern JavaScript Engines

Detect types at runtime and generate efficient machine code


  function sum(x) { // in practice, called with small integers
    var s = 0;
    for (var i = 1; i < x; i++) s += i; // in practice, i is an integer
    return s;
  }
            

Modern JavaScript Engines

Support features like typed arrays that are easy to make fast


  var heap = new Int32Array(10240);
  // ..
  function sumArray(x) {
    var s = 0;
    for (var i = 0; i < x; i++) s += heap[i]; // fast read of int32
    return s;
  }
            

Compiled Code vs. Handwritten JS

Compiled code from a statically-typed language is still implicitly typed, so optimizable

Easy and natural to make compiled use utilize typed arrays for speed

Microbenchmarks

Realistic/large benchmarks

Limitations

While modern JavaScript engines are fast in many cases, they can have trouble on large applications:


More functions, more variables - harder to figure out types

Issues with deoptimizations / recompilations

asm.js

asm.js, which began as a research project at Mozilla, aims to fix these issues


asm.js is an extraordinarily optimizable,
low-level subset of JavaScript


100% backwards compatible: Not a new new language, not a new VM

But can be optimized like a low-level VM

asm.js - example


  function strlen(ptr) { // calculate length of C string
    ptr = ptr|0;
    var curr = 0;
    curr = ptr;
    while (MEM8[curr]|0 != 0) {
      curr = (curr + 1)|0;
    }
    return (curr - ptr)|0;
  }
            

If you've ever seen compiled code from Emscripten or Mandreel, |0 etc. will look familiar

asm.js just formalizes these techniques and gives guarantees (via a type system) they are used properly

asm.js - why it works

Ensures that types are not mixed up

Makes it possible to reason about global program structure


Helps in existing JavaScript engines by making it simpler to detect types and avoid them changing later

Makes ahead of time (AOT) compilation possible with asm.js-specific optimizations

Microbenchmarks

Realistic/large benchmarks

asm.js - Status

Emscripten can emit asm.js output

asm.js code already works in all modern browsers

With asm.js-specific optimizations in Firefox Nightly, performance is within 2x of native. And that's just the beginning!

Big Picture:
Compiling C/C++ to JavaScript

Mature open source tools (emscripten, LLVM, etc.)

Fast code execution, getting close to native speed

Thank you!

Questions?