GNU Classpath


We are proud to announce the release of GNU Classpath 0.99!

GNU Classpath, essential libraries for java, is a project to create free core class libraries for use with runtimes, compilers and tools for the java programming language.

The GNU Classpath developer snapshot releases are not directly aimed at the end user but are meant to be integrated into larger development platforms. For example JamVM, CACAO and Kaffe can make use of an
installed copy of GNU Classpath 0.99, while GCC (gcj) will use the developer snapshots as a base for future versions. For more projects based on GNU Classpath, see http://www.gnu.org/software/classpath/stories.html.

This release brings with it a number of interesting new features:

  • Addition of java.util.regex.Pattern.quote.
  • Addition of java.io.IOError.
  • Addition of java.io.Console.

There have also been many bugfixes over the past year. Those relevant to 0.99 can be found in our bug database.

With the 0.95 release, we switched fully towards the 1.5 generics work that we previously released separately as classpath-generics. All this work is now fully integrated in the main release and various runtimes
(gcj, cacao, jamvm, ikvm, etc) have been extended to take advantage of the new generics, annotations and enumeration support in the core library. As a consequence, only 1.5 capable compilers (currently the
Eclipse Compiler for Java (ecj) and Sun’s javac) may be used to build Classpath.

The GNU Classpath developers site provides detailed information on how to start with helping the GNU Classpath project and gives an overview of the core class library
packages currently provided.

For each snapshot release generated documentation is provided through the gjdoc tool, which is part of GNU Classpath 0.99. Full documentation on the currently implementated packages and classes can
be found at: http://developer.classpath.org/doc/ We are looking into how to extend the documentation experience in the future. Please contact the mailinglist if you would like to help with this effort.

For more information about the project see also:

GNU Classpath 0.99 can be downloaded from ftp://ftp.gnu.org/pub/gnu/classpath/ or one of the ftp.gnu.org mirrors

  • File: classpath-0.99.tar.gz
  • SHA256sum: f929297f8ae9b613a1a167e231566861893260651d913ad9b6c11933895fecc8

New in release 0.99 (Mar 07, 2012)

  • Addition of java.util.regex.Pattern.quote.
  • Addition of java.io.IOError.
  • Addition of java.io.Console.
  • Bug fixes:
    • PR39408: gjavah doesn’t generate constants in header files where they occur in a superclass
    • PR40590: namespace namespace broken in CNI
    • PR40630: java.util.Scanner fails when used for charset generation by the OpenJDK build
    • PR40653: Issue with XML stream writer and namespaces
    • PR40663: Support Stax API 1.0.1
    • PR39177: trunk revision 144128 – jar: internal error: java.lang.NullPointerException
    • PR41696: java.util.zip.Inflater:finished () returns false when it should return true
    • PR43536: CopyOnWriteArrayList bug in delete() when empty
    • PR36560: java.util.zip: Error parsing zip file with larger files in it
    • Restrict access to VM classes.
    • Cleanup use of message resources.
    • Throw exception when encrypted zip file entries are encountered.
    • Fix infinite recursion in javax.print.attribute.standard.JobStateReasons.add.
    • Native code cleanups in GtkToolkit.c and jcl.c.
    • Only log when debugging is on.
    • PR44411: System.nanoTime() is not independent of wall-clock time
    • PR46775: Calling Policy.setPolicy with a new Policy object has no effect on the DefaultSecurityManager
    • Use implementation of VMClass.getSimpleName from gcj.
    • Simplify security determination in ProtectionDomain in situations where all permissions are available.
    • PR42390: Missing Security Manager checks in classpath apis
    • Throw NullPointerExceptions appropriately for compatibility with OpenJDK.
    • Use Integer.parseInt in preference to Integer.decode in java.util.Formatter.
    • Use same default capacity in java.util.HashMap as documented in OpenJDK.
    • Check for hashcode equality before calling equals in java.util.HashMap.put
    • Make sure match is within input data limits in java.util.regex.Matcher.find.
    • Fix misuse of ArrayList.set in javax.swing.text.html.StyleSheet.resolveStyle.
    • PR48131: java.util.zip.ZipException: incomplete dynamic bit lengths tree
    • Check for negative capacity in VMDirectByteBuffer’s native code.
    • PR42823: tcp/ip sockets read/write operations causes memory leak
    • Generate META-INF/INDEX.LST for glibj.zip
    • Fix issues when building with -Werror and gcc 4.6.
    • PR40188: javah creates constants using name of superclass
    • PR45527: gjavah encodes $ as used in inner classes as 00024 where Oracle’s javah does not
    • PR45526: gjavah does not implicitly produce header files for inner classes
    • Fix NullPointerException for null keys in java.util.HashMap.put.
    • Fix BEAST security issue in gnu.javax.net.ssl.provider.
    • RH712013: pdftk crashes with java.lang.ArrayIndexOutOfBoundsException
  • Updated to libtool 2.x.
  • Lots of warning fixes / addition of generics.
  • Fix license headers in tools.
  • Normalise whitespace.
  • Maintenance work on javac detection.
  • Mark plugin as unmaintained and disable by default.

The following people helped with this release:

We would also like to thank the numerous bug reporters and testers! In addition, we’d like to extend our thanks to all those who’ve contributed over the years and have helped in building a thriving and friendly community around the GNU Classpath project.

Join us at FOSDEM 2011 to be a part of our sessions where we’ll discuss the state of Free Java!

Our theme is “Java Sans Frontières”

  • Why Free Java technology is awesome
  • Standing on the Shoulders of Free Java
  • The future of Free Java

The Call For Participation is OPEN NOW, but closes on 3rd December…
So send in a talk proposal today and join us in Brussels 5-6 February!

Why FOSDEM?

  • Engage in scintillating discussions with smart hackers over world famous Belgian Beer
  • Join the Web of Trust by getting your strong new key signed
  • Indulge in exquisite chocolate
  • Visit historic Brussels within walking distance

Why the Free Java DevJam?

  • This is the most significant non-commercial, neutral environment for Java developers to meet
  • Learn how to get involved in technical Free Java projects
  • We will not shy away from politics (especially this year)!
  • We will get together for an awesome dinner!
  • You will meet historic hackers in the evolution of Free Java

Please join the freejava-devroom@lists.fosdem.org list for general discussion about the event.

To submit a formal Talk Proposal follow the guidelines at
http://wiki.debian.org/Java/DevJam/2011/Fosdem/CallForParticipation

Respectfully,

In developing GNU Classpath, one problem that was commonly encountered was that applications would assume that the user was running on the proprietary Sun (now Oracle) JDK. This would enter into the code as the use of internal sun.* and com.sun.* APIs. So, even if all the standard APIs were provided by GNU Classpath, with all specified and unspecified behaviour, these applications would still fail because some undocumented proprietary API was being used.

My guess would be that Apache Harmony has also hit this problem. Certainly it seems it even occurred to developers of javac, as such usage presents a warning:

PluginAppletViewer.java:1516: warning: sun.applet.AppletPanel is internal
proprietary API and may be removed in a future release
    p.sendEvent(AppletPanel.APPLET_DESTROY);

