Search code examples
c#ciltype-safety

Why is the C# compiler emitting a callvirt instruction for a GetType() method call?


I am curious to know why this is happening. Please read the code example below and the corresponding IL that was emitted in comments below each section:

using System;

class Program
{
    static void Main()
    {
        Object o = new Object();
        o.GetType();

        // L_0001: newobj instance void [mscorlib]System.Object::.ctor()
        // L_0006: stloc.0 
        // L_0007: ldloc.0 
        // L_0008: callvirt instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()

        new Object().GetType();

        // L_000e: newobj instance void [mscorlib]System.Object::.ctor()
        // L_0013: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
    }
}

Why did the compiler emit a callvirt for the first section but a call for the second section? Is there any reason that the compiler would ever emit a callvirt instruction for a non-virtual method? And if there are cases in which the compiler will emit a callvirt for a non-virtual method does this create problems for type-safety?


Solution

  • Just playing safe.

    Technically C# compiler doesn't always use callvirt

    For static methods & methods defined on value types, it uses call. The majority is provided via the callvirt IL instruction.

    The difference that swung the vote between the two is the fact that call assumes the "object being used to make the call" is not null. callvirt on the other hand checks for not null and throws a NullReferenceException if required.

    • For static methods, the object is a type object and cannot be null. Ditto for value types. Hence call is used for them - better performance.
    • For the others, the language designers decided to go with callvirt so the JIT compiler verifies that the object being used to make the call is not null. Even for non-virtual instance methods.. they valued safety over performance.

    See Also: Jeff Richter does a better job at this - in his 'Designing Types' chapter in CLR via C# 2nd Ed