Thursday, November 24, 2011

callvirt

The first release of the .NET Framework was about 10 years ago (13 February 2002). How well do you know the framework? Take a look at the following class:

(click to enlarge)

Simple. A static field, a static method and an instance method. Both methods return the static field. Now, imagine that we have the following in main:

(click to enlarge)

As you probably noticed, there's an instance call using a null reference. So, the first idea that pops up in your head when someone asks "Will this code throw an exception?" is "Yes, it will! A NullReference exception to be exact". Well, if we compile it and run it using Visual Studio, it will actually throw an exception:

(click to enlarge)

So, what's the catch? Well, the right answer to the question above is "It depends". If we look at the generated IL, we can see that the compiler emmited the "callvirt" instruction for the instance method:

(click to enlarge)

That's the normal behaviour. The C# compiler emmits a callvirt instruction on every instance method. It does so in order to check for an object reference at runtime (TypeSafety). But, if we write the exact same code in IL and replace the callvirt by a call instruction and compile it using ILASM:

(click to enlarge)

It works:

(click to enlarge)

This is because the instance method is only using a static field and, at that point of the code, the type constructor already did it's work and the method works fine. If you look at both the assemblies ("C# Compiled" and "ILASM compiled") in .NET Reflector, both generate the following C# code (Main):

(click to enlarge)

If you ever get the change to read this, thanks MC.