I've always heard that the JIT compiler compiles 'Just In Time', but by playing with windbg.exe, I was actually able to see that it indeed only compiles the methods that are being called, down to machine code.
Let me show you an example. Here's a super simple piece of code for a console app:
Here's the Add() method:
.method public hidebysig static int32 Add(int32 a, int32 b) cil managed { // Code size 9 (0x9) .maxstack 2 .locals init (int32 V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldarg.1 IL_0003: add IL_0004: stloc.0 IL_0005: br.s IL_0007 IL_0007: ldloc.0 IL_0008: ret } // end of method application::AddOn line IL_0001 and IL_0002, the two method parameters are placed on a 'stack' like structure, then the 'add' method is called on it, the result is stored, loaded and returned.
This, by the way, reveils that I compiled without any optimizers. Because with the -o+ flag, the code is shorter:
.method public hidebysig static int32 Add(int32 a, int32 b) cil managed { // Code size 4 (0x4) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: add IL_0003: ret } // end of method application::AddNo more 'nop' operators, and no more overhead for storing and loading. These 'nop' and store/load operations do have a purpose: they allow the developer to place a breakpoint on that line and inspect the variables at that point.
Now, if run app.exe, open windbg.exe and attach to the process:
Then we need to run a couple of windbg commands.
!loadby sos clr !DumpDomain !DumpDomain !DumpModule -mt 00007ffcaaa040c0 !DumptMT -md 00007ffcaaa059a8
This commands should result in something like the UI below:
So the first line, loads the sons of strike plugin (sos), which contains the commands to inspect the CLR. Commands start with an exclamation mark, by the way.
Now we need to first dump the domain. I called the method twice, since there's a bug in windbg.exe (ironic) apparently. This will show us the application module, and using DumptMT, we get the method table information. Not only does this table show us the methods, it also shows which ones are JIT compiled and which aren't.
As you can see - when we hit the first Console.Readline(), the Add() method is not yet JIT compiled:
However, if we continue execution (note that you also have to continue in windbg), and we use the Add() method to calculate a result, you can see that the method is JIT compiled afterwards.
Et voila! You can see that the JIT compiler only JITs the method when it's going to run this.
If you want to know why I'm diving into these topics and where I learnt how to do it? Read this. I'm just doing what I saw Bart de Smet do on PluralSight
No comments:
Post a Comment