# Sunday, 21 November 2010
How to Detect if a Method is Overridden

Suppose you want to know if (the class of) a particular object overrides a virtual method. For an example of this see OpenJDK's Thread.isCCLOverriden() (line 1573).

In Java the obvious way to do this would be to use reflection. On the CLR there is another way that is both more accurate1 and more efficient.

Here's the MSIL method from IKVM's java.lang.Thread.isCCLOverridden() implementation:

.method private hidebysig static bool isCCLOverridden(class java.lang.Thread A_0) cil managed
{
  ldftn      instance class java.lang.ClassLoader java.lang.Thread::getContextClassLoader()
  ldarg.0
  ldvirtftn  instance class java.lang.ClassLoader java.lang.Thread::getContextClassLoader()
  ceq
  ldftn      instance void java.lang.Thread::setContextClassLoader(class java.lang.ClassLoader)
  ldarg.0
  ldvirtftn  instance void java.lang.Thread::setContextClassLoader(class java.lang.ClassLoader)
  ceq
  and
  ldc.i4.0
  ceq
  ret
}

Instead of running a zillion instructions and accessing a lot of cold data for reflection, this simply leverages the information the JIT already has about virtual methods.

Here's the x86 code this turns into:

  push        ebp 
  mov         ebp,esp 
  push        esi 
  push        ebx 
  mov         esi,ecx 
  push        258F58h 
  mov         ecx,esi 
  mov         edx,259240h 
  call        JIT_VirtualFunctionPointer
  mov         edx,25DCA0h 
  cmp         eax,edx 
  sete        bl 
  movzx       ebx,bl 
  push        2591A0h 
  mov         ecx,esi 
  mov         edx,259240h 
  call        JIT_VirtualFunctionPointer
  mov         edx,25DCB0h 
  cmp         eax,edx 
  sete        al 
  movzx       eax,al 
  and         ebx,eax 
  sete        al 
  movzx       eax,al 
  pop         ebx 
  pop         esi 
  pop         ebp 
  ret

To get an idea what JIT_VirtualFunctionPointer does, take a look at the Shared Source CLI.

On the CLR, in the common case it only executes about 40 instructions.

The downside to this method is that it only works if you have an object instance. Although you could use FormatterServices.GetUninitializedObject() to create an instance.

Why Optimize This?

In the OpenJDK code, isCCLOverridden() is only called if a SecurityManager is installed, but I wanted to use it always to avoid calling getContextClassLoader() during thread construction, because that would trigger the system class loader to be constructed and I my long term goal for IKVM is to make initialization more lazy to reduce the huge startup overhead.


1This method is more accurate (on the CLR) because you don't need to worry about non-virtual methods or virtual methods that are new (and hence don't override the base class virtual method) or explicit overrides that override a method but have a different name.

Update: See this article for a caveat.

Sunday, 21 November 2010 11:36:21 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Wednesday, 17 November 2010
New Development Snapshot

Time for a new snapshot.

Changes:

  • Added support for using MethodImplAttribute as a Java annotation.
  • Fixed class name resolution for xml remapping instructions.
  • Many AWT fixes.
  • Fixed xml remapper to interpret empty sig attribute on call as zero length argument list.
  • Added memory barrier after volatile stores.
  • Added optimization to remove redundant memory barriers.
  • Changed default assembly class loader instantiation to avoid security manager check.
  • Fixed ikvm.exe -D property name parsing to accept properties with equals sign in the name.
  • Fixed JdbcOdbc provider to use Invariant Culture for Decimal/BigDecimal conversion.
  • Fixed column type mapping bugs in JdbcOdbcResultSetMetaData.
  • Fixed resource (and virtual class file) loading regression that caused loading resources from assemblies with an underscore in the name to fail.

Binaries available here: ikvmbin-0.45.3973.zip

Wednesday, 17 November 2010 09:08:33 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]
# Thursday, 11 November 2010
IKVM.NET 0.36 Update 3

On request of an IKVM.NET user still stuck on .NET 1.1 the memory model fix has been backported to 0.36.

Changes:

  • Changed version to 0.36.0.14.
  • Emit a memory barrier after volatile stores.

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

Thursday, 11 November 2010 07:09:06 (W. Europe Standard Time, UTC+01:00)  #    Comments [0]
# Monday, 01 November 2010
C# Async CTP

Last week at the PDC Microsoft released a CTP of the upcoming C# (and VB.NET) async feature. When you install the Async CTP and run the code below with the current IKVM.NET release you'll see something like this:

7
Downloaded 64803 bytes
13

This means that after the async operation completed the method resumed on another thread. However, if you get the current IKVM.NET code from cvs, you'll see:

7
Downloaded 64803 bytes
7

Via the magic of SynchronizationContext the method now resumes on the AWT event thread, if the await happened on that thread.

Here's the demo:

using System;
using System.Threading;
using System.Net;
using java.awt;
using java.awt.@event;

class AsyncDemo : Frame, ActionListener
{
  AsyncDemo()
  {
    var button = new Button("Click Me");
    button.addActionListener(this);
    add(button);
    pack();
    setVisible(true);
  }

  public async void actionPerformed(ActionEvent ae)
  {
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    var wc = new WebClient();
    var data = await wc.DownloadDataTaskAsync("http://weblog.ikvm.net/");
    Console.WriteLine("Downloaded {0} bytes", data.Length);
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
  }

  static void Main()
  {
    new AsyncDemo();
  }
}

Monday, 01 November 2010 15:57:38 (W. Europe Standard Time, UTC+01:00)  #    Comments [2]