# Thursday, 25 June 2015
MethodHandle Performance

Last time I mentioned that with the integration of OpenJDK 8u45 MethodHandle performance went from awful to unusable. That was pretty literal as the JSR 292 test cases that I regularly run went from taking about 8 minutes to more than 30 minutes (when my patience ran out).

Using sophisticated profiling techniques (pressing Ctrl-Break a few times) I determined that a big part of the problem was MethodHandle.asType(). So I wrote a microbenchmark:

   IKVM 8.0.5449.1  IKVM 8.1.5638
asType.permutations(1) 2108 9039
asType.permutations(2) 2476 17269

The numbers are times in milliseconds. Clearly not a good trend. I did not investigate deeply what changed in OpenJDK, but after looking at the 8u45 code it was clear that too many intermediate MethodHandles were being created. So I rewrote asType to create a single LambdaForm to do all the work at once. This improved the performance a bit, but the disturbing increase in time for the second iteration was still there. Once again I decided not to investigate the root cause of this, but simply to assume that it was because of anonymous type creation (the CLR has no anonymous types and creating a type is relatively expensive).

Avoiding anonymous type creation turned out to be easy (well, the high level design was easy, the actual implementation took a lot more time). I just had to replace the LambdaForm compiler. There is a single method that represents the exact point where I can come in and change the implementation:

static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) { ... }

In OpenJDK this method compiles the LambdaForm into a static method in an anonymous class and returns a MemberName that points to the static method. All I had to do was replace this method with my own implementation that directly generates a .NET DynamicMethod. As I said before, the idea was simple, actually getting the implementation correct took a couple of weeks (part time).

With both these optimizations in place, MethodHandle performance is back to awful (actually, it is less afwul than it was before):

   IKVM 8.0.5449.1  IKVM 8.1.5638  IKVM 8.1.5653
asType.permutations(1) 2108 9039 314
asType.permutations(2) 2476 17269 210

The running time of the JSR 292 test cases went down to less than 7 minutes. So I was satisfied. There are many more opportunities to improve the MethodHandle performance on IKVM, but so far no IKVM user has complained about it, so it is not a priority. Note that Java 8 lambdas are not implemented using MethodHandles on IKVM.


  • Fixed performance bug. Base type of java.lang.Object was not cached.
  • Untangled TypeWrapper.Finish() from member linking to improve Finish performance for already compiled types.
  • Improved MethodHandle.asType() performance by directly creating a single LambdaForm to do the conversion, instead of creating various intermediate forms (and MethodHandles).
  • Make non-public final methods defined in map.xml that don't override anything automatically non-virtual.
  • Optimized LambdaForm compiler.
  • IKVM.Reflection: Added Type.__GetGenericParameterConstraintCustomModifiers() API.

Binaries available here: ikvmbin-8.1.5653.zip

Thursday, 25 June 2015 08:59:31 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Tuesday, 09 June 2015
New Development Snapshot

I integrated OpenJDK 8u45, so a new development snapshot is warranted. MethodHandle performance regressed from awful to unusable, so that's something I need to look into.


  • Merged OpenJDK 8u45. Special thanks to @mihi42 for helping me with the download.
  • Bug fix. Don't enforce canonical UTF8 encoding for class file versions <= 47.
  • Added support for "high contrast" desktop property. Inspired by patch from Daniel Zatonyi .
  • Handle more text sources for clipboard copy by using an appropriate Reader for the source data. Patch by Daniel Zatonyi .
  • Fixed drag-n-drop coordinates. Patch by Daniel Zatonyi .
  • Fixed Graphics.clipRect(). Fix by Daniel Zatonyi .
  • Bug fix. ReferenceQueue should not keep registered (but not yet enqueued) Reference objects alive.
  • Added Unsafe.staticFieldOffset() and Unsafe.staticFieldBase() methods.
  • sun.misc.Unsafe: Replaced (broken) TypedReference based field CompareExchange with DynamicMethod based implementation.
  • Fixed clone/finalize invocation via MethodHandle.
  • Fixed build to allow nasgen to work with 1.8.0_40.
  • IKVM.Reflection: Fixed known custom attribute handling. They should be recognized by type name, not type identity.
  • IKVM.Reflection: Added Module.__TryGetImplMap() public API to get ImplMap by token.
  • IKVM.Reflection: Added new public APIs to help deal with built-in types even when they are not defined in mscorlib: Type.__IsBuiltIn and Universe.GetBuiltInType(string ns, string name).

