Tuesday, July 2, 2013

JavaScript's new face

Two and a half years ago I wrote my post about Io. In a comment to that post I was asked about my opinion on node.js, and I replied that it will not help JavaScript to become a better programming language. I also compared it to Ruby on Rails and stated that there are more interesting projects like Rhino or Phonegap. I thought back then that node.js is just another fashionable toy, and that developers will sooner or later loose interest in it.

From a time perspective my opinion turned out to be completely wrong. Thanks to node.js JavaScript gained incredible popularity, much higher than I could ever expect: today node.js is the second most followed repository on Github, and 60% of the most starred projects are now JavaScript or JavaScript-related. I console myself that I was right, at least partly, about two things. First, node.js impact on JavaScript has indeed been similar to the Rails impact on Ruby - it helped the language to break out of its niche and become a popular programming platform. Second, despite its popularity, JavaScript is still not a good language to build large applications. Of course it's doable, but it's also doable in Scheme or Fortran - it's just much harder, but not impossible. But taking into account the language history, especially the fact that Netscape's upper management requirement was that it had to be done in ten days and "look like Java", it is probably the best thing that could have been done, and Brendan Eich deserves a lot of respect for his work. However, after 13 years, JavaScript is still the only programming language supported by the leading web browsers - and because their evolution is relatively slow, it is very hard to fix most of its deficiencies. I never liked JavaScript for its counter-intuitive scope of "this" and for making object oriented programming unnecessarily complicated, and I know quite a few programmers who feel the same.

There is a solution to this problem, however: using JavaScript only as an intermediate language, a kind of bytecode or assembly. There is an impressive list of languages which can work on top of JavaScript, with CoffeeScript being my favourite one. One of the most well known early adapters of CoffeeScript is Dropbox, which migrated all its frontend from JavaScript to CoffeeScript. CoffeeScript is also a default JavaScript compiler in Ruby on Rails since version 3.1. But there are developers who took the whole idea a step further. Alon Zakai created emscripten, a transcompiler which can translate an LLVM bitcode to JavaScript. It means that you can compile a C or C++ source code with LLVM and then, after passing it through emscripten, make it run in the web browser. There are some most impressive applications ported to JavaScript directly from C++, including Unreal Engine 3, ScummVM (which allows you to play some old classic point-and-click DOS games in a web browser without using any emulator), and even whole programming languages, like Lua, Ruby or Python.

I decided to give it a try and installed emscripten on a quad-core Intel i5 2.6 GHz laptop with 8GB of RAM and Ubuntu 12.04. It is crucial to remember at this point to use precisely the same LLVM version as recommended by emscripten's author (current version requires LLVM 3.2 and will not work correctly with any higher or lower versions, especially those provided by Ubuntu repositories). I did some tests compiling my brute-force solution to Project Euler problem 96, which involves solving 50 sudoku puzzles with different difficulty levels. The source was 196 lines of C++ code, which I compiled to native code with clang and to JavaScript with emscripten with and without optimizations. Then I ran the compiled code in different execution environments and noted down execution times reported by the application. Here are the results:

clangemccemcc -O2
shell
1s
-
-
node.js
-
12s
3s
Chrome
-
10s
2s
Firefox 21
-
171s
78s
Firefox 22
-
23s
18s

You should notice a huge performance difference between Firefox 21 and 22. It is because Firefox 22 includes OdinMonkey, an improved Mozilla JavaScript engine, which is optimized for running a strictly defined, low-level subset of JavaScript, known as asm.js. It is quite possible that Google Chrome will also support asm.js, and because node.js uses Google V8 JavaScript engine we can expect that C++ applications compiled to JavaScript will soon be competitive in terms of speed to the native ones.

2 comments:

Ivan said...

Hi, from the numbers you have given it seems V8 does not need asm.js, because even now it's significantly faster compared to Firefox.

Krzysztof Kliś said...

You are absolutely right! But it is possible that thanks to supporting only a subset of Javascript, some parts of V8 can be optimized even more, and make Chrome even faster than it is now :)