# Tuesday, 12 August 2008
Using Mono.Cecil instead of Reflection.Emit in IKVMC

I prototyped a Reflection.Emit layer for Mono.Cecil and integrated it with ikvmc. Preliminary results:

  • It looks like it is feasible to replace "using System.Reflection.Emit;" with "using Cecil.Reflection.Emit;" and only require a handful of "#if CECIL"s sprinkled through the code.
  • Mono.Cecil is lacking some functionality required by ikvmc (global methods, multi module assemblies, support for calli signatures [AFAICT], support for byte[] arguments in custom attributes)
  • Given the architecture of Mono.Cecil I'm worried that it will perform worse than Reflection.Emit (which, on .NET, is already pretty slow).

I'm pretty sure there are more issues waiting to be discovered, but these I found while trying to compile a relatively simple .class file. I got it to generate a verifiable assembly using the following ikvmc command:

        ikvmc test.class -target:library -nostacktraceinfo

If you want to play along, the Cecil.Reflection.Emit layer plus the ikvmc patch (relative to current cvs) can be found here.

At this point I'm not sure what's next. I don't feel working on Mono.Cecil is the best use of my time. I may have to put the multi assembly feature of ikvmc on the back burner (which also means no progress in splitting up IKVM.OpenJDK.ClassLibrary.dll).

On a more possitive note, doing this work made me realize that ConstructorBuilder is a useless annoyance and I can simplify some ikvm code by only using MethodBuilder (it turns out that DefineMethod can also be used to define a constructor).

Well, I will be able to do this once Mono's DefineMethod is fixed so that it notices that a constructor is created and not insert another default constructor.

Update: Zoltan already fixed the Mono bug. Thanks!

Update 2: Jb Evain pointed out that global methods are supported (simply add the methods to the <Module> type) and that calli is supported via Mono.Cecil.CallSite.

Tuesday, 12 August 2008 17:39:21 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Sunday, 10 August 2008
Reflection.Emit Bug

I started working on support for compiling multiple assemblies at once with ikvmc (to support mutual depedencies) and ran into a rather annoying bug:

using System;
using System.Reflection;
using System.Reflection.Emit;

class Program
{
  static void Main()
  {
    AssemblyBuilder ab1 = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("A1"), AssemblyBuilderAccess.Save);
    AssemblyBuilder ab2 = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("A2"), AssemblyBuilderAccess.Save);
    ModuleBuilder mod1 = ab1.DefineDynamicModule("A1");
    ModuleBuilder mod2 = ab2.DefineDynamicModule("A2");

    TypeBuilder tb1 = mod1.DefineType("T1");
    TypeBuilder tb2 = mod2.DefineType("T2");

    ConstructorBuilder cb1 = tb1.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
    ConstructorBuilder cb2 = tb2.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { tb1 });

    ILGenerator ilgen = cb1.GetILGenerator();

    ilgen.Emit(OpCodes.Ldnull);
    ilgen.Emit(OpCodes.Newobj, cb2);
  }
}

Running this on .NET 2.0 SP1 results in:

Unhandled Exception: System.Runtime.InteropServices.COMException (0x80131130): Record not found on lookup. (Exception from HRESULT: 0x80131130)
   at System.Reflection.Module._InternalGetMemberRef(Module refedModule, Int32 tr, Int32 defToken)
   at System.Reflection.Emit.ModuleBuilder.InternalGetConstructorToken(ConstructorInfo con, Boolean usingRef)
   at System.Reflection.Emit.ILGenerator.GetMethodToken(MethodBase method, Type[] optionalParameterTypes)
   at System.Reflection.Emit.ILGenerator.Emit(OpCode opcode, ConstructorInfo con)
   at Program.Main() in c:\vsp\RefEmitBugRepro\Program.cs:line 23

The "no Microsoft bug filing" policy is still in effect, so I won't be filing a bug with Microsoft for this.

Workaround

For the scenario above there is a (painful) workaround. You can create your own ConstructorInfo subclass that represents the constructor you want to call, if you do that ILGenerator.Emit() will end up in a different code path to lookup the token and that code path does work.

I haven't tried it, but I assume this workaround also works for methods and fields.

I think that for ikvmc I won't be using this workaround, but instead I'll treat this as a good reason to finally start looking into using Mono.Cecil instead of Reflection.Emit.

Sunday, 10 August 2008 10:02:40 (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]
# Thursday, 07 August 2008
New Development Snapshot

Time for another snapshot.

Changes since previous development snapshot:

  • Removed support for building with GNU Classpath class library.
  • DatagramSocket: Implemented connected datagram sockets using .NET 2.0 API.
  • DatagramSocket: Used .NET 2.0 Socket.IOControl() API to disable WSAECONNRESET errors (when not connected).
  • DatagramSocket: Throw PortUnreachableException from receive() if we receive WSAECONNRESET while connected.
  • Various java.util.zip compatibility and bug fixes.
  • Fixed bytecode compiler not to generate unneeded GC.KeepAlive() in constructor for Exception types that don't have a finalize() method.
  • Fixed #2001802 contributed by Andy Malakov.
  • Fixed #2001799.
  • Fixed #2006953.
  • Fixed file I/O error handling incompatibilities.
  • Added ghost array tagging to be able to report the instantiated class (instead of the object[] which is allocated instead).
  • Fixed ldc <class> where <class> is a ghost array.
  • Fixed bug in instanceof <class> where <class> is a Serializable[].
  • Removed Mono workarounds that are no longer needed with Mono 2.0.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

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.

