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
23void 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
40void 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
64void 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
96TypeHandle 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
134void 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
178void 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
194void 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
218const 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
243const 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
269BOOL 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
307BOOL 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