CLR/Fastcall: How are large value types passed int

2019-02-18 13:10发布

问题:

Just out of curiosity: value types are generally copied, and the JIT compiler seems to use Microsoft's Fastcall calling convention when calling a method. This puts the first few arguments in registers, for fast access. But how are large value types (i.e. bigger than the size of a register or the width of the stack) passed to the called function?


This book excerpt states that:

The CLR's jitted code uses the fastcall Windows calling convention. This permits the caller to supply the first two arguments (including this in the case of instance methods) in the machine's ECX and EDX registers.

回答1:

It is __clrcall, indeed similar to __fastcall. Two registers are used by the x86 jitter (ecx, edx). Four registers by the x64 jitter (ecx, edx, r8, r9), same as the native x64 calling convention. Large value types like Decimal and large structs are passed by reserving space on the caller's stack, copying the value into it and passing a pointer to this copy. The callee copies it again to its own stack frame.

This is expensive which is why Microsoft recommends that a struct should not be larger than 16 bytes. Intentionally passing a struct by ref to avoid the copy is a workaround, commonly done in C and C++ as well. At the cost of an extra pointer dereference.