# Thursday, August 10, 2006
IKVM 0.30 rc1

Here's the release candidate. Updated japi results are available here.

Changes since previous snapshot:

  • Integrated GNU Classpath 0.92.
  • Fixed ikvmc to handle constructorless classes correctly.
  • Fixed a couple of FileChannelImpl bugs.

Files are available here: ikvm-0.30.0.0.zip (sources + binaries), ikvmbin-0.30.0.0.zip (binaries), ikvmbin-generics-0.30.0.0.zip (binaries built from generics branch)

Thursday, August 10, 2006 10:38:07 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Thursday, August 3, 2006
New Snapshot

I'm preparing for the 0.30 release and this time I decided to do things a little more structured, so I made a branch in cvs: v0_30. I checked out the code into a clean directory changed allsources.lst and classpath.build to point to a clean check out of the GNU Classpath 0.92 release branch (Note that 0.92 has not yet been released) and ran the build script.

The resulting binaries are available here. Note that even though the directory inside the zip is ikvm-0.30.0.0, this is not yet 0.30, but instead should be considered a development snapshot and the binaries are unsigned and have version 0.29.*.

Please test this version and report any bugs, now's the time to get them fixed before 0.30 is released!

Here's what's new:

  • Integrated GNU Classpath 0.92-pre
  • Implemented java.util.concurrent.atomic.AtomicInteger, AtomicIntegerArray, AtomicReference, AtomicReferenceArray, java.util.concurrent.locks.LockSupport and the sun.misc.Unsafe and sun.reflect.Reflection classes required by java.util.concurrent.
  • Added support for Thread parking (as required by j.u.c.l.LockSupport) to VMThread.
  • Added support for ldind.ref, stind.i2, stind.i4, stind.ref and ldelema CIL instruction to remapper.
  • Fixed volatile long/double access to be atomic.
  • Implemented VM specific part of RuntimeMXBean.
  • Implemented VMNetworkInterface using System.Management (via reflection to make sure the code continues to "work" on Mono which doesn't have a System.Management implementation) based on code submitted by Rich Naylor.
  • Implemented DatagramSocket multicast join/leave [implemented by Rich Naylor]
  • Added exception handler to app.config settings reading to ignore exceptions when app.config is invalid.
  • Added support to ikvmstub to generate annotations for custom attributes (but support is limited to a few simple custom attribute signatures currently).
  • Moved assembly attributes from map.xml to AssemblyInfo.java
  • Moved ThreadStatic and DllImport attributes from map.xml to source.
  • Added support for applying assembly attributes (by way of the "assembly" placeholder class).
  • Fixed IsSideEffectFreeStaticInitializer to handle unused class literals and invalid class files.
  • Removed -Xbootclasspath support (it wasn't compatible with Sun and the implementation was very hacky).
  • Cleaned up ikvmstub class loading.
  • Fixed ReflectionOnly (when compiling for WHIDBEY target) bug when handling generic byref method parameters.
  • Fixed DynamicClassLoader.CreateModuleBuilder() to have it return the ikvmc target assembly instead of creating a new assembly.
  • Centralized array type construction.
  • Fixed cli.System.Void.class literal to yield cli.System.Void instead of void type (this also fixes ikvmstub to generate cli.System.Void instead of void when processing mscorlib).
  • Restructured class loading to remove DynamicClassLoader subclass and use delegation instead.
  • Fixed Socket and DatagramSocket to ignore timeout on write operations (reported by David Pirkle).
  • Fixed Socket and DatagramSocket to throw UnknownHostException when dealing with an unresolved SocketAddress.
  • Fixed VMFile.mkdir not to throw exception when trying to create an invalid directory name.
  • Fixed ArrayIndexOutOfBoundsException when trying to load class named "[[".
  • Fixed VMStackWalker.getClassContext() to skip one less frame [this fix makes Eclipse 3.2 start up].
  • Added a hack to prevent the x64 JIT from doing tail call optimizations.
  • Changed IKVM.GNU.Classpath.dll build script to use classpath.security file from GNU Classpath instead of ikvm specific version.
  • Much improved ReflectionOnly support (WHIDBEY target only).
  • Added a CompilationRelaxations assembly attribute to fix a bug that occurred when IKVM.Runtime.dll or ikvmc.exe were NGENed. The code relies on string literals being interned by the CLR, but starting with .NET 2.0 the C# compiler by default annotates the assemblies it generates with the CompilationRelaxations(CompilationRelaxations.NoStringInterning) attribute.
  • Relaxed class name restrictions for 1.5 class files.
  • Added support for Java classes with a Finalize() method (there was a know bug that the generated Finalize stub that calls the real finalize() method would conflict with a user defined Finalize() method).
  • Removed IkvmStubMode hack.
  • Changed naming and loading of CLR generic types.
  • Implemented the remaining 1.5 methods in java.lang.Class.
  • Added consistency checks to Class.getDeclaringClass() and Class.getDeclaredClasses().
  • Simplified loading of "manufactured" nested classes (i.e. the nested Method interface in delegates and the Annotation annotation in attributes).
  • Changed generic type instantiations to have a custom class loader that delegates to the class loaders that were used to create the type (at least when there are no type name clashes).
  • Cleaned up warning generation in ikvmc and added -nowarn option to suppress specific warnings.
  • Fixed volatile read/write on WHIDBEY target build of ikvmc.
  • Made array type construction more lazy. Constructing large dimensional array types is now much faster.
  • Changed ClassLoader.findLoadedClass() to be compatible with 1.5 instead of 1.4 (i.e. it no longer creates new array types).
  • Fixed compiler to mark methods that use getstatic/putstatic on fields in another class as not inlineable (because the instructions are effectively a method call when they trigger the static initializer).
  • Fixed compiler to mark methods that use dynamic getstatic/putstatic/getfield/putfield instructions as not inlineable.
  • Improved optimization in compiler that omits line number table from methods that cannot throw exceptions. It now understands that getfield/putfield on the this reference and getstatic/putstatic on the current class cannot throw.
  • Fixed a bug in exception handling that could cause a TypeInitializationException to turn into a ClassCastException.
  • Added cause exception to NoClassDefFoundError that gets thrown when a type that failed its static initializer is accessed again.

Thursday, August 3, 2006 6:31:36 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Tuesday, August 1, 2006
.NET Generic Types

Recently I changed the way .NET generic types are handled by IKVM. The previous scheme was based on a naive mangling of the .NET Type.FullName property, but that turned out to be problematic for various reasons. The first obvious reason was that type names often were way too long for comfort. For example:

Type t = typeof(System.Collections.Generic.List<string>);
Console.WriteLine(t.FullName);
Console.WriteLine(((java.lang.Class)t).getName());

With IKVM 0.28 this prints out:

System.Collections.Generic.List`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
cli.System.Collections.Generic.List$$00601$$005B$$005B System$$002EString$$002C$$0020mscorlib$$002C$$0020 Version$$003D2$$002E0$$002E0$$002E0$$002C$$0020 Culture$$003Dneutral$$002C$$0020 PublicKeyToken$$003Db77a5c561934e089$$005D$$005D


(I manually inserted some spaces to make the HTML wrap.)

This obviously isn't very practical, but there is also a deeper problem. This literal translation of the name misses the fact that class loading in .NET is fundamentally different from class loading in Java. Which means that it is easy to go from Type to class name, but given a class name it is much harder to construct the corresponding type, especially if on or more of the type parameters are Java types (or remapped types).

In the next release the class name will be:

cli.System.Collections.Generic.List$$00601_$$$_Ljava__lang__String_$$$$_

Not only more readable, but it also correctly reflects the fact that System.String is known as java.lang.String on the Java side.

I also changed the way these names are resolved to be more inline with the way Java works. The name is now parsed by the class loader that first tries to load the class which then in turn loads the component classes and constructs the generic type from that. This means that the following code will now work (if you can somehow convince your Java compiler to compile it):

import cli.System.Collections.Generic.*;

class Test
{
  public static void main(String[] args)
  {
    List$$00601_$$$_LTest_$$$$_ list = new List$$00601_$$$_LTest_$$$$_();
    list.Add(new Test());
  }
}


With the previous scheme there was no way to refer to the Test class in the generic class name, but now the correct class loader is used so you can refer to Java classes as well. That leaves only one question, what does list.getClass().getClassLoader() return? Well, for the time being I've decided to automatically construct a class loader that delegates to the defining class loaders of the classes used to construct the generic type, this ensures (as long as no types with the same names are used) that all types used in the definition of the generic type instance can be loaded by its class loader. It isn't actually clear to me that this is required, but at least for the time being it is, because some of the reflection code relies on this fact.

Finally, as a reminder, all this stuff is still experimental and, frankly, not intended to be practical. The main reason this support exists is to make the life of reflection/ikvmstub easier, otherwise the runtime would have to have all sorts of complicated support to deal with field types and method parameter/return types that take generic type instantiations.

Tuesday, August 1, 2006 3:11:32 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Monday, July 24, 2006
JaCIL

Almann Goo released version 0.6.0.0 of JaCIL on Saturday. The goal of JaCIL is basically to be a reverse ikvmc, it converts .NET assemblies into Java jars.

The binary distribution includes a couple of demos. Naturally I had to try and run them on IKVM :-) I ran into two known IKVM bugs, the first being that JaCIL generates a class and prior to Java 1.5 this wasn't a valid class name, but since Java 1.5 the class name space has been significantly enlarged, almost all checks have been removed. The second bug was that Java classes with both a Finalize() and finalize() method would be compiled incorrectly (under the covers IKVM generates a Finalize() method that overrides System.Object::Finalize and calls java.lang.Object::finalize), I've added support for this by renaming the generated Finalize method when it is necessary.

JaCIL isn't yet at the point where it can compile the ikvmc generated assembly[*], but maybe we'll eventually be able to run Java on .NET on Java on .NET on Java on .NET on Java... ;-)

[*] If you try it, you'll likely to run into an IKVM limitation. JaCIL is a .NET application and uses an ikvmc compiled version of ObjectWeb ASM and currently, IKVM.Runtime.dll gets confused if multiple versions of IKVM.GNU.Classpath.dll are loaded in the AppDomain.

Monday, July 24, 2006 2:18:39 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Wednesday, July 12, 2006
Eclipse 3.2 x64

The Eclipse 3.2 release also includes an "early access" version for Windows x64 (among other 64 bit platforms), so I decided to try to run this version on IKVM.

While trying this I discovered a bug in the 64 bit version of the CLR. It doesn't respect MethodImpl(MethodImplOptions.NoInlining) and this means that Eclipse fails to start up, because it still does that weird stack walking to make sure that a particular method is called by the expected caller. BTW, instead of using the stack trace from an exception, they now use a subclass of SecurityManager and call getClassContext on that. That mechanism is a little better, but it is still incredibly lame.

The good news is that after adding a hack to IKVM to insert some extra junk in that particular method that prevents it from being inlined, Eclipse 3.2 x64 seems to run fine on IKVM.

Coincidentally, Eclipse 3.2 doesn't work on IKVM 0.28.0.1, because my implementation of getClassContext returned one stack frame too few (the GNU Classpath VMStackWalker interface is somewhat inconsistent, the other two methods in it both skip two frames, but getClassContext is apparantly only supposed to skip one frame).

Update: I got an e-mail from someone on the CLR team and he explained that the observed behaviour is by design. The method is not inlined, but the JIT optimizes the call into a tail call, thereby removing the stack frame from the call stack. Strictly speaking this is indeed a legal optimization, but I have to say I don't really see the point, if I wanted a tail call I would have used the tail call instruction.

Wednesday, July 12, 2006 4:59:45 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Wednesday, July 5, 2006
Eclipse Java Compiler

The recent Eclipse 3.2 release includes a release of the stand alone Eclipse Java Compiler (they call it the JDT Core Batch Compiler). It is available as ecj.jar.

I switched to using this version for building GNU Classpath. If you want to use the same version, simply download ecj.jar and run it through ikvmc.

Wednesday, July 5, 2006 5:23:41 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Thursday, June 15, 2006
Custom Attributes as Annotations
I implemented partial and experimental support for applying .NET Custom Attributes in Java code as annotations. The following example now works:


import cli.System.Runtime.InteropServices.DllImportAttribute;

class beep
{
  @DllImportAttribute.Annotation("kernel32")
  private static native int Beep(int dwFreq, int dwDuration);

  public static void main(String[] args)
  {
    for (int i = 1000; i < 3000; i += 200)
      Beep(i, 50);
  }
}

I realise that the name of the annotation type is a bit ugly, but it's consistent with the way delegates are handled and it enables efficient handling of custom attributes at runtime (when compiling code in dynamic mode) and doesn't require access to the ikvmstub generated stub classes.

At the moment only attributes that have a zero arg or single string arg constructor are supported and attribute fields or properties are not exposed.

The Annotation inner interface cannot be used for anything except annotating. If you try to implement it or declare variables or parameters of its type, you will get internal errors in IKVM.Runtime.dll (because there is no corresponding .NET type). I will probably fix this at some point, but for now simply don't use that type except for annotating.

Finally, even though the Annotation annotation type is marked as Retention(RetentionPolicy.RUNTIME), it won't be visible through Java reflection. It's complicated to make this work and the value of it is limited. As an alternative, you can use .NET reflection to access the custom attributes.

Thursday, June 15, 2006 2:31:25 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Thursday, June 8, 2006
More AtomicInteger Performance

In my previous entry on AtomicInteger I showed timings on my single CPU ThinkPad which has a 1.7 GHz Pentium M. Today I investigated the performance on my iMac which has a 1.83 GHz Core Duo and like the ThinkPad runs Windows XP SP2.

I've also modified AtomicInteger to take advantage of Interlocked.Increment, Decrement and Exchange. Instead of following the reference implementation which builds everything on top of the compareAndSet operation.

Running the same test produces the following numbers:

  Time (ms)
JDK 1.5 HotSpot Server VM

2282

JDK 1.5 HotSpot Client VM

2922

IKVM

2406

C#

1922


Note that the test is significantly slower than on the Pentium M. This is most likely because of the bus locking overhead.

It gets even more interesting when we modify the test to have two threads that concurrently increment the same field:

  Time (ms)
JDK 1.5 HotSpot Server VM

22563

JDK 1.5 HotSpot Client VM

25109

IKVM

15016

C#

12000

The first thing to note is the fact that the test now takes an order of magnitude more time. Presumably, this is caused by the communication overhead between the two cores.

The second is that here IKVM significantly outperforms HotSpot Server. The reason for this is simple: IKVM uses Interlocked.Increment which ultimately uses the XADD x86 instruction that atomically performs the load/increment/store. By contrast, the AtomicInteger reference implementation uses the following loop to increment the value:

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

When another thread updates the field between the get and compareAndSet, the compareAndSet will fail and the loop will have to run for another iteration. When multiple CPUs are continuously trying to increment the value this is likely to happen relatively frequently.

Standard disclaimer: As always these microbenchmarks are designed to magnify a particular effect. Be careful about drawing overly large conclusions from them.

Thursday, June 8, 2006 9:08:01 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Thursday, June 1, 2006
IKVM 0.28 bug fix release

A new 0.28 release to fix two bugs reported by users. The first bug is a regression that caused native method resolution not to work for statically compiled code and the second bug is that instanceof didn't work with ghost interface arrays (e.g. obj instanceof Serializable[] would cause the runtime to abort). No other changes.

Files are available here: ikvm-0.28.0.1.zip (sources + binaries), ikvmbin-0.28.0.1.zip (binaries), ikvmbin-generics-0.28.0.1.zip (binaries built from generics branch)

Thursday, June 1, 2006 9:48:05 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Tuesday, May 30, 2006
java.util.concurrent.atomic.AtomicInteger

Last week Tom Tromey posted a proposal for a patch to the Classpath patches mailing list for JSR-166 support. Triggered by this I did some preliminary investigation to see how much work it will be to support this in IKVM.

The reference implementation uses the sun.misc.Unsafe class to calculate the offset of a field in a class and to directly access this field using the appropriate memory model semantics. HotSpot has intrinsic support for the performance cricitical methods in sun.misc.Unsafe. Unfortunately, this model isn't very suitable for IKVM, because the CLI does not specify a way to portably obtain the offset of a field in a class (and it even allows the offset to change over time). I've implemented all the required methods in sun.misc.Unsafe based on reflection, but obviously this is very slow (preliminary measurements show a 10x to 100x slowdown compared to JDK 1.5).

The good news is that some important classes can easily be ported to a more CLI friendly approach. As an example I've modified the reference implementation of AtomicInteger to use System.Threading.Interlocked.CompareExchange() instead of sun.misc.Unsafe.compareAndSwapInt(). This is a small change and allows for good performance. Here is the benchmark I used:

import java.util.concurrent.atomic.*;

public class test {
static AtomicInteger foo = new AtomicInteger(0);
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
foo.incrementAndGet();
}
long end = System.currentTimeMillis();
System.out.println(end - start);
System.out.println(foo);
}
}

Here are the timings (IKVM and C# timings on Microsoft .NET Framework 1.1):

  Time (ms)
JDK 1.5 HotSpot Server VM

861

JDK 1.5 HotSpot Client VM

1312

IKVM

1543

C#

1452


I included the C# version for comparision. Here is the source for it:

using System;
using System.Threading;

public class test {
static int foo;
static void Main() {
int start = Environment.TickCount;
for (int i = 0; i < 100000000; i++) {
Interlocked.Increment(ref foo);
}
int end = Environment.TickCount;
Console.WriteLine(end - start);
Console.WriteLine(foo);
} }

Note how much easier the C# programming model is. Given support for managed by ref arguments, there is no need for an extra indirection or hacks like sun.misc.Unsafe.

Tuesday, May 30, 2006 12:27:17 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]