July 2007


Some good news. It turns out it wasn’t my build of the RVM that was buggy, but rather a case of JikesRVM being too clever for its own good. Observe the name of the class I was trying to load:

gnu.classpath.examples.management.TestClassLoading

Its prefix is ‘gnu.classpath’ which is also used for some of the core classes. JikesRVM only tries to use the bootclassloader if part of the class’ full name (with package) contains one of the packages it considers to be one of the core packages. In full, these are:

private static final byte[][] bootstrapClassPrefixes =
{“Ljava/”.getBytes(),
“Lorg/jikesrvm/”.getBytes(),
“Lgnu/java/”.getBytes(),
“Lgnu/classpath/”.getBytes(),
“Lorg/vmmagic/”.getBytes(),
“Lorg/mmtk/”.getBytes()};

It makes a lot of sense, but is a bit too strict. You’ll note that javax isn’t there, even though a lot of the library classes are in that package (JMX itself for one, along with Swing) and it is one of the prefixes Sun disallows being used for external classes. Why? Because lots of extensions wouldn’t work if it was.

So that line stops the Classpath examples working, and I’ll be patching it on my new JMX branch:

https://jikesrvm.svn.sourceforge.net/svnroot/jikesrvm/rvmroot/branches/RVM-127-JMX

and submitting a patch. I’m not going to remove it completely, but instead be more specific and specify the appropriate residents of gnu.classpath that should be blocked. I’m thinking in the long run it might be nice to have this automatically generated during the build if that’s possible.

I’ve just found that it generates another problem. It stops the VM being self-hosting because it can’t run its own Ant task:

BUILD FAILED
/home/gandalf/projects/java/classpath/jikesrvm.jamvm/build/tasks.xml:28: taskdef class org.jikesrvm.tools.ant.ForEachTask cannot be found

org.jikesrvm, you’ll note, is another disallowed prefix.

OpenJDK

I’m still fairly disappointed with the way OpenJDK is proceeding, and I read Roman’s comments this week with interest. At least it’s not just me that feels this way. I guess it’s just that we’re impatient, but especially with the release of the code, we GNU Classpath hackers feel we want to do something to help.

Just looking at the speed with which IcedTea has developed, it’s clear that the motivation is there. However, there’s a missing link. There’s no way of feeding stuff back in to the OpenJDK project, no live source repository and an unknown bunch of Sun developers working on the same stuff. At some point, their code will appear in one of these ‘b’ source code drops and whatever we’re doing will be rendered obsolete.

Meanwhile, work on GNU Classpath has ground to a halt because there’s no motivation there any more. Why bother implementing a package when the GPLed code is out there in the OpenJDK? But there’s currently no way of joining the two together to create a Free Java implementation. I feel we’re still just as far away as we ever were, with a future much less bright at the moment. I’ve had a fantastic three years of working on GNU Classpath, and through that time the development pace has increased to an unbelievable rate and I’ve met some truly fantastic people.

I’d hate to see the results of this work go to waste. But right now is the most indecisive and scary time I’ve been through while working on the project and I just don’t know what will happen next. The current OpenJDK is in a worst state than Classpath (I’m talking about IcedTea, I don’t consider the version with binary safety pads a Free Java) and the fantastic work coming from the RedHat guys seems a little like stuff we’ve already done in Classpath.

Here’s to better times ahead.. I hope.

Finally seen some success this morning. Firstly, JikesRVM now boots. It won’t load the classes I want it to from a zip but it does boot. I found the solution following some advice from Ian Rogers last night. I copied java.lang.Runtime (the failing class) into the library interface and added a few VM.sysWriteln calls to get some debugging info. As I guessed from looking at the code, it seems the Runtime isn’t null and so an error is thrown. JikesRVM then fails to throw the error because not enough of it is there yet.

The solution is actually quite simple: I extended the test to also check that VM.fullyBooted is true. If it isn’t, it still goes ahead and initialises Runtime and this gets things going to a point where JikesRVM goes ‘oi, specify some classes!’ (well nicer than that, but you get the jist).

Unfortunately, actually specifying some doesn’t seem to work:

Boot sequence completed; finishing boot thread
java.lang.NoClassDefFoundError: Could not find the class gnu.classpath.examples.management.TestClassLoading:
gnu.classpath.examples.management.TestClassLoading

Iced Success

To top it all, I just finally got a build of IcedTea through!

IcedTea is served: openjdk/control/build/linux-amd64

This is on Debian stable with a copy of gcj svn lurking around (from my earlier attempts). Biggest problem was getting it happy with a compiler; I had to use ecj 3.2 in the end from the JikesRVM build as it didn’t like my version or javac. Other funny issues include messing up the generated files because my copy of gcj has some of my debug output in it and linking against a rogue libjvm that was still floating around. It also didn’t like fastjar or any of my Sun tool wrappers, preferring the ones from Classpath.

I also had to drop back to the copy of OpenJDK I originally downloaded on the release. b15 won’t work, either built using IcedTea or from the binary drop. The binary drop of b13 does, so something went wrong since. It also fails for twisti, but he’s doing some weird build stuff with cacao so it could be that… ;)

Comments on IcedTea: seems to work well, although I wonder why it rebuilds rt.jar and jce.jar all the time, and just gets completely confused if I specify an openjdk source dir but no zip file (guess I didn’t understand that option properly)