This version supports .NET 2.0 SP1 and Mono 2.0.

Binaries available here: ikvmbin-0.37.3141.zip

Thursday, 07 August 2008 08:13:00 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Wednesday, 09 July 2008
PDC

I'll be at the PDC again this year. Drop me a line if you're going and want to meet me there to chat (or to buy me a beer ;-)).

Meet me in Los Angeles -- PDC 2008

Wednesday, 09 July 2008 07:35:32 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Monday, 30 June 2008
Exception Performance Part 2

Last time we saw that CLR exception handling is significantly slower than HotSpot exception handling. This time we'll look at two very variations of the ExceptionPerf1 microbenchmark that significantly affect performance.

I've highlighted the changes.

Variation 1

public class ExceptionPerf2 {
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      try {
        Integer.parseInt("");
      }
      catch (NumberFormatException x) {
      }
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Variation 2

public class ExceptionPerf3 {
  static NumberFormatException exc;
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      try {
        Integer.parseInt(null);
      }
      catch (NumberFormatException x) {
        exc = x;
      }
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Results:

      HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
ExceptionPerf1 111 14743 3590 537
ExceptionPerf2 140 15735 10761 36309
ExceptionPerf3 112 14946 9728 24107


.NET/Mono results with IKVM 0.36

Why do these small changes have such a big perf impact?

Both these changes result in additional stack trace data being collected. IKVM has some optimizations that prevent gathering stack traces in very specific circumstances. Normally when you create a Java exception object, the Throwable constructor will call Throwable.fillInStackTrace(). However, since this is a very expensive operation, IKVM tries to remove this call when it is unnecessary (i.e. when it sees that you immediately throw the exception and the exception type doesn't override Throwable.fillInStackTrace()). Additionally, in Java an exception object will always have the complete stack trace, but a .NET exception only has the stack frames from the throw to the catch site. This means that at the catch site IKVM will collect the rest of the stack trace, unless the exception object isn't used (as in the ExceptionPerf1 microbenchmark).

The time it takes to collect a stack traces obviously depends on the call stack depth, so let's look at a microbenchmark to measure that effect:

class ExceptionPerf4 {
  public static void main(String[] args) {
    nest(Integer.parseInt(args[0]));
  }

  static void nest(int depth) {
    if (depth > 0) {
      nest(depth - 1);
    } else {
      run();
    }
  }

  static void run() {
    Exception x = new Exception();
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      x.fillInStackTrace();
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

Results:

Depth     HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
1 64 2930 4611 19377
10 85 3814 6787 34895
100 380 12500 27935  
1000 3543      

For the curious, the IKVM implementation of Throwable.fillInStackTrace() is essentially new System.Diagnostics.StackTrace(true);

Next time we'll wrap things up.

Monday, 30 June 2008 09:22:06 (W. Europe Daylight Time, UTC+02:00)  #    Comments [1]
# Wednesday, 25 June 2008
Exception Performance Part 1

One area where IKVM performance is much worse than HotSpot is in throwing and catching exceptions. This blog is the first of three that will look into why this is the case.

We start out with two microbenchmarks to highlight the differences.

Java

public class ExceptionPerf1 {
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
      try {
        Integer.parseInt(null);
      }
      catch (NumberFormatException x) {
      }
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

C#

using System;

class ExceptionPerf1 {
  public static void Main(string[] args) {
    int start = Environment.TickCount;
    for (int i = 0; i < 100000; i++) {
      try {
        throw new Exception();
      }
      catch (Exception) {
      }
    }
    int end = Environment.TickCount;
    Console.WriteLine(end - start);
  }
}

Results:

      HotSpot 1.6 x86     .NET 1.1 SP1     .NET 2.0 SP1 x86     Mono 1.9 x86
Java* 111 14743 3590 537
C#   11139 2605 187


*.NET/Mono results with IKVM 0.36

This shows that the situation on the CLR is pretty bad. If you care about exception throwing performance, please complain to Microsoft instead of to me. Although I expect that they'll tell you not to throw so many exceptions. ;-)

On the next episode we'll see that the above microbenchmark is actually a best case scenario for IKVM and we'll see how things can get much worse...

Wednesday, 25 June 2008 12:40:19 (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]
Useful Tool

Andy Malakov wrote an Ant task for ikvmc. It also contains a doclet that can generate an xml mapping file that contains all the parameter names that ikvmc can then attach to the .NET methods (ikvmc already does this for methods with debugging information, but that doesn't work for abstract methods).

Good stuff!

Wednesday, 25 June 2008 09:08:54 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Friday, 13 June 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.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

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, 13 June 2008 11:58:01 (W. Europe Daylight Time, UTC+02:00)  #    Comments [3]
# Wednesday, 04 June 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.

WARNING: THIS IS A DEVELOPMENT SNAPSHOT, NOT AN OFFICIAL RELEASE.

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, 04 June 2008 07:24:21 (W. Europe Daylight Time, UTC+02:00)  #    Comments [0]
# Monday, 02 June 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():

@ikvm.internal.HasCallerID
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.

Reflection

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.

Limitations

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, 02 June 2008 08:20:41 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]