Yes, JavaScript is Assembly for the Web. Here’s its OS.

The browser is a lousy excuse for an operating system. So we fixed it.

by John Vilk and Emery Berger

Doppio is an “operating system” for the browser that lets it run applications written in general-purpose languages

Web browsers have taken over. They make it comparatively easy to deliver cross-platform applications, because browsers are essentially everywhere. Practically all computing platforms — from desktops and tablets to mobile phones — ship with web browsers. Browsers are also getting faster all the time. They have just-in-time compilers for JavaScript that produce highly optimized code, and they expose features like access to the GPU through WebGL and high-speed video chat via WebRTC.

This combination of features makes it possible for browsers to host the kind of richly interactive applications that used to be restricted to native environments. In effect, web browsers have become a de facto universal computing platform: its operating system is the browser environment, and its sole “instruction set” is JavaScript.

JavaScript is Your Frenemy.

In short, if you want to program for the web, you need JavaScript. However, JavaScript is not everyone’s favorite language. There are many reasons why browser support for programming languages other than JavaScript would be desirable.

JavaScript is a language that has some nice features but whose design contains numerous pitfalls for programmers. Gary Bernhardt’s famous “WAT” talk below hilariously illustrates just a few.

For example, here’s what happens when you have to create a new language in just 10 days.

Problems with JavaScript have led language implementors to design new languages for the browser that overcome JavaScript’s shortcomings — Dart, TypeScript, and many others — but these solutions all require that programmers learn a new language. Programmers who prefer to program in other paradigms (e.g., functional, object-oriented) currently must abandon these or build hacks onto JavaScript to accommodate their needs.

So. Much. Code.

There’s also a lot of well-debugged, existing code already written in general-purpose programming languages (i.e., not JavaScript). Making it possible to reuse this code would speed application development and reduce the risk of introducing new bugs.

It is already possible to reuse existing C or C++ code via the Emscripten project, which is a backend for LLVM that generates snippets of JavaScript instead of, say, x86 code. An effort is underway to provide really efficient support for JavaScript generated this way (initially ASM.js, now WebAssembly).

Unfortunately, translating, interpreting, or compiling code written in conventional languages to JavaScript is not enough. Browsers lack abstractions that existing programming languages expect, and impose significant limitations.

One At A Time.

JavaScript is a single-threaded event-driven programming language with no support for interrupts. Events have to execute to completion. If your code happens to have a function that takes too long (for some definition of too long), your script will get killed by the browser’s watchdog thread, triggering the dreaded “page(s) unresponsive message”. This makes programming tricky: since it’s difficult to predict how long your code will take, JavaScript programmers routinely have to break up their code into tiny pieces that yield control back to the main JavaScript event loop.

Call Me, Maybe

(Or Not).

Browsers provide web applications with a rich set of functionality, but these APIs are asynchronous — that is, you invoke them with a callback that runs when the function completes. Unfortunately, conventional languages rely on synchronous (blocking) APIs, which don’t need or provide callbacks. Unfortunately, due to the limitations of JavaScript, you can’t directly create synchronous APIs from asynchronous APIs (e.g., by busy-waiting — the browser will just kill your script).

Dude, Where’s My OS?

Browsers lack most of the OS services that standard programming languages take for granted. For example, there’s no file system abstraction. Instead, there’s a panoply of limited storage mechanisms, making it tricky to manage large amounts of persistent data. Also missing: sockets.

So Many Browsers, So Little Time

Another big challenge is the diversity of browsers. Users access the web from a wide range of browser platforms, operating systems, and devices. They also vary widely in their support for and compliance with standards. Each combination may have unique performance characteristics, differing support for JavaScript and Document Object Model (DOM) features, and outright bugs. This diversity makes it hard to address any of the issues above without excluding a large portion of the web audience.

Close But No Cigar.

Although previous work aims at supporting other languages than JavaScript in the browser, these all fall short. Conventional programming languages and their standard libraries expect the relatively rich execution environment that modern operating systems provide. The fact that browsers lack standard operating systems features like threads, file systems, and blocking I/O means that these projects cannot run existing programs without substantial modifications.

Doppio to the Rescue

We have built a runtime system called Doppio that makes it possible to run unmodified applications written in conventional programming languages inside the browser. In short, it’s like a POSIX layer for your browser.

Doppio’s execution environment overcomes the limitations of the JavaScript single-threaded event-driven runtime model. It provides language implementations with emulated threads that support suspending and resuming execution to enable blocking I/O and multithreading in the source language.

Doppio supplies a wide range of common operating system abstractions that support standard library and language features. These include a Unix-based file system abstraction (providing local and Dropbox-based cloud-based storage), network sockets, and an unmanaged heap for dynamic memory allocation. All of this support acts as an abstraction layer over the many differences between browsers, letting code run unmodified across Google Chrome, Firefox, Safari, Opera, and Internet Explorer. Components of Doppio are already being used by the MS-DOS Collection at the Internet Archive.

I Heard You Like Java In Your JavaScript

To further demonstrate Doppio’s power, we built DoppioJVM, a prototype yet robust implementation of a Java Virtual Machine interpreter on top of Doppio. It can run complex unmodified JVM programs in the browser — without that nasty vector for attack, the Java plugin.

The DoppioJVM is not yet exactly fast — it runs between 24× and 42× slower on CPU-intensive benchmarks in Google Chrome — but it’s already fast enough to be useful. It has already been integrated into an educational website by the University of Illinois (codemoo.com) that interactively teaches students how to program in Java. We have also enhanced Emscripten with Doppio and found that it made porting a C++ game to the browser far simpler.

We are currently expanding on this work on two fronts. The first is an implementation of Python on top of Doppio that we call Ninia — also known as the coffee snake. Ninia is not yet complete but it is already able to run some basic Python programs in the browser. We are also developing techniques that promise to dramatically speed up both DoppioJVM and Ninia, expanding their usefulness. We look forward to the day when all programmers can run code in the language of their choice directly inside the browser.

John Vilk (PhD student) and Emery Berger (Professor) are in the PLASMA Lab in the College of Information and Computer Sciences at the University of Massachusetts Amherst.