1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | // |
5 | // typekey.h |
6 | // |
7 | |
8 | // --------------------------------------------------------------------------- |
9 | // |
10 | // Support for type lookups based on components of the type (as opposed to string) |
11 | // Used in |
12 | // * Table of constructed types (Module::m_pAvailableParamTypes) |
13 | // * Types currently being loaded (ClassLoader::m_pUnresolvedClassHash) |
14 | // |
15 | // Type handles are in one-to-one correspondence with TypeKeys |
16 | // In particular, note that tokens in the key are resolved TypeDefs |
17 | // |
18 | // --------------------------------------------------------------------------- |
19 | |
20 | |
21 | #ifndef _H_TYPEKEY |
22 | #define _H_TYPEKEY |
23 | |
24 | class TypeKey |
25 | { |
26 | // ELEMENT_TYPE_CLASS for ordinary classes and generic instantiations (including value types) |
27 | // ELEMENT_TYPE_ARRAY and ELEMENT_TYPE_SZARRAY for array types |
28 | // ELEMENT_TYPE_PTR and ELEMENT_TYPE_BYREF for pointer types |
29 | // ELEMENT_TYPE_FNPTR for function pointer types |
30 | // ELEMENT_TYPE_VALUETYPE for native value types (used in IL stubs) |
31 | CorElementType m_kind; |
32 | |
33 | union |
34 | { |
35 | // m_kind = CLASS |
36 | struct |
37 | { |
38 | Module * m_pModule; |
39 | mdToken m_typeDef; |
40 | DWORD m_numGenericArgs; // 0 for non-generic types |
41 | FixupPointer<TypeHandle> * m_pGenericArgs; // NULL for non-generic types |
42 | // Note that for DAC builds, m_pGenericArgs is a host allocated buffer (eg. by in SigPointer::GetTypeHandleThrowing), |
43 | // not a copy of an object marshalled by DAC. |
44 | } asClass; |
45 | |
46 | // m_kind = ARRAY, SZARRAY, PTR or BYREF |
47 | struct |
48 | { |
49 | TADDR m_paramType; // The element type (actually a TypeHandle, but we don't want its constructor |
50 | // run on a C++ union) |
51 | DWORD m_rank; // Non-zero for ARRAY, 1 for SZARRAY, 0 for PTR or BYREF |
52 | BOOL m_isTemplateMethodTable; // TRUE if this key indexes the template method table for an array, rather than a type-desc |
53 | } asParamType; |
54 | |
55 | // m_kind = FNPTR |
56 | struct |
57 | { |
58 | BYTE m_callConv; |
59 | DWORD m_numArgs; |
60 | TypeHandle* m_pRetAndArgTypes; |
61 | } asFnPtr; |
62 | } u; |
63 | |
64 | public: |
65 | |
66 | // Constructor for BYREF/PTR/ARRAY/SZARRAY types |
67 | TypeKey(CorElementType etype, TypeHandle paramType, BOOL isTemplateMethodTable = FALSE, DWORD rank = 0) |
68 | { |
69 | WRAPPER_NO_CONTRACT; |
70 | SUPPORTS_DAC; |
71 | PRECONDITION(rank > 0 && etype == ELEMENT_TYPE_ARRAY || |
72 | rank == 1 && etype == ELEMENT_TYPE_SZARRAY || |
73 | rank == 0 && (etype == ELEMENT_TYPE_PTR || etype == ELEMENT_TYPE_BYREF || etype == ELEMENT_TYPE_VALUETYPE)); |
74 | PRECONDITION(CheckPointer(paramType)); |
75 | m_kind = etype; |
76 | u.asParamType.m_paramType = paramType.AsTAddr(); |
77 | u.asParamType.m_rank = rank; |
78 | u.asParamType.m_isTemplateMethodTable = isTemplateMethodTable; |
79 | } |
80 | |
81 | // Constructor for instantiated types |
82 | TypeKey(Module *pModule, mdTypeDef token, Instantiation inst = Instantiation()) |
83 | { |
84 | WRAPPER_NO_CONTRACT; |
85 | PRECONDITION(CheckPointer(pModule)); |
86 | PRECONDITION(TypeFromToken(token) == mdtTypeDef); |
87 | PRECONDITION(!IsNilToken(token)); |
88 | m_kind = ELEMENT_TYPE_CLASS; |
89 | u.asClass.m_pModule = pModule; |
90 | u.asClass.m_typeDef = token; |
91 | u.asClass.m_numGenericArgs = inst.GetNumArgs(); |
92 | u.asClass.m_pGenericArgs = inst.GetRawArgs(); |
93 | } |
94 | |
95 | // Constructor for function pointer type |
96 | TypeKey(BYTE callConv, DWORD numArgs, TypeHandle* retAndArgTypes) |
97 | { |
98 | WRAPPER_NO_CONTRACT; |
99 | PRECONDITION(CheckPointer(retAndArgTypes)); |
100 | m_kind = ELEMENT_TYPE_FNPTR; |
101 | u.asFnPtr.m_callConv = callConv; |
102 | u.asFnPtr.m_numArgs = numArgs; |
103 | u.asFnPtr.m_pRetAndArgTypes = retAndArgTypes; |
104 | } |
105 | |
106 | CorElementType GetKind() const |
107 | { |
108 | LIMITED_METHOD_CONTRACT; |
109 | SUPPORTS_DAC; |
110 | return m_kind; |
111 | } |
112 | |
113 | // Accessors on array/pointer types |
114 | DWORD GetRank() const |
115 | { |
116 | LIMITED_METHOD_CONTRACT; |
117 | SUPPORTS_DAC; |
118 | PRECONDITION(CorTypeInfo::IsArray_NoThrow(m_kind)); |
119 | return u.asParamType.m_rank; |
120 | } |
121 | |
122 | BOOL IsTemplateMethodTable() const |
123 | { |
124 | LIMITED_METHOD_CONTRACT; |
125 | SUPPORTS_DAC; |
126 | return u.asParamType.m_isTemplateMethodTable; |
127 | } |
128 | |
129 | TypeHandle GetElementType() const |
130 | { |
131 | WRAPPER_NO_CONTRACT; |
132 | SUPPORTS_DAC; |
133 | PRECONDITION(CorTypeInfo::IsModifier_NoThrow(m_kind) || m_kind == ELEMENT_TYPE_VALUETYPE); |
134 | return TypeHandle::FromTAddr(u.asParamType.m_paramType); |
135 | } |
136 | |
137 | BOOL IsConstructed() const |
138 | { |
139 | LIMITED_METHOD_CONTRACT; |
140 | SUPPORTS_DAC; |
141 | return !(m_kind == ELEMENT_TYPE_CLASS && u.asClass.m_numGenericArgs == 0); |
142 | } |
143 | |
144 | // Accessors on instantiated types |
145 | PTR_Module GetModule() const |
146 | { |
147 | CONTRACTL |
148 | { |
149 | NOTHROW; |
150 | GC_NOTRIGGER; |
151 | SO_TOLERANT; |
152 | MODE_ANY; |
153 | SUPPORTS_DAC; |
154 | } |
155 | CONTRACTL_END; |
156 | if (m_kind == ELEMENT_TYPE_CLASS) |
157 | return PTR_Module(u.asClass.m_pModule); |
158 | else if (CorTypeInfo::IsModifier_NoThrow(m_kind) || m_kind == ELEMENT_TYPE_VALUETYPE) |
159 | return GetElementType().GetModule(); |
160 | else |
161 | return NULL; |
162 | } |
163 | |
164 | mdTypeDef GetTypeToken() const |
165 | { |
166 | LIMITED_METHOD_CONTRACT; |
167 | SUPPORTS_DAC; |
168 | PRECONDITION(m_kind == ELEMENT_TYPE_CLASS); |
169 | return u.asClass.m_typeDef; |
170 | } |
171 | |
172 | // Get the type parameters for this CLASS type. |
173 | // This is an array (host-allocated in DAC builds) of length GetNumGenericArgs(). |
174 | Instantiation GetInstantiation() const |
175 | { |
176 | LIMITED_METHOD_CONTRACT; |
177 | SUPPORTS_DAC; |
178 | PRECONDITION(m_kind == ELEMENT_TYPE_CLASS); |
179 | return Instantiation(u.asClass.m_pGenericArgs, u.asClass.m_numGenericArgs); |
180 | } |
181 | |
182 | DWORD GetNumGenericArgs() const |
183 | { |
184 | LIMITED_METHOD_CONTRACT; |
185 | SUPPORTS_DAC; |
186 | PRECONDITION(m_kind == ELEMENT_TYPE_CLASS); |
187 | return u.asClass.m_numGenericArgs; |
188 | } |
189 | |
190 | BOOL HasInstantiation() const |
191 | { |
192 | LIMITED_METHOD_CONTRACT; |
193 | return m_kind == ELEMENT_TYPE_CLASS && u.asClass.m_numGenericArgs != 0; |
194 | } |
195 | |
196 | // Accessors on function pointer types |
197 | DWORD GetNumArgs() const |
198 | { |
199 | LIMITED_METHOD_CONTRACT; |
200 | SUPPORTS_DAC; |
201 | PRECONDITION(m_kind == ELEMENT_TYPE_FNPTR); |
202 | return u.asFnPtr.m_numArgs; |
203 | } |
204 | |
205 | BYTE GetCallConv() const |
206 | { |
207 | LIMITED_METHOD_CONTRACT; |
208 | SUPPORTS_DAC; |
209 | PRECONDITION(m_kind == ELEMENT_TYPE_FNPTR); |
210 | return u.asFnPtr.m_callConv; |
211 | } |
212 | |
213 | TypeHandle* GetRetAndArgTypes() const |
214 | { |
215 | LIMITED_METHOD_CONTRACT; |
216 | SUPPORTS_DAC; |
217 | PRECONDITION(m_kind == ELEMENT_TYPE_FNPTR); |
218 | return u.asFnPtr.m_pRetAndArgTypes; |
219 | } |
220 | |
221 | BOOL Equals(TypeKey *pKey) const |
222 | { |
223 | WRAPPER_NO_CONTRACT; |
224 | return TypeKey::Equals(this, pKey); |
225 | } |
226 | |
227 | // Comparison and hashing |
228 | static BOOL Equals(const TypeKey *pKey1, const TypeKey *pKey2) |
229 | { |
230 | WRAPPER_NO_CONTRACT; |
231 | if (pKey1->m_kind != pKey2->m_kind) |
232 | { |
233 | return FALSE; |
234 | } |
235 | if (pKey1->m_kind == ELEMENT_TYPE_CLASS) |
236 | { |
237 | if (pKey1->u.asClass.m_typeDef != pKey2->u.asClass.m_typeDef || |
238 | pKey1->u.asClass.m_pModule != pKey2->u.asClass.m_pModule || |
239 | pKey1->u.asClass.m_numGenericArgs != pKey2->u.asClass.m_numGenericArgs) |
240 | { |
241 | return FALSE; |
242 | } |
243 | for (DWORD i = 0; i < pKey1->u.asClass.m_numGenericArgs; i++) |
244 | { |
245 | if (pKey1->u.asClass.m_pGenericArgs[i].GetValue() != pKey2->u.asClass.m_pGenericArgs[i].GetValue()) |
246 | return FALSE; |
247 | } |
248 | return TRUE; |
249 | } |
250 | else if (CorTypeInfo::IsModifier_NoThrow(pKey1->m_kind) || pKey1->m_kind == ELEMENT_TYPE_VALUETYPE) |
251 | { |
252 | return pKey1->u.asParamType.m_paramType == pKey2->u.asParamType.m_paramType |
253 | && pKey1->u.asParamType.m_rank == pKey2->u.asParamType.m_rank |
254 | && pKey1->u.asParamType.m_isTemplateMethodTable == pKey2->u.asParamType.m_isTemplateMethodTable; |
255 | } |
256 | else |
257 | { |
258 | _ASSERTE(pKey1->m_kind == ELEMENT_TYPE_FNPTR); |
259 | if (pKey1->u.asFnPtr.m_callConv != pKey2->u.asFnPtr.m_callConv || |
260 | pKey1->u.asFnPtr.m_numArgs != pKey2->u.asFnPtr.m_numArgs) |
261 | return FALSE; |
262 | |
263 | // Includes return type |
264 | for (DWORD i = 0; i <= pKey1->u.asFnPtr.m_numArgs; i++) |
265 | { |
266 | if (pKey1->u.asFnPtr.m_pRetAndArgTypes[i] != pKey2->u.asFnPtr.m_pRetAndArgTypes[i]) |
267 | return FALSE; |
268 | } |
269 | return TRUE; |
270 | } |
271 | } |
272 | |
273 | DWORD ComputeHash() const |
274 | { |
275 | LIMITED_METHOD_CONTRACT; |
276 | DWORD_PTR hashLarge; |
277 | |
278 | if (m_kind == ELEMENT_TYPE_CLASS) |
279 | { |
280 | hashLarge = ((DWORD_PTR)u.asClass.m_pModule ^ (DWORD_PTR)u.asClass.m_numGenericArgs ^ (DWORD_PTR)u.asClass.m_typeDef); |
281 | } |
282 | else if (CorTypeInfo::IsModifier_NoThrow(m_kind) || m_kind == ELEMENT_TYPE_VALUETYPE) |
283 | { |
284 | hashLarge = (u.asParamType.m_paramType ^ (DWORD_PTR) u.asParamType.m_rank); |
285 | } |
286 | else hashLarge = 0; |
287 | |
288 | #if POINTER_BITS == 32 |
289 | return hashLarge; |
290 | #else |
291 | DWORD hash = *(DWORD *)&hashLarge; |
292 | for (unsigned i = 1; i < POINTER_BITS / 32; i++) |
293 | { |
294 | hash ^= ((DWORD *)&hashLarge)[i]; |
295 | } |
296 | return hash; |
297 | #endif |
298 | } |
299 | }; |
300 | |
301 | |
302 | #endif /* _H_TYPEKEY */ |
303 | |