Understanding asm.js

Tweet

asm.js is currently a trendy subject in web development. Reading a complete guide about asm.js, its goals, and its roadmap is impossible because you’d have to read multiple articles and put them together yourself. This article attempts to wrap up almost everything you need to know about asm.js using a step-by-step guide and real world examples, plus a couple of benchmarks.

History

JavaScript is one of the world’s most popular programming languages. You can use it in web browsers as a client-side language. Now, with the advent of NodeJS, JavaScript is also a popular language for server-side applications. Back in the day (actually, to this day), transpilers (source-to-source compilers) were used to hide some of JavaScript’s ugly parts. CoffeeScript, ClojureScript, and TypeScript are some of the more popular transpilers.

Transpilers mainly use an existing language (such as C or C++) or, they define a new language (like CoffeeScript). Then, instead of writing JavaScript, you can develop in this other language that the transpiler converts to JavaScript. In this article, we are going to review Emscripten, an LLVM bytecode to JavaScript transpiler.

So, What is asm.js?

asm.js is a strict subset of JavaScript. It is not a new language. asm.js is a restricted set of definitions that provide good performance characteristics. These definitions can be combined, like assembly language instructions, to create very fast JavaScript applications. asm.js takes advantage of some low level JavaScript features like Typed Arrays. It does not use any plugins or modules to run the JavaScript code, making it backward compatible.

How it Works

The main idea is generally about using JavaScript more strictly. For instance, eliminating the dynamic types. In order to provide an example, we are going to declare a variable and assign an integer value to it. Then, we declare another variable and assign the previous variable to the new one. Below, you will find the example in standard JavaScript.

var first = 5;
var second = first;

The corresponding asm.js syntax for the code presented above is as follows:

var first = 5;
//By using a bitwise operator, we make sure that the value is 32-bit integer
var second = first | 0;

The only difference between the first and the second code samples is the bitwise OR operator on the last line of the asm.js example. By using the bitwise operator we convert the value of the first variable to a 32-bit integer. This ensures that second is always treated as a 32-bit integer. asm.js has a number of other similar rules. By combining these rules with normal JavaScript, much faster code can be created. For more information about these rules and how they work please refer to the asm.js specification.

It is worth mentioning that it is not a good idea to write asm.js code by hand. The result would be hard to maintain and time consuming to debug. Based on this observation the question that remains is – how can we develop apps using asm.js?

The good news is that a few tools exist for generating JavaScript code according to the asm.js specification from other languages like C or C++. We will focus on Emscripten in this article, but keep in mind that a number of similar tools exist.

So, what is Emscripten? The answer is that it is an LLVM-to-JavaScript compiler. Emscripten accepts LLVM bytecode and converts them to asm.js JavaScript. So, how do you generate LLVM bytecode? You can use Clang to convert C/C++ codes to LLVM! In order to understand this process better, please consider the following diagram:

CPP to JS Workflow

Here are the steps to generate JavaScript code using Emscripten:
1. Create a C/C++ app.
2. Compile it using Clang to generate LLVM bytecode.
3. Pass the bytecode to Emscripten to get the JavaScript code.

It is worth mentioning that Emscripten performs the last two steps itself. Thus, the only thing that you need to do is pass the C/C++ code to Emscripten and get the JavaScript output.

Hello World

Let’s write a simple program in C++ and convert it to an asm.js-based JavaScript application. The following, is a C++ code snippet that calculates the Fibonacci number for n=45.

#include <stdio.h>

int fib(int x) {
  if (x < 2) {
    return 1;
  } else {
    return fib(x - 1) + fib(x - 2);
  }
}

int main() {
  int result = fib(45);

  printf("%d\n", result);
  return 1;
}

As you can see, the algorithm is pretty simple and straightforward. To convert this C++ code to JavaScript, you need to install Emscripten first. Refer to the Emscripten wiki for installation instructions. After installing Emscripten, you can simply convert the C++ code by using the following command.

./emcc -O1 -s ASM_JS=1 ./hello_world.cpp

By setting the ASM_JS property to 1, you force Emscripten to emit JavaScript code based on the asm.js specification. After issuing the command, you will get an a.out.js file. This is a JavaScript file which is created from your C++ code. In order to execute the corresponding JavaScript file, you can install Node.js and issue the following command.

node ./a.out.js

By executing the above command you will see the output of the application. Congratulations, you made your first asm.js app.

Let’s See a Benchmark

In this section, we provide a comparison of the execution time of the native JavaScript code for the Fibonacci example presented above with the asm.js-based version. To have a more suitable picture for this comparison, we compile the C++ code using the Clang compiler and execute the corresponding generated native code. Therefore, we can compare three different environments – (1) normal JavaScript, (2) asm.js code, and (3) native application. To compile the C++ code using clang, simply issue the following command:

clang ./hello_world.cpp

