The short answer is that in the method itself, the value of struct always accessible through a pointer. This means that this method does not work, as if the struct was passed as a regular parameter, it is more like a ref parameter. It also means that the method does not know if it works by box value or not.
Long answer:
Firstly, if I compile your code, then sM(); does not generate any code. The JIT compiler is smart enough to embed a method, and nesting an empty method does not result in missing code. So, I did to apply [MethodImpl(MethodImplOptions.NoInlining)] on SM to avoid this.
Now, here is the native code that your method generates (skipping the proog and epilog function):
// initialize s in register AX xor eax,eax // move s from register AX to stack (SP+28h) mov qword ptr [rsp+28h],rax // load pointer to MethodTable for S to register CX mov rcx,7FFDB00C5B08h // allocate memory for i on heap call JIT_TrialAllocSFastMP_InlineGetThread (07FFE0F824C10h) // copy contents of s from stack to register C movsx rcx,byte ptr [rsp+28h] // copy from register CX to heap mov byte ptr [rax+8],cl // copy pointer to i from register AX to register SI mov rsi,rax // load address to c on stack to register CX lea rcx,[rsp+28h] // call S::M call 00007FFDB01D00C8 // copy pointer to i from register SI to register CX mov rcx,rsi // move address of stub for I::M to register 11 mov r11,7FFDB00D0020h // ??? cmp dword ptr [rcx],ecx // call stub for I::M call qword ptr [r11]
In both cases, the call ends with a call to the same code (which is just one ret statement). The first time, the CX register indicates the allocation of the stack s (SP + 28h in the above code), the second time for the allocated heap i (AX + 8 immediately after the heap allocation function is called).
svick
source share