Weather’s bad ‘ere too

This is for Andrew Cowie — it’s not only Australia seeing abnormal weather at the moment..

Sheffield Floods

Still not much further in getting JikesRVM to build on a GNU Classpath platform. It looks like I may have to give in and use Sun’s code for the time being (hopefully IcedTea, so at least it’s still Free).

Following on from last time, I got twisti to patch the hole in cacao only to fall over another large hole in the annotation support. So that’s cacao out until the student working on annotations completes the getAnnotations method.

I was assured by Andrew Haley that gcj had such support so I went and built the latest svn. And it got past that bit. Then we hit more fun, more very confusing fun.

What JikesRVM is doing at this stage is building a boot image that can then be jumped into by a small bootstrapping piece of C code. This image contains copies of the classes needed to get the VM to be self-hosting. Trouble is, in using a Classpath-based VM, there are more collisions between the new RVM classes and those in the host VM.

This bit of building the boot image involves quite a few Class.forName calls. These get confused over which classes we actually want to get, it seems (still not sure if that is meant to be the case, or whether the classloading is a bit messed up). Presumably with Sun’s VM, it only conflicts on the main API classes, and the code has special cases to deal with these.

The first problem with GCJ I found was that it can reach some odd cases where it loads a class from the RVM jar that is package-private and has a superclass which is loaded by GCJ (giving them different boot loaders, hence the compliant of a IncompatibleClassChangeError). These are anonymous inner classes that are getting named differently by GCJ. My guess is that this is because it’s using an older version of ecj (Jikes is using 3.2).

Suffice to say, JikesRVM has java.util.Collections$CheckedMap$CheckedEntrySet$1 while GCJ has java.util.Collections$6. As the former has a superclass of java.util.Collections$CheckedIterator which is loaded by the bootclassloader, an error is thrown. This isn’t the only case either; a number of inner classes in Collections are prone to this.
I’m still wondering if this is solvable by getting GCJ to build with a newer ecj. This requires adding GCCMain to a newer version. Not sure if this is even possible. I’ve got around it so far on the JikesRVM side by getting the boot image writer to ignore the error, as it does with ClassNotFound and Security exceptions (which suggests that loading the class isn’t required).

The current problem is a NullPointerException:

[echo] Exception in thread “main” java.lang.ExceptionInInitializerError
[echo] at java.lang.Class.initializeClass(libgcj.so.9)
[echo] at java.lang.Class.forName(libgcj.so.9)
[echo] at BootImageWriter.getJdkType(BootImageWriter.java:2473)
[echo] at BootImageWriter.createBootImageObjects(BootImageWriter.java:1150)
[echo] at BootImageWriter.main(BootImageWriter.java:614)
[echo] Caused by: java.lang.NullPointerException
[echo] at java.lang.VMClassLoader.getSystemClassLoaderInternal(libgcj.so.9)
[echo] at java.lang.VMClassLoader.getSystemClassLoader(libgcj.so.9)
[echo] at java.lang.ClassLoader$StaticData.(ClassLoader.java:154)
[echo] at java.lang.Class.initializeClass(libgcj.so.9)

This occurs because JikesRVM is trying to call the static initializer for ClassLoader$StaticData which in turn calls VMClassLoader.getSystemClassLoader. Note that GCJ’s copy doesn’t do this (or even contain this class); it is the Jikes class (from Classpath) that is doing this, so again it’s a case of interaction between the two class libraries.

I’m still not sure exactly where the NPE occurs (it’s somewhere in this native code). Any help would be much appreciated. The offending line is:

_Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::ExtensionClassLoader::system_instance);

which calls code in natClassLoader.cc. This error occurs with a prototype build, but the same NPE occurs with a development build except this time it’s somewhere in the compilation performed by the OPT compiler.

Update

Tried to add GCCMain (from rhug’s gcj-ecj it turns out) to ecj 3.2, and it failed:

org/eclipse/jdt/internal/compiler/batch/GCCMain.java:231: cannot find symbol
symbol : method handleWarningToken(java.lang.String,boolean,boolean)
location: class org.eclipse.jdt.internal.compiler.batch.Main
super.handleWarningToken(token, isEnabling, useEnableJavadoc);
^
org/eclipse/jdt/internal/compiler/batch/GCCMain.java:440: cannot find symbol
symbol : variable destinationPaths
location: class org.eclipse.jdt.internal.compiler.batch.GCCMain
this.destinationPaths = new String[this.filenames.length];
^
org/eclipse/jdt/internal/compiler/batch/GCCMain.java:442: cannot find symbol
symbol : variable destinationPaths
location: class org.eclipse.jdt.internal.compiler.batch.GCCMain
this.destinationPaths[i] = this.destinationPath;
^
org/eclipse/jdt/internal/compiler/batch/GCCMain.java:460: cannot find symbol
symbol : method disableWarnings()
location: class org.eclipse.jdt.internal.compiler.batch.GCCMain
disableWarnings();

Trying JamVM eventually proved successful. I patched the same VMSupportsCS8 hole myself (just returning FALSE), and seem to have managed to work around a bug in VMDouble.toString to do with NaN detection to get a successful build (but not a running RVM…yet…)