# Friday, 16 March 2007
Microsoft dropping J# and JLCA in next version of Visual Studio

Via Lorenzo Barbieri (via Google blog search, I don't read Italian) I learned that Microsoft decided to drop support for J# and the Java Language Conversion Assistant in the next version of Visual Studio (code named Orcas).

I'm glad they finally realised the futility of competing with IKVM.NET ;-)

Friday, 16 March 2007 11:36:58 (W. Europe Standard Time, UTC+01:00)  #    Comments [3]
# Wednesday, 14 March 2007
DST Update

I made a new binary release of 0.32 that includes the back-ported GNU Classpath TimeZone fixes for the updates to the US DST rules.

Available here: ikvmbin-0.32.0.1.zip

Wednesday, 14 March 2007 15:51:01 (W. Europe Standard Time, UTC+01:00)  #    Comments [1]
# 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]
# Monday, 22 January 2007
Events

Like previous years, I'll be attending FOSDEM this year. I'll also be at the Microsoft PDC in October.

If you're going to either of these and would like to meet for a chat, please feel free to contact me.

Monday, 22 January 2007 10:18:11 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Monday, 15 January 2007
AWT/Swing a Little Bit Less Unsupported

I don't want to raise expectations too much because there's still an incredible amount of work to be done, but thanks to great work done by Volker Berlin a lot of progress has been made on the AWT/Swing front. For example, here's a screenshot of the JDK SwingSet2 demo running on the current ikvm version from cvs:

Not everything works and some of the missing functionality will be quite difficult to implement on top of .NET 1.1 or 2.0 (it may be easier with WPF, but I really don't know). There are also a couple of GNU Classpath bugs, but overall it's quite impressive how well this demo works.

Monday, 15 January 2007 08:46:29 (W. Europe Standard Time, UTC+01:00)  #    Comments [4]
# Wednesday, 03 January 2007
java.lang.Comparable

In the entry about object schizophrenia I used java.lang.Comparable as an example in J#, but for IKVM I did not mention it as a ghost interface. In the comments Stuart Ballard asked why Comparable isn't a ghost interface.

Unlike what Stuart claimed, this is definitely not a stupid question. He also figured out part of the answer: java.lang.Comparable maps to System.IComparable.

That's not the whole story though. The reason that I originally mapped Comparable to IComparable was that System.String conveniently implements IComparable and that IComparable.CompareTo is semantically (nearly) identical to Comparable.compareTo. Back then I hadn't yet "invented" the ghost interface idea and this seemed to solve most of the issues (the other two ghost interface candidates, Cloneable and Serializable are only used as marker interfaces, so it didn't seem like a big deal that System.String didn't implement these interfaces. java.lang.CharSequence only appeared in Java 1.4 and I vaguely knew about it, but at the time I chose not to worry about that yet.)

 A nice side effect of mapping Comparable to IComparable is that you get better interop (e.g. Java objects that implement Comparable will sort correctly when used in .NET applications and .NET objects that implement IComparable will sort correctly in Java), so that meant that when I developed ghost interfaces I didn't really want to go back and change Comparable into a ghost interface.

Finally, there is one more complication. Even though Comparable.compareTo and IComparable.CompareTo have identical semantics, there still is a problem with String. Java's String.compareTo is specified more strictly than Comparable.compareTo. The interface method is specified to simply return zero or a signed or unsigned integer, but the String version is actually specified to return the difference between the mismatching characters (or zero, if the strings match.) To handle this correctly, when you call Comparable.compareTo, you're actually calling a static method Comparable.__Helper.compareTo that first does a check to see if the object you're comparing is a String and, if so, it calls a static helper method that implements the specified Java comparision algorithm.

BTW, the reason that the static compareTo helper method lives inside a nested __Helper class is because Reflection.Emit (on .NET 1.x) incorrectly prohibits adding static methods to interfaces (which is entirely legal according to the CLI specification).

Performance Impact

The following table compares the direct methods calls with the interface method calls. Note that these basically represent a worst case estimate, because of limit amount of work the actual compareTo method does. Note also that for notational convenience I used the zero digit, but in the actual benchmark I used a local variable containing new Integer(0).

Method Call Time (ns)
"".compareTo((Object)"") 140
((Comparable)"").compareTo("") 220
0.compareTo(0) 6
((Comparable)0).compareTo(0) 35

These results are on .NET Framework 2.0 (x86). Averaged over 10,000,000 calls and includes the loop overhead.

For comparison, here are the results for JDK 1.5 HotSpot Client VM:

Method Call Time (ns)
"".compareTo((Object)"") 17
((Comparable)"").compareTo("") 21
0.compareTo(0) 7
((Comparable)0).compareTo(0) 15
Wednesday, 03 January 2007 12:12:02 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Thursday, 28 December 2006
IKVM 0.32 Released

I released 0.32 to SourceForge (same bits as rc1).

Thursday, 28 December 2006 16:57:44 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
Object Schizophrenia

Early on in the design of IKVM, I decided that I didn't want to use wrapper objects to bridge the Java and .NET type systems as this leads to either object identity problems (and I just found out that this is sometimes called object schizophrenia and that triggered this post) or horrible performance.

By contrast, J# does use wrapper objects in a least one case and this does indeed lead to object schizophrenia:

public class Program
{
  public static void main(String[] args)
  {
    String foo = "Foo";
    Comparable comp = foo;
    System.out.println(foo == comp);
  }
}

Compiling this Java code with Visual Studio 2005 and running it produces false, while it clearly should print true.

While IKVM doesn't suffer from this, there is a somewhat related problem to look out for when using IKVM ghost interfaces from a .NET language:

using System;
using java.lang;

public class Program
{
  static void Main(string[] args)
  {
    CharSequence seq = "foo";
    object obj1 = seq;
    object obj2 = seq;
    Console.WriteLine(obj1 == obj2);
  }
}

Running this C# app produces False. This is because CharSequence is a ghost interface and represented by a value type. Assigning it to a local variable of type object boxes the value type instead of giving the underlying string object. Note that this only applies to ghost interfaces (i.e. java.lang.CharSequence, java.lang.Cloneable and java.io.Serializable). To fix this problem, you have to explicitly unwrap the object from the value type:

CharSequence seq = "foo";
object obj1 = seq.ToObject();
object obj2 = seq.ToObject();
Console.WriteLine(obj1 == obj2);

Unfortunately .NET doesn't have any mechanism for a value type to prevent (implicit) boxing or defining a custom implicit object conversion operator.

Thursday, 28 December 2006 14:07:23 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
New Snapshot

A new development snapshot. Now that GNU Classpath generics support has been merged in the IKVM.GNU.Classpath.dll has become a little bigger again (mostly because of the metadata associated with generic types and methods). Additionally, because enums and annotations are now fully available I've been able to continue work to support those better (in particular the integration between .NET and Java). It is now possible to use most Java annotations as .NET attributes in a fairly natural way.

Here's an example of using some Java annotations in C#:

[Retention(RetentionPolicy.__Enum.RUNTIME)]
[Target(new ElementType.__Enum[] { ElementType.__Enum.FIELD, ElementType.__Enum.METHOD })]
[Documented]
[Inherited]
[AnnotationLib.MyClassAnnotation(typeof(string))]
[AnnotationLib.MyClassArrayAnnotation(new Type[] { typeof(string), typeof(test) })]
[AnnotationLib.MyIntAnnotation(42)]
[AnnotationLib.MyIntArrayAnnotation(new int[] { 42, 123 })]
[AnnotationLib.MyStringAnnotation("Foo")]
[AnnotationLib.MyStringArrayAnnotation(new string[] { "Foo", "Bar", "Baz" })]
[AnnotationLib.MyPropAnnotation(count = 3)]
[AnnotationLib.MyOptionalValueAnnotation]
interface IFoo
{
}

Note in particular that Java enums are represented as nested .NET enum types (automatically generated by ikvmc whenever it encounters a public enum) and that Java class literals are represented as .NET Type literals. These mappings are required because .NET attributes (like Java annotations) cannot have arbitrary types as parameters.

List of changes:

  • Updated to current GNU Classpath cvs version.
  • Many AWT improvements (done by Volker Berlin, who now has cvs commit access).
  • Fixed bug in handling of annotation parameters of type Class.
  • Changed System.mapLibraryName to look at os.name system property and support the Mac OS X naming convention (but note that os.name needs to be explicitly set to "Mac OS X" for this to work).
  • Implemented most of the support needed to use annotations as .NET attributes. This includes generating a nested .NET enum named __Enum for Java enums (to make them usable in .NET attributes). Using annotations as attribute parameters is not supported (i.e. in .NET languages, for Java code annotations work as specified.)

Binaries are available here. Source is available in cvs.

Thursday, 28 December 2006 09:20:20 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]