# 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.

Changes:

  • 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.

Changes:

  • 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]