A friend asked questions about tppeof, GetType (), is, and as. In the experiment, he used generic writing as an example. A problem was found during JIT disassembly. CLR has some special processing on generic parameters. I did not find an article about generic parameter storage on the Internet, so I did some experiments. With some simple understanding, I recorded this article and hope that the experts in this article can give a comprehensive explanation.
I didn't think about how CLR processes generic parameters when I used generics. Today I checked <expert. NET 2.0 il explorer> it explains a data structure called genericparam metadata table, but it does not solve my doubts. Let's take a look at the code section:
Class C <t, u, v> where T: Class
{
Public void test_class (V)
{
Debugger. Break ();
T = V as t;
}
Public void test_method <X, Y> (x, y)
{
Debugger. Break ();
Type type1 = typeof (X );
Type type2 = typeof (y );
}
}
Class Test
{
Static void main ()
{
C <type, String, Object> C = new C <type, String, Object> ();
String S = "OK ";
Object o = s;
C. test_class (O );
C. test_method (S, O );
}
}
We first execute the test_class method. When the test_class method is entered, the main disassembly and comments are as follows:
T = V as t;
2017003e mov eax, dword ptr [ebp-3Ch] // 1. Get this pointer 01e52b30
00000041 mov eax, dword ptr [eax] // 2. Obtain the method table address of C <t, u, v> 002a3918
00000043 mov eax, dword ptr [eax + 20 h] // 3. Obtain the address of the storage generic parameter 002a3954
00000046 mov eax, dword ptr [eax] // 4. Save the parameter type address 002a3958
00000048 mov eax, dword ptr [eax] // 5. Obtain the True Type of the t parameter. The method table address is 6c18172c.
2017004a mov dword ptr [ebp-48h], eax
2017004d test dword ptr [ebp-48h], 1
00000054 JNE 0000005b
00000056 mov ECx, dword ptr [ebp-48h] // pass the T method table address to ECx prepare call as Method
00000059 JMP 00000061
2017005b mov eax, dword ptr [ebp-48h]
2017005e mov ECx, dword ptr [eax-1]
00000061 mov edX, dword ptr [ebp-40h] // get the parameter o
00000064 call 6c0598f3 // call the as Method
The first two sentences in the Assembly are well understood. After obtaining the this pointer, find the address of the method table based on the 4-byte header of the managed object. The third sentence is to get the type generic parameter information at the 20 h offset of the method table, however, it is worth noting that there is an article "in-depth exploration" on msdn. NET framework, there is an illustration of ethodtable layout in "How to Create a runtime object in CLR", but that figure seems to be. and. the layout method table of net2.0 is different. I have determined the meanings of some bytes through the test (I hope you can give me a complete explanation) as follows:
00 = flags
04 = instance size
08 = ??
0C = ??
10 = ??
14 = module ADDR
18 = mehtodd table end ADDR
1c = eeclass ADDR (the meaning here is unknown for generic classes)
20 = genericparam info ADDR
24 = Gobal interface map table ADDR (?)
28 = tostring ()
2c = equals ()
30 = gethashcode ()
34 = finalize ()
...... Virtual method entry address in the class
...... Endpoint address of constructor for non-generic classes
...... Interface table ADDR (if the interface is inherited)
...... A four-byte record does not know whether there are other meanings of the number of generic parameters (if it is a generic class)
...... Interface table
...... Genericparam Info (for generic classes)
Next let's take a look at the content of the generic parameter information:
0x002a3954 002a3958 6c18172c (type) 6c1808ec (string) 6c180508 (object) 00000000 00000000
It is strange here that the first 4 bytes is used to jump to real data. Let me verify it. (if there are few object methods, use 6c180508 for verification ):
! Dumpmt-MD 6c180508
Eeclass: 6bf13ef0
Module: 6bf11000
Name: system. Object
Mdtoken: 02000002 (C:/Windows/ASSEMBLY/gac_32/mscorlib/2.0.0.0 _ b77a5c561934e089/mscorlib. dll)
Basesize: 0xc
Componentsize: 0x0
Number of ifaces in ifacemap: 0
Slots in vtable: 14
--------------------------------------
Methoddesc table
Entry methoddesc JIT name
6c0d6a70 6bf54934 prejit system. Object. tostring ()
6c0d6a90 6bf5493c prejit system. Object. Equals (system. Object)
6c0d6b00 6bf5496c prejit system. Object. gethashcode ()
6c1472f0 6bf54990 prejit system. Object. Finalize ()
6c1336f0 6bf5492c prejit system. Object .. ctor ()
6c091d94 6bf54984 none system. Object. GetType ()
6c091da4 6bf54998 none system. Object. memberwiseclone ()
6c09742c 6bf549a4 prejit system. Object. fieldsetter (system. String, system. string,
System. Object)
6c09743c 6bf549b0 prejit system. Object. fieldgetter (system. String, system. string,
System. Object byref)
6c09744c 6bf549bc prejit system. Object. getfieldinfo (system. String, system. String)
6c091d80 6bf54944 none system. Object. internalequals (system. Object, system. Object)
6c0d6ab0 6bf54954 prejit system. Object. Equals (system. Object, system. Object)
6c0d6ae0 6bf54960 prejit system. Object. referenceequals (system. Object, system. Object)
6c091d88 6bf54974 none system. Object. internalgethashcode (system. Object)
After the parameters of the generic class are completed, let's talk about the parameters of the generic method. Let's execute the test_method method. The main disassembly and comments after entering the test_method method are as follows:
X tmp = y as X;
00000044 mov eax, dword ptr [EBP + 8] // obtain the address of the genericparam table parameter.
00000047 mov eax, dword ptr [eax + 0ch] // The information address of the generic parameter at the offset 0ch
2017004a mov eax, dword ptr [eax] // obtain the method table address of X, where X is string
The above code is very easy to understand. I will not post memory data any more. Through the above analysis, we can draw a conclusion: the generic method is associated with the generic parameter information through the parameter pressure stack, the generic parameter information of the class is directly stored in methodtable.