Can one line of code in C# JIT compile into two different blocks of code in the same program? This sounds a little tricky but in fact is very easy and happens pretty often. Consider the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System; namespace Reordering { class Program { static void Main(string[] args) { for(int i = 0; i < 10; ++i) { Console.WriteLine("Iteration"); } Console.ReadLine(); } } } |
Now let’s see the loop in the machine code:
1 |
0:003> .loadby sos coreclr |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
0:003> !name2ee * Program Module: 00007fff93581000 Assembly: System.Private.CoreLib.dll -------------------------------------- Module: 00007fff3e914d48 Assembly: Reordering.dll -------------------------------------- Module: 00007fff3e915588 Assembly: System.Runtime.dll -------------------------------------- Module: 00007fff3e915ea8 Assembly: System.Console.dll -------------------------------------- Module: 00007fff3e9170e8 Assembly: System.Threading.dll -------------------------------------- Module: 00007fff3e917a68 Assembly: System.Runtime.Extensions.dll |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
0:003> !dumpmodule -mt 00007fff3e914d48 Name: C:\Users\user\Reordering\bin\Debug\netcoreapp2.0\Reordering.dll Attributes: PEFile SupportsUpdateableMethods Assembly: 000002ac372c1050 LoaderHeap: 0000000000000000 TypeDefToMethodTableMap: 00007fff3e9104b0 TypeRefToMethodTableMap: 00007fff3e9104c8 MethodDefToDescMap: 00007fff3e910538 FieldDefToDescMap: 00007fff3e910550 MemberRefToDescMap: 0000000000000000 FileReferencesMap: 00007fff3e910560 AssemblyReferencesMap: 00007fff3e910568 MetaData start address: 000002ac1d5b208c (1284 bytes) Types defined in this module MT TypeDef Name ------------------------------------------------------------------------------ 00007fff3e915d28 0x02000002 Reordering.Program Types referenced in this module MT TypeRef Name ------------------------------------------------------------------------------ 00007fff93edb2e0 0x0200000c System.Object 00007fff3e916f50 0x0200000d System.Console |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
0:003> !dumpmt -md 00007fff3e915d28 EEClass: 00007fff3ea61098 Module: 00007fff3e914d48 Name: Reordering.Program mdToken: 0000000002000002 File: C:\Users\user\Reordering\bin\Debug\netcoreapp2.0\Reordering.dll BaseSize: 0x18 ComponentSize: 0x0 Slots in VTable: 6 Number of IFaces in IFaceMap: 0 -------------------------------------- MethodDesc Table Entry MethodDesc JIT Name 00007fff93b100b0 00007fff9370b780 PreJIT System.Object.ToString() 00007fff93b100d0 00007fff9370b788 PreJIT System.Object.Equals(System.Object) 00007fff93b10120 00007fff9370b7b0 PreJIT System.Object.GetHashCode() 00007fff93b10130 00007fff9370b7d0 PreJIT System.Object.Finalize() 00007fff3ea70080 00007fff3e915d20 NONE Reordering.Program..ctor() 00007fff3ea70480 00007fff3e915d10 JIT Reordering.Program.Main(System.String[]) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
0:003> !U 00007fff3e915d10 Normal JIT generated code Reordering.Program.Main(System.String[]) Begin 00007fff3ea70480, size 80 C:\Users\user\Reordering\Program.cs @ 8: 00007fff`3ea70480 55 push rbp 00007fff`3ea70481 57 push rdi 00007fff`3ea70482 56 push rsi 00007fff`3ea70483 4883ec30 sub rsp,30h 00007fff`3ea70487 488d6c2440 lea rbp,[rsp+40h] 00007fff`3ea7048c 488bf1 mov rsi,rcx 00007fff`3ea7048f 488d7de0 lea rdi,[rbp-20h] 00007fff`3ea70493 b904000000 mov ecx,4 00007fff`3ea70498 33c0 xor eax,eax 00007fff`3ea7049a f3ab rep stos dword ptr [rdi] 00007fff`3ea7049c 488bce mov rcx,rsi 00007fff`3ea7049f 48894d10 mov qword ptr [rbp+10h],rcx 00007fff`3ea704a3 833d1e4deaff00 cmp dword ptr [00007fff`3e9151c8],0 00007fff`3ea704aa 7405 je 00007fff`3ea704b1 00007fff`3ea704ac e80f34c35f call coreclr!JIT_DbgIsJustMyCode (00007fff`9e6a38c0) 00007fff`3ea704b1 90 nop C:\Users\user\Reordering\Program.cs @ 9: 00007fff`3ea704b2 33c9 xor ecx,ecx 00007fff`3ea704b4 894dec mov dword ptr [rbp-14h],ecx 00007fff`3ea704b7 90 nop 00007fff`3ea704b8 eb1d jmp 00007fff`3ea704d7 C:\Users\user\Reordering\Program.cs @ 10: 00007fff`3ea704ba 90 nop C:\Users\user\Reordering\Program.cs @ 11: 00007fff`3ea704bb 48b96830f42eac020000 mov rcx,2AC2EF43068h 00007fff`3ea704c5 488b09 mov rcx,qword ptr [rcx] 00007fff`3ea704c8 e863feffff call 00007fff`3ea70330 00007fff`3ea704cd 90 nop C:\Users\user\Reordering\Program.cs @ 12: 00007fff`3ea704ce 90 nop C:\Users\user\Reordering\Program.cs @ 9: 00007fff`3ea704cf 8b45ec mov eax,dword ptr [rbp-14h] 00007fff`3ea704d2 ffc0 inc eax 00007fff`3ea704d4 8945ec mov dword ptr [rbp-14h],eax 00007fff`3ea704d7 8b4dec mov ecx,dword ptr [rbp-14h] 00007fff`3ea704da 83f90a cmp ecx,0Ah 00007fff`3ea704dd 0f9cc1 setl cl 00007fff`3ea704e0 0fb6c9 movzx ecx,cl 00007fff`3ea704e3 894de8 mov dword ptr [rbp-18h],ecx 00007fff`3ea704e6 8b4de8 mov ecx,dword ptr [rbp-18h] 00007fff`3ea704e9 85c9 test ecx,ecx 00007fff`3ea704eb 75cd jne 00007fff`3ea704ba C:\Users\user\Reordering\Program.cs @ 14: 00007fff`3ea704ed e8cefdffff call 00007fff`3ea702c0 (System.Console.ReadLine(), mdToken: 0000000006000075) 00007fff`3ea704f2 488945e0 mov qword ptr [rbp-20h],rax 00007fff`3ea704f6 90 nop C:\Users\user\Reordering\Program.cs @ 15: 00007fff`3ea704f7 90 nop 00007fff`3ea704f8 488d65f0 lea rsp,[rbp-10h] 00007fff`3ea704fc 5e pop rsi 00007fff`3ea704fd 5f pop rdi 00007fff`3ea704fe 5d pop rbp 00007fff`3ea704ff c3 ret |
You can see that C:\Users\user\Reordering\Program.cs @ 9:
appears twice. This is just a loop header which in fact has two separate parts.