# Monday, 01 December 2003
« More On Finalization | Main | ThinkPad »
Finalization and the JIT

One of the subtle differences between the JVM bytecode instruction set and the CLR instructin set is that the JVM splits object instantiation in two steps: 1) allocation and 2) initialization. The CLR combines both steps in a single instruction.

This usually isn't a big difference. The CLR way makes the verifier a little easier because it doesn't need to keep track of uninitialized references. However, in the face of finalization, the difference is actually detectable.

Here is a Java example:

class foo {
  static int throwException() {
    throw new Error();
  }

  foo(int i) {
  }

  public static void main(String[] args) {
    try {
      new foo(throwException());
    } catch(Error x) {
      System.gc();
      System.runFinalization();
      throw x;
    }
  }

  protected void finalize() {
    System.out.println("finalize");
  }
}

When this class is run, it prints "finalizable" and a stack trace. Looking at the bytecode of the main method, it is obvious why:

   0  new foo
   3  invokestatic <Method foo throwException()I>
   6  invokespecial <Method foo <init>(I)V>
   9  goto 21
  12  astore_1
  13  invokestatic <Method java/lang/System gc()V>
  16  invokestatic <Method java/lang/System runFinalization()V>
  19  aload_1
  20  athrow
  21  return

The first instruction is a new that allocates the foo instance. Even if the following call to throwException throws an exception, the foo instance already exists and will be finalized.

Here is the (approximately) corresponding C# code:

class Foo {
  Foo(int i) {
  }

  ~Foo() {
    System.Console.WriteLine("Finalize");
  }

  static int ThrowException() {
    throw new System.Exception();
  }

  static void Main() {
    try {
      new Foo(ThrowException());
    } catch(System.Exception x) {
      System.Console.WriteLine(x);
    }
  }
}

When this code is run, the output should be just the stack trace, but it turns out that it will also print "Finalize" (on .NET, not on Mono). This is a bug in the .NET JIT. It moves the object allocation up to be able to more efficiently construct the call stack for the constructor invocation, but in doing so it subtly changes the semantics. When the above code is compiled with debugging enabled, it works as expected.

Monday, 01 December 2003 21:17:03 (W. Europe Standard Time, UTC+01:00)  #    Comments [1] Tracked by:
"looking for a diet pill that works" (looking for a diet pill that works) [Trackback]
"Free Online Poker" (Free Online Poker) [Trackback]