This will create an a.out file containing your native executable.

The normal JavaScript example is shown in the following code.

var result = 0;

function fib(x) {
  if (x < 2) {
    return 1;
  } else {
    return fib(x - 1) + fib(x - 2);
  }
}

result = fib(45);
console.log(result);

We can run the normal JavaScript and asm.js examples using the following commands.

node ./handmade.js
node ./a.out.js

To execute the native app, run the following command.

./a.out

The resulting execution times are shown in the following figure. The experiments were performed on an OS X 10.9.2 operating system leveraging the latest version of Clang, Node.js, and Emscripten.

JS vs. asm.js vs. Native Performance

Conclusion

In this article, we talked about asm.js, one of the Mozilla’s specifications to create a low-level JavaScript environment. asm.js is a faster subset of the JavaScript programming language. We studied Emscripten, which is a tool to convert C/C++ code to LLVM bytecode and then to asm.js JavaScript code. We also created a very simple “Hello world” program using C++ code which we converted to asm.js using Emscripten. Furthermore, we provided some benchmarks in order to demonstrate the considerable difference in performance between the regular and asm.js-based JavaScript codes. It should be noted that asm.js is still a work in progress, and the performance gains should get even better in the future.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Josh Bambrick

    I would like to find out how/if you can interact with the dom in C code compiled to asm.js javascript. There are a number of APIs provided by the browser – can you still use these in code compiled to asm.js javascript? In the above helloworld program, the printf was converted to console.log – where can we find out about other standard API conversions?

    • jokeyrhyme

      The idea is to do this for raw algorithms, like 3D game engines, encryption, etc. ASM.JS is intentionally limited to certain numeric data types and operations.

      Use regular JavaScript for DOM APIs, and for gluing together your calls to ASM.JS functions.

      • Josh Bambrick

        This is all fine and reasonable, but I haven’t seen any talk about the interface that allows your javascript code to communicate with your asm.js code. In fact, I can’t seem to find an information at all about how asm.js code can interface with the outside world for inputs and outputs – obviously there must be something as otherwise your code would be useless. The only such mention that I can find is in this article where it ouputs console.log.

    • afshin

      The main idea of using asm.js is to boost the algorithms performance, not the performance of fetching or altering DOM elements. For instance, you can declare or alter integer variables faster than before using asm.js specifications.

      Also, using asm.js you can provide a better performance in loop statements, etc.

  • SixKnight

    Why I should program in C++ and compile then my code to javascript? In my opinion this makes absolutely no sense. Also, how would you debug your C++ code if it’s not anymore C++?
    There are already enough languages in web development (HTML, CSS, JavaScript, PHP/Ruby/Perl whatever) and I don’t think we need more.

    • ᴍᴀsᴏᴜᴅ

      There are a lot of topics that it can be very useful, for example asm.js allows a developer to bring C/C++ games to the web and reach near-native speeds. With WebGL and Web Audio, it enables fast, rich, and immersive 3D gaming experiences on the Web without plugins.

      take a look: https://blog.mozilla.org/blog/2014/03/12/mozilla-and-epic-preview-unreal-engine-4-running-in-firefox/

      • afshin

        Indeed.

    • afshin

      As I said before in the article, the idea of asm.js is to provide a low-level JavaScript environment. Thus, you can gain a better performance by using a dynamic language like JavaScript with asm.js approach.

      The asm.js comes handy when you need to build a high-performance app, like a 3D game using Unity game engine or something.

  • techs

    Few important things that i can’t google…as of now oct 15, 2014. Which browsers support asmjs and how much? which plan to do soon? ..secondly, how do you run asmjs code in browser..what do you have to do exactly? thirdly, how does normal js code suppose to interact with asmjs code? 4th, doesn’t this mean asmjs can be used to speedup nodejs apps as well.? 5th, when asmjs will be ready, or usuable? 6th, what are the things that you are allowed to do in c++?

    Please answer as many as you can.

    • spongessuck

      At least Firefox and Chrome support it right now. asm.js code runs exactly like Javscript does- just include the .js file.

      asm.js code IS Javascript. You can call a function in an asm.js file from regular Javascript. I don’t see why it couldn’t be used to speed up algorithms used for Node.js.

      You can play a few demos of games using asm.js right now at the Humble Bundle homepage- it should be up for a little while longer:

      https://www.humblebundle.com/

  • Thomas Körner

    I can’t get it working. After porting the C++ to JavaScript with Emscripten, it puts out a really big file with nearly 10000 lines of code and its much slower than the handwritten Javascript. I tried different optimizationlevels and other options to get better result, but no success. Somebody have an idea, whats the problem?

  • http://thereactivearts.com Quazi Irfan

    This may look like a stupid question, but how low level can asm.js/javascript can get? Is it strictly confined within the browser? or can it ever be able to execute command line operations on any OS?