15 Sep 2010

Some time ago, I wrote how the call instruction could actually call an instance method on a null reference, and that inside this instance method, the this keyword would reference to null.

I find that very interesting, so I kept on disassembling some sample code to see what’s the generated IL and try to grasp some of the compiler’s logic.

Here is some simple code used to see what’s the IL generated by the C# compiler:

class Hello1
{
    internal String GetHello()
    {
        return "Hello1";
    }
}

sealed class Hello2
{
    internal String GetHello()
    {
        return "Hello2";
    }
}

static void Main(string[] args)
{
    var h1 = new Hello1();
    Console.WriteLine(h1.GetHello());

    var h2 = new Hello2();
    Console.WriteLine(h2.GetHello());

    Console.WriteLine(new Hello1().GetHello());

    Console.WriteLine(new Hello2().GetHello());

    Console.ReadLine();
}

In the first two calls, we use a local variable that we call the GetHello method on, and in the two last calls we instantiate the object and call the GetHello method on the reference returned by the constructor, reference that we don’t keep.

Here’s the IL generated for the Main method:

CallCallvirtIL

We can see that in the first two call, the callvirt instruction is emitted by the compiler. As the call happens on a variable, the runtime type of the object could be different from the compile type, meaning that using the callvirt instruction makes sense (the compiler is not “smart” enough to detect that the compile time and the runtime types are the same).

In the two subsequent calls, however, as the method call is done on the reference returned by the constructor, the instruction emitted is call, which is slightly more performant than callvirt.

For more information on call and callvirt instructions, see ECMA 335 12.4.1.2.



blog comments powered by Disqus