I suspect they did this for a different reason; having external code depending on these APIs means that changes cause complaints from external developers and this warning seems to act as a way of absolving the JDK developers of responsibility for such breakage. Releases of JDK6 are already restricted into keeping the specified API the same. Restricting internal APIs as well would make the appearance of new features like Nimbus midway through the JDK6 release cycle impossible.

The reason I raise this issue now is that the danger of such usage seems to be increasing. Development of GNU Classpath and its associated JDKs has dropped significantly since the appearance of OpenJDK, and now that IBM have left Harmony for OpenJDK, development there is also likely to plummet.

This drop in diversity in the JDK space leads to an increasing dependence on one defacto JDK (OpenJDK) and the concomitant assumptions that users will be using this and so there is no reason not to use internal APIs or test on other solutions. I guess some people will see this as beneficial. It’s not. Having a standard API is beneficial. Having everyone reliant on one implementation of that API discourages good specification of that API.

We already have a situation where the TCK has only been run successfully against class libraries derived from the Sun/Oracle implementation (Harmony and GNU Classpath have never been able to license it under acceptable terms) and so there’s no assurance that it doesn’t depend on peculiarities specific to that implementation. It seems these recent developments in the JDK space will only see more homogenisation and further lower the likelihood that there will ever be an alternative clean-room implementation of the JDK.

Lillian ran into a few minor problems trying to build ‘raw’ OpenJDK6 (i.e. the tarball direct from Sun without any of the numerous IcedTea patches, fixes and extensions) yesterday, and so I decided to give it a go as well. Unfortunately, it seems it still isn’t possible to build it out of the box on a modern GNU/Linux system. In the end, I had to apply three patches (effectively two as one was split into two by the HotSpot build changes in IcedTea). patches/hotspot/original/icedtea-gcc-4.3.patch and patches/icedtea-gcc-4.3.patch from IcedTea6 is needed to fix some issues when building with GCC 4.3 which is the default on most current distributions. In released versions, this is a single patch, but in current Mercurial and the upcoming 1.4 release, the HotSpot changes in all patches are split off to enable the version of HotSpot used by the build to be changed. patches/icedtea-no-bcopy.patch was needed to remove some local defines of some BSD functions such as bcopy. There was some noise about taking this upstream on the mailing lists, but it’s not yet in a tarball it seems.

With these patches, I could build as follows:

$ mkdir openjdk
$ tar xzf openjdk-6-src-b14-25_nov_2008.tar.gz -C openjdk
$ cd openjdk
$ patch -Np1 < $ICEDTEA_SOURCES/patches/icedtea-gcc-4.3.patch
$ patch -Np1 < $ICEDTEA_SOURCES/patches/hotspot/original/icedtea-gcc-4.3.patch
$ patch -Np1 < $ICEDTEA_SOURCES/patches/icedtea-no-bcopy.patch
$ cd control/build
$ unset JAVA_HOME
$ unset LD_LIBRARY_PATH
$ JAVAC= LANG=C make ALT_BOOTDIR=$CURRENT_ICEDTEA_INSTALL \
 IMPORT_BINARY_PLUGS=false ANT=/usr/bin/ant ANT_HOME=/usr/share/ant

...sometime later...

