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
24class 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
64public:
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