Binaries available here: ikvmbin-8.1.5638.zip
Sources: ikvmsrc-8.1.5638.zip, openjdk-8u45-b14-stripped.zip

Tuesday, 09 June 2015 13:50:20 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Tuesday, 24 March 2015
New Development Snapshot

After debugging a stack overflow caused by a weird class loader, I decided to make the runtime more robust against this and as a side effect I added the ability to disable eager class loading. This in turn made it easier to test the late binding infrastructure (which is used when a class is not yet available while a method is compiled) and that testing revealed a large number of bugs that have now been fixed.


  • Bug fix. When -Xsave is used the modopt types should be attached to unloadable types in inherited method signatures.
  • Bug fix. Don't try to get constructor on generic instantiation containing a TypeBuilder generic parameter.
  • Use the last write time of the input file for resources read from the file system.
  • Enable UniverseOptions.DeterministicOutput for ikvmc (unless -debug option is used).
  • Copy timestamps from source files for generated files that end up in resources.jar.
  • The zip file timestamp is in local time, but for deterministic builds we don't want to depend on system timezone, so we have to store the UTC time.
  • Bug fix. Removed legacy (incorrect) array assignability check that compensated for the lack of ghost array typing. This should have been removed when ghost array tagging was introduced.
  • Bug fix. Verifier should disallow using invokeinterface on private methods.
  • The message of a VM generated java.lang.NoClassDefFoundError exception should be the class name, not the message of the underlying exception.
  • Bug fix. Don't crash if java.lang.invoke.LambdaMetafactory class is not loadable.
  • Added Unsafe.reallocateMemory() and fixed allocateMemory() to do nothing if zero length is allocated.
  • Bug fix. Return background color (instead of foreground color). Fix by Daniel Zatonyi .
  • Bug fix. Dynamically created ghost arrays should get tagged.
  • Bug fix. When catching a dynamically loaded .NET exception type the exception should not be remapped.
  • Bug fix. Bootstrap classes that use .NET types in their signatures should be accessible via MethodHandles.
  • Bug fix. Allow MethodHandle for cli.System.Object methods to work on (Java compatble) arrays to handle a hole in the type system.
  • Bug fix. Handle unloadable types in interface stub signatures.
  • Bug fix. MethodHandle and JNI should be able to set static final fields.
  • Bug fix. If a miranda method signature differs from its base class miranda method (due to unloadable types), we need to emit an override stub.
  • Bug fix. Allow value type default constructor to be invoked using MethodHandle.
  • Bug fix. Allow invokedynamic with unloadable type in signature.
  • Bug fix. Handle late-bound MethodHandle.invokeExact() with unloadable type in signature.
  • Bug fix. Late bound instanceof and castclass should behave the same as regular versions (with respect to type system holes caused by .NET types).
  • Bug fix. MethodHandle interface method lookup should support methods inherited from base interfaces.
  • Bug fix. Late bound delegate signature conversion should use explicitCastArguments instead of asType to handle varargs correctly.
  • Implemented delegate constructor invocation on existing object (to enable MethodHandle to construct a delegate).
  • Bug fix. Handle unloadable return type in native method signature.
  • Bug fix. Handle unloadable types in native method signature in JniProxyBuilder (used when -Xsave is used).
  • Bug fix. Late bound invokespecial should also be handled in local variable analysis.
  • Bug fix. Handle unloadable type in BSM extra arguments.
  • Bug fix. Verifier would incorrectly report a loader constraints violated if a field type was not unloadable, but the field ref type was unloadable.
  • Bug fix. Make sure declaring class is loadable.
  • Bug fix. Try loading unloadable declared classes instead of simply throwing a NoClassDefFoundError.
  • Bug fix. Make sure inner classes are loadable.
  • Bug fix. Disallow invokevirtual MH constant to resolve to interface method and disallow invokeinterface MH constant to resolve to non-public method.
  • Bug fix. Handle unloadable type in MH.invoke() signature.
  • Bug fix. Handle invocation of method on unloadable value type.
  • Bug fix. Handle ghost and value types in override stub signatures.
  • Added a hack to the deprecated Reflection.getCallerClass(int) version to skip LamdbaForm methods to report the right caller when dynamic binding is used.
  • Bug fix. Dynamica caller id should return host class for anonymous classes injected into host class.
  • Avoid infinite recursion if (broken) class loader triggers a load of a class currently being finished.
  • Added environment switch IKVM_DISABLE_EAGER_CLASS_LOADING to enable testing late binding.
  • IKVM.Reflection: Added CoreCLR target.
  • IKVM.Reflection: Fixed ModuleBuilder.DefineManifestResource() to support very large resources.
  • IKVM.Reflection: Added new public API ModuleBuilder.__PEHeaderTimeDateStamp property.
  • IKVM.Reflection: Added UniverseOptions.DeterministicOutput to enable deterministic output (i.e. setting the PE file header time stamp to zero and computing the module version id based on the contents, instead of using a random guid).