>>>Finished making images @ Fri Jan 30 10:59:43 GMT 2009 ...
make[1]: Leaving directory `/tmp/openjdk/jdk/make'
Control build finished: 09-01-30 10:59
$ ../build/linux-amd64/j2sdk-image/bin/java -version
openjdk version "1.6.0-internal"
OpenJDK Runtime Environment (build 1.6.0-internal-andrew_30_jan_2009_10_46-b00)
OpenJDK 64-Bit Server VM (build 11.0-b17, mixed mode)

You can build a bit quicker if you make use of parallelisation which I neglected to do here; add

ALT_PARALLEL_COMPILE_JOBS=$PARALLEL_JOBS  HOTSPOT_BUILD_JOBS=$PARALLEL_JOBS

where PARALLEL_JOBS is how many processes you want to run simultaneously. The usual rule is number of cores plus one. IcedTea of course supports doing this too; just add --with-parallel-jobs=$PARALLEL_JOBS when you run configure and it will add the necessary make wizardry for you.

For the configuration, CURRENT_ICEDTEA_INSTALL should point to your existing IcedTea install. This is the only way to build OpenJDK6; I didn't try it this time round, but I know from experience that it still needs a fair few patches to remove Sunisms from the OpenJDK source code in order to allow a GNU Classpath JDK like GCJ to be used instead. This shouldn't be a problem though; you'll find IcedTea in Fedora (yum install java-1.6.0-openjdk), Gentoo (emerge -v icedtea6-bin), Ubuntu and Debian testing (aptitude install openjdk-6-jdk). The magic path is usually something like /usr/lib/jvm/blah where blah is java-1.6.0-openjdk on Fedora and /usr/lib/jvm/icedtea6 on Gentoo.

ICEDTEA_SOURCES points to a copy of the IcedTea tree. If you get this from a release tarball rather than hg, then you don't need to try finding the second gcc patch... you'd have a hard time doing so ;)

The OpenJDK build doesn't like environment variables like LD_LIBRARY_PATH and JAVA_HOME being set. It also complains about you having any fancy modern locale set in LANG so it's simplest just to run make with LANG=C. The JAVAC environment variable is a funny one; it allows the path to javac to be overridden for the build, but it doesn't only override the binary path as it should, but also drops all the necessary memory and classpath options passed to it. Thus, I don't see how any build which sets JAVAC could work... Gentoo seems to like to set both JAVA_HOME and JAVAC for some reason, so make sure they are unset before you build.

Of course, with the resulting build, you'll be missing a lot of features that IcedTea provides...

  • A web plugin
  • Java web start
  • PulseAudio sound support
  • Support for architectures like PPC, ARM and MIPS via Zero or CACAO
  • A faster more recent HotSpot if you use the current Mercurial tree or the upcoming 1.4 release
  • Lots of other lovely stuff provided by our patches including a more up-to-date version of Gervill, the results of the XRender pipeline project and support for testing your build with JTReg.

You also avoid the pain of having to remember those crazy make variables; it's just ./configure; make on most modern GNU/Linux systems; file a bug if that's not the case.

I still feel that the IcedTea project does a very important job in taking the raw materials provided by Sun and turning them into something useful. That's why you'll find it's IcedTea being shipped with all those distros, and not 'straight' OpenJDK (which in most cases actually means the version that may-eventually-be-1.7). Thanks to all the great developers for their continued efforts and for the support of Red Hat on this effort.

The other thing about your own build is you can't of course actually call it 'Java'; one of the things you need to do before you can is run it through the Java Compatibility Kit. It has lots of tests your build has to pass. Unfortunately, Sun still keep this as a horrible proprietary blob of code which means you have to sign up to get a copy, be 'approved' and then work on your testing in a dark clammy room in secret. Fortunately, the kind people at Red Hat have already undertaken this momentous task for you, so you can just grab one of the OpenJDK builds in Fedora which has already passed. Thus, according to Sun's FAQ, the Fedora binaries 'are compatible with the Java(TM) SE 6 platform' :)

Let's hope things continue to improve in the direction of making more things in the Java world open and Free. In the Free Java room at this year's FOSDEM (happening just next weekend), you'll be able to find out all about what's coming next and meet some of the brave people forging the new frontiers...

Happy hacking! :)

While working out where the class library makes calls to the VM can be tricky at times, such points are usually well-delimited (e.g. all in jvm.h in OpenJDK as we saw last time) and there are a variety of clues to help find them. Firstly, if a non-Java VM is in use, then the possible VM-utilising methods is already limited to those that are declared native. Secondly, failures in this area usually produce clear runtime errors such as linking errors (e.g. libjava.so can’t resolve the symbol JVM_IHashCode on loading). Thus, the main issues to deal with are usually ‘what should this method do?’ and ‘what state(s) can I expect this method to be executed from?’.

Library calls made from the VM are much more subtle. First of all, they of course vary from VM to VM. Some VMs may choose to call up to the library much more often than others. Certainly, this will be the case with a Java-based VM where the boundaries between the two are less clear, being delimited by packages rather than language/linking boundaries (though this also applies a little in the opposite direction too). Over the past few weeks, I’ve been attempting to get JamVM to run with the OpenJDK class library, simply by swapping glibj.zip from GNU Classpath for the rt.jar from OpenJDK*. This has revealed a number of cases where both JamVM and HotSpot call methods in their corresponding class libraries and thus depend on their presence.

As mentioned briefly last time, one of the first things I noticed was that it was assumed that the VM boot process would link libjava.so. As CACAO has also done, I had to add this to JamVM’s boot process in initialiseNatives.
Another area where a unspoken relationship between the VM and the class library exists is in the 1.4 JNI NIO support. The VM needs to be able to create a java.nio.DirectByteBuffer which maps onto a native buffer underneath. Both OpenJDK/HotSpot and GNU Classpath/JamVM do this in a similar way, but there are two notable differences between them:

  1. JamVM relies on GNU Classpath’s java.nio.DirectByteBufferImpl$ReadWrite class, which doesn’t exist on OpenJDK. Sun’s implementation is simply java.nio.DirectByteBuffer.
  2. The pointer to the buffer is passed from HotSpot to the OpenJDK class library as a jlong (a Java long, not to be confused with a C long, which may vary in size; Java longs are always 64-bit). GNU Classpath encapsulates pointers in a wrapper class called either Pointer32 or Pointer64, both of which have the common superclass of gnu.classpath.Pointer. This has the advantage of making it clearer that the number being stored is a pointer, with the disadvantage of having to create an object instance.

For now, I’ve altered JamVM to use the OpenJDK/HotSpot way of doing things, but it may be worth providing a Pointer class in OpenJDK, as it does have safety advantages. The only other minor difference is that the GNU Classpath constructor seems to take a few more arguments, but the same values were being provided by both JamVM and the superconstructor call in the OpenJDK class library.

Both issues highlighted so far have fairly trivial solutions and involve minimal interaction between the VM and class library. However, the biggest interaction point between the two is at boot-time. It is the VM that is started by the user (or in the case of OpenJDK, the launcher which then starts the VM via JNI). However, the actual code needs to be executing with direct reference to the class library, not the VM. This, again, differs between native and non-native VMs, where the former have to also make the switch from native code to Java code before the user code can be executed.

The runtime overview of HotSpot, provided by the HotSpot team, provides a good overview of the boot process from HotSpot’s perspective, although it doesn’t go into full detail on the interaction with the class library. Here, we concern ourselves mainly with the call to JNI_CreateJavaVM by the launcher, which takes us into src/share/vm/prims/jni.cpp in the HotSpot VM, and the class and thread initialisation that follows.

Most of the work (2-12) actually goes on in src/share/vm/runtime/thread.cpp and the create_vm method. The main part of this which is of interest for VM–>library interaction is the process by which the native OS thread is linked to a java.lang.Thread object. HotSpot makes three calls to the class library:

  1. (create_initial_thread_group) It creates an instance of java.lang.ThreadGroup using its no-arg constructor. This constructor is private and so can only be accessed by HotSpot for this purpose. This default constructor creates the root thread group, “system”.
  2. (create_initial_thread_group) It creates another java.lang.ThreadGroup instance using the public constructor which takes a parent group and a name. It uses this to create a child of “system” called “main”.
  3. (create_initial_thread) Calls the public constructor of java.lang.Thread to create a thread in the “main” group with the name “main”.

Apart from this, it initialises several core classes including java.lang.String, java.lang.reflect.Method, java.lang.ref.Finalizer and java.lang.Class, along with a number of exception and error classes such as java.lang.OutOfMemoryError. Additional classes are initialised if some options are enabled, such as java.util.HashMap if aggressive optimisations are turned on.

Although parts of this are specific to HotSpot, there is an implicit assumption in the class library that, for example, certain classes will have been initialised before the VM is fully operational. Thus another implementing VM has to do the same, calling the same internal methods such as the private thread group constructor described above. GNU Classpath has similar requirements, and in both cases, it is important we make such requirements explicit.

Note that GNU Classpath’s handling of threads differs considerably and I think there is some room for improvement here. JamVM does not pass or create any thread groups. An internal constructor expects a java.lang.VMThread which is then stored in java.lang.Thread and used for later calls such as start. Notably, the VM has to remember to set the group after the constructor concludes, and the hierarchy is different; GNU Classpath provides a root group called “main” which is created on java.lang.Thread class initialisation and JamVM places the main thread in that. There is no “system” group.

Both solutions leave the management of the thread itself to the VM, and it’s hard to see what the advantage is of GNU Classpath storing the VMThread. Calling general VMThread methods with the Thread instance may be a better solution. Where possible, general work should be taken off the VM and into the class library, and so it would be better if the group addition was handled by the constructor of Thread rather than relying on the VM to remember to do it.

I’d welcome comments on how different VMs handle this bootup process and what is the best solution for ensuring that the method contract between VM and class library is well documented and adhered to.

* Note that this means we still JamVM as the launcher for now. CACAO’s OpenJDK implementation takes a different approach with CACAO merely providing a replacement libjvm.so into a JDK tree and thus using the same launcher as HotSpot.

The biggest difference between the GNU Classpath and Sun OpenJDK VM interfaces is the point at which control shifts from the library to the virtual machine. Both solutions do provide separation between the library and the VM. Contrary to what may be initially assumed, this is true of OpenJDK even though both HotSpot and the JDK are maintained in the same location. This is what allows different versions of HotSpot to be swapped in, as mentioned in the OpenJDK trademark license. That said, there are likely to be closer ties between the JDK within OpenJDK and HotSpot than there are between GNU Classpath and any of its VMs, simply because of the number of and variance between the latter.

OpenJDK’s VM interface is entirely C-based. The class library calls into the VM using a number of functions with the prefix ‘JVM_’ that are listed in src/share/javavm/export/jvm.h. Implementations of these functions can be found both in HotSpot’s src/share/vm/prims/jvm.cpp and CACAO’s src/native/vm/openjdk/jvm.c. These are dynamically linked in at runtime for a variety of dynamic libraries held in jre/lib/${arch} where ${arch} is the architecture in use such as amd64. The output below shows their use in the recent b31 drop:

Checking build/linux-amd64/j2sdk-image/jre/lib/amd64/libjava.so...
                 U JVM_ActiveProcessorCount@@SUNWprivate_1.1
                 U JVM_ArrayCopy@@SUNWprivate_1.1
                 U JVM_AssertionStatusDirectives@@SUNWprivate_1.1
                 U JVM_Available@@SUNWprivate_1.1
                 U JVM_ClassDepth@@SUNWprivate_1.1
                 U JVM_ClassLoaderDepth@@SUNWprivate_1.1
                 U JVM_Clone@@SUNWprivate_1.1
                 U JVM_Close@@SUNWprivate_1.1
                 U JVM_CompileClass@@SUNWprivate_1.1
                 U JVM_CompileClasses@@SUNWprivate_1.1
                 U JVM_CompilerCommand@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetClassAt@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetClassAtIfLoaded@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetDoubleAt@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetFieldAt@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetFieldAtIfLoaded@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetFloatAt@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetIntAt@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetLongAt@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetMemberRefInfoAt@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetMethodAt@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetMethodAtIfLoaded@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetSize@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetStringAt@@SUNWprivate_1.1
                 U JVM_ConstantPoolGetUTF8At@@SUNWprivate_1.1
                 U JVM_CountStackFrames@@SUNWprivate_1.1
                 U JVM_CurrentClassLoader@@SUNWprivate_1.1
                 U JVM_CurrentLoadedClass@@SUNWprivate_1.1
                 U JVM_CurrentThread@@SUNWprivate_1.1
                 U JVM_CurrentTimeMillis@@SUNWprivate_1.1
                 U JVM_DefineClassWithSource@@SUNWprivate_1.1
                 U JVM_DesiredAssertionStatus@@SUNWprivate_1.1
                 U JVM_DisableCompiler@@SUNWprivate_1.1
                 U JVM_DoPrivileged@@SUNWprivate_1.1
                 U JVM_DumpThreads@@SUNWprivate_1.1
                 U JVM_EnableCompiler@@SUNWprivate_1.1
                 U JVM_FillInStackTrace@@SUNWprivate_1.1
                 U JVM_FindClassFromClassLoader@@SUNWprivate_1.1
                 U JVM_FindLibraryEntry@@SUNWprivate_1.1
                 U JVM_FindLoadedClass@@SUNWprivate_1.1
                 U JVM_FindPrimitiveClass@@SUNWprivate_1.1
                 U JVM_FindSignal@@SUNWprivate_1.1
                 U JVM_FreeMemory@@SUNWprivate_1.1
                 U JVM_GC@@SUNWprivate_1.1
                 U JVM_GetAllThreads@@SUNWprivate_1.1
                 U JVM_GetArrayElement@@SUNWprivate_1.1
                 U JVM_GetArrayLength@@SUNWprivate_1.1
                 U JVM_GetCallerClass@@SUNWprivate_1.1
                 U JVM_GetClassAccessFlags@@SUNWprivate_1.1
                 U JVM_GetClassAnnotations@@SUNWprivate_1.1
                 U JVM_GetClassConstantPool@@SUNWprivate_1.1
                 U JVM_GetClassContext@@SUNWprivate_1.1
                 U JVM_GetClassDeclaredConstructors@@SUNWprivate_1.1
                 U JVM_GetClassDeclaredFields@@SUNWprivate_1.1
                 U JVM_GetClassDeclaredMethods@@SUNWprivate_1.1
                 U JVM_GetClassInterfaces@@SUNWprivate_1.1
                 U JVM_GetClassLoader@@SUNWprivate_1.1
                 U JVM_GetClassModifiers@@SUNWprivate_1.1
                 U JVM_GetClassName@@SUNWprivate_1.1
                 U JVM_GetClassSignature@@SUNWprivate_1.1
                 U JVM_GetClassSigners@@SUNWprivate_1.1
                 U JVM_GetComponentType@@SUNWprivate_1.1
                 U JVM_GetDeclaredClasses@@SUNWprivate_1.1
                 U JVM_GetDeclaringClass@@SUNWprivate_1.1
                 U JVM_GetEnclosingMethodInfo@@SUNWprivate_1.1
                 U JVM_GetInheritedAccessControlContext@@SUNWprivate_1.1
                 U JVM_GetInterfaceVersion@@SUNWprivate_1.1
                 U JVM_GetLastErrorString@@SUNWprivate_1.1
                 U JVM_GetPrimitiveArrayElement@@SUNWprivate_1.1
                 U JVM_GetProtectionDomain@@SUNWprivate_1.1
                 U JVM_GetStackAccessControlContext@@SUNWprivate_1.1
                 U JVM_GetStackTraceDepth@@SUNWprivate_1.1
                 U JVM_GetStackTraceElement@@SUNWprivate_1.1
                 U JVM_GetSystemPackage@@SUNWprivate_1.1
                 U JVM_GetSystemPackages@@SUNWprivate_1.1
                 U JVM_Halt@@SUNWprivate_1.1
                 U JVM_HoldsLock@@SUNWprivate_1.1
                 U JVM_IHashCode@@SUNWprivate_1.1
                 U JVM_InitProperties@@SUNWprivate_1.1
                 U JVM_InternString@@SUNWprivate_1.1
                 U JVM_Interrupt@@SUNWprivate_1.1
                 U JVM_InvokeMethod@@SUNWprivate_1.1
                 U JVM_IsArrayClass@@SUNWprivate_1.1
                 U JVM_IsInterface@@SUNWprivate_1.1
                 U JVM_IsInterrupted@@SUNWprivate_1.1
                 U JVM_IsNaN@@SUNWprivate_1.1
                 U JVM_IsPrimitiveClass@@SUNWprivate_1.1
                 U JVM_IsSupportedJNIVersion@@SUNWprivate_1.1
                 U JVM_IsThreadAlive@@SUNWprivate_1.1
                 U JVM_LatestUserDefinedLoader@@SUNWprivate_1.1
                 U JVM_LoadLibrary@@SUNWprivate_1.1
                 U JVM_Lseek@@SUNWprivate_1.1
                 U JVM_MaxMemory@@SUNWprivate_1.1
                 U JVM_MaxObjectInspectionAge@@SUNWprivate_1.1
                 U JVM_MonitorNotify@@SUNWprivate_1.1
                 U JVM_MonitorNotifyAll@@SUNWprivate_1.1
                 U JVM_MonitorWait@@SUNWprivate_1.1
                 U JVM_NanoTime@@SUNWprivate_1.1
                 U JVM_NativePath@@SUNWprivate_1.1
                 U JVM_NewArray@@SUNWprivate_1.1
                 U JVM_NewInstanceFromConstructor@@SUNWprivate_1.1
                 U JVM_NewMultiArray@@SUNWprivate_1.1
                 U JVM_Open@@SUNWprivate_1.1
                 U JVM_RaiseSignal@@SUNWprivate_1.1
                 U JVM_Read@@SUNWprivate_1.1
                 U JVM_RegisterSignal@@SUNWprivate_1.1
                 U JVM_ResolveClass@@SUNWprivate_1.1
                 U JVM_ResumeThread@@SUNWprivate_1.1
                 U JVM_SetArrayElement@@SUNWprivate_1.1
                 U JVM_SetClassSigners@@SUNWprivate_1.1
                 U JVM_SetLength@@SUNWprivate_1.1
                 U JVM_SetPrimitiveArrayElement@@SUNWprivate_1.1
                 U JVM_SetProtectionDomain@@SUNWprivate_1.1
                 U JVM_SetThreadPriority@@SUNWprivate_1.1
                 U JVM_Sleep@@SUNWprivate_1.1
                 U JVM_StartThread@@SUNWprivate_1.1
                 U JVM_StopThread@@SUNWprivate_1.1
                 U JVM_SupportsCX8@@SUNWprivate_1.1
                 U JVM_SuspendThread@@SUNWprivate_1.1
                 U JVM_Sync@@SUNWprivate_1.1
                 U JVM_TotalMemory@@SUNWprivate_1.1
                 U JVM_TraceInstructions@@SUNWprivate_1.1
                 U JVM_TraceMethodCalls@@SUNWprivate_1.1
                 U JVM_UnloadLibrary@@SUNWprivate_1.1
                 U JVM_Write@@SUNWprivate_1.1
                 U JVM_Yield@@SUNWprivate_1.1
Checking build/linux-amd64/j2sdk-image/jre/lib/amd64/libmanagement.so...
                 U JVM_ActiveProcessorCount@@SUNWprivate_1.1
                 U JVM_GetAllThreads@@SUNWprivate_1.1
                 U JVM_GetManagement@@SUNWprivate_1.1
Checking build/linux-amd64/j2sdk-image/jre/lib/amd64/libnet.so...
                 U JVM_Connect@@SUNWprivate_1.1
                 U JVM_CurrentTimeMillis@@SUNWprivate_1.1
                 U JVM_FindLibraryEntry@@SUNWprivate_1.1
                 U JVM_GetHostName@@SUNWprivate_1.1
                 U JVM_GetSockName@@SUNWprivate_1.1
                 U JVM_GetSockOpt@@SUNWprivate_1.1
                 U JVM_InitializeSocketLibrary@@SUNWprivate_1.1
                 U JVM_Listen@@SUNWprivate_1.1
                 U JVM_Send@@SUNWprivate_1.1
                 U JVM_SetSockOpt@@SUNWprivate_1.1
                 U JVM_Socket@@SUNWprivate_1.1
                 U JVM_SocketAvailable@@SUNWprivate_1.1
                 U JVM_SocketClose@@SUNWprivate_1.1
                 U JVM_SocketShutdown@@SUNWprivate_1.1
Checking build/linux-amd64/j2sdk-image/jre/lib/amd64/librmi.so...
                 U JVM_LatestUserDefinedLoader@@SUNWprivate_1.1
Checking build/linux-amd64/j2sdk-image/jre/lib/amd64/libverify.so...
                 U JVM_FindClassFromClass@@SUNWprivate_1.1
                 U JVM_GetCPClassNameUTF@@SUNWprivate_1.1
                 U JVM_GetCPFieldClassNameUTF@@SUNWprivate_1.1
                 U JVM_GetCPFieldModifiers@@SUNWprivate_1.1
                 U JVM_GetCPFieldSignatureUTF@@SUNWprivate_1.1
                 U JVM_GetCPMethodClassNameUTF@@SUNWprivate_1.1
                 U JVM_GetCPMethodModifiers@@SUNWprivate_1.1
                 U JVM_GetCPMethodNameUTF@@SUNWprivate_1.1
                 U JVM_GetCPMethodSignatureUTF@@SUNWprivate_1.1
                 U JVM_GetClassCPEntriesCount@@SUNWprivate_1.1
                 U JVM_GetClassCPTypes@@SUNWprivate_1.1
                 U JVM_GetClassFieldsCount@@SUNWprivate_1.1
                 U JVM_GetClassMethodsCount@@SUNWprivate_1.1
                 U JVM_GetClassNameUTF@@SUNWprivate_1.1
                 U JVM_GetFieldIxModifiers@@SUNWprivate_1.1
                 U JVM_GetMethodIxArgsSize@@SUNWprivate_1.1
                 U JVM_GetMethodIxByteCode@@SUNWprivate_1.1
                 U JVM_GetMethodIxByteCodeLength@@SUNWprivate_1.1
                 U JVM_GetMethodIxExceptionIndexes@@SUNWprivate_1.1
                 U JVM_GetMethodIxExceptionTableEntry@@SUNWprivate_1.1
                 U JVM_GetMethodIxExceptionTableLength@@SUNWprivate_1.1
                 U JVM_GetMethodIxExceptionsCount@@SUNWprivate_1.1
                 U JVM_GetMethodIxLocalsCount@@SUNWprivate_1.1
                 U JVM_GetMethodIxMaxStack@@SUNWprivate_1.1
                 U JVM_GetMethodIxModifiers@@SUNWprivate_1.1
                 U JVM_GetMethodIxNameUTF@@SUNWprivate_1.1
                 U JVM_GetMethodIxSignatureUTF@@SUNWprivate_1.1
                 U JVM_IsConstructorIx@@SUNWprivate_1.1
                 U JVM_IsInterface@@SUNWprivate_1.1
                 U JVM_IsSameClassPackage@@SUNWprivate_1.1
                 U JVM_ReleaseUTF@@SUNWprivate_1.1
Checking build/linux-amd64/j2sdk-image/jre/lib/amd64/libzip.so...
                 U JVM_Close@@SUNWprivate_1.1
                 U JVM_GetLastErrorString@@SUNWprivate_1.1
                 U JVM_Lseek@@SUNWprivate_1.1
                 U JVM_NativePath@@SUNWprivate_1.1
                 U JVM_Open@@SUNWprivate_1.1
                 U JVM_RawMonitorCreate@@SUNWprivate_1.1
                 U JVM_RawMonitorDestroy@@SUNWprivate_1.1
                 U JVM_RawMonitorEnter@@SUNWprivate_1.1
                 U JVM_RawMonitorExit@@SUNWprivate_1.1

Clearly most of these are found in libjava.so, which is the library that contains the native code for the core classes like those in java.lang. What’s interesting about libjava is that, unlike for example libnet, it isn’t loaded via a call to LoadLibrary in the class library code. Rather, it is expected that the VM will know about and load this. In CACAO, a special OpenJDK case is provided in src/native/vm/nativevm.c to handle this. This needs to happen early in the VM initialisation process before any of the native calls in the core classes are used.

In contrast, GNU Classpath interacts with the VM while still at the Java level. Each call which may need to go to the VM is first handed off to a package-private VM class, for example vm/reference/java/lang/VMObject.java provides methods like wait() and notify(). The reference version of these classes tend to do what the OpenJDK classes do in the original classes like java.lang.Object; define the methods as native. However, a VM can replace these VM* classes as needed. Some are mandatory, as it isn’t possible to provide a generic reference implementation in the class library. In both cases, missing implementations are visible through linking errors at runtime.

To further clarify the difference, let’s trace the path of one such function, java.lang.Object#wait(). In GNU Classpath, java.lang.Object defines it as:

  public final void wait()
    throws IllegalMonitorStateException, InterruptedException
  {
    VMObject.wait(this, 0, 0);
  }

in java/lang/Object.java. In the reference version of VMObject.java, we find:

  static native void wait(Object o, long ms, int ns)
    throws IllegalMonitorStateException, InterruptedException;

In some cases, there is also a reference native implementation under native/jni/${package name}/${package_name}_${class_name}.c (native/jni/java-lang/java_lang_VMObject.c in this case), but this isn’t the case here. Instead, we look to CACAO and find this in src/native/vm/gnuclasspath/java_lang_VMObject.cpp:

JNIEXPORT void JNICALL Java_java_lang_VMObject_wait(JNIEnv *env, jclass clazz, java_lang_Object *o, int64_t ms, int32_t ns)

How about for OpenJDK? Again, we start in java.lang.Object and find this in src/share/classes/java/lang/Object.java:

public final native void wait(long timeout) throws InterruptedException;

Unlike with GNU Classpath, the java.lang.Object code goes straight to the native implementation found in src/share/native/java/lang/Object.c. However, we don’t find an implementation there. Instead, we need to look at another function in Object.c called registerNatives:

static JNINativeMethod methods[] = {
    {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
    {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
    {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
    {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
    {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
};

JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
    (*env)->RegisterNatives(env, cls,
                            methods, sizeof(methods)/sizeof(methods[0]));
}

The array, methods, tells us that wait maps to JVM_MonitorWait. Looking at the list above, we see that JVM_MonitorWait is one of the VM symbols in the java library. And sure enough, we find it in src/share/javavm/export/jvm.h:

JNIEXPORT void JNICALL
JVM_MonitorWait(JNIEnv *env, jobject obj, jlong ms);

and a corresponding implementation in HotSpot’s src/share/vm/prims/jvm.cpp

JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))

and CACAO’s jvm.c:

void JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms)

Clearly, there isn’t that much difference between the two. The main issue is finding the right functions and where and how they are called. One other major difference is that Classpath VMs provide their own launchers (you run ‘cacao’, ‘jamvm’, ‘gij’, ‘kaffe’ etc. binaries) while the ‘java’ in OpenJDK is a standard launcher (also used for other tools) which invokes the VM via JNI and libjvm.so. There’s also a mechanism for selecting VM in this manner through src/(solaris|windows)/bin/${arch}/jvm.cfg, which we’ll look at later.

With the CVMI project, we aim to document these issues and also experiment with providing an OpenJDK interface more at the Java level. Comments and suggestions welcome.

I’ve been meaning to write this blog for a while, but other things have cropped up in the meantime. The topic is something that came up when trying to lower the number of warnings produced by a build of GNU Classpath.

While GNU Classpath has required a 1.5 capable compiler since 0.95, so we could implement things like java.lang.Enum, the use of generics and such has only largely being applied to the creation of new classes (like java.util.ServiceLoader) and the suppression of JAPI differences. The internal code, such as that in the gnu.* packages and the private variables within the java.* and javax.* classes has remained in 1.4 form. As a result, the compiler generates a lot of ‘unchecked’ warnings, mainly due to the use of ‘raw’ collections (I’ll explain what these are shortly). ecj is still our preferred compiler (being the most tested and the one we had available as Free Software first) and it generates far more warnings by default than Sun’s javac. At present count, Classpath CVS generates just over 10,000 warnings with ecj 3.3. We clearly need to cut this down so we can spot real problems. In the past, we’ve simply turned them off but it’s better for the codebase in general if these are properly cleaned up and in some cases it does cause bugs to be discovered.

So what’s the problem? Well, mainly it’s a case of most of the GNU Classpath code still looking like:

List list = new ArrayList();
list.add("Potato");

or:

Map map = new HashMap();
map.put("key", new Value());

Map, List, ArrayList and HashMap are now referred to as raw types because the versions in Java 1.5 and above have one or more type parameters. These type parameters can be used to tell us what is stored inside the collection. We should be using Map<K,V>, List<T>, ArrayList<T> and HashMap<K,V>, the parameterized types. The type parameters, (K, V and T in this case) can be used in methods to specify that the type of an argument or return value depends on the type given when the collection is created. Thus, Map<K,V> has:

V put(K key, V value)

as opposed to:

Object put(Object key, Object value)

K is the type of key used for the map, and V is the value. In our original example, our Map should be replaced with Map<String,Value> because it maps keys of type String to values of type Value. The main advantage of using these is you no longer need to cast elements when they are returned from the collection. So a get call on a List<T> or Map<K,V> returns a value of type T or V respectively, not simply an Object which has to be cast manually by the user. In reality, backwards compatibility means these casts are still being inserted by the compiler, but for it to do this it must have been determined to be safe to do so.

So how do we clean up these warnings? It means going through the code and adding appropriate type parameters to our collections. This isn’t always as easy as it sounds. In some cases, the collection will only be used with one type so it’s simply a matter of determining what that is (usually by looking for the casts when objects are retrieved from the collection — these casts can soon be removed). However, because raw collections take Objects as input, there can be a mix of types so a common supertype has to be found.

In some cases, this has to be Object. So, you may think, what’s the point of turning Map into Map<Object,Object>? Surely they are the same thing. No they’re not, and this is one of the more interesting aspects of collections and one you’ll especially come across when you have to deal with using a raw collection coming from legacy code without generating unchecked warnings. Map the raw type is actually equivalent to Map<?,?>, where ? represents a wildcard. Wildcards allow the use of existential types; instead of having a strict instantiation of a type parameter, we can refer to any type within certain bounds. By default, a wildcard has an upper bound of Object and a lower bound of null i.e. Map<?,?> is the same as Map<? extends Object super null, ? extends Object super null>. What does this say in English? It says that the keys and values of the map are of some type that extends Object but we don’t know exactly what. In contrast, Map<Object,Object> says that the keys and values must be Objects.

We don’t want to work with wildcard types practically because we can’t have variables of type ?. Instead, we use them when importing and exporting from parameterized types. For example, to import objects from a collection, addAll is not defined as:

void addAll(Collection<T> t)

because doing so would mean that we can only take objects from collections of exactly the same type. Instead, we want to also allow collections of some subtype. For example, a collection of Objects should be allowed to be filled from a Collection of Strings. The above signature doesn’t allow this, but:

void addAll(Collection<? extends T> t)

does. This says that the collection from which the elements are to be taken must contain objects of some type which is a subtype of T. A similar example for super is the use of Comparator<? super T>. When we want something that can compare two objects of type T, we can work with both something that can compare two elements of type T but we can also use a more general comparison method that compares some supertype. For example, a Comparator<Object> can be used to compare Strings. In this case, we can’t go the other way; it would be inappropriate to try using a Comparator for Integers to compare general Number instances.

The most confusing aspect of dealing with generics is how to handle legacy code where you can’t make the incoming type a parameterized type. Take the following legacy method:

  public List createFruits()
  {
    List x = new ArrayList();
    x.add("Strawberry");
    x.add("Banana");
    x.add("Pineapple");
    return x;
  }

This returns a raw type, List. Now imagine we can’t see the body of the method. All we know is that the method returns a List; we don’t know what is in that list. This is how the compiler sees the method.

We of course know that it contains String objects. So we try and pass it to a method that takes a List<String>:

  public void printList(List<String> l)
  {
    for (String s : l)
      System.out.println(s);
  }

The obvious solution to do this is:

printList(testFruits())

and this will compile, but it produces an unchecked warning:

warning: [unchecked] unchecked conversion
found   : java.util.List
required: java.util.List<java.lang.String>
    printList(createFruits());

So we take the obvious solution to this from the old 1.4 days and cast it:

printList((List<String>) testFruits())

Again, this compiles but we get a different unchecked warning:

warning: [unchecked] unchecked cast
found   : java.util.List
required: java.util.List<java.lang.String>
    printList((List<String>) createFruits());

So we get a warning with the cast, and one without. What do we do?

The answer is to take a step back and think about what this incoming List really is. As we noted before, the equivalent of List in the new 1.5 world is List<?> so:

List<?> l = (List<?>) testFruits();

No warnings, so far so good. This is deemed a safe cast because we are merely telling the compiler to move from the 1.4 to 1.5 version of the same thing. But how do we change this into a List<String>?

Remember that the ? wildcard without explicit bounds is telling us that the most we know about the contents of the list is that they are some subtype of Object. As such, the only thing we can safely retrieve them as is Objects:

    List<Object> newList = new ArrayList<Object>();
    for (Object o : l)
      newList.add(o);
    printList(newList);

This takes each Object from the list and puts it in a new list which holds Objects. By doing so we have removed the doubt about what is in the collection and telling the compiler to simply treat them all as Objects. What we have now is equivalent to what we thought we had to start with. However, this still won’t work with our printList method:

printList(java.util.List<java.lang.String>) in Test cannot be applied to (java.util.List<java.lang.Object>)
    test.printList(newList);

This is an error so the code will now not even compile. This is good; we don’t want the compiler to allow us to pass collections of mere Objects to methods requiring collections of Strings. This would take us straight back to Java 1.4 days. The solution is to create a List<String> instead of a List<Object> and check that each objects is a String in the body of the loop which adds them to the collection.

    List<String> newList = new ArrayList<String>();
    for (Object o : l)
      if (o instanceof String)
        newList.add((String) o);
    printList(newList);

Finally we have working code which has no warnings, while still using the legacy code. This however can be quite inefficient; in some cases, we want to avoid iterating over the entire collection when we know this is going to happen anyway. A common place where this happens is using the addAll method of collections. The addAll will take each object and cast it in adding it to the list anyway (the retrieval from the producer list will generate such a cast). In these cases, we can use the annotation @SuppressWarnings(“unchecked”) to turn off the warning we know is superfluous.

This should be used with care. It should also cover the minimum area possible to avoid suppressing other warnings. Annotations can go on individual assignments so there is no need to suppress warnings for the entire method. For example, here is Classpath’s getAnnotation method:

  public <T extends Annotation> T getAnnotation(Class>T> annotationClass)
  {
    // Inescapable as the VM layer is 1.4 based.
    @SuppressWarnings("unchecked")
      T ann = (T) cons.getAnnotation(annotationClass);
    return ann;
  }

cons.getAnnotation will return something of type Annotation as our VM layer is strictly 1.4 only. As we know from the input class that the annotation will be of type T, we can forcibly apply a cast and disable the warning. Note that the suppression applies only to the one line, and the explicit assignment of ann is used to allow this (an annotation can’t be attached to a return statement). We also add a comment to explain the reasoning behind adding this annotation. This should be used sparingly and where possible generics should be used properly. In some cases, we don’t even need to convert the collection; retrieving the size can be achieved simply from a List<?> or similar.

My thanks to Joshua Bloch and his ‘Effective Java’ book for finally explaining some of the solutions documented here. I didn’t realise until reading this that annotations could be applied to such a narrow scope or that it was safe to cast to a wildcard type from a raw type. This has enabled me to clean up a lot of the Classpath code.

Congratulations also to the IcedTea team, especially the OpenJDK Debian Team, for getting openjdk-6 into sid!

And finally, congratulations to Mark and Petri on the birth of their son, Jonas :)

We are proud to announce the release of GNU Classpath 0.97.2, the second bugfix release for GNU Classpath 0.97.

GNU Classpath, essential libraries for java, is a project to create free core class libraries for use with runtimes, compilers and tools for the java programming language.

The GNU Classpath developer snapshot releases are not directly aimed at the end user but are meant to be integrated into larger development platforms. For example JamVM, CACAO and Kaffe can make use of an installed copy of GNU Classpath 0.97.2, while GCC (gcj) will use the developer snapshots as a base for future versions. For more projects based on GNU Classpath, see http://www.gnu.org/software/classpath/stories.html

This is the second of a new series of bugfix releases that follow a major (0.x) release. A 0.x.y release will only contain minor bug fixes. It will not cause major changes in the functionality of GNU Classpath, either for better or for worse.

With this bugfix release, the following issues have been resolved:

* Include headers in the release tarball.
* Allow the building of tools to be optional.
* Only check for a Java compiler when required.
* Allow VMOperatingSystemMXBeanImpl to compile on Solaris.
* Documentation typo fixes
* Fix memory leak in native/jni/classpath/jcl.c
* Web page updates (PR classpath/22883)
* Fixes to pass the JSR166 TCK
* Use awk to construct the classlist on building
* Fix deadlock in Logger (PR classpath/35974)
* Fix regression in java.lang.String (PR classpath/35482)
* Allow Classpath tools to handle @file options.
* Allow parseInt to handle a + prefix correctly.
* Remove use of 1.5 language constructs in the VM layer.

From the 0.95 release, we switched fully towards the 1.5 generics work that we previously released separately as classpath-generics. All this work is now fully integrated in the main release and various runtimes (GCJ, CACAO, JamVM, JikesRVM etc) have been extended to take advantage of the new generics, annotations and enumeration support in the core library. As a consequence, only 1.5 capable compilers (currently the Eclipse Compiler for Java (ecj) and Sun’s javac) may be used to build Classpath.

The GNU Classpath developers site (http://developer.classpath.org/) provides detailed information on how to start with helping the GNU Classpath project and gives an overview of the core class library packages currently provided.

For each snapshot release generated documentation is provided through the GNU Classpath Tools gjdoc project, which will become part of GNU Classpath itself with the release of 0.98. A documentation generation framework for java source files used by the GNU project. Full documentation on the currently implemented packages and classes can be found at: http://developer.classpath.org/doc/ We are looking into how to extend the documentation experience in the future. Please contact the mailinglist if you would like to help with this effort.

For more information about the project see also:

GNU Classpath home page: http://www.gnu.org/software/classpath/
Developer information (wiki): http://developer.classpath.org/
Full class documentation: http://developer.classpath.org/doc/
GNU Classpath hackers: http://planet.classpath.org/
Autobuilder, current build status, build snapshots:

http://builder.classpath.org/

Application test pages (wiki):

http://developer.classpath.org/mediation/Applets

http://developer.classpath.org/mediation/FreeAWTTestApps

http://developer.classpath.org/mediation/FreeSwingTestApps

http://developer.classpath.org/mediation/FreeSWTTestApps

GNU Classpath hacking with Eclipse (wiki):

http://developer.classpath.org/mediation/ClasspathHackingWithEclipse

GNU Classpath promotion banners:

http://developer.classpath.org/mediation/ClasspathBanners

GNU Classpath 0.97.2 is available from ftp://ftp.gnu.org/pub/gnu/classpath/, one of the ftp.gnu.org mirrors (http://www.gnu.org/order/ftp.html) or the Classpath continuous integration system (http://builder.classpath.org/dist)

File: classpath-0.97.2.tar.gz
MD5sum: 6a35347901ace03c31cc49751b338f31
SHA1sum: 627e9781f9bb744b1a70e4aaff88d2d0440cbf1f

The following people helped fix bugs in Classpath 0.97.1:

Andrew John Hughes, Michael Koch, Jim Meyering, Robert Schuster, Mario Torre, Tom Tromey, Ralf Wildenhues

The following people helped with the release of Classpath 0.97 and/or 0.97.1:

Luciano Chavez, Thomas Fitzsimmons, Bernhard Fischer, Jeroen Frijters, Stefan Huehner, Andrew John Hughes, Jakub Jelinek, Ito Kazumitsu, Roman Kennke, Alexandre Oliva, Petteri Raety, Ian Rogers, Robert Schuster, Leen Toelen, Mario Torre, Dalibor Topic, Tom Tromey, David Walluck, Mark Wielaard and Ralf Wildenhues.

We would also like to thank the numerous bug reporters and testers! In addition, we’d like to extend our thanks to all those who’ve contributed over the years and have helped in building a thriving and friendly community around the GNU Classpath project.

One interesting issue when writing a runtime class library for Java is how to give implementation packages, whether they be in gnu.* or com.sun.*, specialised access to the core runtime classes like those in java.lang. We ran across this problem again recently with GNU Classpath when trying to write CPStringBuilder. This is a StringBuilder variant that differs in how it utilises its internal character array. StringBuffer and StringBuilder both maintain their own character array throughout their life, creating a new larger one and copying when appropriate. When toString() or substring(int,int) is called, the new String object is given a copy of the array.

CPStringBuilder instead optimises for the frequent cases where a StringBuilder is created, used to build a String and then discarded after toString() is called. It does so by handing a reference to the character array to the new String object on creation. Once this is done, it flags internally that the array has been used and creates a new one if any further writes are requested. Thus, using CPStringBuilder should always be one copy more efficient than using StringBuilder or StringBuffer (possibly even creating just a single array if the final string is within the initial capacity) and we now use it internally when the builder does not need to be thread-safe.

The problem with implementing this is that it requires passing the array to the constructor of the String object. There is no such constructor in the public API for String, although Classpath has had a package-private one for sometime (GCJ and String itself already use it). But how do we access this from the gnu.java.lang package? Our current method is to use reflection, and thus we have VMCPStringBuilder so VMs can optimise this natively.

When looking through OpenJDK for the VM project, I noticed that they have a rather interesting solution to this. This is encapsulated in sun.misc.SharedSecrets. This class provides access to instances of a number of public interfaces, such as sun.misc.JavaLangAccess. The actual implementations are provided as inner classes in the appropriate package e.g. java.lang, where it has access to the private and package-private variables and methods within. For instance, JavaLangAccess provides access to the constant pool for a particular class.

The only noticeable negative side effect of this is that any external class may also call these methods. For example:

import sun.misc.SharedSecrets;

public class TestSecrets
{
  public static void main(String[] args)
  {
    System.out.println(SharedSecrets.getJavaLangAccess().getConstantPool(String.class));
  }
}

whereas the equivalent for GNU Classpath:

import gnu.java.lang.VMCPStringBuilder;

public class TestCPSecrets
{
  public static void main(String[] args)
  {
    System.out.println(VMCPStringBuilder.toString(new char[]{'H','e','l','l','o'},0,5));
  }
}

fails to compile because VMCPStringBuilder is package-private (although the equivalent is possible by using CPStringBuilder in this case). As a result, it becomes slightly more important to ensure that the possible damage from using these classes is limited.

That said, this may be an interesting and more efficient method for us to look into for GNU Classpath.

(more…)

So I went to the rms talk last Thursday and throughly enjoyed it. This was the second time I’d seen him speak, and can certainly recommend it to others. As others have remarked, he is quite entertaining to listen to and the way he upholds and adheres to his values is worthy of admiration. The last time I saw him speak (maybe three or four years ago in Sheffield), it was on the subject of software patents. This time round, I was treated to a more general FOSS talk, which touched on well-known topics such as the history of GNU, the whole GNU/Linux debacle and truly Free distros along with DRM. rms also made specific mention of commercial Free Software (a common point of confusion for many) and of Free Software in education.

The latter I feel is very important and, as I currently work in a University, it’s a topic close to my heart. Access to source code is an invaluable learning aid. The few pieces of source code our students see, that they haven’t developed with their own hands, are throughly mothballed pieces of code which barely hang together by a string, having being developed by one academic long ago and then passed on like some hand-me-down. They certainly aren’t examples of good coding, but you won’t always find this in Free Software either. What you will find is code that has been used by hundreds if not thousands of users. Code which has been built on numerous platforms and maintained by GNU/Linux distributions. Code which has stood the test of time and experience, even if it still comes out dirty at the end. By contrast, the examples most students see are reused year after year with little to no change to the code. One of our lecturers is currently only distributing the code the students need as binary simply because the code itself is so ugly and hairy he doesn’t want them to use it as an example. The advent of the OpenJDK project will help, because it should mean that the software on the desktops of Free Software users more and more utilises Java. Why is this important? Because the majority of students are taught Java first and foremost. Most of our students never use C throughout their undergraduate life. So examples of big bodies of Java code are what’s needed and the OpenJDK is a great contribution in this respect, as is GNU Classpath — they both provide samples of the good, the bad and the ugly.

The other important point about Free Software in Education is the ‘get them while they’re young’ theory, which rms likened to addicting children to drugs. He seems to like harsh metaphors, but this one I feel is not too overboard. Certainly, proprietary software vendors provide school and university students with cut-down or gratis copies of their wares. The students get used to this software and start to use it. In many cases, they are effectively forced to, as part of their studies. When they then step out into the big wide world, this is all they know. And our teachers and lecturers, far from promoting sharing and education as they should, are helping this addiction process, even if it’s simply by distributing a Word document to students or using that as the format for a handin. I’ve had to repeatedly mail back our university admin staff of late to obtain the minutes to meetings in a format other than the Word document they keep dropping in my inbox. One would hope they would start to take the hint…

For the finale of the talk, we were lucky enough to be visited by St. IGNUcius of the Church of Emacs. rms then took questions from the audience for well over an hour. He has a very admirable way of doing this; he clearly takes in every word being said, and you can hear the response before it comes when someone mentions ‘open source’ rather than ‘free software’ or some other faux pax, which they really should have known better than to utter, given the preceding two hours talk. I’m really surprised rms didn’t get more exsasperated than he did at some of them. I guess he must be used to it by now. He certainly seems to have a clear well-thought out answer for everything.

For those who couldn’t make the talk, I recorded it in full (with questions) and, with the help of Tim Dobson from the Manchester Free Software group, have made this available on-line. Where possible, we’d prefer you obtain the video from the torrent to reduce bandwidth load on those kind enough to host this. You can find the appropriate links on my website. If anyone would like to provide a further HTTP mirror of this, please get in touch. You can also help the Free Software community by helping to seed this via BitTorrent — this will help others get a copy :)

Next Page »