Search code examples
c#pinvokecil

How is pinning represented in IL


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"?


Solution

  • .locals init (
        [0] int32& pinned
    )
    

    The use of pinned is responsible for the pinning. This article explains it: How does the 'fixed' keyword work? The article points to the following excerpt from Standard ECMA-335 Common Language Infrastructure (CLI):

    II.7.1.2 pinned

    The signature encoding for pinned shall appear only in signatures that describe local variables (§II.15.4.1.3). While a method with a pinned local variable is executing, the VES shall not relocate the object to which the local refers. That is, if the implementation of the CLI uses a garbage collector that moves objects, the collector shall not move objects that are referenced by an active pinned local variable.

    [Rationale: If unmanaged pointers are used to dereference managed objects, these objects shall be pinned. This happens, for example, when a managed object is passed to a method designed to operate with unmanaged data. end rationale]

    VES = Virtual Execution System, CLI = Common Language Infrastructure