The way JIT works in .NET is that before a method has been jitted the method table entry points to a small stub that will JIT the method when invoked. After that the method table is updated to reference the location of the JIT compiled code.
Given that only methods that are invoked are JIT compiled there's no JIT overhead for methods that are not invoked.
The JIT compiler will compile an entire method when needed. If it is a release build code may be optimized away but otherwise the method is compiled in full.
You can inspect the method tables using WinDbg/SOS. Consider the following:
class SomeType
{
public void Called()
{
Console.WriteLine("called");
}
public void NotCalled()
{
Console.WriteLine("not called");
}
}
Assume that we create an instance of SomeType
, call Called
and then inspect the method table for SomeType
. On x86 you'll see something like this:
0:000> !dumpmt -md 00a7381c
EEClass: 00a712d0
Module: 00a72e94
Name: ConsoleApplication1.SomeType
mdToken: 02000002
File: c:\temp\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
BaseSize: 0xc
ComponentSize: 0x0
Slots in VTable: 7
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
Entry MethodDe JIT Name
72ca4960 729a6728 PreJIT System.Object.ToString()
72c98790 729a6730 PreJIT System.Object.Equals(System.Object)
72c98360 729a6750 PreJIT System.Object.GetHashCode()
72c916f0 729a6764 PreJIT System.Object.Finalize()
00df00d8 00a73814 JIT ConsoleApplication1.SomeType..ctor()
00df0110 00a737fc JIT ConsoleApplication1.SomeType.Called()
00a7c031 00a73808 NONE ConsoleApplication1.SomeType.NotCalled()
Notice that Called
is JIT compiled, but as we have not invoked NotCalled
yet, it has not been JIT compiled.
Also, notice that the methods from object
have all been PreJIT compiled.
Keep in mind that in release build short methods may be inlined in which case they are not called as methods, but simply included as part of the generated code for the call site.