Understanding asm.js

Share this article

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.

Frequently Asked Questions (FAQs) about Asm.js

What is the main purpose of Asm.js?

Asm.js is a strict subset of JavaScript that acts as a low-level, efficient target language for compilers. It was designed to allow applications and games to run at near-native speed in web browsers, without requiring plugins or non-standard extensions. This makes it a powerful tool for developers who want to create high-performance web applications.

How does Asm.js achieve near-native performance?

Asm.js achieves near-native performance by limiting itself to a subset of JavaScript that can be optimized effectively. It uses a static typing system and avoids certain JavaScript features that are difficult to optimize, such as garbage collection. This allows JavaScript engines to generate efficient machine code for Asm.js programs.

Is Asm.js compatible with all web browsers?

Asm.js is designed to be compatible with all ECMAScript compliant web browsers. However, not all browsers optimize for Asm.js. Browsers that do optimize for Asm.js, such as Firefox and Chrome, can execute Asm.js code much faster than regular JavaScript.

How does Asm.js compare to WebAssembly?

Asm.js and WebAssembly are both low-level languages designed for high-performance web applications. However, WebAssembly is a binary format, while Asm.js is a subset of JavaScript. This means that WebAssembly can be smaller and faster to decode, but Asm.js has the advantage of being backwards compatible with all JavaScript engines.

Can I use Asm.js in Node.js?

Yes, Asm.js can be used in Node.js. However, since Node.js is not a web browser, the performance benefits of Asm.js may not be as significant. Nonetheless, Asm.js can still be useful in Node.js for running compiled code.

How do I compile code to Asm.js?

There are several compilers that can target Asm.js, including Emscripten and Mandreel. These compilers can take code written in languages like C and C++, and compile it to Asm.js.

What types of applications can benefit from Asm.js?

Applications that require high performance, such as games, image processing, and physics simulations, can benefit from Asm.js. By compiling to Asm.js, these applications can run at near-native speed in the browser.

Is Asm.js still relevant with the advent of WebAssembly?

While WebAssembly has many advantages over Asm.js, Asm.js is still relevant. It is fully compatible with all JavaScript engines, and can be a good choice for applications that need to support older browsers.

Can I write Asm.js code by hand?

While it is possible to write Asm.js code by hand, it is not recommended. Asm.js is designed to be a target for compilers, and writing Asm.js code by hand can be error-prone and difficult.

What is the future of Asm.js?

The future of Asm.js is uncertain. With the advent of WebAssembly, many developers are shifting their focus to the newer technology. However, Asm.js is still being used and maintained, and it remains a viable option for high-performance web applications.

Afshin MehrabaniAfshin Mehrabani
View Author

Afshin Mehrabani is a software engineer and an open source programmer. He is also a computer software engineering student. He started with programming and PHP web development when he was 12 years old. Later, he entered the Iran Technical and Vocational Training Organization. He was ranked first and has also bagged a golden medal in a competition on web development in his country. He also became a member of the Iran's National Elite Foundation by producing a variety of new programming ideas.

asm.jsEmscriptenNode-JS-Tools
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week