# Saturday, 31 May 2008
« Invokedynamic Proof of Concept Part 2 | Main | Introducing CallerID Part 2 »
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.

Class.forName()

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 {
    Class.forName("java.lang.Object");
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++)
      Class.forName("java.lang.Object");
    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.)

Method.invoke()

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++)
      m.invoke(null);
    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, 31 May 2008 17:20:40 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]