When you put a simple class.
public sealed class C {
public static void M() {
}
}
into https://sharplab.io/
it translates to (with annotations from me): (source)
C.M()
L0000: push ebp /////////////////////
L0001: mov ebp, esp // function frame initialization
L0003: push edi /////////////////////
L0004: cmp dword ptr [0x281dc19c], 0 // if (0 == ???)
L000b: je short L0012 // then: jump to actual method body
L000d: call 0x727a8790 // else: call ??? what ???
L0012: nop // the actual method body
L0013: nop // the actual method body
L0014: pop edi /////////////////////
L0015: pop ebp // function frame teardown/exit
L0016: ret /////////////////////
What's the purpose of L0004 to L000d?
L0004: cmp dword ptr [0x281dc19c], 0 // if (0 == ???)
L000b: je short L0012 // then: jump to actual method body
L000d: call 0x727a8790 // else: call ??? what ??
What is the called function?
Is it terminating the process?
Why does C# JIT put this in every method?
I thought it might be something with inheritance, but i sealed the class and made the method static to eliminate that option.
Is it some kind of sanity check? like a check for:
- method overload
- corrupt code
- stack overflow
- segfault
The IL does not give a clue:
.method public hidebysig static
void M () cil managed
{
// Method begins at RVA 0x2069
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
}
Update:
Thx @Dai, setting it to release removes the code. To be sure that the complete removal was not cased by the empty method body i added a simple statement
public static void M() {
System.Console.WriteLine(7);
}
jit in release mode results in (source):
C.M()
L0000: mov ecx, 7
L0005: call dword ptr [0x10a25768]
L000b: ret
like @Dai said without the mentioned cmp-je
je's branch tocall 0x7...isCORINFO_HELP_DBG_IS_JUST_MY_CODE.