# Tuesday, 03 December 2002
SWT

I've been working on getting the SWT (the Eclipse windowing toolkit) examples to run. This mostly involved implementing a lot of JNI methods.

The examples now run, but they do run into the occasional random NullPointerException. Probably caused by a sneaky bug in the (un)managed C++ code.

Here is a statically compiled version ControlExample (including all the supporting DLLs needed).

Note that this will only run on Windows, because my JNI implementation is written in Managed C++ it will not run on Mono.

Some interesting findings:

  • SWT has a reference to the sun.awt.windows.WEmbeddedFrame class. What's that about?
  • In order to get the FileViewer example to run, I had to use the STAThread attribute on my main method. Boy I'm I glad I missed the whole COM thing (was busy doing Java). This just too lame.
  • Reflection.Emit does not support embedding resources in a module (lame!). I had to add resource support to ikvmc (and the VM) to get ControlExample to work, statically compiled, so I added initialized global public fields to the assembly and used System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray to copy the field data to an array.
Tuesday, 03 December 2002 09:32:32 (W. Europe Standard Time, UTC+01:00)  #    Comments [10]
# Saturday, 30 November 2002
Interfaces & the Verifier

To my surprise to following code (Jasmin source) is verifiable and runs without throwing any exceptions (Sun's JRE 1.4.1):

.class public ifmerge3
.super java/lang/Object
.field public static r Ljava/lang/Runnable;
.method public <init>()V
   .limit locals 2
   .limit stack 8
   aload_0
   invokenonvirtual java/lang/Object/<init>()V
   return
.end method
.method public static main([Ljava/lang/String;)V
   .limit stack 5
   .limit locals 4
   ldc ""
   putstatic ifmerge3/r Ljava/lang/Runnable;
   return
.end method

The red lines are the interesting ones. It is apparantly (the vmspec doesn't really talk about this) legal to use any object reference in any place where an interface reference is expected.

This has an interesting implication for the performance of interfaces in Java. It means that whenever an interface method is invoked, the VM will always need to check if the reference does in fact implement the interface in question. This should make interface invocation slower. To test this theory, I wrote a small benchmark:

class ifperf implements Runnable {
  public void
run() {}
  public static void
main(String[] args) {
    Runnable r =
new
ifperf();
    Runnable[] ar =
new
Runnable[10000];
    for(int
i = 0; i < ar.length; i++)
      ar[i] = r;
    long
start = System.currentTimeMillis();
    for(int
i = 0; i < 1000; i++)
      for(int
j = 0; j < ar.length; j++)
        ar[j].run();
    long
end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Sun's J2RE 1.4.1: 300 ms
IKVM (on .NET 1.1 beta): 150 ms

John Lam has written about the implementation of .NET's interface method dispatch here. I haven't been able to find any articles that talk about HotSpot's implementation of interface method dispatch. Let's look at the code that is generated by both JITs.

.NET 1.1 beta code (inner loop only):

07591DCC  cmp         edi,dword ptr [esi+4] 
07591DCF  jl          07591DD4
07591DD1  inc         ebx 
07591DD2  jmp         07591D91
07591DD4  cmp         edi,dword ptr [esi+4]
07591DD7  jae         07591DED
07591DD9  mov         ecx,dword ptr [esi+edi*4+0Ch]
07591DDD  mov         eax,dword ptr [ecx]
07591DDF  mov         eax,dword ptr [eax+0Ch]
07591DE2  mov         eax,dword ptr [eax+94h]
07591DE8  call        dword ptr [eax]
07591DEA  inc         edi 
07591DEB  jmp         07591DCC
07591E80  ret              

J2RE 1.4.1 HotSpot code (inner loop only):

00AC7023  mov         esi,dword ptr [ebp-18h] 
00AC7026  mov         edi,dword ptr [ebp-0Ch]
00AC7029  cmp         edi,dword ptr [esi+8]
00AC702C  jae         00AC7146
00AC7032  mov         esi,dword ptr [esi+edi*4+0Ch]
00AC7036  mov         dword ptr [esp],esi
00AC7039  mov         ecx,esi
00AC703B  cmp         eax,dword ptr [ecx]
00AC703D  mov         eax,6B68778h
00AC7042  call        00ABCE25
00AC7047  inc         dword ptr [ebp-0Ch]
00AC704A  mov         esi,dword ptr [ebp-18h]
00AC704D  mov         esi,dword ptr [esi+8]
00AC7050  mov         edi,dword ptr [ebp-0Ch]
00AC7053  es:
00AC7054  cs:
00AC7055  fs:
00AC7056  gs:
00AC7057  nop
00AC7058  cmp         edi,esi
00AC705A  jl          00AC7023
00ABCE25  mov         edx,dword ptr [eax+0Ch] 
00ABCE28  mov         ebx,dword ptr [eax+8]
00ABCE2B  cmp         edx,dword ptr [ecx+4]
00ABCE2E  jne         00ABB6C0
00ABCE34  cmp         dword ptr [ebx+38h],0
00ABCE3B  jne         00ABB8C0
00ABCE41  jmp         00A67940
00A67940  ret              

The first thing to notice, is that HotSpot (in this particular example) is not very good at optimizing register usage, compared to the .NET JIT. .NET uses EDI as the loop counter and ESI as the array reference, whereas HotSpot keeps both the counter and the array reference on the stack. This difference probably accounts for a large part of the performance difference.

The second thing to notice, is that both HotSpot and .NET do not eliminate the array bounds check (again, in this particular example).

The code at 00ABCE25 is where it gets really interesting. After running a while, HotSpot noticed that all calls to Runnable.run() at this site actually resolved to ifperf.run() and so it emitted code that takes advantage of that fact. However, since it cannot prove that this will always be true, it has generated code that checks that the reference does indeed refer to an ifperf object (the cmp instruction at 00ABCE2B does this), and if it doesn't, it jumps to some code at 00ABB6C0 to do the interface method lookup and patch the call at 00AC7042 to point to a new location that does the interface method lookup and does the profiling that started this optimization in the first place. I'm not sure what the second comparison does, but it's something similar. The final branch at 00ABCE41 jumps to the ifperf.run() implementation (bypassing any dynamic dispatch!).

Conclusions: All of this complex optimization (and on-the-fly deoptimization!) makes micro benchmarking fairly useless (as many others have previously demonstrated). As an example, storing just a single non ifperf Runnable in the array slows HotSpot down by about 10%, while in .NET this has no effect. However, interleaving two different Runnable object types in the array slows HotSpot down by about 20% whereas it slows down .NET by about 300% (and I cannot explain that).

Now, the real question is, does IK.VM.NET need to support assigning object references (that do not implement a particular interface) to references of that interface type? The current design (although the implementation isn't quite correct) is to allow the code above to be verified, but when it runs it throws an IncompatibleClassChangeError when the putstatic is executed.

Saturday, 30 November 2002 14:20:15 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Monday, 25 November 2002
More Miranda

The System.TypeLoadException I mentioned here turns out to be caused by a bug in the .NET 1.0 CLR (MS has already fixed it in the current 1.1 beta).

Here is some code that triggers it:

interface __Shape
{
    public abstract __Rectangle getBounds();
    public abstract __Rectangle2D getBounds2D();
}
abstract class __RectangularShape implements __Shape
{
    public __Rectangle getBounds()
    {
return null;
    }
}
abstract class __Rectangle2D extends __RectangularShape
{
    public __Rectangle2D getBounds2D()
    {
        return null;
    }
}
class __Rectangle extends __Rectangle2D implements __Shape
{
    public __Rectangle getBounds()
    {
        return null;
    }
    public __Rectangle2D getBounds2D()
    {
        return null;
    }
}

If this code was compiled with Jikes 1.18 (which doesn't emit Miranda methods) and then run in IK.VM.NET, it failed with a System.TypeLoadException. The fix was easy, just emit an abstract method for each interface method that a type doesn't implement. A compiled DLL of the above code can be found here. When run through peverify 1.0, it will fail verification, in 1.1 this is fixed.

I compiled the Classpath code I got on Friday with Jikes 1.18 and made a new release based on that (including, of course, all the VM fixes I had to do).

Updated the binaries and source snaphots.

Monday, 25 November 2002 10:05:05 (W. Europe Standard Time, UTC+01:00)  #    Comments [1]
# Saturday, 23 November 2002
Eclipse

For the time being I switched back to jikes 1.15. When trying to start Eclipse (M2), it failed with a ClassNotFoundException: org.xml.sax.InputSource.

It turns out that in org.eclipse.core.internal.runtime.InternalPlatform the following method causes a problem:

public synchronized static
PluginRegistryModel parsePlugins(URL[] pluginPath,
                               
 Factory factory,
                                 boolean
debug) {
// If the platform is not running then simply parse the
//
 registry.
//
 We don't need to play any funny class loader games as
//
 we assume the XML classes are on the class path
// This happens when we are running this code as part of
// a
 utility (as opposed to starting or inside the
// platform).

if (!(InternalBootLoader.isRunning() ||
     InternalBootLoader.isStarting()))
  return RegistryLoader.parseRegistry(pluginPath,
                                      factory,
                                      debug);

// If we are running the platform, we want to conserve
// class loaders.
// Temporarily install the xml class loader as a
// prerequisite
of the platform class loader
// This allows us to find the xml classes. Be sure to
// reset the prerequisites after loading.

PlatformClassLoader.getDefault().setImports(
  
new DelegatingURLClassLoader[]
    { xmlClassLoader });

try {
  return RegistryLoader.parseRegistry(pluginPath,
                                      factory,
                                      debug);
} finally {
 
PlatformClassLoader.getDefault().setImports(null);
}
}

The bold line basically adds the xerces plugin to the classpath, this is needed because RegistryLoader depends on it. However, in IK.VM.NET the RegistryLoader class gets compiled when the above parsePlugins method is JITted by the .NET runtime, and at that moment the xerces code is not yet available.

This is an interesting problem, but I'm not sure if this construction is actually guaranteed to work on all VMs by the spec.

Saturday, 23 November 2002 14:19:31 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Friday, 22 November 2002
Swamp

I tried to get Eclipse to run. This led to an interesting series of events:

  • I found that I didn't set the ProtectionDomain of a Class instance. Fixed.
  • I found that FileOutputStream in append mode didn't work. Fixed.
  • I found that Eclipse requires a 1.3.0 VM, but doesn't give any feedback whatsoever if the version isn't good enough. Workaround: ikvm -Djava.version=1.3.0
  • The bytecode compiler didn't implement migrating uninitialized object references into and out of try-blocks. Fixed.
  • The version of java.io.File.listFiles() that I used couldn't deal with the native method returning null. Fixed by getting the latest version from CVS.
  • Classpath's java.net.URL has bug where it doesn't try its own pool of protocol handlers, if a factory is installed, but the factory refuses a particular protocol. In order to fix this, I first had to update my Classpath code, to get the most recent URL code (it changed quite a bit, but the bug is still there).
  • After I got the latest version of Classpath from CVS, jikes would hang when compiling (it later turned out that jikes wasn't hanging, but that it was actually nAnt, but at that moment I suspected jikes).
  • I downloaded a new version of jikes, 1.18 (the version I was using was 1.15), generally tried as sorts of stupid things (including accidentally deleting my whole Classpath tree).
  • Not exactly sure why, but this whole exercize caused a number of bugs to appear when compiling classpath.dll. Here are some examples:
  • When this code is compiled by jikes 1.15:
    class Outer {
        private static class Inner {
            private Inner() {}
        }
        public static void main(String[] args) {
           new Inner() { };
        }
    }
    First of all, I don't why this is legal. IMO since the constructor of Inner is private, you shouldn't be able to instantiate in Outer, but Sun's 1.4 compiler compiles it, and so does jikes. However, jikes 1.15 actually emits code that calls the private constructor from the constructor of the anonymous class. This is clearly incorrect (and it is fixed in 1.18), but it took me a while before I had figured out what was going on. BTW, the "correct" compilation is to inject a synthetic constructor in Inner that accepts a reference to the Outer class (and has package accessibility).
  • jikes doesn't generate Miranda methods. Take the following class, for example:
    abstract class Foo implements Runnable {
        Foo() {
            run();
        }
    }
    This compiles (and is legal). When javac compiles this code, it inserts an public abstract void run() method into Foo, this method is called a Miranda method. Older VMs (probably in the 1.0 time frame) didn't think the class was valid without this method. Jikes doesn't do this and IK.VM.NET couldn't handle that. Fixed.
  • Access check for fields had a bug. java.awt.Component directly accesses the id field of several events, this is legal because in the java.awt.AWTEvent class the id field is declared protected (which also implies package accessibility). However, jikes 1.18 decided that the reference to the field should not be compiled as a reference to java.awt.AWTEvent.id, but to (e.g.) java.awt.event.ComponentEvent.id, perfectly legal, because the field is inherited, but the compiler incorrectly did the package accessibility check on the class name in the reference, instead of on the class name where the field is actually declared. Fixed.

At the moment I'm stuck on an exception that the .NET framework throws (when I'm compiling classpath.dll with ikvmc):

System.TypeLoadException: Method getBounds2D in type java.awt.Rectangle from assembly getBounds2D does not have an implementation.
   at System.Reflection.Emit.TypeBuilder.TermCreateClass(TypeToken handle, Module module)
   at System.Reflection.Emit.TypeBuilder.CreateType()

I have no idea why this happens. Interestingly enough, it doesn't happen when I compile with jikes 1.15.

Friday, 22 November 2002 15:45:26 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Thursday, 21 November 2002
ikvmc

Inspired by Stuart's comment to yesterday's post, I decided to clean up ikvmc a little to make it possible to compile executables.

Other changes:

  • it's now possible to specify an IL implementation of a native method in map.xml. At the moment this is used only for System.identityHashCode() to solve this issue.
  • map.xml is now parsed using the XmlSerializer (see yesterday's post on why this is not a good idea)
  • implemented a work-around for the stack overflow that occurred when the compiler couldn't find java.lang.ClassNotFoundException
  • ikvm now supports -classpath switch (thanks dIon)

I've only compiled a simple Hello World type executable with ikvmc and here are some things to look out for:

  • all classes (or jars) that are referenced by the application must be specified (except for the Classpath classes)
  • a reference (-reference:<path>) to the classpath.dll must be specified
  • when compiling an executable the class containing the main method must be specified
  • code that expects to be loaded by the system classloader will probably not work. Statically compiled code will be loaded by the bootstrap (aka null) classloader.

Example:
    ikvmc -out:hello.exe -reference:bin/classpath.dll -main:Hello Hello.class

Updated the binaries and source snaphots.

Thursday, 21 November 2002 12:53:45 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Wednesday, 20 November 2002
map.xml

I wasn't happy with the handling of map.xml, so I rewrote the code that deals with it to use XmlSerialization. Cool stuff, but it turns out to be totally unsuitable for this purpose. I only need to parse the xml file once (at startup of the VM), and the XmlSerializer generates a C# file (and compiles it) to do the parsing. This is great if you have to parse lots of files (that adhere to the same schema), but it is very wasteful (i.e. slow) if you only need to parse a single file.

After a lot of thinking, I came to the conclusion that I should statically generate an assembly from the map.xml file. In other words, compile it.

Other thoughts: I'm still trying to find ways to make implementing the classpath "native" methods easier (and more efficient, by getting rid of reflection) and I'm contemplating the following idea: Turning classpath.dll, ik.vm.net.dll & the new compiled map.xml into a multi module assembly. This solves two problems: 1) The native methods implementations no longer have to be public, 2) native methods can be statically compiled against the non-native (i.e. compiled Java) code. Downside: more icky circular dependencies and it won't be possible anymore to run without a precompiled classpath.dll

Wednesday, 20 November 2002 09:49:12 (W. Europe Standard Time, UTC+01:00)  #    Comments [3]
# Wednesday, 13 November 2002
F.A.Q.

I wrote a small F.A.Q. that hopefully answers most questions people have without them having to go read through the entire history of the project.

It lives here.

Wednesday, 13 November 2002 10:42:17 (W. Europe Standard Time, UTC+01:00)  #    Comments [6]
# Sunday, 03 November 2002
Conference

Yesterday I arrived in Keystone, Colorado for the Colorado Software Summit, a most excellent Java & XML conference.

I hope to get some hacking done this week, but if I don't it'll be because I'm having too much fun at the conference ;-)

Sunday, 03 November 2002 18:52:13 (W. Europe Standard Time, UTC+01:00)  #    Comments [3]
# Friday, 01 November 2002
GetHashCode & reflection

What is the output of the following code fragment?

  object o = "foo";
  Console.WriteLine(o.GetHashCode());
  Console.WriteLine(typeof(object).GetMethod("GetHashCode").Invoke(o, null));
  Console.WriteLine(typeof(string).GetMethod("GetHashCode").Invoke(o, null));

.NET 1.0 says:

193410979
23
193410979

.NET 1.1 beta says:

193410979
193410979
193410979

Mono 0.13 says:

101574
1554225471
1554225471

Mono 0.16 says:

101574
33369132
101574

Note: the actual numbers are irrelevant, it matters if they match up or not.

.NET 1.1 is correct, the others aren't. The funny thing is, I just realised that IK.VM.NET currently depends (for its System.identityHashCode implementation) on the broken behavior.

.NET 1.0 only behaves this way for methods in String, for other types reflective method invocation works the same as a virtual method call.

In Mono 0.16 all reflective method invocations appear to be non-virtual.

Friday, 01 November 2002 14:41:12 (W. Europe Standard Time, UTC+01:00)  #    Comments [5]