Why do we only have JS in the browser

The evolution of the Web has seen JavaScript (JS) embed itself into Web user agents as the standard (and standards-backed) client-side programming language that lets you access the user agent’s DOM for a given page, and access standardised user agent APIs to communicate with the outside world.

The Web’s programming model lets you do other important things — persisting data across the increasingly blurred boundary of a page request springs to mind — but overwhelmingly JS is sent to the user agent and executed by it to communicate with remote systems and update the DOM based on the results of that communication.

Today’s state of things is such that it’s possible to create rich, full-featured and computationally powerful applications that are delivered by remote systems and executed locally, completely in the Web client. Indeed, I’m writing this blog entry entirely on a complete computer system whose operating system only exists as a Web browser.

You even have mostly ubiquitous access to 3D hardware acceleration on your system using modern clients. It’s a pretty exciting and fertile ground to operate in as a programmer.

There’s just one problem: you’re limited to client-side execution inside just one programming language runtime. Note that I didn’t solely mention JS there, given the number of other languages that can compile to JS and be executed by the client’s JS runtime.

The modern embodiment of that is asm.js, which defines a subset of JS for other compilers to emit during code generation. Type wise, because of JavaScript’s lack of native number types, you have a muddle of numerical value types in asm.js that get coerced and manipulated to fit JavaScript’s limited numerical computation model.

Care has been taken to give asm.js a set of value types that map reasonably well to the basic execution core of most modern CPUs, but it’s limited — no explicit vector types for example — and it necessarily requires constant casting in the JS core for integer arithmetic. That’s no different to JS on its own, but it means asm.js inherits that restriction.

There’s also Emscripten, which is an LLVM bitcode compiler which emits JS. Any language that can be compiled to LLVM bitcode therefore also has a chance of executing in the browser, which opens the doors even wider than asm.js. C and C++ are the popular source languages by virtue of the clang LLVM compiler front-end.

Obviously you need to be able to compile all of your program’s library dependencies to LLVM bitcode before Emscripten can compile it to JS, which necessarily is highly likely to include libc or libstdc++ if you’re compiling from C or C++. LLVM gives you help there in the latter case, via libcxxabi, which Emscripten makes use of, and its libc support is also quite mature.

My overriding feeling about these technologies, despite what they’re capable of and despite that capability being undeniably impressive in many cases, is that they’re solving the problem in the wrong place. Surely there’s still room in the specification of the Web and its clients for more than one language runtime?

While Emscripten hosts an impressive array of language variants, I wonder what’s stopping the Web from specifying a language agnostic runtime environment that can efficiently target modern computer hardware and doesn’t box all client side Web computation into the JavaScript runtime.

LLVM is the obvious technology to leverage there since almost everything required is already built and quite mature. There are myriad language front-ends, high performance optimisers that know how to target modern hardware, and mature compilers, including JIT. All are built around a well specified type system which acknowledges the machine, which I believe to be the key to efficient execution on modern hardware.

Embedding an LLVM bitcode runtime seems to be the right thing to do at this point. JS still gets to execute as the Web’s current first class citizen and its performance, a critical thing these days, stays high. Then on top of that the Web programming world wins in innumerable ways as the floor is opened to almost all modern programmable languages.

In particular, the oft-cited goal of unifying client and server languages in order to share code and reduce development costs gets much easier, as the intersection of client and server languages results in a set much much bigger than 1.