# Friday, 09 February 2007
Class Loading Architecture

As I previously blogged, 0.32 has a new class loading architecture. I promised to explain the architecture, but I accidentally deleted the blog post I wrote about it a while ago and I didn't feel like rewriting it straight away, but I still need to do it, so here it is ;-)

The Basic Idea

Every .NET assembly has its own corresponding ClassLoader instance. This is true for assemblies generated with ikvmc as well as other .NET languages. The class loader instance corresponding to an assembly is known as the assembly class loader. It does not have a parent class loader (ClassLoader.getParent() returns null), but it does do a form of delegation. When the assembly class loader is used to load a class or resource, first it will search the corresponding assembly, if that doesn't result in the requested item, the assemblies directly referenced by the assembly are searched (and if that also doesn't find the item, the IKVM.GNU.Classpath assembly is searched).

The System Class Loader

By default the system class loader will be set to the assembly class loader of the main application executable assembly. If there is no main executable assembly (e.g. the main executable is unmanaged or the AppDomain was created without one) or the java.class.path or java.ext.dirs properties are set, then a URLClassLoader that searches the classpath is used. This means that in most scenarios no dynamic Java class loading is enabled by default. This also means that you don't have to worry about your application being affected by the CLASSPATH environment variable as set on the system where the application runs (which previously could -- and did -- result in hard to diagnose problems on some systems with a weird CLASSPATH setting.)

Dynamically Loading a Class

Class.forName() just works if the class loader it uses (and, like Java, it uses the class loader that loaded the calling class) can find the class. It can also be used to load classes from assemblies that are not referenced by any class loader that is already available. This is done by specifying the assembly qualified name of the type (in .NET form, without the cli prefix). Here's an example:

class MsgBox
{
  public static void main(String[] args) throws Exception
  {
    Class c = Class.forName("System.Windows.Forms.MessageBox, " +
                "System.Windows.Forms, " +
                "Version=1.0.5000.0, " +
                "Culture=neutral, " +
                "PublicKeyToken=b77a5c561934e089");
    c.getMethod("Show", String.class).invoke(null, "Hello, World!");
  }
}

Versioning

One nice benefit of the new architecture is that it is now possible for two (or more) different versions of a jar to be loaded and used in the same AppDomain. Previously that would sort of work, but it would break down if the code used Class.forName() or tried to load resources. However, now the class loader namespaces can be fully seperated (you still can't have a single assembly that directly references two versions of the same code, but indirectly it works fine.) Here's an example of an application that uses two different assemblies that both depend on different versions of the same assembly:

The rectangles represent assemblies and the ovals represent class loaders. The pink oval is the assembly class loader for App.exe and can see classes in both Foo.dll and Bar.dll, but won't be able to see any classes from either of the Widgets assemblies. The yellow oval is the assembly class loader of Foo.dll and it allows Foo.dll to see the correct version of Widgets.dll, but not the other one (nor any classes in App.exe, unless it uses the system class loader). Each Widgets.dll assembly will also have its own assembly class loader (not shown in the diagram) and that will only be able to load classes from the corresponding Widgets assembly.

JSR 277

The limitations of the Java class loading architecture have long been known and several hacks have been developed to work around some of those limitations, but it is clearly desirable (at least to some people) to replace the current architecture with something better. JSR 277 is trying to define that new architecture. I believe that the architecture that IKVM 0.32 introduced is very similar to what JSR 277 is going to end up like, so in the future it should be possible to support JSR 277 without any major changes. Also, if your Java code requires changes to be compatible with the IKVM architecture, it almost certainly will require similar changes to deal with JSR 277 and making these changes now will make it easier to migrate to JSR 277 based modules in the future.

Friday, 09 February 2007 09:27:03 (W. Europe Standard Time, UTC+01:00)  #    Comments [3]
# Monday, 05 February 2007
New Snapshot

It's been a while since the 0.32 release and there has been a fair bit of change going on, so I thought I'd release a snapshot for people who want to play with up to date binaries.

Changes:

  • Updated to current GNU Classpath cvs version.
  • Added support for representing .NET enum types as Java enums for use in annotations (.NET enum types now have an inner class __Enum).
  • Added support for adding fields to classes in map.xml.
  • Fixed remapping infrastructure to not generate superfluous method body for interface methods.
  • Added partial support for enum types in .NET attribute annotations.
  • Added Java 1.6 methods to java.lang.String.
  • Added -warnaserror option to ikvmc (suggested by David Ehrlich).
  • Many AWT improvements (by Volker Berlin).
  • Added caching to VMStackWalker.isHideFromJava to speed up stack walking (suggested by Trevor Bell).
  • Fixed handling of non-vector arrays.
  • Made JNIEnv.FatalError more compatible with JDK and removed call to JVM.CriticalFailure (which is reserved for IKVM bugs).
  • Centralised OEM string decoding in JNI code.
  • Changed JVM.CriticalFailure to write message to console instead of displaying a message box in ikvmc.
  • Fixed AnnotationBuilder to add ImplementsAttribute to annotation attribute, so that reflection correctly reports the implemented annotation interface.
  • Fixed AnnotationBuilder to ignore annotation attribute properties of type Annotation (as .NET attributes have no way to encode them).
  • Implemented annotation support in StubGenerator (used by ikvmstub and other code that reads statically compiled classes as resources).
  • Added warning to ikvmc when skipping a class that is already in a referenced assembly.
  • Changed ikvmc -nowarn to use only the first variable string in a warning as a key.
  • Changed ikvmc to fail with a Link Error when it detects a loader constraints violation (instead of emitting code that throws a LinkageError at runtime).
  • Fixed handling of bridge methods with covariant return types in ikvmc (to allow other .NET languages to call these methods [i.e. the non-bridge counterparts]).
  • Changed ikvmc to add EditorBrowsable(Never) attribute to bridge and synthetic methods.
  • Fixed workaround for Mono bug (lack of proper token support in reflection emit api) in field reflection support.
  • Fixed system property initialization to handle case where IKVM.GNU.Classpath doesn't have a Location (e.g. when it is loaded with Assembly.Load(byte[]) (suggested by Bill Seddon).

Binaries are available here. Source is available in cvs.

Monday, 05 February 2007 07:48:55 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]