Java on Coffeescript.
Doppio is also the Italian word for 'double', and is another name for a double espresso.
Doppio started out as the mid-term project for a Graduate Systems Seminar. It has since taken on a life of its own, and is complete enough to run the following programs:
- GNU Diff
- LZW compression
- The Java 6 compiler
- Kawa Scheme
- Probably many more! Let us know if you find anything cool that runs in Doppio.
The code has been tested on the latest versions of Chrome, Firefox, Safari, Opera, IE 9, IE 10, and Node, but should run in just about any browser.
Check out the demo!
Notes on Architecture
Doppio was built with the goal of supporting as much of the Java Class Library as possible. As the official Java Class Library is mostly implemented in Java, Doppio uses the Java 6 JCL with reimplementations of any needed "native methods", which were originally implemented in C, in CoffeeScript.
Doppio is designed to run both on the console and the browser. In the console implementation, system calls are handled by Node.JS. In the browser, we emulate a simple LocalStorage-backed filesystem with an API very similar to Node's, so the same code can operate in both environments. If the browser does not support LocalStorage, then the filesystem exists purely in memory and is cleared when the user leaves the page.
Since LocalStorage has a storage limit of 5MB, Doppio's web frontend will only store files created or modified by the user or by programs run by the user. We do this to avoid storing massive amounts of JCL classes in the limited storage available to us.
Floats are slightly tricky; while the common case is handled nicely by a double, there are some edge cases that need to be specifically addressed (mainly, +/- infinity and underflow, which Doppio handles).
64-bit longs are tough. They cannot fit into the 52 bits of precision provided by a double. Fortunately, this problem has already been tackled in the Google Closure library.
Objects (Heap Management)
JVM objects are mapped to JS objects with the same field names, bundled inside a
larger object that contains some metadata. Instead of simulating an actual heap,
we pass JS object references around. Thus, garbage collection is automatically
hashCode require each
Object to have a unique ID, we store an
ref field in each object's metadata that acts as an imaginary
At the moment, these yield points occur only at the following times:
- Starting a new thread.
- Waiting a thread on a lock (can be explicitly stated in the Java code, or implicitly when entering a monitor-guarded method)
We hope to improve thread support in the next release to expand the amount of programs that are compatible with Doppio.
We solved this by implementing a 'yield' construct: upon encountering a
blocking function, we throw a
YieldException to pause the VM. This exception
would also contain the asynchronous function that we are waiting on, which
eventually calls the VM and resumes the program. We used this for standard
input operations, among other things.
We have a class for each type of opcode in the JVM. Each bytecode instruction in
a method is translated into an object and placed into an array of instructions.
Running a method is a matter of jumping to the correct opcode, calling its
run method, and repeating until the method completes.
We had experimented with doing a giant
switch statement, but we could not get
it to perform as well as the one-object-per-instruction design due to the large
number of JVM opcodes. We hope to perform more experiments in the future to
see if we can further increase the performance of the main interpreter loop.
There is much more to do! We are currently trying to refine the JVM internals before trying to bolt on a compilation engine.
Up next on our roadmap is:
- Improving threads support; due to our yielding strategy, we currently have difficulty with ad-hoc synchronization implemented through atomic instructions.
- Refactoring core JVM logic for speed.
- Fixing any remaining bugs in JVM logic.
- AWT/Swing support for GUI applications.
- Cloud storage support in our filesystem.
- Architecting the core JVM so we can eventually implement JIT compilation on a per-method basis. There are a number of concerns that we have to deal with before this will be possible.
Doppio uses the jQuery and Underscore.js libraries. Editing is provided by the Ace editor, and the console is a fork based off Chris Done's jquery-console. Layout is based off Twitter's Bootstrap. The font for 'Doppio' is Bitter from Google Web Fonts, and the coffee icon is by Maximilian Becker, from The Noun Project collection.