A VM in Java with tail-calls and continuations

Tuesday, July 26, 2005

The first commit...

OK, so I did my first commit today. You can keep track of the project's code by either browsing it through the web-based viewer (which is usually a couple hours off), or by using the anonymous access:

cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/jauvm login
cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/jauvm co -P jauvm

You may be wondering what took me so long. It's true, I've been available since Friday when I last posted, and yet no news.

I've been struggling to solve my first problem: the promised Monitor class. That class involved the creation of methods to implement unbalanced monitorenter and monitorexit operations. Although those can't be expressed directly in Java, they could easily be implemented directly in JVM bytecode.

To avoid having an extra compile-time dependency, I'd decided to use ASM, defining the class in XML. It all worked pretty well (including a couple of ANT tasks to automate it), until I actually tried running the code, just to find out that the JVM checks to guarantee at runtime that no method does an unbalanced locking operation.

The check was added in 1.4, and is - in my opinion - pretty stupid (sorry clever guys at Sun, but read on). Unbalanced locks are useful, so much so that they are present in rival .NET, and consequently a form of those appeared in 1.5 in the new java.util.concurrent package.

This new API though, however “dangerous” for purists, does not suit my needs, because, au contraire of what happens in .NET, this it's not “compatible” with the common synchronized block (in the sense that it's not possible to unbalancedly synchronize on an arbitrary object, you can only lock locks). The API's existence however, proves it can be done - most likely through JNI (I know, that sucks, but that's the JVM we've got).

So the bad news is, in general, synchronization won't work for the time being. Your options will be: using java.util.concurrent.locks.Locks where you can; or, waiting for the JNI implementation of Monitor.enter and Monitor.exit, if you can tolerate JNI.

Note that this affects all synchronization, meaning all the usages of the synchronized keyword (blocks and methods) in interpreted code (and not just the direct usage of the Monitor class): these will all throw UnsupportedOperationExceptions until further notice. This is so, because the monitorenter and monitorexit opcodes would have themselves to be implemented through Monitor. Sorry there really seams to be nothing I can do about this.

I won't just give up over this - I knew synchronization would be a problem, and it's really not an unsolvable one (it's just nasty when you can't use plain Java to do safe, simple stuff like this).

I'll move on, for now, and will look into the design of Frame objects - which are responsible for keeping the interpreter's state. There are a few different possibilities: some faster, others simpler - as usual. I'll go with the simpler version for now, probably, but I'm trying to abstract enough of the inner workings of frames inside the Frame class, to make it easy to latter (as in during or after the summer =) replace it with the faster version.

That's all that's been going on, remember to keep an eye on the repository if you're interested.

No comments: