# Monday, 24 July 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, 24 July 2006 14:18:39 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Wednesday, 12 July 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, 12 July 2006 16:59:45 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Wednesday, 05 July 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, 05 July 2006 17:23:41 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Thursday, 15 June 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, 15 June 2006 14:31:25 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Thursday, 08 June 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, 08 June 2006 21:08:01 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Thursday, 01 June 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, 01 June 2006 09:48:05 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Tuesday, 30 May 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, 30 May 2006 12:27:17 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Tuesday, 23 May 2006
IKVM 0.28 Released

I released 0.28 (same bits as last week's release candidate) to SourceForge.

Tuesday, 23 May 2006 13:30:32 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Tuesday, 16 May 2006
Using foreach to enumerate Java collections in C# 3.0
A long standing feature request for IKVM has been to make Java collections implement System.IEnumerable and I've always resisted doing that for various reasons.

I while ago -- while discussing this with Stuart Ballard -- I realised that with the proposed C# 3.0 language extensions, in particular "extension methods" it should be possible to make Java collections foreach-able with little effort:

namespace java.util
{
  public static class CollectionExtensionMethods
  {
    public static IEnumerator GetEnumerator(this java.util.Collection col)
    {
       return new CollectionEnumerator(col);
    }
  }
}

For those who don't know how extension methods work, basically the above code (note the this keyword before the argument type) adds a method to java.util.Collection that feels like an instance method.

Given the way foreach works, I had expected that it too would recognize this GetEnumerator method and therefore work on all Java collections, but alas that is not the case.
If you want to see this changed before C# 3.0 is released, please vote. Alternatively, if you're Miguel and on the ECMA C# committee, it should be obvious what to do ;-)

Tuesday, 16 May 2006 15:03:28 (W. Europe Daylight Time, UTC+02:00)  #    Comments [4]
IKVM 0.28 rc1

A new release candidate based on GNU Classpath 0.91. I did some perf work and a fair bit of restructuring in the way class loaders work, to better support ikvmc and ikvmstub on assemblies loaded in the ReflectionOnly context (on .NET 2.0). The perf work resulted in a significantly improved startup time for Eclipse (IKVM 0.26: 1 minute 23 seconds, IKVM 0.28: 55 seconds).

Updated japi results are available here. The comparison is against JDK 1.5 now and ignores the generics metadata.

Changes:

  • Integrated GNU Classpath 0.91 plus one patch.
  • Added explicit null check for return value of GetEntryAssembly() in VMSystemProperties.
  • Implemented socket timeout by using Socket.Poll() instead of setting the timeout on the underlying socket (because .NET 2.0 considers the socket broken after a Read timed out).
  • Removed classLoader field from TypeWrapper and made GetClassLoader() abstract (to enable subclasses to use a more efficient way to store the class loader).
  • Moved creation of java.lang.Class object from TypeWrapper constructor (because it would trigger a call to GetClassLoader before that was ready to return meaningful data and also because it wasn't semantically correct to expose the TypeWrapper instance before it was fully constructed).
  • Added ikvm.lang.Internal annotation to mark types and members as internal to the assembly (supported by ikvmc only, not in dynamic mode.) Note that ikvm.lang.Internal should only be applied to public types and members. Note also that to reflection these internal types and members will appears as package private.
  • Removed map.xml hacks to work around cross package accessibility issues (now done by marking the appropriate types/members public and annotating them with @ikvm.lang.Internal).
  • Added map.xml implementation of Class.newInstance (to support @ikvm.lang.Internal).
  • Changed ClassFile to pack major version and flags together to reduce the size of the object.
  • Changed ClassFile.FieldOrMethod to pack flags together.
  • Simplified (and made more consistent) member access checking in reflection.
  • Added -privatepackage option to ikvmc (to mark all classes in a package tree as internal).
  • Fixed object model remapping to add methods inherited from Object to Throwable.
  • Fixed some edge cases in method override resolution.
  • Added optimization to compiler to devirtualize method calls on this reference when it is safe to do so.
  • Added volatile opcode prefix to remapper.
  • Added support for specifying .NET types in catch block to remapper.
  • Made 1.5 support part of the standard build.
  • Restructed ikvmc.exe and IKVM.Runtime.dll.
  • Centralized caching of ByteCodeHelper MethodInfos in ByteCodeHelperMethods.
  • Fixed Thread.join() bug that caused join to spin for large timeouts.
  • Added optimization to not emit linenumbertable for methods that cannot throw exceptions.
  • Much improved annotation support.
  • Fixed ikvmc to only generate corresponding .NET attributes for annotations that have RetentionPolicy.RUNTIME.
  • Fixed ikvmc to add AttributeUsageAttribute to annotation attributes (based on the Target annotation).
  • Optimized verifier a little by making InstructionState use copy-on-write strategy.
  • Changed string comparisons to ReferenceEquals when possible (identifiers are interned, so this is usually possible).
  • Improved VMStackWalker.getCalling[Class|ClassLoader] performance by removing the unnecessary check for HideFromJava/HideFromReflection attributes.
  • Almost completely removed usage of custom attributes for dynamically compiled code (because defining custom attributes is slow).
  • Fixed race condition when two threads define the same class name in two different class loaders at the same time.
  • Fixed possible deadlock while finishing dynamically loaded types.
  • Fixed bug in Class.getModifiers() for statically compiled anonymous inner classes.
  • Moved loading .NET types by their assembly qualified names from the class loader to Class.forName.
  • Fixed class loader not to load Java classes, by their .NET array, pointer or reference name.
  • Moved hack to return system class loader for .NET and statically compiled types from [Compiled|DotNet]TypeWrapper to Class.getClassLoader.

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

Tuesday, 16 May 2006 11:06:10 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]