Binaries available here: ikvmbin-8.1.5561.zip

Tuesday, 24 March 2015 14:43:45 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Monday, 12 January 2015
IKVM.NET 8.0 Release Candidate 1

The second release candidate is available. It can be downloaded here or from NuGet.

What's New (relative to rc 0):

  • Fixed build error when using Java 8u25 or newer.
  • Bug fix. Unsafe.compareAndSwapObject should resolve field before passing it to MakeTypedReference.
  • Implemented OperatingSystemMXBean.getFreePhysicalMemorySize and OperatingSystemMXBean.getTotalPhysicalMemorySize.

Binaries available here: ikvmbin-8.0.5449.1.zip

Sources: ikvmsrc-8.0.5449.1.zip, openjdk-8-b132-stripped.zip

Monday, 12 January 2015 15:11:00 (W. Europe Standard Time, UTC+01:00)  #    Comments [4]
# Tuesday, 02 December 2014
IKVM.NET 8.0 Release Candidate 0

The first release candidate is available. It can be downloaded here or from NuGet.

What's New (relative to IKVM.NET 7.4):

  • Merged OpenJDK 8 b132.
  • Support for Java 8 features.
  • Improvements to sun.misc.Unsafe compatibility.
  • Various bug fixes.

Changes since previous development snapshot:

  • Assemblies are strong named.

Binaries available here: ikvmbin-8.0.5449.0.zip

Sources: ikvmsrc-8.0.5449.0.zip, openjdk-8-b132-stripped.zip

Tuesday, 02 December 2014 14:52:48 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Monday, 01 December 2014
Running Minecraft on IKVM.NET

With the fixes I did in the snapshot released on October 29, it is now possible to run Minecraft on IKVM.NET (on Windows). To be clear, I'm talking about the Minecraft client, not the server that has been running on IKVM.NET for a long time.

The Minecraft client uses native code for the 3D graphics and sound, so it doesn't run into IKVM limitations there.

To get it to run download the most recent IKVM.NET snapshot (currently available here) and unzip it. Download minecraft.jar and run it like this:

ikvm -jar minecraft.jar

It takes a while to start up, so be patient.

If you get an exception when trying to log in, you may have to visit https://authserver.mojang.com/ in Internet Explorer to add the root certificate to the Windows certificate store (just visiting the site causes IE to download it from Microsoft). After that you have to restart Minecraft.

Monday, 01 December 2014 14:42:28 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Wednesday, 19 November 2014
New Development Snapshot

