An early look at WebAssembly

published: 05 August 2016

reading time: 10 mins

author: Thom

thom

Keeping on the cutting edge of frontend technology can feel like you're trying to herd cats at times. The huge choice of tooling, libraries and frameworks has simultaneously improved the developer experience and caused a lot of buzz about 'fatigue' and 'churn' with people trying to keep up. In this post I'm going to take a look at what may significantly change how we develop webpages in the future and become The Next Big Thing™: WebAssembly.

WebAssembly is about as bleeding-edge as you can get at the moment. Even the logo hasn't been finalised yet. But before we look at WebAssembly, we need to talk about translating compilers.

A translating compiler (transpiler) is a compiler that can take the source code of a program written in one programming language and produce the equivalent source code for another programming language. For a while we've been able to use transpilers like Babel to convert non-JavaScript code to JavaScript. This allows us to write code in languages with different features or syntax and transpile it to run in any environment that JavaScript can. Typically this is used for compile-to-JS languages like TypeScript or CoffeeScript, but even extends to being able to write code from proposed versions of the JavaScript spec and run it in older browsers. Literally allowing you to write code from the future.

Emscripten is a transpiler that can convert much lower level languages like C and C++ to JavaScript. It's been used to port things like the Unreal Engine and SQLite to the browser. If you've ever wanted to run Windows 95 in the browser, Emscripten has got your back.

Windows 95 in the browser

 

While it's true that Emscripten transpiles to JavaScript, it would be more accurate to say it transpiles to asm.js, a subset of JavaScript designed in such a way that browsers can support running it with similar performance characteristics to the original languages. This brings the performance significantly closer to the corresponding native implementation.

Emscripten allows people to use the language and paradigms of their choice in the browser, but since the compile target is JavaScript (despite the optimisations from asm.js and ahead-of-time compiling) there is still a performance bottleneck.

This is where WebAssembly comes in.

WebAssembly is a specification for a native bytecode compile target. The idea is that you can compile the language of your choice directly to a WebAssembly executable and have it run as true native code. This is great news for people wanting to do 3D rendering, compression or anything performance intensive directly on the web.

Currently, the only way to produce a WebAssembly binary is from a piece of asm.js source. We could use Emscripten to do this, but let's keep it simple and write our own;

function AddModule(stdlib, foreign, heap) { "use asm"; function add(x, y) { x = x|0; y = y|0; return (x + y)|0; } return { add: add }; }

This should be fairly familiar. Anyone used to writing in strict mode will recognise the prologue directive for notifying the browser to treat this code as asm.js. The bitfield OR zero operation is used in asm.js to denote integers.

Next we need to download a copy of the WebAssembly toolchain Binaryen and compile it. After compiling, we can use the asm2wasm tool to produce a human-readable representation of the WebAssembly bytecode in the current S-Expression format.

(module (memory 256 256) (export "memory" memory) (export "add" $add) (func $add (param $0 i32) (param $1 i32) (result i32) (i32.add (get_local $0) (get_local $1) ) ) )

Lisp programmers will probably feel quite at home looking at this syntax. For everyone else, you're looking at a tree representation of the abstract syntactic structure of WebAssembly bytecode. From here, we can use wasm-as to produce our final binary;

00 61 73 6D 0B 00 00 00 04 74 79 70 65 87 80 80 80 00 01 40 02 01 01 01 01 08 66 75 6E 63 74 69 6F 6E 82 80 80 80 00 01 00 06 6D 65 6D 6F 72 79 85 80 80 80 00 80 02 80 02 01 06 65 78 70 6F 72 74 86 80 80 80 00 01 00 03 61 64 64 04 63 6F 64 65 8C 80 80 80 00 01 86 80 80 80 00 00 14 00 14 01 40 04 6E 61 6D 65 86 80 80 80 00 01 03 61 64 64 00

Now we finally have a web executable! Unfortunately... 

Error

After playing around trying to enable the experimental WebAssembly support in Chromium it just won't run for me, even after manually hex editing the binary to try and conform to whatever implementation I have installed. 

Being so early in the development timeline of WebAssembly I kind of expected this to happen. Not put off, I decided to try the latest nightly of Chrome Canary.

Success

Hurrah! Finally running native code on the web. I must have been using a more recent version of Binaryen than that is implemented in Chromium. Enabling WebAssembly support exposes a `Wasm` global variable and you can use its instantiateModule method to load your custom WebAssembly binary.

So where does this leave JavaScript now that anyone can write in their preferred language and have it run on the web? One thing to note is that WebAssembly isn't exactly meant to be a replacement for JavaScript, but it will prove to be a much better alternative in resource intensive operations. It is intended that things like complex DOM manipulation will be better suited to being done in JavaScript.

It's very early days for WebAssembly at the moment. Expect support to gradually improve and the intermediate asm.js step to be phased out as tooling develops.

Further information including a roadmap can be found at GitHub.

author
Thom

Thom is a web application developer focused on data visualisation and modern tech.

more articles