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…)