Getting closer to a release.


  • Optimized ForkJoinPool unsafe usage.
  • Optimized java.lang.[Integer|Long].[compare|divide|remainder]Unsigned().
  • Bug fix. Default interface methods should not conflict with their own base interfaces.
  • Bug fix. Miranda method in base class should not interfere with default interface methods.
  • Bug fix. Conflicting default interface methods should throw IncompatibleClassChangeError instead of AbstractMethodError.
  • Bug fix. LockSupport.parkUntil() didn't convert milliseconds to nanoseconds.
  • Implemented TwoStacksPlainDatagramSocketImpl.socketLocalAddress() and TwoStacksPlainDatagramSocketImpl.isAdapterIpv6Enabled().
  • Made sun.misc.Unsafe interlocked operations truly atomic (except for unaligned array access and int/long array access on different array types).
  • Made sun.misc.Unsafe array access more compatible with JDK. It is now possible to get/set primitive values from arrays of a different (primitive) type.
  • Fixed font file clean up issue on Windows 8.
  • Bug fix. NetGraphicsDevice.getDefaultConfiguration() should take the screen into account. Thanks to Maria Papendieck for this fix.
  • Bug fix. NetComponentPeer.getLocationOnScreen() should take insets into account. Thanks to Maria Papendieck for this fix.

Binaries available here: ikvmbin-8.0.5436.zip

Wednesday, 19 November 2014 14:56:25 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Wednesday, 29 October 2014
New Development Snapshot

I've been busy with other things, but there have been enough fixes to warrant a new snapshot.


  • Bug fix. When reading a .class resource from an assembly (to attempt to dynamically define it), read all the bytes.
  • Bug fix. Reading/writing java.nio.file attributes of non-existing file should throw NoSuchFileException.
  • Bug fix. Fixed bitmap synchronization in java.awt.image.BufferedImage and com.sun.imageio.plugins.jpeg.JPEGImageWriter.
  • Ignore -Xmn and -XX: Oracle Java specific command line options in ikvm.exe.
  • Enabled pack200 unpacking algorithm.
  • IKVM.Reflection: Bug fix. If custom attribute named argument parsing fails due to missing type, ConstructorArguments should still work.

Binaries available here: ikvmbin-8.0.5415.zip

Wednesday, 29 October 2014 13:24:17 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Wednesday, 16 July 2014
Java Method Overriding Is FUBAR Part 10 of ∞

Yesterday's JDK 7u65 and 8u11 updates changed method overriding yet again and, of course, it is still broken.

Take this example:

package pkg1;

public class A {
  { foo(); }
  void foo() { System.out.println("A.foo"); }

package pkg2;

public class B extends pkg1.A {
  { foo(); }
  void foo() { System.out.println("B.foo"); }

package pkg1;

public class C extends pkg2.B {
  { foo(); }
  void foo() { System.out.println("C.foo"); }

package pkg2;

public class D extends pkg1.C {
  { foo(); }
  void foo() { System.out.println("D.foo"); }

public class test {
  public static void main(String[] args) {
    new pkg2.D();

Running this with JDK 8u5 yields:


Which is, of course, wrong. In yesterday's updates they tried to fix this, but only partially succeeded:


The sensible output would be:


Wednesday, 16 July 2014 13:27:41 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
Java Security Fixes

In Februari I reported two Java vulnerabilities to Oracle. Yesterday they released the update that fixed them, so here are the descriptions of the two issues.


Internally, the JDK uses the LambdaForm.Compiled annotation to mark methods that should be skipped in a security stack walk. In JDK 7 it was possible to apply this annotation to untrusted code. Here's an example:

import java.lang.annotation.*;

@interface java_lang_invoke_LambdaForm$Compiled { }

class test {
  public static void main(String[] args) throws Throwable {

If you compile and run this with JDK 1.7.0_60 with a security manager, you get the appropriate AccessControlException. However, if you edit test.class to replace java_lang_invoke_LambdaForm with java/lang/invoke/LambdaForm and run it again, you see that the main method is now skipped in the security check and hence is allowed to access a privileged class.

The fix can be seen here.


This example demonstrates that the JDK 1.7.0_60 LambdaForm method handle implementation has a type safety bug when dealing with method signatures with the maximum number of parameters.

Wednesday, 16 July 2014 08:53:16 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]