# Friday, June 13, 2008
New Development Snapshot

I've finally updated to a new drop of OpenJDK. If you want to build IKVM from source you'll need the directory resulting from a full build of OpenJDK 6 b10 on Linux AMD64 (although I suppose that if you change the paths in ikvm/openjdk/allsources.lst you'll be able to use an x86 version as well). At some point I'll release a zip file containing just the needed artifacts, but that will take some more time.

IKVM.OpenJDK.ClassLibrary.dll grew in size to 31,657,984 bytes, mostly because the character de-/encoders that live inside charsets.jar are now included as well. I know size is a big issue for many people and as previously discussed I'm still planning to split the class library assembly into several different files.

Changes since previous development snapshot:

  • Integrated OpenJDK 6 b10.
  • Fixed Method.getParameterAnnotations() bug introduced by CallerID support.
  • Changed forked AbstractQueuedSynchronizer to use AtomicReferenceFieldUpdater instead of map.xml based compareAndSet methods to reduce the number of differences between upstream and our version.
  • Fixed three String bugs found by OpenJDK string tests.


Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

If you want to run this version on Mono, you'll need a Mono version built from recent svn, it does not work on Mono 1.9.

Binaries available here: ikvmbin-0.37.3086.zip

Friday, June 13, 2008 11:58:01 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]
# Wednesday, June 4, 2008
New Development Snapshot

Changes since previous development snapshot:

  • Code clean up and refactoring.
  • Removed security asserts in JVM.CriticalFailure, because they no longer work now that IKVM.Runtime is security transparent.
  • Implemented CallerID infrastructure.
  • Marked various methods with HasCallerID annotation.
  • Applied awt patch #1979656 by Daniel Wilson.


Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

If you want to run this version on Mono, you'll need a Mono version built from recent svn, it does not work on Mono 1.9.

Binaries available here: ikvmbin-0.37.3077.zip

Wednesday, June 4, 2008 7:24:21 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Monday, June 2, 2008
Introducing CallerID Part 3

This is the last part of a three part backward running series on the design, implementation and performance results of the CallerID feature.

How To Pass Information From Caller To Callee

The obvious solution is to use a method parameter, but in this case there is a slight complication: We can't necessarily trust the caller to provide truthful information.

The first scheme I came up with was something like this:

class CallSiteExample {
  private static CallerID __callerID;

