Java Virtual Machine in pure Node.js
github.com
github.com
My current research project, Doppio [1], implements the native portions of the OpenJDK Java Class Library so it can use an unmodified copy of the OpenJDK JCL. As a result, it can run a bunch of nontrivial programs (javac/javap/Rhino/Kawa-Scheme).
One issue you will run into is with multithreading. Since JavaScript has no true threading implementation with shared memory, you'll need to be able to suspend and resume virtual JVM threads. For this reason, Doppio maintains an explicit JVM stack representation.
Anyway, feel free to check out our code, reuse portions of it, or contribute if you're interested; it's MIT Licensed and under active development. :)
[1] Demo: http://doppiojvm.org/ Code: https://github.com/int3/doppio
You are right that we could extract more performance by mapping particular classes directly onto efficient browser functionality -- such as String. In the future, we could implement specific classes such as String directly in JavaScript for a performance boost. :)
As a side note, ASM.js itself does not have a String type, which leads me to believe that this particular optimization might not be beneficial if we switch to an efficient JIT strategy.
Granted, it's possible that it invokes a native function somewhere deep inside itself that we don't implement yet, but fixing those are usually very simple.
We are planning to update the demo (and perhaps post on HN) once I fix some IE issues (since we strive to be compatible with IE9).
It's too slow at the moment for production use, since it is an interpreter. But if we add JIT compilation support, I believe it will be fast enough for usably running legacy code/libraries in the browser.
We had an excellent Google Summer of Code student work on AWT support for half of the summer. We discovered that the OpenJDK AWT implementation betrays its own internal abstractions, making it impossible to implement a new backend without forking the Java Class Library and making nontrivial changes.
You can read more about the problem here: http://mail.openjdk.java.net/pipermail/challenge-discuss/200...
Unfortunately, the project described in the above link appears to be defunct and unmaintained. :( We don't have the resources to work further on the problem at the moment.
Regarding performance, we are about 20-40X slower than the HotSpot Interpreter in Google Chrome, with similar numbers in other browsers. There is a significant amount of work that we can and plan to do to make that much better, though.
I'm sure I'll see a demo showing off something that barely runs on modern hardware that we were more than capable of running with good performance in 1990.
sigh I feel like I'm being such a Debbie-downer even if this is a really cool hack.
It could be we haven't improved those either, but there's more to life than raw performance you see.
Looking at lots of "web-scale" technologies, I can't help but think that lots of what we're trying to solve with racks of computers could probably be handled with ease by a single modern machine if the software wasn't so inefficient.
1. the software was an order of magnitude or two less complex- in terms of features and platform. That is, there was maybe a dozen different kinds of (highly predictable,testable) home computers instead of a combinatorial infinity of videocards/motherboards/soundcards/operating systems/etc.., plus, the GUI/Evented model is more conceptually difficult for programmers to cope with than straightforward "I own the machine" imperative blocking code. If we want to have guis, we need languages that either abtract away events, or at least provide tools to more easily handle events than C or assembler could provide. Such languages tend to be fairly complex (in implementation)/"inefficient"/garbage collected (since events link to memory/state that must be disposed of eventually,somehow, safely,without segfaulting). Failing that, we need programmers that are smart and capable enough to just plow through the complexity of events in plain C or C++. It's a different caliber of programmer than those who could singlehandedly make simple computer games on an 8-bit home microcomputer.
2. In cases of more complex software, ports were achieved by first designing and implementing a one off virtual machine, then simply porting the virtual machine to the different platforms. See ScummVM, Z-machine, Another World, etc. Surely that threw away some notion of efficiency. You made up for it by implementing the performance sensitive routines inside the VM itself.
3. The inefficiency of software is usually a tradeoff for development speed. To make a virtual platform work consistently across the many different real platforms they must run on, the efficiency of the virtual platform becomes (roughly) a function of ( platform implementors / platform count ) * time. We're only 5 years down the road of this round of serious javascript optimisation. At the end of the day, the curve of that function isn't that different from java, or C or C++ or anything else. those other things just have a huge head start.
This project at least provides the potential for people like myself who have existing Java projects with longstanding functioning methods that I don't want to rewrite in Node.js... Yes it's another layer, but for some functions that layer can be less complicated then reimplementation.
In this case, wouldn't a java-to-js translator be more efficient than rewriting the whole jvm for Node.js?
There are lots of CPU cycles, and plenty of cases where trading a few for increased flexibility makes a ton of sense.
*In general and not supported by facts of any kind other than my own anecdotia.
You should not use virtual runtimes for everything your application does but using them in overnight cronjobs is ok.
Right now we are working on some middleware because the customers wants to use existing reporting tools(c#/windows only) with our product(perl/linux).
>Look how fast and simple this is! > >Yeah nice so how do I genearte my <wateva> reports? > >Well we can do the same with our <another> reporting service! > >No I want to keep my <goodOldstuff> based reports can you integrate those?
Not yet, we can't. Mozilla is working on the WebUSB[0] API that'll allow access to USB devices via javascript as part of their ongoing WebAPI effort. They need this for FirefoxOS at some point, and these APIs are being implemented in desktop Firefox as well.
Really cool proof of concept! I would really enjoy seeing more projects like this!
Why did you spell it in all-caps here?
JAVA = Just Another Vague Acronym.
That and you need to use xml for everything to be enterprise.
Java 1.2 (1998) used a JIT and a generational collector. It was probably faster than today's Ruby, Python, or PHP.
What was slow was start up. Applets in particular were really horrible since they completely froze the browser for several seconds.
If I remember correctly, this was finally fixed many years later with some version of Java 6.0.
About that time, I needed to decide whether to use Java or Delphi (an ahead-of-time Pascal compiler) for a new project. I was worried about garbage collection overhead. So, I designed a trivial benchmark wherein an array of simple objects was constructed in a loop (as we revisit each slot in the array, we replace the old object with a new one). Java came out ahead. The superiority of GC, along with platform independence, convinced me to go with Java.
PS. I can't swear to it that you could do a decent lazy delete or free and get better performance in C or C++, but it doesn't sound absurd on its face. What the standard library could not do is run its own background thread and update memory structures asynchronously, the way some advanced GCs do. But the whole problem can be avoided by doing fewer allocations in the first place, and performance will be consistently good no matter what the platform.
Emulate x86 in v8 run hotspot inside emulator.
now you got your performance back.
Only one problem. Where's node.js?
kind of like the espruino but even moreso?
https://github.com/int3/doppio/wiki/Successes
> We're also making progress on others, but we're not quite there yet: JRuby, Clojure, Scala REPL
I think I just had a micro heart attack reading that.
...but I'd rather stab myself in the face with a screwdriver.
-Reads in real .class files
-Uses the JS run-time to implement the Java run-time (e.g. there isn't a garbage collector written in JS, the JS collector is used)
-Only implemented part of java.lang and java.io
https://github.com/szatkus/js2me
Although I targeted only J2ME subset. Also I found few similar projects:
[1]The basic .class file attribute parsers are located in libs/classfile, while a simple bytecode interpreter can be found in jvm.js. It doesn't load a real runtime library (classpath, apache harmony,openjdk,etc...) but it partially implements a few java.* classes in pure javascript under libs/java.
Regarding the loader, it can load a few sections from a classfile, the one containing methods bytecodes, the exceptions table and the constant pool (i.e. where all your string are stored with some other "constants"). How much it could take for a full implementation? It depends of what you mean by full. Even using one of the opensource runtime library like openjdk,classpath,harmony/android i'd say a few years done solo, and not much less with more people, to build something complete and stable enough for general use. Definitely not a simple project.
Edit: It's already here :) https://github.com/jterrace/js.js/
Demo: http://doppiojvm.org/
You could even write one in Java (and I'm sure it's been done, many times). EDIT e.g. http://igormaznitsa.com/projects/mjvm/index.html
Of course, doing all the tricky JIT etc of the JVM is a different story...
Which one would perform best?
Next step: Java compiler in node
I'm not trying to say I wouldn't like to see it, but I don't think anyone would use it, is all. And it's sad when cool software doesn't get used.