When I heard of it, it sounded great: a highly optimizable subset of JS, that can be dropped seamlessly into any existing code. It reminded me of Winamp's charming evallib compiler, used in AVS and Milkdrop, which only did floating point expressions. It spawned a whole subculture of visual hackery based on little more than a dozen or so math functions and some clever graphics routines. It showed the power of being able to turn scripts into optimal machine code on the fly, and having a multimedia platform at your disposal while doing so.
Asm.js deserves closer inspection for two reasons. First, it's the one "native browser VM" that doesn't massively reinvent wheels. Second, it's the only time a browser vendor's "next-gen JS" attempts have actually gotten everybody else to pay attention. But what are we transitioning into exactly?
LLVM to Asm
To understand Asm.js, you have to understand LLVM. Contrary to its name, it's not really a Virtual Machine but rather a compiler. More precisely, it's the modular core of a compiler, along with assorted tools and libraries. You plug in different front-ends to parse different languages (e.g. C or C++), and different back-ends to target different machines (e.g. Intel or ARM). LLVM can do common tasks like optimization in a platform and language agnostic way, and as such should probably be considered an open-source treasure.
LLVM architecture (source)
What this means in practice is a directive "use asm" in a block of tailored code, along with implicit type annotations for arguments, casts and return values. Type casts are
double. These annotations are parsed and validated, and optimized code is emitted for the entire code block. This doesn't look bad at all. However, it also looks nothing like real Asm.js code in the wild.
Looking around, in the browser there's CoffeeScript, TypeScript and Dart. Outside, there's Python, Ruby, Go and Rust. Even CSS now has offspring. The future of the web is definitely multilingual and some people want to jump ship, they're just not sure which one will actually sail yet.
When faced with a legacy mechanism like UTF-8 or indeed Asm.js, we have to ask, is it actually necessary? In the case of UTF-8, it's a resounding yes: we need to assign unique names to things, and this name has to work with both modern and legacy software, passing through unharmed as much as possible. UTF-8 solves a bunch of problems while causing very few.
But with Asm.js, it's just a nice to have. All Asm.js code is new, there is no vault of legacy code that will stop working if we do it wrong. We can already generate functioning JS for legacy browsers, along with something new for alternative VMs. Having one .js file that does both is merely a convenience, and a dubious one at that.
Indeed, the unique appeal of Asm.js is for the browser maker who implements it first: it lets their JS VM race closer to that much desired Native line. It also turns any demo that uses Asm.js into an instant benchmark, which other vendors have to catch up with. It's a rational choice made in self interest, but also a tragedy of the commons.
Maybe that's a bit hyperbolic, but work with me here. There's a serious amount of defeatism and learned helplessness at work here, and again a contradiction. We seek to get ever closer to native performance, yet fall short by design, resigning ourselves to never quite reaching it. I can't be the only one who finds that completely bizarre, when there's laptops and phones running entirely on a web stack now?
Part of Unreal Engine, JSified.
So fast forward a year or two. Firefox has completed its wishlist and Asm.js has filled its instruction set gaps. Meanwhile Chrome has continued to optimize V8. Will they have the same new language features that Firefox has? Will they officially support Asm.js? Or push Dart and PNaCl, expanding their influence through ChromeOS and Android? Your guess is as good as mine. As for IE and Safari, I'll just pencil in "behind" for now and leave it at that.
But a certain phrase comes to mind: embrace and extend. From multiple fronts.
It looks like a future where your best bet to get things running fast in a browser is to do decidedly non-web things. You compile something like C to the different flavors of web at your disposal, either papering over their strengths, or tailoring for each individually. That's not something I personally look forward to, as much as it might arouse Epic's executives and shareholders today.
I admit, I don't know what the post-JS low level future should look like either, but it should probably be closer to LLJS's nicely struct'ed and typed order, than either the featherweight of Asm.js or the monolithic Flash-replacement that is PNaCl.
The big problem with Asm.js isn't that it runs off script rather than bytecode, it's that the code is generated to match how JS engines work rather than how CPUs compute. At best it will be replaced with something more sensible later or just fizz out as an optimization fad. At worst it'll become the IA-32 of the web, still pretending to be an 8086 if asked to.
Looking ahead, there's computation with WebCL, advanced GLSL shaders and more on the horizon. That's a whole set of problems that can become much simpler when "browser" is a language that everyone can speak, to and from, rather than a weird write-only dialect built on a tower of Babel. We don't just need a compilation target, we need a compilation source, as well as a universal intermediate representation.
And this is really the biggest contradiction of them all. Tons of people have invested countless hours to build these VMs, these new languages, these compilers, these optimizations. Yet somehow, they all seem to agree that it is impossible for them to sit down and define the most basic glue that binds their platforms, and implement a shared baseline for their many innovations.
We really should aim higher than a language frozen after 10 days, thawing slowly over 20 years.