Things I'll Forget In A Month Tech scratchpad and musings


JSava: a Java bytecode interpreter in JavaScript

Here's another cool project I've been working on - it's an interpreter for Java bytecodes (i.e., like the JVM). What's more interesting about it, however, is that it's written in JavaScript. Furthermore, it runs on top of Mozilla Rhino, which means it's actually C code (the JVM) which runs Java code (Rhino) which runs JavaScript code (the interpreter, JSava) which runs Java code (a user program). The double-interpreter thing does take a hit on speed, but the point isn't to beat the JVM for speed - it's to just accomplish something cool in a quirky language like JavaScript.

This may seem like deja vu to Slashdot readers, which is what prompted me to post this. I think JSava is particularly interesting, however, because it can handle many fairly advanced features of the JVM and is capable of executing much (most?) of the JDK standard library. Some feature highlights include:

  • All 200 JVM opcodes are implemented.
  • All native Java types are supported, including 64-bit Longs, which are not natively supported by JavaScript. This is because JavaScript represents everything as 64-bit floating point numbers, which cannot store the full range of 64-bit integer values.
  • Full support for the Java threading model, including multithreading, synchronization between threads, and monitors (wait() and notify()). However, note that multithreading does not imply parallelism, which is at the moment effectively impossible in JavaScript - JSava provides threading support by timeslicing a single actual thread of execution.
  • JSava is complete enough to execute most major JDK library classes, such as java.util.HashMap and java.util.Random. Even some more exotic classes are mostly functional, such as java.util.concurrent.ExecutorService and company.
  • Substantial support for the Reflection API. This may seem like a weird thing to support, but reflection is heavily used in the JDK library classes, so supporting it is critical in enabling complete functionality.
  • All the usual Java goodness: exceptions, inheritance, interfaces, runtime error checking, etc... basically all the language features we know and love.
  • Native method handling capabilities for handing off to JavaScript implementations (e.g., System.arraycopy(), Thread.start() and lots of JDK support methods).
  • Rudimentary I/O support, accomplished through a lot of low-level trickery involving intercepting file descriptors and mapping them to native Java streams. JavaScript itself has effectively zero I/O support, but the only time Java is invoked to handle I/O is in the lowest level native methods (e.g., 'write these bytes to this file handle'). Everything above that (such as I/O buffering) is handled inside the interpreter.

The JDK class files which JSava was developed with are taken from the Mac OS X 10.6 JDK (Java SE 6). The interpreter may work on Linux, but probably won't on Windows without a little bit of tweaking, particularly for I/O (it's on my todo list).

As usual, I've also created a new program page for the project. The runnable archive provides the entire JSava runtime environment, including Rhino and JDK library classes (3.3M). If you have Java installed, running the interpreter is as easy as executing one command (no building required!). If you only want to look at the source code and not actually run the interpreter, you can also download the source only (54K).

There were a lot of engineering tricks that went into JSava and I may write about some of them in the future. However, JSava is still very much a work in progress and I plan to extend it to handle even more than it already does.

Comments (4) Trackbacks (2)
  1. Does it work in the browser? That is the main reason anyone uses Javascript after all. We have users who have browsers that only run Javascript. We want them to be able to run Java (and Scala, etc.) programs in their browsers. If we drop the requirement for running in the browser then we may as well just use a real language and forget about Javascript.

  2. @Richard: Right now it doesn’t run in in a browser (well, in a JS-only browser) due to the internal dependency on Rhino. However, the only real reason it’s Rhino-dependent is to simplify the implementation of native JDK functionality — 95% of the code is in pure JS, and would be able to run in a browser. I may look into this in the future, but at the moment it’s mostly just an interesting toy.

  3. @Mike: Yes, web workers are one way, in theory, to have real parallelism in JS. The actual implementation of that, however, would be pretty dicey — you’d need to deal with all sorts of synchronization issues and the fact that web workers can’t operate on the same instance on a variable. This would mean a lot of bookkeeping for even simple threaded programs. It would also make synchronization much harder — right now the atomic unit of work in JSava is a single bytecode, but this would no longer be the case with web workers.

Leave a comment