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 | // typectxt.cpp |
6 | // |
7 | |
8 | // |
9 | // Simple struct to record the data necessary to interpret ELEMENT_TYPE_VAR |
10 | // and ELEMENT_TYPE_MVAR within pieces of metadata, in particular within |
11 | // signatures parsed by MetaSig and SigPointer. |
12 | // |
13 | |
14 | |
15 | |
16 | #include "common.h" |
17 | #include "method.hpp" |
18 | #include "typehandle.h" |
19 | #include "field.h" |
20 | |
21 | |
22 | |
23 | void SigTypeContext::InitTypeContext(MethodDesc *md, Instantiation exactClassInst, Instantiation exactMethodInst, SigTypeContext *pRes) |
24 | { |
25 | LIMITED_METHOD_CONTRACT; |
26 | STATIC_CONTRACT_SO_TOLERANT; |
27 | MethodTable *pMT = md->GetMethodTable(); |
28 | |
29 | if (pMT->IsArray()) |
30 | { |
31 | pRes->m_classInst = exactClassInst.IsEmpty() ? pMT->GetClassOrArrayInstantiation() : exactClassInst; |
32 | } |
33 | else |
34 | { |
35 | pRes->m_classInst = exactClassInst; |
36 | } |
37 | pRes->m_methodInst = exactMethodInst; |
38 | } |
39 | |
40 | void SigTypeContext::InitTypeContext(MethodDesc *md, SigTypeContext *pRes) |
41 | { |
42 | CONTRACTL { |
43 | NOTHROW; |
44 | GC_NOTRIGGER; |
45 | FORBID_FAULT; |
46 | SO_TOLERANT; |
47 | SUPPORTS_DAC; |
48 | |
49 | PRECONDITION(CheckPointer(md)); |
50 | } CONTRACTL_END; |
51 | |
52 | MethodTable *pMT = md->GetMethodTable(); |
53 | if (pMT->IsArray()) |
54 | { |
55 | pRes->m_classInst = pMT->GetClassOrArrayInstantiation(); |
56 | } |
57 | else |
58 | { |
59 | pRes->m_classInst = pMT->GetInstantiation(); |
60 | } |
61 | pRes->m_methodInst = md->GetMethodInstantiation(); |
62 | } |
63 | |
64 | void SigTypeContext::InitTypeContext(MethodDesc *md, TypeHandle declaringType, SigTypeContext *pRes) |
65 | { |
66 | CONTRACTL { |
67 | NOTHROW; |
68 | GC_NOTRIGGER; |
69 | FORBID_FAULT; |
70 | SO_TOLERANT; |
71 | SUPPORTS_DAC; |
72 | |
73 | PRECONDITION(CheckPointer(md)); |
74 | } CONTRACTL_END; |
75 | |
76 | if (declaringType.IsNull()) |
77 | { |
78 | SigTypeContext::InitTypeContext(md, pRes); |
79 | } |
80 | else |
81 | { |
82 | MethodTable *pMDMT = md->GetMethodTable(); |
83 | if (pMDMT->IsArray()) |
84 | { |
85 | pRes->m_classInst = declaringType.GetClassOrArrayInstantiation(); |
86 | } |
87 | else |
88 | { |
89 | pRes->m_classInst = declaringType.GetInstantiationOfParentClass(pMDMT); |
90 | } |
91 | pRes->m_methodInst = md->GetMethodInstantiation(); |
92 | } |
93 | } |
94 | |
95 | #ifndef DACCESS_COMPILE |
96 | TypeHandle GetDeclaringMethodTableFromTypeVarTypeDesc(TypeVarTypeDesc *pTypeVar, MethodDesc *pMD) |
97 | { |
98 | LIMITED_METHOD_CONTRACT; |
99 | |
100 | // This currently should only happen in cases where we've already loaded the constraints. |
101 | // Currently, the only known case where use this code is reflection over methods exposed on a TypeVariable. |
102 | _ASSERTE(pTypeVar->ConstraintsLoaded()); |
103 | |
104 | if (pTypeVar->ConstraintsLoaded()) |
105 | { |
106 | DWORD cConstraints; |
107 | TypeHandle *pTypeHandles = pTypeVar->GetCachedConstraints(&cConstraints); |
108 | for (DWORD iConstraint = 0; iConstraint < cConstraints; iConstraint++) |
109 | { |
110 | if (pTypeHandles[iConstraint].IsGenericVariable()) |
111 | { |
112 | TypeHandle th = GetDeclaringMethodTableFromTypeVarTypeDesc(pTypeHandles[iConstraint].AsGenericVariable(), pMD); |
113 | if (!th.IsNull()) |
114 | return th; |
115 | } |
116 | else |
117 | { |
118 | MethodTable *pMT = pTypeHandles[iConstraint].GetMethodTable(); |
119 | while (pMT != NULL) |
120 | { |
121 | if (pMT == pMD->GetMethodTable()) |
122 | { |
123 | return TypeHandle(pMT); |
124 | } |
125 | |
126 | pMT = pMT->GetParentMethodTable(); |
127 | } |
128 | } |
129 | } |
130 | } |
131 | return TypeHandle(); |
132 | } |
133 | |
134 | void SigTypeContext::InitTypeContext(MethodDesc *md, TypeHandle declaringType, Instantiation exactMethodInst, SigTypeContext *pRes) |
135 | { |
136 | CONTRACTL { |
137 | NOTHROW; |
138 | GC_NOTRIGGER; |
139 | FORBID_FAULT; |
140 | SO_TOLERANT; |
141 | |
142 | PRECONDITION(CheckPointer(md)); |
143 | } CONTRACTL_END; |
144 | |
145 | if (declaringType.IsNull()) |
146 | { |
147 | SigTypeContext::InitTypeContext(md, pRes); |
148 | } |
149 | else |
150 | { |
151 | // <TODO> factor this with the work above </TODO> |
152 | if (declaringType.IsGenericVariable()) |
153 | { |
154 | declaringType = GetDeclaringMethodTableFromTypeVarTypeDesc(declaringType.AsGenericVariable(), md); |
155 | } |
156 | |
157 | if (declaringType.IsNull()) |
158 | { |
159 | SigTypeContext::InitTypeContext(md, pRes); |
160 | } |
161 | else |
162 | { |
163 | MethodTable *pMDMT = md->GetMethodTable(); |
164 | if (pMDMT->IsArray()) |
165 | { |
166 | pRes->m_classInst = declaringType.GetClassOrArrayInstantiation(); |
167 | } |
168 | else |
169 | { |
170 | pRes->m_classInst = declaringType.GetInstantiationOfParentClass(pMDMT); |
171 | } |
172 | } |
173 | } |
174 | pRes->m_methodInst = !exactMethodInst.IsEmpty() ? exactMethodInst : md->GetMethodInstantiation(); |
175 | } |
176 | #endif // !DACCESS_COMPILE |
177 | |
178 | void SigTypeContext::InitTypeContext(FieldDesc *pFD, TypeHandle declaringType, SigTypeContext *pRes) |
179 | { |
180 | CONTRACTL { |
181 | NOTHROW; |
182 | GC_NOTRIGGER; |
183 | FORBID_FAULT; |
184 | SO_TOLERANT; |
185 | |
186 | PRECONDITION(CheckPointer(declaringType, NULL_OK)); |
187 | PRECONDITION(CheckPointer(pFD)); |
188 | } CONTRACTL_END; |
189 | LIMITED_METHOD_CONTRACT; |
190 | InitTypeContext(pFD->GetExactClassInstantiation(declaringType),Instantiation(), pRes); |
191 | } |
192 | |
193 | |
194 | void SigTypeContext::InitTypeContext(TypeHandle th, SigTypeContext *pRes) |
195 | { |
196 | CONTRACTL { |
197 | NOTHROW; |
198 | GC_NOTRIGGER; |
199 | FORBID_FAULT; |
200 | SO_TOLERANT; |
201 | } CONTRACTL_END; |
202 | |
203 | if (th.IsNull()) |
204 | { |
205 | InitTypeContext(pRes); |
206 | } |
207 | else if (th.GetMethodTable()->IsArray()) |
208 | { |
209 | InitTypeContext(th.GetMethodTable()->GetClassOrArrayInstantiation(), Instantiation(), pRes); |
210 | } |
211 | else |
212 | { |
213 | InitTypeContext(th.GetInstantiation(), Instantiation(), pRes); |
214 | } |
215 | } |
216 | |
217 | |
218 | const SigTypeContext * SigTypeContext::GetOptionalTypeContext(MethodDesc *md, TypeHandle declaringType, SigTypeContext *pRes) |
219 | { |
220 | CONTRACTL |
221 | { |
222 | NOTHROW; |
223 | GC_NOTRIGGER; |
224 | SO_TOLERANT; |
225 | MODE_ANY; |
226 | } |
227 | CONTRACTL_END; |
228 | |
229 | _ASSERTE(md); |
230 | if (md->HasClassOrMethodInstantiation() || md->GetMethodTable()->IsArray()) |
231 | { |
232 | SigTypeContext::InitTypeContext(md, declaringType,pRes); |
233 | return pRes; |
234 | } |
235 | else |
236 | { |
237 | _ASSERTE(pRes->m_classInst.IsEmpty()); |
238 | _ASSERTE(pRes->m_methodInst.IsEmpty()); |
239 | return NULL; |
240 | } |
241 | } |
242 | |
243 | const SigTypeContext * SigTypeContext::GetOptionalTypeContext(TypeHandle th, SigTypeContext *pRes) |
244 | { |
245 | CONTRACTL |
246 | { |
247 | NOTHROW; |
248 | GC_NOTRIGGER; |
249 | SO_TOLERANT; |
250 | MODE_ANY; |
251 | } |
252 | CONTRACTL_END; |
253 | |
254 | _ASSERTE (!th.IsNull()); |
255 | if (th.HasInstantiation() || th.GetMethodTable()->IsArray()) |
256 | { |
257 | SigTypeContext::InitTypeContext(th,pRes); |
258 | return pRes; |
259 | } |
260 | else |
261 | { |
262 | // It should already have been null-initialized when allocated on the stack. |
263 | _ASSERTE(pRes->m_classInst.IsEmpty()); |
264 | _ASSERTE(pRes->m_methodInst.IsEmpty()); |
265 | return NULL; |
266 | } |
267 | } |
268 | |
269 | BOOL SigTypeContext::IsValidTypeOnlyInstantiationOf(const SigTypeContext *pCtxTypicalMethodInstantiation, const SigTypeContext *pCtxTypeOnlyInstantiation) |
270 | { |
271 | CONTRACTL |
272 | { |
273 | NOTHROW; |
274 | GC_NOTRIGGER; |
275 | SO_TOLERANT; |
276 | MODE_ANY; |
277 | } |
278 | CONTRACTL_END; |
279 | |
280 | // Compare class inst counts |
281 | if (pCtxTypicalMethodInstantiation->m_classInst.GetNumArgs() != pCtxTypeOnlyInstantiation->m_classInst.GetNumArgs()) |
282 | return FALSE; |
283 | |
284 | // Compare method inst counts |
285 | if (pCtxTypicalMethodInstantiation->m_methodInst.GetNumArgs() != pCtxTypeOnlyInstantiation->m_methodInst.GetNumArgs()) |
286 | return FALSE; |
287 | |
288 | DWORD i; |
289 | |
290 | // Ensure that no type variables are part of the instantiation of the generic type |
291 | for (i = 0; i < pCtxTypicalMethodInstantiation->m_classInst.GetNumArgs(); i++) { |
292 | if (pCtxTypeOnlyInstantiation->m_classInst[i].IsGenericVariable()) |
293 | return FALSE; |
294 | } |
295 | |
296 | // Compare method inst values to ensure they represent the same generic method parameters |
297 | for (i = 0; i < pCtxTypicalMethodInstantiation->m_methodInst.GetNumArgs(); i++) { |
298 | _ASSERTE(pCtxTypicalMethodInstantiation->m_methodInst[i].IsGenericVariable()); |
299 | |
300 | if (pCtxTypicalMethodInstantiation->m_methodInst[i] != pCtxTypeOnlyInstantiation->m_methodInst[i]) |
301 | return FALSE; |
302 | } |
303 | |
304 | return TRUE; |
305 | } |
306 | |
307 | BOOL SigTypeContext::Equal(const SigTypeContext *pCtx1, const SigTypeContext *pCtx2) |
308 | { |
309 | WRAPPER_NO_CONTRACT; |
310 | |
311 | // Compare class inst counts |
312 | if (pCtx1->m_classInst.GetNumArgs() != pCtx2->m_classInst.GetNumArgs()) |
313 | return FALSE; |
314 | |
315 | // Compare method inst counts |
316 | if (pCtx1->m_methodInst.GetNumArgs() != pCtx2->m_methodInst.GetNumArgs()) |
317 | return FALSE; |
318 | |
319 | DWORD i; |
320 | |
321 | // Compare class inst values |
322 | for (i = 0; i < pCtx1->m_classInst.GetNumArgs(); i++) { |
323 | if (pCtx1->m_classInst[i] != pCtx2->m_classInst[i]) |
324 | return FALSE; |
325 | } |
326 | |
327 | // Compare method inst values |
328 | for (i = 0; i < pCtx1->m_methodInst.GetNumArgs(); i++) { |
329 | if (pCtx1->m_methodInst[i] != pCtx2->m_methodInst[i]) |
330 | return FALSE; |
331 | } |
332 | |
333 | return TRUE; |
334 | } |
335 | |
336 | |