  static void method() {
    Class.forName("...", ref __callerID);

Here CallerID would be a value type defined in IKVM.Runtime and its content (a Class and ClassLoader reference field) would only be accessible to the runtime and core class library. Inside the callee there would be a check to see if the required field in the CallerID value had been initialized and if not, it would walk up the stack to determine the caller and store the result in the CallerID value.

The obvious downside of this scheme is that it would still require a stack walk the first time a call site does a call. A less obvious downside is that this approach makes it harder to pass the CallerID to another method. This is used in a couple of places where the callee doesn't do the actual work of looking at the caller. Take for exampe java.lang.reflect.Field.get():

public Object get(Object obj)
    throws IllegalArgumentException, IllegalAccessException
    return getFieldAccessor(obj, CallerID.getCallerID()).get(obj);

Here the actual access check is in getFieldAccessor (actually, it in turn calls another method to do the security check) and I used the CallerID.getCallerID() intrinsic to pass the implicit callerID parameter explicitly to this other method. Doing this with the value type byref approach would have made this a lot harder.

Nested Types

The design sketched above is actually fairly old, but I had never implemented it due to a nagging feeling that it wasn't quite right. I think my primary concern was that it didn't actually get rid of the stack walk, it only reduced them to at most one per caller. Last week as I was helping someone with a problem that turned out to be caused by a stack walking issue on Mono running on ARM I realized that I should get rid of the stack walk altogether and came up with the trick of using a nested type to create an unforgeable token to represent a class.


Another instance of passing around the CallerID is found in reflection. When you call a method via reflection, the immediate caller of that method will, of course, be some VM internal method or Method.invoke() depending on the exact implementation, so the stack walking mechanism that the JDK (and previous IKVM versions) use skips all stack frames related to reflection to get to the real caller. However, with the new scheme, Method.invoke() already gets passed in the CallerID, so it would be a shame not to use this and, of course, it is trivial to pass this value along to the call stub which can then (if required) pass it along to the method being called.

Why the Explicit HasCallerID Annotation?

I could have made ikvmc add the implicit CallerID parameter to every method that calls one of the intrinsics that return the caller, but this has three downsides. The first is that it would have made compiling the core class library slower, because ikvmc would have had to check every method to see if it calls one of these intrinsics (the .NET method signature gets determined way before the method body is processed). The second is that since the additional parameter is, in a sense, part of the public API it should be a conscious decision. The third reasons is that the implicit approach doesn't work with methods that indirectly look at the caller, like the Field.get() example above, so I would have needed to add a mechanism for that anyway.


The current implementation doesn't support adding a CallerID parameter to constructors. This is simply the result of the fact that there aren't any constructors that require CallerID that I'm aware of. Another limitation is that the HasCallerID annotation is only recognized for static methods or instance methods on final classes. This means that ClassLoader.getParent() doesn't currently have CallerID support, even though it does want to look at the caller if there is a security manager installed.

Security Considerations

While it's generally not possible to inject a nested type into an arbitrary type, it may be possible to trick another (dynamic) CLR language into creating such a type. However, I think the risk of that is sufficiently low to make it acceptable.

Another risk is that someone may steal a CallerID object from another type and try to impersonate that type. Since .NET 2.0 SP1 it is actually possible for partially trusted code to use reflection to access private fields if you have the RestrictedMemberAccess permission and both assemblies have the same security grant set. However, since this requires .NET reflection (the callerID field isn't visible from the Java reflection APIs) and there already are several ways to bypass Java's security model by directly using .NET APIs this is also a non-issue.

Finally, it is not possible for untrusted Java code to use the HasCallerID annotation, because ikvmc only recognizes the HasCallerID annotation while compiling the core class library and the IKVM runtime only recognizes CallerID methods in the core class library.

Monday, June 2, 2008 8:20:41 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Sunday, June 1, 2008
Introducing CallerID Part 2

In part 1 we saw the Java source for the ForName benchmark, now let's look at some C# code that is roughly equivalent to what IKVM generates from the Java version:

class ForName  {
  private static readonly __CallerID __callerID = new __CallerID();
  private sealed class __CallerID : ikvm.@internal.CallerID { }

  public static void Main(string[] args) {
    java.lang.Class.forName("java.lang.Object", __callerID);
    long start = java.lang.System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
      java.lang.Class.forName("java.lang.Object", __callerID);
    long end = java.lang.System.currentTimeMillis();
    java.lang.System.@out.println(end - start);

This shows that the compiler passes an extra parameter to the Class.forName() method that carries the identity of the caller's class.

The source for ikvm.internal.CallerID is available in cvs. The class is public and has a protected constructor but has no public methods (they are all internal to the IKVM.OpenJDK.ClassLibrary assembly). The intended usage is shown above, you should extend it with a private class that is nested inside the class whose identity you want to pass to a CallerID requiring API.

The example also demonstrates how you can call these methods from C# if you want to get the best performance, however I recommend using the standard versions of the APIs unless the performance difference is critical to your application.

Above we looked at the caller, now let's look at the callee. Here's the Java source for the Class.forName() method:

public static Class forName(String className)
            throws ClassNotFoundException {
  return forName0(className, true, ClassLoader.getCallerClassLoader());

I added the HasCallerID annotation to signal to ikvmc that it should add the implicit CallerID parameter and ClassLoader.getCallerClassLoader() has been turned into an intrinsic that calls getCallerClassLoader() on the passed in CallerID object instead. Here's the C# equivalent that ikvmc produces for the Class.forName() method:

public static java.lang.Class forName(string className, ikvm.@internal.CallerID callerID) {
  return java.lang.Class.forName0(className, truee, callerID.getCallerClassLoader());

public static java.lang.Class forName(string className) {
  System.Diagnostics.StackFrame caller = new System.Diagnostics.StackFrame(1, false);
  return forName(className, ikvm.@internal.CallerID.create(caller));

In part 3 we'll look at the design decisions behind this implementation.

Sunday, June 1, 2008 10:15:18 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Saturday, May 31, 2008
Introducing CallerID Part 1

In the Java API there are a number of APIs that rely on being able to walk up the call stack to determine certain properties of the immediate caller of the API. The most common scenario is determining the caller's class or class loader. This information is used to implement security checks or to use the right class loader.

Up until now IKVM used the System.Diagnostics.StackFrame .NET API to walk the stack. There are however two major issues with this API. The first issue is that it is unreliable and IKVM jumps through various hoops to make sure that the CLR doesn't inline methods it shouldn't inline or use tail call optimizations it shouldn't use. The second issue is that it is relatively slow.

I finally got around to implementing an alternative scheme that eliminates the usage of System.Diagnostics.StackFrame in most cases. In part 2 I'll describe the implementation, but for now let's just look at some performance numbers.

I've cooked up two microbenchmarks that clearly demonstrate the difference between the current approach and the new approach.


In this microbenchmark we look at the Class.forName() API. It walks the call stack to determine the class loader of the immediate caller, because that is the class loader that it needs to use to load the class.

class ForName {
  public static void main(String[] args) throws Exception {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
    long end = System.currentTimeMillis();
    System.out.println(end - start);

ForName results:

  x86 x64
IKVM 0.37.3063             4350     3959
IKVM 0.37.3073 45 49
JDK 1.6 138 97

(The difference between JDK 1.6 x86 and x64 is mostly due to x86 defaulting to HotSpot Client and x64 to HotSpot Server.)


The Method.invoke() API uses the caller class to perform the required access checks when you are calling a non-public method or a method in non-public class.

class Invoke {
  public static void main(String[] args) throws Exception {
    java.lang.reflect.Method m = Invoke.class.getDeclaredMethod("foo");
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
    long end = System.currentTimeMillis();
    System.out.println(end - start);

  private static void foo() { }

Invoke results:

  x86 x64
IKVM 0.37.3063             6083     5572
IKVM 0.37.3073 14 16
JDK 1.6 82 39

To be continued in part 2...

Saturday, May 31, 2008 5:20:40 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
# Friday, May 23, 2008
Invokedynamic Proof of Concept Part 2

Rémi Forax inspired me to make my invokedynamic proof of concept a little more real, so I implemented it (still only as a proof of concept, not production quality code) in an IKVM 0.37 fork.

I used the following Java test case:

interface java_dyn_Dynamic
  void printSubstring(int startIndex, int length);
  int length();

class InvokeDynamic
      java.lang.reflect.Method m = InvokeDynamic.class.getDeclaredMethod("bootstrapInvokeDynamic",
                                     java.dyn.CallSite.class, Object.class, Object[].class);
      java.dyn.MethodHandle mh = java.dyn.MethodHandles.unreflect(m);
      java.dyn.Linkage.registerBootstrapMethod(InvokeDynamic.class, mh);
    catch (Exception x)

  public static void main(String[] args)
    java_dyn_Dynamic obj = (java_dyn_Dynamic)(Object)"invokedynamic";
    for (int i = 0; i < 3; i++)
      System.out.println("len = " + obj.length());
      obj.printSubstring(3, 2);

  public static void printSubstring(String str, int startIndex, int length)
    System.out.println(str.substring(startIndex, startIndex + length));

  private static Object bootstrapInvokeDynamic(java.dyn.CallSite cs, Object receiver, Object[] args)
    throws Exception
    if (cs.getStaticContext().getName().equals("length"))
      java.lang.reflect.Method m = String.class.getMethod("length");
      return m.invoke(receiver);
      Class c = cs.getStaticContext().getCallerClass();
      java.lang.reflect.Method m = c.getMethod("printSubstring", String.class, int.class, int.class);
      return m.invoke(null, receiver, args[0], args[1]);

After compiling this with javac I used a hex editor to patch the file (changed java_dyn_Dynamic to java/dyn/Dynamic and C0 00 03 to 00 00 00 to remove the checkcast instruction).

Current limitations:

  • java.dyn.MethodType is not implemented.
  • MethodHandles can only be created on methods with a couple of arguments and from the primitive types only int can be used as an argument or return type.
  • Not all of the IKVM specific corner cases are supported (e.g. calling .NET methods or methods on remapped types).
  • The CallSite and MethodHandle implementation objects do not have a proper class (i.e. CallSite.getClass() doesn't work).
  • Only a small subset of the MethodHandle functionality is implemented (e.g. no bound or Java method handles).

None of these limitations pose any interesting challenges, so implementing them does not add much value to this proof of concept.


Friday, May 23, 2008 3:17:04 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Wednesday, May 21, 2008
Invokedynamic Proof of Concept

A few days ago the JSR 292 expert group released an early draft review for the invokedynamic instruction.

To investigate how this would work out for IKVM, I cooked up a proof of concept in C#.

class InvokeDynamicPoC
  private static InvokeDynamic<object, CallSite, object, object[]> __bootstrapMethod =
  private static CallSiteImpl<InvokeDynamicVoid<string, int, int>> __site1 =
    new CallSiteImpl<InvokeDynamicVoid<string, int, int>>(
      new StaticContextImpl(typeof(InvokeDynamicPoC), "printSubstring"));

  private static void Main()
    for (int j = 0; j < 2; j++)
      int start = Environment.TickCount;
      for (int i = 0; i < 10/*0000000/**/; i++)
        string obj = "invokedynamic";
        int arg1 = 3;
        int arg2 = 2;
        MethodHandleImpl<InvokeDynamicVoid<string, int, int>> mh = __site1.mh;
        if (mh == null)
          __bootstrapMethod(__site1, obj, new object[] { java.lang.Integer.valueOf(arg1),
                                                         java.lang.Integer.valueOf(arg2) });
          mh.d(obj, arg1, arg2);
      int end = Environment.TickCount;
      Console.WriteLine(end - start);

  private static void printSubstring(string s, int startIndex, int length)
    Console.WriteLine(s.Substring(startIndex, length));

  private static object bootstrapInvokeDynamic(CallSite cs, object receiver, object[] arguments)
    java.lang.Class c = typeof(InvokeDynamicPoC);
    java.lang.reflect.Method m = c.getDeclaredMethod(cs.getStaticContext().getName(),
                                                     typeof(string), typeof(int), typeof(int));
    MethodHandle mh = MethodHandles.unreflect(m);
    return m.invoke(null, receiver, arguments[0], arguments[1]);

The full (compilable and working) source is available here.

Wednesday, May 21, 2008 9:56:49 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
New Development Snapshot

More .NET 2.0 work and bug fixing, but the biggest change is that class library initialization has been refactored (building on the property support added in the previous snaphot which allows java.lang.System to lazily initialize the I/O streams). Instead of it being an all or nothing approach (i.e. initialize all core classes at once, like in Java) the initialization dependencies have been mostly removed and each part can now be initialized on demand. This makes the code easier to follow, startup more efficient and removed the need for some ugly hacks to make initialization work correctly.

One thing isn't yet working, if you specify a Java security manager in your app.config it isn't guaranteed that the security manager will be installed immediately (currently it's only installed the first time ClassLoader.getSystemClassLoader() is called.) I'm not sure if it is worth fixing this, because using the Java security manager in this way doesn't seem to make much sense (i.e. if you are running your application as a .NET application, why would you use the Java security manager to restrict what it can do, it won't be able do a good job anyway, since it doesn't know about your non-Java .NET code that directly calls .NET Framework APIs.)

Changes since previous development snapshot:

  • Call suppressFillInStackTrace before instantiating a remapped exception in the remap implementation method.
  • Added assembly location to verbose class cast exception if the assembly fullnames matches but the locations don't.
  • Create the generic delegate type before compiling the rest of the core class library, to allow the core class library to use delegates.
  • Fixed name mangling bug. Dots in nested type names should be mangled, because they shouldn't affect the package name.
  • Include exception message in ClassCastException.
  • Added hack to support instantiating fake enums for types loaded in ReflectionOnly (to support custom attribute annotations that have enum values in ikvmstub).
  • Added -reference option to ikvmstub to load referenced assemblies from a specific location.
  • Refactored class library initialization.
  • Implemented Runtime.availableProcessor() using .NET 2.0 API.
  • Moved most java.lang.System "native" methods to the Java side.
  • Moved java.lang.Thread "native" methods to Java.
  • Implemented support for specifying Thread stack size.
  • Fix deserialization of double arrays.
  • Added more efficient float/double to/from int/long bits converters.
  • Made Double.doubleToRawLongBits/longBitsToDouble and Float.floatToRawIntBits/intBitsToFloat intrinsics.
  • Generalized the support infrastructure for adding compiler intrinsics.
  • Fixed Graphics2D.rotate() to convert rotation angle from radians (Java) to degrees (.NET).
  • Fixed libikvm-native.so build to include reference to gmodule-2.0 library.
  • Fixed build issue on Mono (gmcs implicitly references System.Core.dll and that caused a conflict with our locally defined ExtensionAttribute).
  • Fixed ikvmc not to open the key file for write access.
  • Added workarounds for mcs compiler bug (related to the mutual dependencies of IKVM assemblies).
  • Restructured code to remove (mcs) compiler warnings.


Development snapshots are intended for evaluating and keeping track of where the project is going, not for production usage. The binaries have not been extensively tested and are not strong named.

If you want to run this version on Mono, you'll need a Mono version built from recent svn, it does not work on Mono 1.9.

Binaries available here: ikvmbin-0.37.3063.zip

Wednesday, May 21, 2008 7:16:08 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Friday, May 9, 2008
Compiler Intrinsics

Most compilers have some (or in some cases many) intrinsic functions. HotSpot has a number of them (see here, search for "intrinsics known to the runtime") as does the CLR JIT. IKVM has had a couple as well (System.arraycopy(), AtomicReferenceFieldUpdater.newUpdater(), String.toCharArray()). These were sort of hacked into the compiler and I finally decided to clean that up a little and add more scalable support for adding intrinsincs. The trigger to do this was that I added four more intrinsics: Float.floatToRawIntBits(), Float.intBitsToFloat(), Double.doubleToRawLongBits() and Double.longBitsToDouble().


Here's a micro benchmark:

public class test {
  public static void main(String[] args) {
    long sum = 1;
    long start = System.currentTimeMillis();
    for (int i = 0; i < 10000000; i++) {
      sum += Double.doubleToRawLongBits(sum);
    long end = System.currentTimeMillis();
    System.out.println(end - start);

Here are the results:

         x86 (aligned)     x86 (unaligned)                      x64
JDK 1.6 HotSpot Server VM    287   109
JDK 1.6 HotSpot Client VM 335    
IKVM 0.36 .NET 1.1 479 565  
IKVM 0.36 .NET 2.0 570 704 124
IKVM 0.37 338 468 101

Since the x86 .NET results are highly sensitive as to whether the double on the stack happens to be aligned or not, I included both results.


Here's the MSIL that IKVM generates for the loop:

IL_000b:   ldloc.2
IL_000c:   ldc.i4    0x989680
IL_0011:   bge       IL_0028
IL_0016:   ldloc.0
IL_0017:   ldloc.0
IL_0018:   conv.r8
IL_0019:   ldloca.s  V_3
IL_001b:   call      int64 [IKVM.Runtime]IKVM.Runtime.DoubleConverter::ToLong(float64,
                     valuetype [IKVM.Runtime]IKVM.Runtime.DoubleConverter&)
IL_0020:   add
IL_0021:   stloc.0
IL_0022:   ldloc.2
IL_0023:   ldc.i4.1
IL_0024:   add
IL_0025:   stloc.2
IL_0026:   br.s      IL_000b

The conversion isn't actually inlined, but instead a local variable of value type IKVM.Runtime.DoubleConverter is added to the method and a static method on that type that takes the value to be converted and a reference to the local variable is called. Here's the code for IKVM.Runtime.DoubleConverter:

public struct DoubleConverter
  private double d;
  private long l;

  public static long ToLong(double value, ref DoubleConverter converter)
    converter.d = value;
    return converter.l;

  public static double ToDouble(long value, ref DoubleConverter converter)
    converter.l = value;
    return converter.d;

It uses the .NET feature that allows you to explicitly control the layout of a struct  to overlay the double and long fields. Note that this construct is fully verifiable.

For comparison, the standard System.BitConverter.DoubleToInt64Bits() uses unsafe code and looks something like this:

public static unsafe long DoubleToInt64Bits(double value)
  return *((long*)&value);

For some reason (probably because it isn't verifiable) the JIT doesn't like this so much and doesn't inline this method.

JIT Code

Here's the x86 code generated by the .NET 2.0 SP1 JIT:

049E15CE  cmp    ebx,989680h
049E15D4  jge    049E1600
049E15D6  lea    ecx,[esp+8]
049E15DA  mov    dword ptr [esp+10h],esi
049E15DE  mov    dword ptr [esp+14h],edi
049E15E2  fild   qword ptr [esp+10h]
049E15E6  fstp   qword ptr [esp+10h]
049E15EA  fld    qword ptr [esp+10h]
049E15EE  fstp   qword ptr [ecx]
049E15F0  mov    eax,dword ptr [ecx]
049E15F2  mov    edx,dword ptr [ecx+4]
049E15F5  add    eax,esi
049E15F7  adc    edx,edi
049E15F9  mov    esi,eax
049E15FB  mov    edi,edx
049E15FD  inc    ebx
049E15FE  jmp    049E15CE

Here's the x64 code generated by the .NET 2.0 SP1 JIT:

00000642805B8A90  cmp        ecx,989680h
00000642805B8A96  jge        00000642805B8AB1
00000642805B8A98  cvtsi2sd   xmm0,rdi
00000642805B8A9D  lea        rax,[rsp+20h]
00000642805B8AA2  movsd      mmword ptr [rax],xmm0
00000642805B8AA6  mov        rax,qword ptr [rax]
00000642805B8AA9  add        rdi,rax
00000642805B8AAC  add        ecx,1
00000642805B8AAF  jmp        00000642805B8A90

In both cases the construct is inlined properly. It is also obvious why the x64 code is so much faster, it uses SSE (as we've seen before) and only uses one memory store/load combination.


For completeness, here's the code generated by HotSpot x64:

0000000002772EA0  cvtsi2sd   xmm0,r11
0000000002772EA5  add        ebp,10h
0000000002772EA8  movsd      mmword ptr [rsp+20h],xmm0
0000000002772EAE  mov        r10,qword ptr [rsp+20h]
0000000002772EB3  add        r10,r11
0000000002772EB6  cvtsi2sd   xmm0,r10
0000000002772EBB  movsd      mmword ptr [rsp+20h],xmm0
0000000002772EC1  mov        r11,qword ptr [rsp+20h]
0000000002772EC6  add        r11,r10
0000000002772EC9  cvtsi2sd   xmm0,r11
0000000002772ECE  movsd      mmword ptr [rsp+20h],xmm0
0000000002772ED4  mov        r10,qword ptr [rsp+20h]
0000000002772ED9  add        r10,r11
0000000002772FC0  cvtsi2sd   xmm0,r10
0000000002772FC5  movsd      mmword ptr [rsp+20h],xmm0
0000000002772FCB  mov        r11,qword ptr [rsp+20h]
0000000002772FD0  add        r11,r10
0000000002772FD3  cmp        ebp,r9d
0000000002772FD6  jl         0000000002772EA0

It actually unrolled the loop 16 times (which appears not be helping in the case), but otherwise the code generated is pretty similar to what we saw on the CLR. Of course, in HotSpot Double.doubleToRawIntBits() is also an intrinsic because in Java the only alternative would be to write it in native code and the JNI transition would add significant overhead in this case.

Friday, May 9, 2008 11:27:51 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]
# Monday, May 5, 2008
IKVM 0.36 Update 2 Release Candidate 1

A couple of fixes.


  • Remapped exceptions with explicit remapping code now call suppressFillInStackTrace (to make sure the proper stack trace is captured).
  • Fixed memory mapped file bug (mapping at a non-zero file offset would fail).
  • Fixed .NET type name mangling for nested types that contain a dot in their name (which the C# 3.0 compiler generates for some private helper types).
  • Fixed java.io.File.getCanonicalPath() to swallow System.NotSupportedException (thrown when the path contains a colon, other than the one following the drive letter).
  • Fixed bug in deserialization of double arrays.

Binaries available here: ikvmbin-
Sources (+ binaries):ikvm-

Monday, May 5, 2008 6:23:35 AM (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]