12

Per my understanding, both instance methods and static methods are treated same by CLR compiler and the IL code is JITted whenever the method is called first time. Today I had a discussion with my colleague and he told me that the static methods are not treated the same way as instance methods. i.e. Static methods are JITted as soon as the assembly is loaded into application domain whereas instance methods are JITted as they are called for the first time.

I am actually confused and do not see a reason as to why the static methods should be eagerly compiled by CLR? I understand about static constructors or finalizer methods of the Critical Finalizer Objects or when constrained execution regions are used. But if some class has a combination of static and instance methods, I am really not sure why all static methods would be JITted as soon as the assembly containing the class would be loaded into memory?

Please help me in understanding this behavior.

jags
  • 2,022
  • 26
  • 34
  • I would think they are jitted as soon as the _type_ is first loaded. This tends to be when the assembly loads. – Oded Oct 03 '12 at 16:16
  • Does your colleague have a reference for this? Maybe it also explains the behaviour. Otherwise you're asking someone to explain why something that might not even be going on is happening. – millimoose Oct 03 '12 at 16:19

2 Answers2

11

Looking at when the methods get JIT compiled using WinDbg/SOS shows that static methods are not compiled prior to calling them.

Consider the following class:

class SomeType
{
    [MethodImpl(MethodImplOptions.NoInlining)]
    public void InstanceMethod()
    {
        Console.WriteLine("instance");
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static void TypeMethod()
    {
        Console.WriteLine("type");
    }
}

I use the NoInlining option to prevent the compiler from inlining these methods in a release build.

If I run a small app like below and attach the WinDbg I can observe when the methods get JIT compiled.

var st = new SomeType();

Console.WriteLine("attach");
Console.ReadLine();

Console.WriteLine("calling methods");
st.InstanceMethod();
SomeType.TypeMethod();

Console.ReadLine();

At the point of attach the method table for SomeType looks like this:

0:004> !dumpmt -md 0041387c
EEClass:         004114d4
Module:          00412e94
Name:            ConsoleApplication2.SomeType
mdToken:         02000007
File:                c:\temp\ConsoleApplication1\ConsoleApplication1\bin\Release\ConsoleApplication1.exe
BaseSize:        0xc
ComponentSize:   0x0
Slots in VTable: 7
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
   Entry MethodDe    JIT Name
6d374960 6d076728 PreJIT System.Object.ToString()
6d368790 6d076730 PreJIT System.Object.Equals(System.Object)
6d368360 6d076750 PreJIT System.Object.GetHashCode()
6d3616f0 6d076764 PreJIT System.Object.Finalize()
0041c035 00413874   NONE ConsoleApplication2.SomeType..ctor()
0041c02d 0041385c   NONE ConsoleApplication2.SomeType.InstanceMethod()
0041c031 00413868   NONE ConsoleApplication2.SomeType.TypeMethod()

After the methods have been explicitly invoked it looks like this:

0:007> !dumpmt -md 0041387c
EEClass:         004114d4
Module:          00412e94
Name:            ConsoleApplication2.SomeType
mdToken:         02000007
File:            c:\temp\ConsoleApplication1\ConsoleApplication1\bin\Release\ConsoleApplication1.exe
BaseSize:        0xc
ComponentSize:   0x0
Slots in VTable: 7
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
   Entry MethodDe    JIT Name
6d374960 6d076728 PreJIT System.Object.ToString()
6d368790 6d076730 PreJIT System.Object.Equals(System.Object)
6d368360 6d076750 PreJIT System.Object.GetHashCode()
6d3616f0 6d076764 PreJIT System.Object.Finalize()
0041c035 00413874   NONE ConsoleApplication2.SomeType..ctor()
004700e0 0041385c    JIT ConsoleApplication2.SomeType.InstanceMethod()
00470110 00413868    JIT ConsoleApplication2.SomeType.TypeMethod()

I.e. the methods are not JIT compiled until they are actually invoked.

(For the record this was done on .NET 4.5)

Brian Rasmussen
  • 114,645
  • 34
  • 221
  • 317
  • I think this explains pretty well how and when the methods are getting JITted. I will share link to this Q&A with my colleague. Thank you very much for your help. – jags Oct 03 '12 at 16:38
  • Nice exploration answer. Consider adding CLR/.NET versions used, though -- just in case this changes in the future (or has not always been the same). –  Oct 03 '12 at 16:59
1

As far as I know static methods are not threated differently from instance methods, maybe your colleague is talking about static constructors that actually are invoked as soon the type is referred in the calling assembly. and thus jitted.

Update For 4.0 ( thanks @JulienLebosquain for pointing )

.NET 4.0 uses a so called Lazy Type Initialization, that basically change the behavior and statics constructor are called just when as soon a static field is acceded the first time.

Felice Pollano
  • 32,832
  • 9
  • 75
  • 115
  • 3
    +1 for "not treated differently"; about static constructors, this is not true anymore, please see http://msmvps.com/blogs/jon_skeet/archive/2010/01/26/type-initialization-changes-in-net-4-0.aspx – Julien Lebosquain Oct 03 '12 at 16:22