I was wondering how field pinning is expressed in .Net's IL language, so I took a look at the example code:
struct S
{
public fixed int buf[8];
}
S s = default(S);
public void MyMethod() {
fixed (int* ptr = s.buf){
*ptr = 2;
}
}
This generates the IL:
.method private hidebysig instance void MyMethod () cil managed
{
// Method begins at RVA 0x2050
// Code size 25 (0x19)
.maxstack 2
.locals init (
[0] int32& pinned
)
IL_0000: ldarg.0 // Load argument 0 onto the stack
IL_0001: ldflda valuetype C/S C::s // Push the address of field of object obj on the stack
IL_0006: ldflda valuetype C/S/'<buf>e__FixedBuffer' C/S::buf // Push the address of field of object obj on the stack
IL_000b: ldflda int32 C/S/'<buf>e__FixedBuffer'::FixedElementField // Push the address of field of object obj on the stack
IL_0010: stloc.0 // Pop a value from stack into local variable 0
IL_0011: ldloc.0 // Load local variable 0 onto stack
IL_0012: conv.i // Convert to native int, pushing native int on stack
IL_0013: ldc.i4.2 // Push 2 onto the stack as int32
IL_0014: stind.i4 // Store value of type int32 into memory at address
IL_0015: ldc.i4.0 // Push 0 onto the stack as int32
IL_0016: conv.u // Convert to native unsigned int, pushing native int on stack
IL_0017: stloc.0 // Pop a value from stack into local variable 0
IL_0018: ret // Return from method, possibly with a value
} // end of method C::MyMethod
I'm not seeing anything here, that would explicitly tell the GC to pin the array, which instruction is actually responsible for pinning? Also, are there other basic operations which involve pinning "under the hood"?