navigation

Lately I’ve been very intrigued about Mozilla’s asm.js specification.
ASM.js is a subset of javascript that allows javascript interpreters to compile
code ahead of time, directly into assembly code. This results in huge speed increases.

Current benchmarks of asm.js code running in Firefox’s Nightly build, place
javascript at only half the speed of native compiled code! A big difference
from the usual, which is around 4 to 10 times slower. One fun showcase
of this was the recently ported Unreal Engine 3 to Asm.js.

Of course, being curious and well caffeinated, I like to play around. I did a simple
benchmark and a little proof of concept of my own. But first, let’s quickly
go over asm.js.

asm.js Modules in a nutshell

Firstly, a disclaimer. asm.js code is a pain to write by hand. (I do so because I
drink too much coffee…) I don’t really recommend starting any large project thinking that you’ll
write it in asm.js from scratch. Likely, the best way to leverage asm.js will be to write in
another language (like C++, or something like LLJS), and then
“compile” it into asm.js. The painful part is mainly that it feels like
writing in two languages at once. It’s javascript… but it feels like something
else… anyways, let’s move on.

Asm.js contexts begin with a declaration like this:

"use asm";

This is in the spirit of the "use strict"; declaration, that you are hopefully
familiar with. (If not, google it. It’s good to know).

This will most often be placed inside a function that acts as a “factory”
for an asm.js module. This asm.js module format looks like this:

When this function is run, it will return an instance of an asm.js module.
If asm.js is supported, the methods in the returned object will be compiled
into native code. If not, they will be javascript with identical functionality.

Inside the module factory, stdlib will hold standard global functionality
(like Math), foreign is user specified and can be used to escape back into
regular javascript, and heap is a fixed-size ArrayBuffer for storage.

The magic that happens in between relies on a very restrictive requirement
that all primitives must be statically typed as integers, or floats.
Numerical computation is pretty much all you can do in an asm.js context
(and that’s why it’s so fast). Of course, javascript doesn’t allow for declaring
types, so this is done by transforming variables into their types like so:

However, one of the big pains to writing it by hand is dealing with memory allocation.
The only thing you really have access to in terms of memory, is the fixed-size
ArrayBuffer you specify when you instantiate the asm.js module. You then
have to then create views into the array buffer to manipulate data.

Easier asm.js Memory Management

Memory management becomes cumbersome. After playing around with it, I decided I needed to write
a quick helper module to make
this easier.

Basically, the helper lets you manipulate “collections” of objects that store
all of their (primitive) properties in an array buffer. For example:

var coln = ASMHelpers.Collection({
foo: 'int16'
});

This would create a collection instance that holds objects that hold
16 bit integers in their foo properties. You can then add one of these
objects to the collection and all of the ArrayBuffer memory management is
taken care of behind the scenes:

coln.add({
foo: 42
});
var obj = coln.at( 0 );
obj.foo; // => 42

The objects have getters and setters defined, so if you change the
property, it will get changed in the array buffer.

obj.foo = 34; // changed in array buffer

Unfortunately, non of those tricks can be used in the context of an asm.js
module. But that’s ok, because the helper collection sets up
pointer addresses that can be used in asm.js. Here’s how: