
February 18th | 2010
Quirks in .NET Part -1 Call vs Callvirt
There are a lot of cool yet strange things in the .NET Framework. A lot of them make you go, “Huh. I didn’t know that.” Let’s take a look at a few of them.
call vs. callvirt
This one is especially interesting to me. In the Microsoft IL specification there are two instructions to call a method, put simply—call and callvirt. call will simply call a method, while callvirt is used to a late-bound method call, meaning that the method which is going to be called is chosen at runtime and not compile time as the simple call would. This is needed for virtual methods when a VTable lookup is required.
Interestingly, all calls to instance classes are compiled as callvirt, even if the method being called is not virtual (thus at compile time we know exactly which method will be called.) I thought it was a bug at first, but really it was a fix for another bug. Consider this code:
class Program { static void Main() { HelloWorld instance = null; instance.SayHello(); } } public class HelloWorld { public void SayHello() { System.Console.WriteLine("Hello World!"); } }
Looks like it would immediately blow up, right? We should get a NullReferenceException. And in fact, if we compile this with the C# compiler, we do! Let’s look at the IL for the Main() method.
L_0000: nop
L_0001: ldnull
L_0002: stloc.0
L_0003: ldloc.0
L_0004: callvirt instance void HelloWorld::SayHello()
L_0009: nop
L_000a: ret
Sure enough, it uses a callvirt, but here’s the interesting part: If the compiler used a call, rather than callvirt, this code would actually run. In fact, we can do that, too. Let’s change the callvirt to a call, recompile the IL using ilasm, and see what happens.

Yeah, it appears that our program, which should be causing a NullReferenceException, isn’t. This is why the .NET compilers don’t use call, even though using call is a perfectly acceptable in this case. For that matter, the only time a regular call will be used is when you call a method on a struct, or a static method on a class.
If you use the Reflection.Emit namespace frequently, or are looking into it, this is something to watch out for.
In Quirks in .Net Part 2. we’ll look at Marshalling Booleans.
[...] Quirks in .NET – Part 1, we talked about the quirky call vs. callvirt [...]
“callvirt is used to a late-bound method call”
Not quite – there’s a huge difference between a virtual method call and a late-bound method call.
Richard,
Speaking in general terminology “Late Bound” can mean a lot of things. Late bound resolution can mean resolving which method is invoked as part of a VTable lookup. Take for example the definition of “Dynamic Binding”
http://en.wikipedia.org/wiki/Dynamic_binding_(computer_science)