Having had a very brief look at the compilation of generic classes, I thought it would be good to see how generic methods are handled by the CLR. The following example contains a TestMethod specialized on a generic parameter.
public S(T x)
Console.WriteLine("start" + x);
void TestMethod<T>(T x)
S<T> a = new S<T>(x);
S<T> b = new S<T>(x);
static void Main()
object foo = new object();
Program z = new Program();
If we look at the first call to TestMethod in Main we see it has the code
00000069 push 979938h
0000006e mov edx,dword ptr [ebp-3Ch]
00000071 mov ecx,dword ptr [ebp-40h]
00000074 cmp dword ptr [ecx],ecx
00000076 call FD2BB058
The surprising thing is that an extra argument, 979938h, is being passed into the method. Why do we need the extra method parameters? Well, the body of TestMethod creates a new instance, and in order to do this we need a type handle for the newly created type. The purpose of this extra argument is to cache the handles for new instances.
At the point of instantiation in the TestMethod, we can see how the this table is used.
S<T> a = new S<T>(x);
00000043 mov eax,dword ptr [ebp+8]
00000046 mov eax,dword ptr [eax+0Ch]
00000049 add eax,4
0000004c mov dword ptr [ebp-50h],eax
0000004f mov eax,dword ptr [ebp-50h]
00000052 mov eax,dword ptr [eax]
00000054 mov dword ptr [ebp-54h],eax
00000057 cmp dword ptr [ebp-54h],0
0000005b jne 00000073
0000005d push 0
0000005f push dword ptr [ebp-50h]
00000062 push 0
00000064 mov ecx,dword ptr [ebp+8]
00000067 mov edx,1B000001h
0000006c call 7689C368
00000071 jmp 00000076
00000073 mov eax,dword ptr [ebp-54h]
00000076 mov ecx,eax
00000078 call FD2A09CC
0000007d mov dword ptr [ebp-4Ch],eax
00000080 mov edx,dword ptr [ebp-40h]
00000083 mov ecx,dword ptr [ebp-4Ch]
00000086 call FD2BAFA0
0000008b mov eax,dword ptr [ebp-4Ch]
0000008e mov dword ptr [ebp-44h],eax
After the load at line 43, we have eax containing
0x00979938 43000001 00050004 009798f8 00979914
and the 0xC offset points to the table. Here 7933061c is the handle for the object type.
0x00979914 7933061c 00000000 00000000 00000000
By the time we get to 76, the table has been filled with another type handle by the call at 6c.
0x00979914 7933061c 00979ad8 00000000 00000000
By the time we get to 7D, we have constructed the new object on the heap, using the handle from the table as the header
0x01394D14 00979ad8 00000000
And we are now ready to call the constructor at 86.
Next time we go through the code, we lift the type handle from the table without the need to call any code to fill it. Zero is used to represent an unfilled entry with the conditional code at 53 using any previously calculated value.