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// siginfo.cpp
6//
7// Signature parsing code
8//
9
10
11#include "common.h"
12
13#include "siginfo.hpp"
14#include "clsload.hpp"
15#include "vars.hpp"
16#include "excep.h"
17#include "gcheaputilities.h"
18#include "field.h"
19#include "eeconfig.h"
20#include "runtimehandles.h" // for SignatureNative
21#include "winwrap.h"
22#include <formattype.h>
23#include "sigbuilder.h"
24#include "../md/compiler/custattr.h"
25#include <corhlprpriv.h>
26#include "argdestination.h"
27
28/*******************************************************************/
29const CorTypeInfo::CorTypeInfoEntry CorTypeInfo::info[ELEMENT_TYPE_MAX] =
30{
31#define TYPEINFO(enumName,nameSpace,className,size,gcType,isArray,isPrim,isFloat,isModifier,isGenVar) \
32 { nameSpace, className, enumName, size, gcType, isArray, isPrim, isFloat, isModifier, isGenVar },
33#include "cortypeinfo.h"
34# undef TYPEINFO
35};
36
37/*******************************************************************/
38/* static */
39CorElementType
40CorTypeInfo::FindPrimitiveType(LPCUTF8 name)
41{
42 LIMITED_METHOD_CONTRACT;
43
44 _ASSERTE(name != NULL);
45
46 for (unsigned int i = 1; i < _countof(CorTypeInfo::info); i++)
47 { // can skip ELEMENT_TYPE_END (index 0)
48 if ((info[i].className != NULL) && (strcmp(name, info[i].className) == 0))
49 return (CorElementType)i;
50 }
51
52 return ELEMENT_TYPE_END;
53}
54
55const ElementTypeInfo gElementTypeInfo[] = {
56
57#ifdef _DEBUG
58#define DEFINEELEMENTTYPEINFO(etname, cbsize, gcness, inreg) {(int)(etname),cbsize,gcness,inreg},
59#else
60#define DEFINEELEMENTTYPEINFO(etname, cbsize, gcness, inreg) {cbsize,gcness,inreg},
61#endif
62
63// Meaning of columns:
64//
65// name - The checked build uses this to verify that the table is sorted
66// correctly. This is a lookup table that uses ELEMENT_TYPE_*
67// as an array index.
68//
69// cbsize - The byte size of this value as returned by SizeOf(). SPECIAL VALUE: -1
70// requires type-specific treatment.
71//
72// gc - 0 no embedded objectrefs
73// 1 value is an objectref
74// 2 value is an interior pointer - promote it but don't scan it
75// 3 requires type-specific treatment
76//
77// reg - put in a register?
78//
79// Note: This table is very similar to the one in file:corTypeInfo.h with these exceptions:
80// reg column is missing in corTypeInfo.h
81// ELEMENT_TYPE_VAR, ELEMENT_TYPE_GENERICINST, ELEMENT_TYPE_MVAR ... size -1 vs. TARGET_POINTER_SIZE in corTypeInfo.h
82// ELEMENT_TYPE_CMOD_REQD, ELEMENT_TYPE_CMOD_OPT, ELEMENT_TYPE_INTERNAL ... size -1 vs. 0 in corTypeInfo.h
83// ELEMENT_TYPE_INTERNAL ... GC type is TYPE_GC_NONE vs. TYPE_GC_OTHER in corTypeInfo.h
84//
85// name cbsize gc reg
86DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_END, -1, TYPE_GC_NONE, 0)
87DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_VOID, 0, TYPE_GC_NONE, 0)
88DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_BOOLEAN, 1, TYPE_GC_NONE, 1)
89DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_CHAR, 2, TYPE_GC_NONE, 1)
90
91DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_I1, 1, TYPE_GC_NONE, 1)
92DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_U1, 1, TYPE_GC_NONE, 1)
93DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_I2, 2, TYPE_GC_NONE, 1)
94DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_U2, 2, TYPE_GC_NONE, 1)
95
96DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_I4, 4, TYPE_GC_NONE, 1)
97DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_U4, 4, TYPE_GC_NONE, 1)
98DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_I8, 8, TYPE_GC_NONE, 0)
99DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_U8, 8, TYPE_GC_NONE, 0)
100
101DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_R4, 4, TYPE_GC_NONE, 0)
102DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_R8, 8, TYPE_GC_NONE, 0)
103DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_STRING, TARGET_POINTER_SIZE, TYPE_GC_REF, 1)
104DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_PTR, TARGET_POINTER_SIZE, TYPE_GC_NONE, 1)
105
106DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_BYREF, TARGET_POINTER_SIZE, TYPE_GC_BYREF, 1)
107DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_VALUETYPE, -1, TYPE_GC_OTHER, 0)
108DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_CLASS, TARGET_POINTER_SIZE, TYPE_GC_REF, 1)
109DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_VAR, -1, TYPE_GC_OTHER, 1)
110
111DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_ARRAY, TARGET_POINTER_SIZE, TYPE_GC_REF, 1)
112
113DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_GENERICINST, -1, TYPE_GC_OTHER, 0)
114
115DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_TYPEDBYREF, TARGET_POINTER_SIZE*2,TYPE_GC_BYREF, 0)
116DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED, -1, TYPE_GC_NONE, 0)
117DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_I, TARGET_POINTER_SIZE, TYPE_GC_NONE, 1)
118DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_U, TARGET_POINTER_SIZE, TYPE_GC_NONE, 1)
119DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_R_UNSUPPORTED, -1, TYPE_GC_NONE, 0)
120
121DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_FNPTR, TARGET_POINTER_SIZE, TYPE_GC_NONE, 1)
122DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_OBJECT, TARGET_POINTER_SIZE, TYPE_GC_REF, 1)
123DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_SZARRAY, TARGET_POINTER_SIZE, TYPE_GC_REF, 1)
124
125DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_MVAR, -1, TYPE_GC_OTHER, 1)
126DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_CMOD_REQD, -1, TYPE_GC_NONE, 1)
127DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_CMOD_OPT, -1, TYPE_GC_NONE, 1)
128DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_INTERNAL, -1, TYPE_GC_NONE, 0)
129};
130
131unsigned GetSizeForCorElementType(CorElementType etyp)
132{
133 LIMITED_METHOD_DAC_CONTRACT;
134 _ASSERTE(gElementTypeInfo[etyp].m_elementType == etyp);
135 return gElementTypeInfo[etyp].m_cbSize;
136}
137
138const ElementTypeInfo* GetElementTypeInfo(CorElementType etyp)
139{
140 LIMITED_METHOD_CONTRACT;
141 _ASSERTE(gElementTypeInfo[etyp].m_elementType == etyp);
142 return &gElementTypeInfo[etyp];
143}
144
145#ifndef DACCESS_COMPILE
146
147void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, BOOL bSkipCustomModifier)
148{
149 CONTRACTL
150 {
151 INSTANCE_CHECK;
152 STANDARD_VM_CHECK;
153
154 PRECONDITION(CheckPointer(pSigModule));
155 }
156 CONTRACTL_END
157
158 SigPointer sigStart = *this;
159
160 CorElementType typ = ELEMENT_TYPE_END;
161
162 // Check whether we need to skip custom modifier
163 // Only preserve custom modifier when calculating IL stub hash blob
164 if (bSkipCustomModifier)
165 {
166 // GetElemType eats sentinel and custom modifiers
167 IfFailThrowBF(GetElemType(&typ), BFA_BAD_COMPLUS_SIG, pSigModule);
168 }
169 else
170 {
171 BYTE byElemType;
172
173 IfFailThrowBF(SkipAnyVASentinel(), BFA_BAD_COMPLUS_SIG, pSigModule);
174
175 // Call GetByte and make sure we don't lose custom modifiers
176 IfFailThrowBF(GetByte(&byElemType), BFA_BAD_COMPLUS_SIG, pSigModule);
177 typ = (CorElementType) byElemType;
178 }
179
180 if (typ == ELEMENT_TYPE_CLASS || typ == ELEMENT_TYPE_VALUETYPE)
181 {
182 IfFailThrowBF(GetToken(NULL), BFA_BAD_COMPLUS_SIG, pSigModule);
183 TypeHandle th = sigStart.GetTypeHandleThrowing(pSigModule, pTypeContext);
184
185 pSigBuilder->AppendElementType(ELEMENT_TYPE_INTERNAL);
186 pSigBuilder->AppendPointer(th.AsPtr());
187 return;
188 }
189
190 if (pTypeContext != NULL)
191 {
192 ULONG varNum;
193 if (typ == ELEMENT_TYPE_VAR)
194 {
195 IfFailThrowBF(GetData(&varNum), BFA_BAD_COMPLUS_SIG, pSigModule);
196 THROW_BAD_FORMAT_MAYBE(varNum < pTypeContext->m_classInst.GetNumArgs(), BFA_BAD_COMPLUS_SIG, pSigModule);
197
198 pSigBuilder->AppendElementType(ELEMENT_TYPE_INTERNAL);
199 pSigBuilder->AppendPointer(pTypeContext->m_classInst[varNum].AsPtr());
200 return;
201 }
202 if (typ == ELEMENT_TYPE_MVAR)
203 {
204 IfFailThrowBF(GetData(&varNum), BFA_BAD_COMPLUS_SIG, pSigModule);
205 THROW_BAD_FORMAT_MAYBE(varNum < pTypeContext->m_methodInst.GetNumArgs(), BFA_BAD_COMPLUS_SIG, pSigModule);
206
207 pSigBuilder->AppendElementType(ELEMENT_TYPE_INTERNAL);
208 pSigBuilder->AppendPointer(pTypeContext->m_methodInst[varNum].AsPtr());
209 return;
210 }
211 }
212
213 pSigBuilder->AppendElementType(typ);
214
215 if (!CorIsPrimitiveType(typ))
216 {
217 switch (typ)
218 {
219 default:
220 THROW_BAD_FORMAT(BFA_BAD_COMPLUS_SIG, pSigModule);
221 break;
222 case ELEMENT_TYPE_VAR:
223 case ELEMENT_TYPE_MVAR:
224 {
225 ULONG varNum;
226 // Skip variable number
227 IfFailThrowBF(GetData(&varNum), BFA_BAD_COMPLUS_SIG, pSigModule);
228 pSigBuilder->AppendData(varNum);
229 }
230 break;
231 case ELEMENT_TYPE_OBJECT:
232 case ELEMENT_TYPE_STRING:
233 case ELEMENT_TYPE_TYPEDBYREF:
234 break;
235
236 case ELEMENT_TYPE_BYREF: //fallthru
237 case ELEMENT_TYPE_PTR:
238 case ELEMENT_TYPE_PINNED:
239 case ELEMENT_TYPE_SZARRAY:
240 ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier);
241 break;
242
243 case ELEMENT_TYPE_FNPTR:
244 ConvertToInternalSignature(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier);
245 break;
246
247 case ELEMENT_TYPE_ARRAY:
248 {
249 ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier);
250
251 ULONG rank = 0; // Get rank
252 IfFailThrowBF(GetData(&rank), BFA_BAD_COMPLUS_SIG, pSigModule);
253 pSigBuilder->AppendData(rank);
254
255 if (rank)
256 {
257 ULONG nsizes = 0;
258 IfFailThrowBF(GetData(&nsizes), BFA_BAD_COMPLUS_SIG, pSigModule);
259 pSigBuilder->AppendData(nsizes);
260
261 while (nsizes--)
262 {
263 ULONG data = 0;
264 IfFailThrowBF(GetData(&data), BFA_BAD_COMPLUS_SIG, pSigModule);
265 pSigBuilder->AppendData(data);
266 }
267
268 ULONG nlbounds = 0;
269 IfFailThrowBF(GetData(&nlbounds), BFA_BAD_COMPLUS_SIG, pSigModule);
270 pSigBuilder->AppendData(nlbounds);
271
272 while (nlbounds--)
273 {
274 ULONG data = 0;
275 IfFailThrowBF(GetData(&data), BFA_BAD_COMPLUS_SIG, pSigModule);
276 pSigBuilder->AppendData(data);
277 }
278 }
279 }
280 break;
281
282 case ELEMENT_TYPE_INTERNAL:
283 {
284 // this check is not functional in DAC and provides no security against a malicious dump
285 // the DAC is prepared to receive an invalid type handle
286#ifndef DACCESS_COMPILE
287 if (pSigModule->IsSigInIL(m_ptr))
288 THROW_BAD_FORMAT(BFA_BAD_COMPLUS_SIG, pSigModule);
289#endif
290
291 TypeHandle hType;
292
293 IfFailThrowBF(GetPointer((void**)&hType), BFA_BAD_COMPLUS_SIG, pSigModule);
294
295 pSigBuilder->AppendPointer(hType.AsPtr());
296 }
297 break;
298
299 case ELEMENT_TYPE_GENERICINST:
300 {
301 TypeHandle genericType = GetGenericInstType(pSigModule);
302
303 pSigBuilder->AppendElementType(ELEMENT_TYPE_INTERNAL);
304 pSigBuilder->AppendPointer(genericType.AsPtr());
305
306 ULONG argCnt = 0; // Get number of parameters
307 IfFailThrowBF(GetData(&argCnt), BFA_BAD_COMPLUS_SIG, pSigModule);
308 pSigBuilder->AppendData(argCnt);
309
310 while (argCnt--)
311 {
312 ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier);
313 }
314 }
315 break;
316
317 // Note: the following is only for correctly computing IL stub hash for modifiers in order to support C++ scenarios
318 case ELEMENT_TYPE_CMOD_OPT:
319 case ELEMENT_TYPE_CMOD_REQD:
320 {
321 mdToken tk;
322 IfFailThrowBF(GetToken(&tk), BFA_BAD_COMPLUS_SIG, pSigModule);
323 TypeHandle th = ClassLoader::LoadTypeDefOrRefThrowing(pSigModule, tk);
324 pSigBuilder->AppendPointer(th.AsPtr());
325
326 ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier);
327 }
328 break;
329 }
330 }
331}
332
333void SigPointer::ConvertToInternalSignature(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, BOOL bSkipCustomModifier)
334{
335 CONTRACTL
336 {
337 INSTANCE_CHECK;
338 STANDARD_VM_CHECK;
339
340 PRECONDITION(CheckPointer(pSigModule));
341 }
342 CONTRACTL_END
343
344 BYTE uCallConv = 0;
345 IfFailThrowBF(GetByte(&uCallConv), BFA_BAD_COMPLUS_SIG, pSigModule);
346
347 if ((uCallConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_FIELD)
348 THROW_BAD_FORMAT(BFA_UNEXPECTED_FIELD_SIGNATURE, pSigModule);
349
350 pSigBuilder->AppendByte(uCallConv);
351
352 // Skip type parameter count
353 if (uCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
354 {
355 ULONG nParams = 0;
356 IfFailThrowBF(GetData(&nParams), BFA_BAD_COMPLUS_SIG, pSigModule);
357 pSigBuilder->AppendData(nParams);
358 }
359
360 // Get arg count;
361 ULONG cArgs = 0;
362 IfFailThrowBF(GetData(&cArgs), BFA_BAD_COMPLUS_SIG, pSigModule);
363 pSigBuilder->AppendData(cArgs);
364
365 cArgs++; // +1 for return type
366
367 // Skip args.
368 while (cArgs)
369 {
370 ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier);
371 cArgs--;
372 }
373}
374#endif // DACCESS_COMPILE
375
376
377//---------------------------------------------------------------------------------------
378//
379// Default constructor for creating an empty Signature, i.e. with a NULL raw PCCOR_SIGNATURE pointer.
380//
381
382Signature::Signature()
383{
384 LIMITED_METHOD_CONTRACT;
385
386 m_pSig = NULL;
387 m_cbSig = 0;
388}
389
390//---------------------------------------------------------------------------------------
391//
392// Primary constructor for creating a Signature.
393//
394// Arguments:
395// pSig - raw PCCOR_SIGNATURE pointer
396// cbSig - length of the signature
397//
398
399Signature::Signature(PCCOR_SIGNATURE pSig,
400 DWORD cbSig)
401{
402 LIMITED_METHOD_CONTRACT;
403 SUPPORTS_DAC; // host-only data structure - not marshalled
404
405 m_pSig = pSig;
406 m_cbSig = cbSig;
407}
408
409//---------------------------------------------------------------------------------------
410//
411// Check if the Signature is empty, i.e. has a NULL raw PCCOR_SIGNATURE
412//
413// Return Value:
414// TRUE if the raw PCCOR_SIGNATURE is NULL
415//
416
417BOOL Signature::IsEmpty() const
418{
419 LIMITED_METHOD_CONTRACT;
420 SUPPORTS_DAC;
421 return (m_pSig == NULL);
422}
423
424//---------------------------------------------------------------------------------------
425//
426// Create a SigParser over the Signature. In DAC builds, grab the signature bytes from out of process first.
427//
428// Return Value:
429// a SigpParser for this particular Signature
430//
431
432SigParser Signature::CreateSigParser() const
433{
434 CONTRACTL
435 {
436 NOTHROW;
437 GC_NOTRIGGER;
438 MODE_ANY;
439 }
440 CONTRACTL_END;
441
442#if defined(DACCESS_COMPILE)
443 // Copy the signature bytes from the target process.
444 PCCOR_SIGNATURE pTargetSig = (PCCOR_SIGNATURE)DacInstantiateTypeByAddress((TADDR)m_pSig, m_cbSig, true);
445 return SigParser(pTargetSig, m_cbSig);
446#else // !DACCESS_COMPILE
447 return SigParser(m_pSig, m_cbSig);
448#endif // !DACCESS_COMPILE
449}
450
451//---------------------------------------------------------------------------------------
452//
453// Create a SigPointer over the Signature. In DAC builds, grab the signature bytes from out of process first.
454//
455// Return Value:
456// a SigPointer for this particular Signature
457//
458
459SigPointer Signature::CreateSigPointer() const
460{
461 CONTRACTL
462 {
463 NOTHROW;
464 GC_NOTRIGGER;
465 MODE_ANY;
466 }
467 CONTRACTL_END;
468
469#if defined(DACCESS_COMPILE)
470 // Copy the signature bytes from the target process.
471 PCCOR_SIGNATURE pTargetSig = (PCCOR_SIGNATURE)DacInstantiateTypeByAddress((TADDR)m_pSig, m_cbSig, true);
472 return SigPointer(pTargetSig, m_cbSig);
473#else // !DACCESS_COMPILE
474 return SigPointer(m_pSig, m_cbSig);
475#endif // !DACCESS_COMPILE
476}
477
478//---------------------------------------------------------------------------------------
479//
480// Pretty-print the Signature. This is just a wrapper over code:PrettyPrintSig().
481//
482// Arguments:
483// pszMethodName - the name of the method in question
484// pqbOut - a CQuickBytes array for allocating memory
485// pIMDI - a IMDInternalImport interface for resolving tokens
486//
487// Return Value:
488// whatever PrettyPrintSig() returns
489//
490
491void Signature::PrettyPrint(const CHAR * pszMethodName,
492 CQuickBytes * pqbOut,
493 IMDInternalImport * pIMDI) const
494{
495 WRAPPER_NO_CONTRACT;
496 PrettyPrintSig(this->GetRawSig(), this->GetRawSigLen(), pszMethodName, pqbOut, pIMDI, NULL);
497}
498
499//---------------------------------------------------------------------------------------
500//
501// Get the raw signature pointer contained in this Siganture.
502//
503// Return Value:
504// the raw signature pointer
505//
506// Notes:
507// Use this ONLY IF there is no other way to do what you want to do!
508// In most cases you just want a SigParser/SigPointer from the Signature.
509//
510
511PCCOR_SIGNATURE Signature::GetRawSig() const
512{
513 LIMITED_METHOD_CONTRACT;
514 SUPPORTS_DAC;
515 return m_pSig;
516}
517
518//---------------------------------------------------------------------------------------
519//
520// Get the length of the raw signature contained in this Siganture.
521//
522// Return Value:
523// the length of the raw signature
524//
525// Notes:
526// Use this ONLY IF there is no other way to do what you want to do!
527// In most cases you just want a SigParser/SigPointer from the Signature.
528//
529
530DWORD Signature::GetRawSigLen() const
531{
532 LIMITED_METHOD_DAC_CONTRACT;
533 return m_cbSig;
534}
535
536
537//---------------------------------------------------------------------------------------
538//
539// Constructor.
540//
541void MetaSig::Init(
542 PCCOR_SIGNATURE szMetaSig,
543 DWORD cbMetaSig,
544 Module * pModule,
545 const SigTypeContext * pTypeContext,
546 MetaSigKind kind)
547{
548 CONTRACTL
549 {
550 CONSTRUCTOR_CHECK;
551 NOTHROW;
552 MODE_ANY;
553 GC_NOTRIGGER;
554 FORBID_FAULT;
555 PRECONDITION(CheckPointer(szMetaSig));
556 PRECONDITION(CheckPointer(pModule));
557 PRECONDITION(CheckPointer(pTypeContext, NULL_OK));
558 SUPPORTS_DAC;
559 }
560 CONTRACTL_END
561
562
563#ifdef _DEBUG
564 FillMemory(this, sizeof(*this), 0xcc);
565#endif
566
567 // Copy the type context
568 SigTypeContext::InitTypeContext(pTypeContext,&m_typeContext);
569 m_pModule = pModule;
570
571 SigPointer psig(szMetaSig, cbMetaSig);
572
573 HRESULT hr;
574
575 switch (kind)
576 {
577 case sigLocalVars:
578 {
579 ULONG data = 0;
580 IfFailGo(psig.GetCallingConvInfo(&data)); // Store calling convention
581 m_CallConv = (BYTE)data;
582
583 IfFailGo(psig.GetData(&data)); // Store number of arguments.
584 m_nArgs = data;
585
586 m_pRetType = SigPointer(NULL, 0);
587 break;
588 }
589 case sigMember:
590 {
591 ULONG data = 0;
592 IfFailGo(psig.GetCallingConvInfo(&data)); // Store calling convention
593 m_CallConv = (BYTE)data;
594
595 // Store type parameter count
596 if (m_CallConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
597 {
598 IfFailGo(psig.GetData(NULL));
599 }
600
601 IfFailGo(psig.GetData(&data)); // Store number of arguments.
602 m_nArgs = data;
603 m_pRetType = psig;
604 IfFailGo(psig.SkipExactlyOne());
605 break;
606 }
607 case sigField:
608 {
609 ULONG data = 0;
610 IfFailGo(psig.GetCallingConvInfo(&data)); // Store calling convention
611 m_CallConv = (BYTE)data;
612
613 m_nArgs = 1; //There's only 1 'arg' - the type.
614 m_pRetType = SigPointer(NULL, 0);
615 break;
616 }
617 default:
618 {
619 UNREACHABLE();
620 goto ErrExit;
621 }
622 }
623
624
625 m_pStart = psig;
626
627 m_flags = 0;
628
629 // Reset the iterator fields
630 Reset();
631
632 return;
633
634ErrExit:
635 // Invalid signature or parameter
636 m_CallConv = 0;
637 INDEBUG(m_CallConv = 0xff;)
638
639 m_nArgs = 0;
640 m_pRetType = SigPointer(NULL, 0);
641} // MetaSig::MetaSig
642
643
644// Helper constructor that constructs a method signature MetaSig from a MethodDesc
645// IMPORTANT: if classInst/methodInst is omitted and the MethodDesc is shared between generic
646// instantiations then the instantiation info for the method will be representative. This
647// is OK for GC, field layout etc. but not OK where exact types matter.
648//
649// Also, if used on a shared instantiated method descriptor or instance method in a shared generic struct
650// then the calling convention is fixed up to include the extra dictionary argument
651//
652// For method descs from array types the "instantiation" is set to the element type of the array
653// This lets us use VAR in the signatures for Get, Set and Address
654MetaSig::MetaSig(MethodDesc *pMD, Instantiation classInst, Instantiation methodInst)
655{
656 CONTRACTL
657 {
658 NOTHROW;
659 GC_NOTRIGGER;
660 MODE_ANY;
661 }
662 CONTRACTL_END;
663
664 SigTypeContext typeContext(pMD, classInst, methodInst);
665
666 PCCOR_SIGNATURE pSig;
667 DWORD cbSigSize;
668 pMD->GetSig(&pSig, &cbSigSize);
669
670 Init(pSig, cbSigSize, pMD->GetModule(),&typeContext);
671
672 if (pMD->RequiresInstArg())
673 SetHasParamTypeArg();
674}
675
676MetaSig::MetaSig(MethodDesc *pMD, TypeHandle declaringType)
677{
678 CONTRACTL
679 {
680 NOTHROW;
681 GC_NOTRIGGER;
682 MODE_ANY;
683 }
684 CONTRACTL_END;
685
686 SigTypeContext typeContext(pMD, declaringType);
687 PCCOR_SIGNATURE pSig;
688 DWORD cbSigSize;
689 pMD->GetSig(&pSig, &cbSigSize);
690
691 Init(pSig, cbSigSize, pMD->GetModule(),&typeContext);
692
693 if (pMD->RequiresInstArg())
694 SetHasParamTypeArg();
695}
696
697#ifdef _DEBUG
698//*******************************************************************************
699static BOOL MethodDescMatchesSig(MethodDesc* pMD, PCCOR_SIGNATURE pSig, DWORD cSig, Module * pModule)
700{
701 CONTRACTL
702 {
703 THROWS;
704 GC_TRIGGERS;
705 INJECT_FAULT(COMPlusThrowOM());
706 MODE_ANY;
707 }
708 CONTRACTL_END
709
710 PCCOR_SIGNATURE pSigOfMD;
711 DWORD cSigOfMD;
712 pMD->GetSig(&pSigOfMD, &cSigOfMD);
713
714 return MetaSig::CompareMethodSigs(pSig, cSig, pModule, NULL,
715 pSigOfMD, cSigOfMD, pMD->GetModule(), NULL);
716}
717#endif // _DEBUG
718
719MetaSig::MetaSig(BinderMethodID id)
720{
721 CONTRACTL
722 {
723 CONSTRUCTOR_CHECK;
724 THROWS;
725 MODE_ANY;
726 GC_TRIGGERS;
727 INJECT_FAULT(COMPlusThrowOM());
728 }
729 CONTRACTL_END
730
731 Signature sig = MscorlibBinder::GetMethodSignature(id);
732
733 _ASSERTE(MethodDescMatchesSig(MscorlibBinder::GetMethod(id),
734 sig.GetRawSig(), sig.GetRawSigLen(), MscorlibBinder::GetModule()));
735
736 Init(sig.GetRawSig(), sig.GetRawSigLen(), MscorlibBinder::GetModule(), NULL);
737}
738
739MetaSig::MetaSig(LPHARDCODEDMETASIG pwzMetaSig)
740{
741 CONTRACTL
742 {
743 CONSTRUCTOR_CHECK;
744 THROWS;
745 MODE_ANY;
746 GC_TRIGGERS;
747 INJECT_FAULT(COMPlusThrowOM());
748 }
749 CONTRACTL_END
750
751 Signature sig = MscorlibBinder::GetSignature(pwzMetaSig);
752
753 Init(sig.GetRawSig(), sig.GetRawSigLen(), MscorlibBinder::GetModule(), NULL);
754}
755
756// Helper constructor that constructs a field signature MetaSig from a FieldDesc
757// IMPORTANT: the classInst is omitted then the instantiation info for the field
758// will be representative only as FieldDescs can be shared
759//
760MetaSig::MetaSig(FieldDesc *pFD, TypeHandle declaringType)
761{
762 CONTRACTL
763 {
764 CONSTRUCTOR_CHECK;
765 NOTHROW;
766 MODE_ANY;
767 GC_NOTRIGGER;
768 PRECONDITION(CheckPointer(pFD));
769 }
770 CONTRACTL_END
771
772 PCCOR_SIGNATURE pSig;
773 DWORD cSig;
774
775 pFD->GetSig(&pSig, &cSig);
776
777 SigTypeContext typeContext(pFD, declaringType);
778
779 Init(pSig, cSig, pFD->GetModule(),&typeContext, sigField);
780}
781
782//---------------------------------------------------------------------------------------
783//
784// Returns type of current argument index. Returns ELEMENT_TYPE_END
785// if already past end of arguments.
786//
787CorElementType
788MetaSig::PeekArg() const
789{
790 WRAPPER_NO_CONTRACT;
791
792 if (m_iCurArg == m_nArgs)
793 {
794 return ELEMENT_TYPE_END;
795 }
796 return m_pWalk.PeekElemTypeClosed(GetModule(), &m_typeContext);
797}
798
799//---------------------------------------------------------------------------------------
800//
801// Returns type of current argument index. Returns ELEMENT_TYPE_END
802// if already past end of arguments.
803//
804CorElementType
805MetaSig::PeekArgNormalized(TypeHandle * pthValueType) const
806{
807 WRAPPER_NO_CONTRACT;
808
809 if (m_iCurArg == m_nArgs)
810 {
811 return ELEMENT_TYPE_END;
812 }
813 return m_pWalk.PeekElemTypeNormalized(m_pModule, &m_typeContext, pthValueType);
814}
815
816//---------------------------------------------------------------------------------------
817//
818// Returns type of current argument, then advances the argument
819// index. Returns ELEMENT_TYPE_END if already past end of arguments.
820//
821CorElementType
822MetaSig::NextArg()
823{
824 CONTRACTL
825 {
826 INSTANCE_CHECK;
827 NOTHROW;
828 MODE_ANY;
829 GC_NOTRIGGER;
830 FORBID_FAULT;
831 SUPPORTS_DAC;
832 }
833 CONTRACTL_END
834
835 m_pLastType = m_pWalk;
836
837 if (m_iCurArg == m_nArgs)
838 {
839 return ELEMENT_TYPE_END;
840 }
841 m_iCurArg++;
842 CorElementType mt = m_pWalk.PeekElemTypeClosed(GetModule(), &m_typeContext);
843 if (FAILED(m_pWalk.SkipExactlyOne()))
844 {
845 m_pWalk = m_pLastType;
846 return ELEMENT_TYPE_END;
847 }
848 return mt;
849}
850
851//---------------------------------------------------------------------------------------
852//
853// Advance the argument index. Can be used with GetArgProps() to
854// to iterate when you do not have a valid type context
855//
856void
857MetaSig::SkipArg()
858{
859 WRAPPER_NO_CONTRACT;
860
861 m_pLastType = m_pWalk;
862
863 if (m_iCurArg < m_nArgs)
864 {
865 m_iCurArg++;
866 if (FAILED(m_pWalk.SkipExactlyOne()))
867 {
868 m_pWalk = m_pLastType;
869 m_iCurArg = m_nArgs;
870 }
871 }
872}
873
874//---------------------------------------------------------------------------------------
875//
876// reset: goto start pos
877//
878VOID
879MetaSig::Reset()
880{
881 LIMITED_METHOD_DAC_CONTRACT;
882
883 m_pWalk = m_pStart;
884 m_iCurArg = 0;
885 return;
886}
887
888#ifndef DACCESS_COMPILE
889
890//---------------------------------------------------------------------------------------
891//
892BOOL
893IsTypeRefOrDef(
894 LPCSTR szClassName,
895 Module * pModule,
896 mdToken token)
897{
898 CONTRACTL
899 {
900 NOTHROW;
901 GC_NOTRIGGER;
902 FORBID_FAULT;
903 MODE_ANY;
904 }
905 CONTRACTL_END
906
907 LPCUTF8 pclsname;
908 LPCUTF8 pszNamespace;
909
910 IMDInternalImport *pInternalImport = pModule->GetMDImport();
911
912 if (TypeFromToken(token) == mdtTypeDef)
913 {
914 if (FAILED(pInternalImport->GetNameOfTypeDef(token, &pclsname, &pszNamespace)))
915 {
916 return false;
917 }
918 }
919 else if (TypeFromToken(token) == mdtTypeRef)
920 {
921 if (FAILED(pInternalImport->GetNameOfTypeRef(token, &pszNamespace, &pclsname)))
922 {
923 return false;
924 }
925 }
926 else
927 {
928 return false;
929 }
930
931 // If the namespace is not the same.
932 int iLen = (int)strlen(pszNamespace);
933 if (iLen)
934 {
935 if (strncmp(szClassName, pszNamespace, iLen) != 0)
936 return(false);
937
938 if (szClassName[iLen] != NAMESPACE_SEPARATOR_CHAR)
939 return(false);
940 ++iLen;
941 }
942
943 if (strcmp(&szClassName[iLen], pclsname) != 0)
944 return(false);
945 return(true);
946} // IsTypeRefOrDef
947
948TypeHandle SigPointer::GetTypeHandleNT(Module* pModule,
949 const SigTypeContext *pTypeContext) const
950{
951 CONTRACTL
952 {
953 INSTANCE_CHECK;
954 NOTHROW;
955 MODE_ANY;
956 GC_TRIGGERS;
957 }
958 CONTRACTL_END
959
960 TypeHandle th;
961 EX_TRY
962 {
963 th = GetTypeHandleThrowing(pModule, pTypeContext);
964 }
965 EX_CATCH
966 {
967 }
968 EX_END_CATCH(SwallowAllExceptions)
969 return(th);
970}
971
972#endif // #ifndef DACCESS_COMPILE
973
974
975#ifdef _PREFAST_
976#pragma warning(push)
977#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
978#endif
979
980// Method: TypeHandle SigPointer::GetTypeHandleThrowing()
981// pZapSigContext is only set when decoding zapsigs
982//
983TypeHandle SigPointer::GetTypeHandleThrowing(
984 Module * pModule,
985 const SigTypeContext * pTypeContext,
986 ClassLoader::LoadTypesFlag fLoadTypes/*=LoadTypes*/,
987 ClassLoadLevel level/*=CLASS_LOADED*/,
988 BOOL dropGenericArgumentLevel/*=FALSE*/,
989 const Substitution * pSubst/*=NULL*/,
990 // ZapSigContext is only set when decoding zapsigs
991 const ZapSig::Context * pZapSigContext) const
992{
993 CONTRACT(TypeHandle)
994 {
995 INSTANCE_CHECK;
996 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
997 MODE_ANY;
998 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
999 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1000 if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != ClassLoader::LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
1001 PRECONDITION(CheckPointer(pModule));
1002 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1003 POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == ClassLoader::LoadTypes) ? NULL_NOT_OK : NULL_OK)));
1004 SUPPORTS_DAC;
1005 }
1006 CONTRACT_END
1007
1008 // We have an invariant that before we call a method, we must have loaded all of the valuetype parameters of that
1009 // method visible from the signature of the method. Normally we do this via type loading before the method is called
1010 // by walking the signature of the callee method at jit time, and loading all of the valuetype arguments at that time.
1011 // For NGEN, we record which valuetypes need to be loaded, and force load those types when the caller method is first executed.
1012 // However, in certain circumstances involving generics the jit does not have the opportunity to observe the complete method
1013 // signature that may be used a signature walk time. See example below.
1014 //
1015 //
1016//using System;
1017//
1018//struct A<T> { }
1019//struct B<T> { }
1020//
1021//interface Interface<T>
1022//{ A<T> InterfaceFunc(); }
1023//
1024//class Base<T>
1025//{ public virtual B<T> Func() { return default(B<T>); } }
1026//
1027//class C<U,T> where U:Base<T>, Interface<T>
1028//{
1029// public static void CallFunc(U u) { u.Func(); }
1030// public static void CallInterfaceFunc(U u) { u.InterfaceFunc(); }
1031//}
1032//
1033//class Problem : Base<object>, Interface<object>
1034//{
1035// public A<object> InterfaceFunc() { return new A<object>(); }
1036// public override B<object> Func() { return new B<object>(); }
1037//}
1038//
1039//class Test
1040//{
1041// static void Main()
1042// {
1043// C<Problem, object>.CallFunc(new Problem());
1044// C<Problem, object>.CallInterfaceFunc(new Problem());
1045// }
1046//}
1047//
1048 // In this example, when CallFunc and CallInterfaceFunc are jitted, the types that will
1049 // be loaded during JIT time are A<__Canon> and <__Canon>. Thus we need to be able to only
1050 // search for canonical type arguments during these restricted time periods. IsGCThread() || IsStackWalkerThread() is the current
1051 // predicate for determining this.
1052
1053#ifdef _DEBUG
1054 if ((IsGCThread() || IsStackWalkerThread()) && (fLoadTypes == ClassLoader::LoadTypes))
1055 {
1056 // The callers are expected to pass the right arguments in
1057 _ASSERTE(level == CLASS_LOAD_APPROXPARENTS);
1058 _ASSERTE(dropGenericArgumentLevel == TRUE);
1059 }
1060#endif
1061
1062 TypeHandle thRet;
1063 SigPointer psig = *this;
1064 CorElementType typ = ELEMENT_TYPE_END;
1065 IfFailThrowBF(psig.GetElemType(&typ), BFA_BAD_SIGNATURE, pModule);
1066
1067 if ((typ < ELEMENT_TYPE_MAX) &&
1068 (CorTypeInfo::IsPrimitiveType_NoThrow(typ) || (typ == ELEMENT_TYPE_STRING) || (typ == ELEMENT_TYPE_OBJECT)))
1069 {
1070 // case ELEMENT_TYPE_VOID = 0x01,
1071 // case ELEMENT_TYPE_BOOLEAN = 0x02,
1072 // case ELEMENT_TYPE_CHAR = 0x03,
1073 // case ELEMENT_TYPE_I1 = 0x04,
1074 // case ELEMENT_TYPE_U1 = 0x05,
1075 // case ELEMENT_TYPE_I2 = 0x06,
1076 // case ELEMENT_TYPE_U2 = 0x07,
1077 // case ELEMENT_TYPE_I4 = 0x08,
1078 // case ELEMENT_TYPE_U4 = 0x09,
1079 // case ELEMENT_TYPE_I8 = 0x0a,
1080 // case ELEMENT_TYPE_U8 = 0x0b,
1081 // case ELEMENT_TYPE_R4 = 0x0c,
1082 // case ELEMENT_TYPE_R8 = 0x0d,
1083 // case ELEMENT_TYPE_I = 0x18,
1084 // case ELEMENT_TYPE_U = 0x19,
1085 //
1086 // case ELEMENT_TYPE_STRING = 0x0e,
1087 // case ELEMENT_TYPE_OBJECT = 0x1c,
1088 //
1089 thRet = TypeHandle(MscorlibBinder::GetElementType(typ));
1090 }
1091 else
1092 {
1093 // This function is recursive, so it must have an interior probe
1094 INTERIOR_STACK_PROBE_FOR_NOTHROW_CHECK_THREAD(10, NO_FORBIDGC_LOADER_USE_ThrowSO(););
1095
1096#ifdef _DEBUG_IMPL
1097 // This verifies that we won't try and load a type
1098 // if FORBIDGC_LOADER_USE_ENABLED is true.
1099 //
1100 // The FORBIDGC_LOADER_USE is limited to very specific scenarios that need to retrieve
1101 // GC_OTHER typehandles for size and gcroot information. This assert attempts to prevent
1102 // this abuse from proliferating.
1103 //
1104 if (FORBIDGC_LOADER_USE_ENABLED() && (fLoadTypes == ClassLoader::LoadTypes))
1105 {
1106 TypeHandle th = GetTypeHandleThrowing(pModule,
1107 pTypeContext,
1108 ClassLoader::DontLoadTypes,
1109 level,
1110 dropGenericArgumentLevel,
1111 pSubst,
1112 pZapSigContext);
1113 _ASSERTE(!th.IsNull());
1114 }
1115#endif
1116 //
1117 // pOrigModule is the original module that contained this ZapSig
1118 //
1119 Module * pOrigModule = (pZapSigContext != NULL) ? pZapSigContext->pInfoModule : pModule;
1120 ClassLoader::NotFoundAction notFoundAction;
1121 CorInternalStates tdTypes;
1122
1123 switch((DWORD)typ) {
1124 case ELEMENT_TYPE_TYPEDBYREF:
1125 {
1126 thRet = TypeHandle(g_TypedReferenceMT);
1127 break;
1128 }
1129
1130#ifdef FEATURE_PREJIT
1131 case ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG:
1132 {
1133#ifndef DACCESS_COMPILE
1134 TypeHandle baseType = psig.GetTypeHandleThrowing(pModule,
1135 pTypeContext,
1136 fLoadTypes,
1137 level,
1138 dropGenericArgumentLevel,
1139 pSubst,
1140 pZapSigContext);
1141 if (baseType.IsNull())
1142 {
1143 thRet = baseType;
1144 }
1145 else
1146 {
1147 thRet = baseType.GetMethodTable();
1148 }
1149#else
1150 DacNotImpl();
1151 thRet = TypeHandle();
1152#endif
1153 break;
1154 }
1155
1156 case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG:
1157 {
1158#ifndef DACCESS_COMPILE
1159 TypeHandle baseType = psig.GetTypeHandleThrowing(pModule,
1160 pTypeContext,
1161 fLoadTypes,
1162 level,
1163 dropGenericArgumentLevel,
1164 pSubst,
1165 pZapSigContext);
1166 if (baseType.IsNull())
1167 {
1168 thRet = baseType;
1169 }
1170 else
1171 {
1172 thRet = ClassLoader::LoadNativeValueTypeThrowing(baseType, fLoadTypes, level);
1173 }
1174#else
1175 DacNotImpl();
1176 thRet = TypeHandle();
1177#endif
1178 break;
1179 }
1180
1181 case ELEMENT_TYPE_CANON_ZAPSIG:
1182 {
1183#ifndef DACCESS_COMPILE
1184 assert(g_pCanonMethodTableClass != NULL);
1185 thRet = TypeHandle(g_pCanonMethodTableClass);
1186#else
1187 DacNotImpl();
1188 thRet = TypeHandle();
1189#endif
1190 break;
1191 }
1192
1193 case ELEMENT_TYPE_MODULE_ZAPSIG:
1194 {
1195#ifndef DACCESS_COMPILE
1196 DWORD ix;
1197 IfFailThrowBF(psig.GetData(&ix), BFA_BAD_SIGNATURE, pModule);
1198
1199 PREFIX_ASSUME(pZapSigContext != NULL);
1200 pModule = pZapSigContext->GetZapSigModule()->GetModuleFromIndex(ix);
1201
1202 if ((pModule != NULL) && pModule->IsInCurrentVersionBubble())
1203 {
1204 thRet = psig.GetTypeHandleThrowing(pModule,
1205 pTypeContext,
1206 fLoadTypes,
1207 level,
1208 dropGenericArgumentLevel,
1209 pSubst,
1210 pZapSigContext);
1211 }
1212 else
1213 {
1214 // For ReadyToRunCompilation we return a null TypeHandle when we reference a non-local module
1215 //
1216 thRet = TypeHandle();
1217 }
1218#else
1219 DacNotImpl();
1220 thRet = TypeHandle();
1221#endif
1222 break;
1223 }
1224
1225 case ELEMENT_TYPE_VAR_ZAPSIG:
1226 {
1227#ifndef DACCESS_COMPILE
1228 DWORD rid;
1229 IfFailThrowBF(psig.GetData(&rid), BFA_BAD_SIGNATURE, pModule);
1230
1231 mdGenericParam tkTyPar = TokenFromRid(rid, mdtGenericParam);
1232
1233 TypeVarTypeDesc *pTypeVarTypeDesc = pModule->LookupGenericParam(tkTyPar);
1234 if (pTypeVarTypeDesc == NULL && (fLoadTypes == ClassLoader::LoadTypes))
1235 {
1236 mdToken tkOwner;
1237 IfFailThrow(pModule->GetMDImport()->GetGenericParamProps(tkTyPar, NULL, NULL, &tkOwner, NULL, NULL));
1238
1239 if (TypeFromToken(tkOwner) == mdtMethodDef)
1240 {
1241 MemberLoader::GetMethodDescFromMethodDef(pModule, tkOwner, FALSE);
1242 }
1243 else
1244 {
1245 ClassLoader::LoadTypeDefThrowing(pModule, tkOwner,
1246 ClassLoader::ThrowIfNotFound,
1247 ClassLoader::PermitUninstDefOrRef);
1248 }
1249
1250 pTypeVarTypeDesc = pModule->LookupGenericParam(tkTyPar);
1251 if (pTypeVarTypeDesc == NULL)
1252 {
1253 THROW_BAD_FORMAT(BFA_BAD_COMPLUS_SIG, pOrigModule);
1254 }
1255 }
1256 thRet = TypeHandle(pTypeVarTypeDesc);
1257#else
1258 DacNotImpl();
1259 thRet = TypeHandle();
1260#endif
1261 break;
1262 }
1263#endif // FEATURE_PREJIT
1264
1265 case ELEMENT_TYPE_VAR:
1266 {
1267 if ((pSubst != NULL) && !pSubst->GetInst().IsNull())
1268 {
1269#ifdef _DEBUG_IMPL
1270 _ASSERTE(!FORBIDGC_LOADER_USE_ENABLED());
1271#endif
1272 DWORD index;
1273 IfFailThrow(psig.GetData(&index));
1274
1275 SigPointer inst = pSubst->GetInst();
1276 for (DWORD i = 0; i < index; i++)
1277 {
1278 IfFailThrowBF(inst.SkipExactlyOne(), BFA_BAD_SIGNATURE, pOrigModule);
1279 }
1280
1281 thRet = inst.GetTypeHandleThrowing(
1282 pSubst->GetModule(),
1283 pTypeContext,
1284 fLoadTypes,
1285 level,
1286 dropGenericArgumentLevel,
1287 pSubst->GetNext(),
1288 pZapSigContext);
1289 }
1290 else
1291 {
1292 thRet = (psig.GetTypeVariableThrowing(pModule, typ, fLoadTypes, pTypeContext));
1293 if (fLoadTypes == ClassLoader::LoadTypes)
1294 ClassLoader::EnsureLoaded(thRet, level);
1295 }
1296 break;
1297 }
1298
1299 case ELEMENT_TYPE_MVAR:
1300 {
1301 thRet = (psig.GetTypeVariableThrowing(pModule, typ, fLoadTypes, pTypeContext));
1302 if (fLoadTypes == ClassLoader::LoadTypes)
1303 ClassLoader::EnsureLoaded(thRet, level);
1304 break;
1305 }
1306
1307 case ELEMENT_TYPE_GENERICINST:
1308 {
1309 mdTypeDef tkGenericType = mdTypeDefNil;
1310 Module *pGenericTypeModule = NULL;
1311
1312 // Before parsing the generic instantiation, determine if the signature tells us its module and token.
1313 // This is the common case, and when true we can avoid dereferencing the resulting TypeHandle to ask for them.
1314 bool typeAndModuleKnown = false;
1315 if (pZapSigContext && pZapSigContext->externalTokens == ZapSig::NormalTokens && psig.IsTypeDef(&tkGenericType))
1316 {
1317 typeAndModuleKnown = true;
1318 pGenericTypeModule = pModule;
1319 }
1320
1321 TypeHandle genericType = psig.GetGenericInstType(pModule, fLoadTypes, level, pZapSigContext);
1322
1323 if (genericType.IsNull())
1324 {
1325 thRet = genericType;
1326 break;
1327 }
1328
1329 if (!typeAndModuleKnown)
1330 {
1331 tkGenericType = genericType.GetCl();
1332 pGenericTypeModule = genericType.GetModule();
1333 }
1334 else
1335 {
1336 _ASSERTE(tkGenericType == genericType.GetCl());
1337 _ASSERTE(pGenericTypeModule == genericType.GetModule());
1338 }
1339
1340 if (level == CLASS_LOAD_APPROXPARENTS && dropGenericArgumentLevel && genericType.IsInterface())
1341 {
1342 thRet = genericType;
1343 break;
1344 }
1345
1346 // The number of type parameters follows
1347 DWORD ntypars = 0;
1348 IfFailThrowBF(psig.GetData(&ntypars), BFA_BAD_SIGNATURE, pOrigModule);
1349
1350 DWORD dwAllocaSize = 0;
1351 if (!ClrSafeInt<DWORD>::multiply(ntypars, sizeof(TypeHandle), dwAllocaSize))
1352 ThrowHR(COR_E_OVERFLOW);
1353
1354 if ((dwAllocaSize/GetOsPageSize()+1) >= 2)
1355 {
1356 DO_INTERIOR_STACK_PROBE_FOR_NOTHROW_CHECK_THREAD((10+dwAllocaSize/GetOsPageSize()+1), NO_FORBIDGC_LOADER_USE_ThrowSO(););
1357 }
1358 TypeHandle *thisinst = (TypeHandle*) _alloca(dwAllocaSize);
1359
1360 // Finally we gather up the type arguments themselves, loading at the level specified for generic arguments
1361 for (unsigned i = 0; i < ntypars; i++)
1362 {
1363 ClassLoadLevel argLevel = level;
1364 TypeHandle typeHnd = TypeHandle();
1365 BOOL argDrop = FALSE;
1366
1367 if (dropGenericArgumentLevel)
1368 {
1369 if (level == CLASS_LOAD_APPROXPARENTS)
1370 {
1371 SigPointer tempsig = psig;
1372
1373 CorElementType elemType = ELEMENT_TYPE_END;
1374 IfFailThrowBF(tempsig.GetElemType(&elemType), BFA_BAD_SIGNATURE, pOrigModule);
1375
1376 if (elemType == (CorElementType) ELEMENT_TYPE_MODULE_ZAPSIG)
1377 {
1378 // Skip over the module index
1379 IfFailThrowBF(tempsig.GetData(NULL), BFA_BAD_SIGNATURE, pModule);
1380 // Read the next elemType
1381 IfFailThrowBF(tempsig.GetElemType(&elemType), BFA_BAD_SIGNATURE, pModule);
1382 }
1383
1384 if (elemType == ELEMENT_TYPE_GENERICINST)
1385 {
1386 CorElementType tmpEType = ELEMENT_TYPE_END;
1387 IfFailThrowBF(tempsig.PeekElemType(&tmpEType), BFA_BAD_SIGNATURE, pOrigModule);
1388
1389 if (tmpEType == ELEMENT_TYPE_CLASS)
1390 typeHnd = TypeHandle(g_pCanonMethodTableClass);
1391 }
1392 else if ((elemType == (CorElementType) ELEMENT_TYPE_CANON_ZAPSIG) ||
1393 (CorTypeInfo::GetGCType_NoThrow(elemType) == TYPE_GC_REF))
1394 {
1395 typeHnd = TypeHandle(g_pCanonMethodTableClass);
1396 }
1397
1398 argDrop = TRUE;
1399 }
1400 else
1401 // We need to make sure that typekey is always restored. Otherwise, we may run into unrestored typehandles while using
1402 // the typekey for lookups. It is safe to not drop the levels for initial NGen-specific loading levels since there cannot
1403 // be cycles in typekeys.
1404 if (level > CLASS_LOAD_APPROXPARENTS)
1405 {
1406 argLevel = (ClassLoadLevel) (level-1);
1407 }
1408 }
1409
1410 if (typeHnd.IsNull())
1411 {
1412 typeHnd = psig.GetTypeHandleThrowing(pOrigModule,
1413 pTypeContext,
1414 fLoadTypes,
1415 argLevel,
1416 argDrop,
1417 pSubst,
1418 pZapSigContext);
1419 if (typeHnd.IsNull())
1420 {
1421 // Indicate failure by setting thisinst to NULL
1422 thisinst = NULL;
1423 break;
1424 }
1425 }
1426 thisinst[i] = typeHnd;
1427 IfFailThrowBF(psig.SkipExactlyOne(), BFA_BAD_SIGNATURE, pOrigModule);
1428 }
1429
1430 // If we failed to get all of the instantiation type arguments then we return the null type handle
1431 if (thisinst == NULL)
1432 {
1433 thRet = TypeHandle();
1434 break;
1435 }
1436
1437 // Group together the current signature type context and substitution chain, which
1438 // we may later use to instantiate constraints of type arguments that turn out to be
1439 // typespecs, i.e. generic types.
1440 InstantiationContext instContext(pTypeContext, pSubst);
1441
1442 // Now make the instantiated type
1443 // The class loader will check the arity
1444 // When we know it was correctly computed at NGen time, we ask the class loader to skip that check.
1445 thRet = (ClassLoader::LoadGenericInstantiationThrowing(pGenericTypeModule,
1446 tkGenericType,
1447 Instantiation(thisinst, ntypars),
1448 fLoadTypes, level,
1449 &instContext,
1450 pZapSigContext && pZapSigContext->externalTokens == ZapSig::NormalTokens));
1451 break;
1452 }
1453
1454 case ELEMENT_TYPE_CLASS:
1455 // intentional fallthru to ELEMENT_TYPE_VALUETYPE
1456 case ELEMENT_TYPE_VALUETYPE:
1457 {
1458 mdTypeRef typeToken = 0;
1459
1460 IfFailThrowBF(psig.GetToken(&typeToken), BFA_BAD_SIGNATURE, pOrigModule);
1461
1462#if defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
1463 if ((pOrigModule != pModule) && (pZapSigContext->externalTokens == ZapSig::IbcTokens))
1464 {
1465 // ibcExternalType tokens are actually encoded as mdtTypeDef tokens in the signature
1466 RID typeRid = RidFromToken(typeToken);
1467 idExternalType ibcToken = RidToToken(typeRid, ibcExternalType);
1468 typeToken = pOrigModule->LookupIbcTypeToken(pModule, ibcToken);
1469
1470 if (IsNilToken(typeToken))
1471 {
1472 COMPlusThrow(kTypeLoadException, IDS_IBC_MISSING_EXTERNAL_TYPE);
1473 }
1474 }
1475#endif
1476
1477 if ((TypeFromToken(typeToken) != mdtTypeRef) && (TypeFromToken(typeToken) != mdtTypeDef))
1478 THROW_BAD_FORMAT(BFA_UNEXPECTED_TOKEN_AFTER_CLASSVALTYPE, pOrigModule);
1479
1480 if (IsNilToken(typeToken))
1481 THROW_BAD_FORMAT(BFA_UNEXPECTED_TOKEN_AFTER_CLASSVALTYPE, pOrigModule);
1482
1483 if (fLoadTypes == ClassLoader::LoadTypes)
1484 {
1485 notFoundAction = ClassLoader::ThrowButNullV11McppWorkaround;
1486 tdTypes = tdNoTypes;
1487 }
1488 else
1489 {
1490 notFoundAction = ClassLoader::ReturnNullIfNotFound;
1491 tdTypes = tdAllTypes;
1492 }
1493
1494 TypeHandle loadedType =
1495 ClassLoader::LoadTypeDefOrRefThrowing(pModule,
1496 typeToken,
1497 notFoundAction,
1498 // pZapSigContext is only set when decoding zapsigs
1499 // ZapSigs use uninstantiated tokens to represent the GenericTypeDefinition
1500 (pZapSigContext ? ClassLoader::PermitUninstDefOrRef : ClassLoader::FailIfUninstDefOrRef),
1501 tdTypes,
1502 level);
1503
1504 // Everett C++ compiler can generate a TypeRef with RS=0 without respective TypeDef for unmanaged valuetypes,
1505 // referenced only by pointers to them. For this case we treat this as an ELEMENT_TYPE_VOID, and perform the
1506 // same operations as the appropriate case block above.
1507 if (loadedType.IsNull())
1508 {
1509 if (TypeFromToken(typeToken) == mdtTypeRef)
1510 {
1511 loadedType = TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_VOID));
1512 thRet = loadedType;
1513 break;
1514 }
1515 }
1516
1517#ifndef DACCESS_COMPILE
1518 //
1519 // Check that the type that we loaded matches the signature
1520 // with regards to ET_CLASS and ET_VALUETYPE
1521 //
1522 if (fLoadTypes == ClassLoader::LoadTypes)
1523 {
1524 // Skip this check when using zap sigs; it should have been correctly computed at NGen time
1525 // and a change from one to the other would have invalidated the image.
1526 if (pZapSigContext == NULL || pZapSigContext->externalTokens != ZapSig::NormalTokens)
1527 {
1528 bool typFromSigIsClass = (typ == ELEMENT_TYPE_CLASS);
1529 bool typLoadedIsClass = (loadedType.GetSignatureCorElementType() == ELEMENT_TYPE_CLASS);
1530
1531 if (typFromSigIsClass != typLoadedIsClass)
1532 {
1533 if (pModule->GetMDImport()->GetMetadataStreamVersion() != MD_STREAM_VER_1X)
1534 {
1535 pOrigModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(),
1536 typeToken,
1537 BFA_CLASSLOAD_VALUETYPEMISMATCH);
1538 }
1539 }
1540 }
1541
1542 // Assert that our reasoning above was valid (that there is never a zapsig that gets this wrong)
1543 _ASSERTE(((typ == ELEMENT_TYPE_CLASS) == (loadedType.GetSignatureCorElementType() == ELEMENT_TYPE_CLASS)) ||
1544 pZapSigContext == NULL || pZapSigContext->externalTokens != ZapSig::NormalTokens);
1545
1546 }
1547#endif // #ifndef DACCESS_COMPILE
1548
1549 thRet = loadedType;
1550 break;
1551 }
1552
1553 case ELEMENT_TYPE_ARRAY:
1554 case ELEMENT_TYPE_SZARRAY:
1555 {
1556 TypeHandle elemType = psig.GetTypeHandleThrowing(pModule,
1557 pTypeContext,
1558 fLoadTypes,
1559 level,
1560 dropGenericArgumentLevel,
1561 pSubst,
1562 pZapSigContext);
1563 if (elemType.IsNull())
1564 {
1565 thRet = elemType;
1566 break;
1567 }
1568
1569 ULONG rank = 0;
1570 if (typ == ELEMENT_TYPE_ARRAY) {
1571 IfFailThrowBF(psig.SkipExactlyOne(), BFA_BAD_SIGNATURE, pOrigModule);
1572 IfFailThrowBF(psig.GetData(&rank), BFA_BAD_SIGNATURE, pOrigModule);
1573
1574 _ASSERTE(0 < rank);
1575 }
1576 thRet = ClassLoader::LoadArrayTypeThrowing(elemType, typ, rank, fLoadTypes, level);
1577 break;
1578 }
1579
1580 case ELEMENT_TYPE_PINNED:
1581 // Return what follows
1582 thRet = psig.GetTypeHandleThrowing(pModule,
1583 pTypeContext,
1584 fLoadTypes,
1585 level,
1586 dropGenericArgumentLevel,
1587 pSubst,
1588 pZapSigContext);
1589 break;
1590
1591 case ELEMENT_TYPE_BYREF:
1592 case ELEMENT_TYPE_PTR:
1593 {
1594 TypeHandle baseType = psig.GetTypeHandleThrowing(pModule,
1595 pTypeContext,
1596 fLoadTypes,
1597 level,
1598 dropGenericArgumentLevel,
1599 pSubst,
1600 pZapSigContext);
1601 if (baseType.IsNull())
1602 {
1603 thRet = baseType;
1604 }
1605 else
1606 {
1607 thRet = ClassLoader::LoadPointerOrByrefTypeThrowing(typ, baseType, fLoadTypes, level);
1608 }
1609 break;
1610 }
1611
1612 case ELEMENT_TYPE_FNPTR:
1613 {
1614#ifndef DACCESS_COMPILE
1615 ULONG uCallConv = 0;
1616 IfFailThrowBF(psig.GetData(&uCallConv), BFA_BAD_SIGNATURE, pOrigModule);
1617
1618 if ((uCallConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_FIELD)
1619 THROW_BAD_FORMAT(BFA_FNPTR_CANNOT_BE_A_FIELD, pOrigModule);
1620
1621 if ((uCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC) > 0)
1622 THROW_BAD_FORMAT(BFA_FNPTR_CANNOT_BE_GENERIC, pOrigModule);
1623
1624 // Get arg count;
1625 ULONG cArgs = 0;
1626 IfFailThrowBF(psig.GetData(&cArgs), BFA_BAD_SIGNATURE, pOrigModule);
1627
1628 ULONG cAllocaSize;
1629 if (!ClrSafeInt<ULONG>::addition(cArgs, 1, cAllocaSize) ||
1630 !ClrSafeInt<ULONG>::multiply(cAllocaSize, sizeof(TypeHandle), cAllocaSize))
1631 {
1632 ThrowHR(COR_E_OVERFLOW);
1633 }
1634
1635 if ((cAllocaSize/GetOsPageSize()+1) >= 2)
1636 {
1637 DO_INTERIOR_STACK_PROBE_FOR_NOTHROW_CHECK_THREAD((10+cAllocaSize/GetOsPageSize()+1), NO_FORBIDGC_LOADER_USE_ThrowSO(););
1638 }
1639
1640 TypeHandle *retAndArgTypes = (TypeHandle*) _alloca(cAllocaSize);
1641 bool fReturnTypeOrParameterNotLoaded = false;
1642
1643 for (unsigned i = 0; i <= cArgs; i++)
1644 {
1645 retAndArgTypes[i] = psig.GetTypeHandleThrowing(pOrigModule,
1646 pTypeContext,
1647 fLoadTypes,
1648 level,
1649 dropGenericArgumentLevel,
1650 pSubst,
1651 pZapSigContext);
1652 if (retAndArgTypes[i].IsNull())
1653 {
1654 thRet = TypeHandle();
1655 fReturnTypeOrParameterNotLoaded = true;
1656 break;
1657 }
1658
1659 IfFailThrowBF(psig.SkipExactlyOne(), BFA_BAD_SIGNATURE, pOrigModule);
1660 }
1661
1662 if (fReturnTypeOrParameterNotLoaded)
1663 {
1664 break;
1665 }
1666
1667 // Now make the function pointer type
1668 thRet = ClassLoader::LoadFnptrTypeThrowing((BYTE) uCallConv, cArgs, retAndArgTypes, fLoadTypes, level);
1669#else
1670 DacNotImpl();
1671 thRet = TypeHandle();
1672#endif
1673 break;
1674 }
1675
1676 case ELEMENT_TYPE_INTERNAL :
1677 {
1678 TypeHandle hType;
1679 // this check is not functional in DAC and provides no security against a malicious dump
1680 // the DAC is prepared to receive an invalid type handle
1681#ifndef DACCESS_COMPILE
1682 if (pModule->IsSigInIL(m_ptr))
1683 THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module*)pModule);
1684#endif
1685 CorSigUncompressPointer(psig.GetPtr(), (void**)&hType);
1686 thRet = hType;
1687 break;
1688 }
1689
1690 case ELEMENT_TYPE_SENTINEL:
1691 {
1692#ifndef DACCESS_COMPILE
1693
1694 mdToken token = 0;
1695
1696 IfFailThrowBF(psig.GetToken(&token), BFA_BAD_SIGNATURE, pOrigModule);
1697
1698 pOrigModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(),
1699 token,
1700 IDS_CLASSLOAD_GENERAL);
1701#else
1702 DacNotImpl();
1703 break;
1704#endif // #ifndef DACCESS_COMPILE
1705 }
1706
1707 default:
1708#ifdef _DEBUG_IMPL
1709 _ASSERTE(!FORBIDGC_LOADER_USE_ENABLED());
1710#endif
1711 THROW_BAD_FORMAT(BFA_BAD_COMPLUS_SIG, pOrigModule);
1712 }
1713
1714 END_INTERIOR_STACK_PROBE;
1715 }
1716
1717 RETURN thRet;
1718}
1719#ifdef _PREFAST_
1720#pragma warning(pop)
1721#endif
1722
1723TypeHandle SigPointer::GetGenericInstType(Module * pModule,
1724 ClassLoader::LoadTypesFlag fLoadTypes/*=LoadTypes*/,
1725 ClassLoadLevel level/*=CLASS_LOADED*/,
1726 const ZapSig::Context * pZapSigContext)
1727{
1728 CONTRACTL
1729 {
1730 INSTANCE_CHECK;
1731 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1732 MODE_ANY;
1733 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1734 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(return TypeHandle();); }
1735 if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != ClassLoader::LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
1736 SUPPORTS_DAC;
1737 }
1738 CONTRACTL_END
1739
1740 Module * pOrigModule = (pZapSigContext != NULL) ? pZapSigContext->pInfoModule : pModule;
1741
1742 CorElementType typ = ELEMENT_TYPE_END;
1743 IfFailThrowBF(GetElemType(&typ), BFA_BAD_SIGNATURE, pOrigModule);
1744
1745 TypeHandle genericType;
1746
1747 if (typ == ELEMENT_TYPE_INTERNAL)
1748 {
1749 // this check is not functional in DAC and provides no security against a malicious dump
1750 // the DAC is prepared to receive an invalid type handle
1751#ifndef DACCESS_COMPILE
1752 if (pModule->IsSigInIL(m_ptr))
1753 THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module*)pModule);
1754#endif
1755
1756 IfFailThrow(GetPointer((void**)&genericType));
1757 }
1758 else
1759 {
1760 mdToken typeToken = mdTypeRefNil;
1761 IfFailThrowBF(GetToken(&typeToken), BFA_BAD_SIGNATURE, pOrigModule);
1762
1763#if defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
1764 if ((pOrigModule != pModule) && (pZapSigContext->externalTokens == ZapSig::IbcTokens))
1765 {
1766 // ibcExternalType tokens are actually encoded as mdtTypeDef tokens in the signature
1767 RID typeRid = RidFromToken(typeToken);
1768 idExternalType ibcToken = RidToToken(typeRid, ibcExternalType);
1769 typeToken = pOrigModule->LookupIbcTypeToken(pModule, ibcToken);
1770
1771 if (IsNilToken(typeToken))
1772 {
1773 COMPlusThrow(kTypeLoadException, IDS_IBC_MISSING_EXTERNAL_TYPE);
1774 }
1775 }
1776#endif
1777
1778 if ((TypeFromToken(typeToken) != mdtTypeRef) && (TypeFromToken(typeToken) != mdtTypeDef))
1779 THROW_BAD_FORMAT(BFA_UNEXPECTED_TOKEN_AFTER_GENINST, pOrigModule);
1780
1781 if (IsNilToken(typeToken))
1782 THROW_BAD_FORMAT(BFA_UNEXPECTED_TOKEN_AFTER_GENINST, pOrigModule);
1783
1784 ClassLoader::NotFoundAction notFoundAction;
1785 CorInternalStates tdTypes;
1786
1787 if (fLoadTypes == ClassLoader::LoadTypes)
1788 {
1789 notFoundAction = ClassLoader::ThrowIfNotFound;
1790 tdTypes = tdNoTypes;
1791 }
1792 else
1793 {
1794 notFoundAction = ClassLoader::ReturnNullIfNotFound;
1795 tdTypes = tdAllTypes;
1796 }
1797
1798 genericType = ClassLoader::LoadTypeDefOrRefThrowing(pModule,
1799 typeToken,
1800 notFoundAction,
1801 ClassLoader::PermitUninstDefOrRef,
1802 tdTypes,
1803 level);
1804
1805 if (genericType.IsNull())
1806 {
1807 return genericType;
1808 }
1809
1810#ifndef DACCESS_COMPILE
1811 if (fLoadTypes == ClassLoader::LoadTypes)
1812 {
1813 // Skip this check when using zap sigs; it should have been correctly computed at NGen time
1814 // and a change from one to the other would have invalidated the image. Leave in the code for debug so we can assert below.
1815 if (pZapSigContext == NULL || pZapSigContext->externalTokens != ZapSig::NormalTokens)
1816 {
1817 bool typFromSigIsClass = (typ == ELEMENT_TYPE_CLASS);
1818 bool typLoadedIsClass = (genericType.GetSignatureCorElementType() == ELEMENT_TYPE_CLASS);
1819
1820 if (typFromSigIsClass != typLoadedIsClass)
1821 {
1822 pOrigModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(),
1823 typeToken,
1824 BFA_CLASSLOAD_VALUETYPEMISMATCH);
1825 }
1826 }
1827
1828 // Assert that our reasoning above was valid (that there is never a zapsig that gets this wrong)
1829 _ASSERTE(((typ == ELEMENT_TYPE_CLASS) == (genericType.GetSignatureCorElementType() == ELEMENT_TYPE_CLASS)) ||
1830 pZapSigContext == NULL || pZapSigContext->externalTokens != ZapSig::NormalTokens);
1831 }
1832#endif // #ifndef DACCESS_COMPILE
1833 }
1834
1835 return genericType;
1836}
1837
1838// SigPointer should be just after E_T_VAR or E_T_MVAR
1839TypeHandle SigPointer::GetTypeVariableThrowing(Module *pModule, // unused - may be used later for better error reporting
1840 CorElementType et,
1841 ClassLoader::LoadTypesFlag fLoadTypes/*=LoadTypes*/,
1842 const SigTypeContext *pTypeContext)
1843{
1844 CONTRACT(TypeHandle)
1845 {
1846 INSTANCE_CHECK;
1847 PRECONDITION(CorTypeInfo::IsGenericVariable_NoThrow(et));
1848 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1849 MODE_ANY;
1850 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1851 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1852 POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == ClassLoader::LoadTypes) ? NULL_NOT_OK : NULL_OK)));
1853 SUPPORTS_DAC;
1854 }
1855 CONTRACT_END
1856
1857 TypeHandle res = GetTypeVariable(et, pTypeContext);
1858#ifndef DACCESS_COMPILE
1859 if (res.IsNull() && (fLoadTypes == ClassLoader::LoadTypes))
1860 {
1861 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1862 }
1863#endif
1864 RETURN(res);
1865}
1866
1867// SigPointer should be just after E_T_VAR or E_T_MVAR
1868TypeHandle SigPointer::GetTypeVariable(CorElementType et,
1869 const SigTypeContext *pTypeContext)
1870{
1871
1872 CONTRACT(TypeHandle)
1873 {
1874 INSTANCE_CHECK;
1875 PRECONDITION(CorTypeInfo::IsGenericVariable_NoThrow(et));
1876 NOTHROW;
1877 GC_NOTRIGGER;
1878 POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // will return TypeHandle() if index is out of range
1879 SUPPORTS_DAC;
1880#ifndef DACCESS_COMPILE
1881 // POSTCONDITION(RETVAL.IsNull() || RETVAL.IsRestored() || RETVAL.GetMethodTable()->IsRestoring());
1882#endif
1883 MODE_ANY;
1884 }
1885 CONTRACT_END
1886
1887 DWORD index;
1888 if (FAILED(GetData(&index)))
1889 {
1890 TypeHandle thNull;
1891 RETURN(thNull);
1892 }
1893
1894 if (!pTypeContext
1895 ||
1896 (et == ELEMENT_TYPE_VAR &&
1897 (index >= pTypeContext->m_classInst.GetNumArgs()))
1898 ||
1899 (et == ELEMENT_TYPE_MVAR &&
1900 (index >= pTypeContext->m_methodInst.GetNumArgs())))
1901 {
1902 LOG((LF_ALWAYS, LL_INFO1000, "GENERICS: Error: GetTypeVariable on out-of-range type variable\n"));
1903 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid type context: either this is an ill-formed signature (e.g. an invalid type variable number) or you have not provided a non-empty SigTypeContext where one is required. Check back on the callstack for where the value of pTypeContext is first provided, and see if it is acquired from the correct place. For calls originating from a JIT it should be acquired from the context parameter, which indicates the method being compiled. For calls from other locations it should be acquired from the MethodTable, EEClass, TypeHandle, FieldDesc or MethodDesc being analyzed.");
1904 TypeHandle thNull;
1905 RETURN(thNull);
1906 }
1907 if (et == ELEMENT_TYPE_VAR)
1908 {
1909 RETURN(pTypeContext->m_classInst[index]);
1910 }
1911 else
1912 {
1913 RETURN(pTypeContext->m_methodInst[index]);
1914 }
1915}
1916
1917
1918#ifndef DACCESS_COMPILE
1919
1920// Does this type contain class or method type parameters whose instantiation cannot
1921// be determined at JIT-compile time from the instantiations in the method context?
1922// Return a combination of hasClassVar and hasMethodVar flags.
1923// See header file for more info.
1924VarKind SigPointer::IsPolyType(const SigTypeContext *pTypeContext) const
1925{
1926 CONTRACTL
1927 {
1928 INSTANCE_CHECK;
1929 NOTHROW;
1930 GC_NOTRIGGER;
1931 MODE_ANY;
1932 }
1933 CONTRACTL_END
1934
1935 SigPointer psig = *this;
1936 CorElementType typ;
1937
1938 if (FAILED(psig.GetElemType(&typ)))
1939 return hasNoVars;
1940
1941 switch(typ) {
1942 case ELEMENT_TYPE_VAR:
1943 case ELEMENT_TYPE_MVAR:
1944 {
1945 VarKind res = (typ == ELEMENT_TYPE_VAR ? hasClassVar : hasMethodVar);
1946 if (pTypeContext != NULL)
1947 {
1948 TypeHandle ty = psig.GetTypeVariable(typ, pTypeContext);
1949 if (ty.IsCanonicalSubtype())
1950 res = (VarKind) (res | (typ == ELEMENT_TYPE_VAR ? hasSharableClassVar : hasSharableMethodVar));
1951 }
1952 return (res);
1953 }
1954
1955 case ELEMENT_TYPE_U:
1956 case ELEMENT_TYPE_I:
1957 case ELEMENT_TYPE_STRING:
1958 case ELEMENT_TYPE_OBJECT:
1959 case ELEMENT_TYPE_I1:
1960 case ELEMENT_TYPE_U1:
1961 case ELEMENT_TYPE_BOOLEAN:
1962 case ELEMENT_TYPE_I2:
1963 case ELEMENT_TYPE_U2:
1964 case ELEMENT_TYPE_CHAR:
1965 case ELEMENT_TYPE_I4:
1966 case ELEMENT_TYPE_U4:
1967 case ELEMENT_TYPE_I8:
1968 case ELEMENT_TYPE_U8:
1969 case ELEMENT_TYPE_R4:
1970 case ELEMENT_TYPE_R8:
1971 case ELEMENT_TYPE_VOID:
1972 case ELEMENT_TYPE_CLASS:
1973 case ELEMENT_TYPE_VALUETYPE:
1974 case ELEMENT_TYPE_TYPEDBYREF:
1975 return(hasNoVars);
1976
1977 case ELEMENT_TYPE_GENERICINST:
1978 {
1979 VarKind k = psig.IsPolyType(pTypeContext);
1980 if (FAILED(psig.SkipExactlyOne()))
1981 return hasNoVars;
1982
1983 ULONG ntypars;
1984 if(FAILED(psig.GetData(&ntypars)))
1985 return hasNoVars;
1986
1987 for (ULONG i = 0; i < ntypars; i++)
1988 {
1989 k = (VarKind) (psig.IsPolyType(pTypeContext) | k);
1990 if (FAILED(psig.SkipExactlyOne()))
1991 return hasNoVars;
1992 }
1993 return(k);
1994 }
1995
1996 case ELEMENT_TYPE_ARRAY:
1997 case ELEMENT_TYPE_SZARRAY:
1998 case ELEMENT_TYPE_PINNED:
1999 case ELEMENT_TYPE_BYREF:
2000 case ELEMENT_TYPE_PTR:
2001 {
2002 return(psig.IsPolyType(pTypeContext));
2003 }
2004
2005 case ELEMENT_TYPE_FNPTR:
2006 {
2007 if (FAILED(psig.GetData(NULL)))
2008 return hasNoVars;
2009
2010 // Get arg count;
2011 ULONG cArgs;
2012 if (FAILED(psig.GetData(&cArgs)))
2013 return hasNoVars;
2014
2015 VarKind k = psig.IsPolyType(pTypeContext);
2016 if (FAILED(psig.SkipExactlyOne()))
2017 return hasNoVars;
2018
2019 for (unsigned i = 0; i < cArgs; i++)
2020 {
2021 k = (VarKind) (psig.IsPolyType(pTypeContext) | k);
2022 if (FAILED(psig.SkipExactlyOne()))
2023 return hasNoVars;
2024 }
2025
2026 return(k);
2027 }
2028
2029 default:
2030 BAD_FORMAT_NOTHROW_ASSERT(!"Bad type");
2031 }
2032 return(hasNoVars);
2033}
2034
2035BOOL SigPointer::IsStringType(Module* pModule, const SigTypeContext *pTypeContext) const
2036{
2037 WRAPPER_NO_CONTRACT;
2038
2039 return IsStringTypeHelper(pModule, pTypeContext, FALSE);
2040}
2041
2042
2043BOOL SigPointer::IsStringTypeThrowing(Module* pModule, const SigTypeContext *pTypeContext) const
2044{
2045 WRAPPER_NO_CONTRACT;
2046
2047 return IsStringTypeHelper(pModule, pTypeContext, TRUE);
2048}
2049
2050BOOL SigPointer::IsStringTypeHelper(Module* pModule, const SigTypeContext* pTypeContext, BOOL fThrow) const
2051{
2052 CONTRACTL
2053 {
2054 INSTANCE_CHECK;
2055 if (fThrow)
2056 {
2057 THROWS;
2058 GC_TRIGGERS;
2059 }
2060 else
2061 {
2062 NOTHROW;
2063 GC_NOTRIGGER;
2064 }
2065
2066 MODE_ANY;
2067 PRECONDITION(CheckPointer(pModule));
2068 }
2069 CONTRACTL_END
2070
2071 IMDInternalImport *pInternalImport = pModule->GetMDImport();
2072 SigPointer psig = *this;
2073 CorElementType typ;
2074 if (FAILED(psig.GetElemType(&typ)))
2075 {
2076 if (fThrow)
2077 {
2078 ThrowHR(META_E_BAD_SIGNATURE);
2079 }
2080 else
2081 {
2082 return FALSE;
2083 }
2084 }
2085
2086 switch (typ)
2087 {
2088 case ELEMENT_TYPE_STRING :
2089 return TRUE;
2090
2091 case ELEMENT_TYPE_CLASS :
2092 {
2093 LPCUTF8 pclsname;
2094 LPCUTF8 pszNamespace;
2095 mdToken token;
2096
2097 if (FAILED( psig.GetToken(&token)))
2098 {
2099 if (fThrow)
2100 {
2101 ThrowHR(META_E_BAD_SIGNATURE);
2102 }
2103 else
2104 {
2105 return FALSE;
2106 }
2107 }
2108
2109 if (TypeFromToken(token) == mdtTypeDef)
2110 {
2111 if (FAILED(pInternalImport->GetNameOfTypeDef(token, &pclsname, &pszNamespace)))
2112 {
2113 if (fThrow)
2114 {
2115 ThrowHR(COR_E_BADIMAGEFORMAT);
2116 }
2117 else
2118 {
2119 return FALSE;
2120 }
2121 }
2122 }
2123 else
2124 {
2125 BAD_FORMAT_NOTHROW_ASSERT(TypeFromToken(token) == mdtTypeRef);
2126 if (FAILED(pInternalImport->GetNameOfTypeRef(token, &pszNamespace, &pclsname)))
2127 {
2128 if (fThrow)
2129 {
2130 ThrowHR(COR_E_BADIMAGEFORMAT);
2131 }
2132 else
2133 {
2134 return FALSE;
2135 }
2136 }
2137 }
2138
2139 if (strcmp(pclsname, g_StringName) != 0)
2140 return FALSE;
2141
2142 if (pszNamespace == NULL)
2143 return FALSE;
2144
2145 return (strcmp(pszNamespace, g_SystemNS) == 0);
2146 }
2147
2148 case ELEMENT_TYPE_VAR :
2149 case ELEMENT_TYPE_MVAR :
2150 {
2151 TypeHandle ty;
2152
2153 if (fThrow)
2154 {
2155 ty = psig.GetTypeVariableThrowing(pModule, typ, ClassLoader::LoadTypes, pTypeContext);
2156 }
2157 else
2158 {
2159 ty = psig.GetTypeVariable(typ, pTypeContext);
2160 }
2161
2162 TypeHandle th(g_pStringClass);
2163 return (ty == th);
2164 }
2165
2166 default:
2167 break;
2168 }
2169 return FALSE;
2170}
2171
2172
2173//------------------------------------------------------------------------
2174// Tests if the element class name is szClassName.
2175//------------------------------------------------------------------------
2176BOOL SigPointer::IsClass(Module* pModule, LPCUTF8 szClassName, const SigTypeContext *pTypeContext) const
2177{
2178 WRAPPER_NO_CONTRACT;
2179
2180 return IsClassHelper(pModule, szClassName, pTypeContext, FALSE);
2181}
2182
2183
2184//------------------------------------------------------------------------
2185// Tests if the element class name is szClassName.
2186//------------------------------------------------------------------------
2187BOOL SigPointer::IsClassThrowing(Module* pModule, LPCUTF8 szClassName, const SigTypeContext *pTypeContext) const
2188{
2189 WRAPPER_NO_CONTRACT;
2190
2191 return IsClassHelper(pModule, szClassName, pTypeContext, TRUE);
2192}
2193
2194BOOL SigPointer::IsClassHelper(Module* pModule, LPCUTF8 szClassName, const SigTypeContext* pTypeContext, BOOL fThrow) const
2195{
2196 CONTRACTL
2197 {
2198 INSTANCE_CHECK;
2199
2200 if (fThrow)
2201 {
2202 THROWS;
2203 GC_TRIGGERS;
2204 }
2205 else
2206 {
2207 NOTHROW;
2208 GC_NOTRIGGER;
2209 }
2210
2211 MODE_ANY;
2212 PRECONDITION(CheckPointer(pModule));
2213 PRECONDITION(CheckPointer(szClassName));
2214 }
2215 CONTRACTL_END
2216
2217 SigPointer psig = *this;
2218 CorElementType typ;
2219 if (FAILED(psig.GetElemType(&typ)))
2220 {
2221 if (fThrow)
2222 ThrowHR(META_E_BAD_SIGNATURE);
2223 else
2224 return FALSE;
2225 }
2226
2227 BAD_FORMAT_NOTHROW_ASSERT((typ == ELEMENT_TYPE_VAR) || (typ == ELEMENT_TYPE_MVAR) ||
2228 (typ == ELEMENT_TYPE_CLASS) || (typ == ELEMENT_TYPE_VALUETYPE) ||
2229 (typ == ELEMENT_TYPE_OBJECT) || (typ == ELEMENT_TYPE_STRING) ||
2230 (typ == ELEMENT_TYPE_INTERNAL) || (typ == ELEMENT_TYPE_GENERICINST));
2231
2232
2233 if (typ == ELEMENT_TYPE_VAR || typ == ELEMENT_TYPE_MVAR)
2234 {
2235 TypeHandle ty;
2236
2237 if (fThrow)
2238 ty = psig.GetTypeVariableThrowing(pModule, typ, ClassLoader::LoadTypes, pTypeContext);
2239 else
2240 ty = psig.GetTypeVariable(typ, pTypeContext);
2241
2242 return(!ty.IsNull() && IsTypeRefOrDef(szClassName, ty.GetModule(), ty.GetCl()));
2243 }
2244 else if ((typ == ELEMENT_TYPE_CLASS) || (typ == ELEMENT_TYPE_VALUETYPE))
2245 {
2246 mdTypeRef typeref;
2247 if (FAILED(psig.GetToken(&typeref)))
2248 {
2249 if (fThrow)
2250 ThrowHR(META_E_BAD_SIGNATURE);
2251 else
2252 return FALSE;
2253 }
2254
2255 return( IsTypeRefOrDef(szClassName, pModule, typeref) );
2256 }
2257 else if (typ == ELEMENT_TYPE_OBJECT)
2258 {
2259 return( !strcmp(szClassName, g_ObjectClassName) );
2260 }
2261 else if (typ == ELEMENT_TYPE_STRING)
2262 {
2263 return( !strcmp(szClassName, g_StringClassName) );
2264 }
2265 else if (typ == ELEMENT_TYPE_INTERNAL)
2266 {
2267 TypeHandle th;
2268
2269 // this check is not functional in DAC and provides no security against a malicious dump
2270 // the DAC is prepared to receive an invalid type handle
2271#ifndef DACCESS_COMPILE
2272 if (pModule->IsSigInIL(m_ptr))
2273 {
2274 if (fThrow)
2275 ThrowHR(META_E_BAD_SIGNATURE);
2276 else
2277 return FALSE;
2278 }
2279#endif
2280
2281 CorSigUncompressPointer(psig.GetPtr(), (void**)&th);
2282 _ASSERTE(!th.IsNull());
2283 return(IsTypeRefOrDef(szClassName, th.GetModule(), th.GetCl()));
2284 }
2285
2286 return( false );
2287}
2288
2289//------------------------------------------------------------------------
2290// Tests for the existence of a custom modifier
2291//------------------------------------------------------------------------
2292BOOL SigPointer::HasCustomModifier(Module *pModule, LPCSTR szModName, CorElementType cmodtype) const
2293{
2294 CONTRACTL
2295 {
2296 INSTANCE_CHECK;
2297 NOTHROW;
2298 GC_NOTRIGGER;
2299 FORBID_FAULT;
2300 MODE_ANY;
2301 }
2302 CONTRACTL_END
2303
2304
2305 BAD_FORMAT_NOTHROW_ASSERT(cmodtype == ELEMENT_TYPE_CMOD_OPT || cmodtype == ELEMENT_TYPE_CMOD_REQD);
2306
2307 SigPointer sp = *this;
2308 CorElementType etyp;
2309 if (sp.AtSentinel())
2310 sp.m_ptr++;
2311
2312 BYTE data;
2313
2314 if (FAILED(sp.GetByte(&data)))
2315 return FALSE;
2316
2317 etyp = (CorElementType)data;
2318
2319
2320 while (etyp == ELEMENT_TYPE_CMOD_OPT || etyp == ELEMENT_TYPE_CMOD_REQD) {
2321
2322 mdToken tk;
2323 if (FAILED(sp.GetToken(&tk)))
2324 return FALSE;
2325
2326 if (etyp == cmodtype && IsTypeRefOrDef(szModName, pModule, tk))
2327 {
2328 return(TRUE);
2329 }
2330
2331 if (FAILED(sp.GetByte(&data)))
2332 return FALSE;
2333
2334 etyp = (CorElementType)data;
2335
2336
2337 }
2338 return(FALSE);
2339}
2340
2341#endif // #ifndef DACCESS_COMPILE
2342
2343//------------------------------------------------------------------------
2344// Tests for ELEMENT_TYPE_CLASS or ELEMENT_TYPE_VALUETYPE followed by a TypeDef,
2345// and returns the TypeDef
2346//------------------------------------------------------------------------
2347BOOL SigPointer::IsTypeDef(mdTypeDef* pTypeDef) const
2348{
2349 CONTRACTL
2350 {
2351 INSTANCE_CHECK;
2352 NOTHROW;
2353 GC_NOTRIGGER;
2354 FORBID_FAULT;
2355 MODE_ANY;
2356 }
2357 CONTRACTL_END;
2358
2359 SigPointer sigTemp(*this);
2360
2361 CorElementType etype = ELEMENT_TYPE_END;
2362 HRESULT hr = sigTemp.GetElemType(&etype);
2363 if (FAILED(hr))
2364 return FALSE;
2365
2366 if (etype != ELEMENT_TYPE_CLASS && etype != ELEMENT_TYPE_VALUETYPE)
2367 return FALSE;
2368
2369 mdToken token = mdTypeRefNil;
2370 hr = sigTemp.GetToken(&token);
2371 if (FAILED(hr))
2372 return FALSE;
2373
2374 if (TypeFromToken(token) != mdtTypeDef)
2375 return FALSE;
2376
2377 if (pTypeDef)
2378 *pTypeDef = (mdTypeDef)token;
2379
2380 return TRUE;
2381}
2382
2383CorElementType SigPointer::PeekElemTypeNormalized(Module* pModule, const SigTypeContext *pTypeContext, TypeHandle * pthValueType) const
2384{
2385 CONTRACTL
2386 {
2387 INSTANCE_CHECK;
2388 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2389 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2390 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2391 MODE_ANY;
2392 SO_TOLERANT;
2393 SUPPORTS_DAC;
2394 }
2395 CONTRACTL_END
2396
2397 CorElementType type = PeekElemTypeClosed(pModule, pTypeContext);
2398 _ASSERTE(type != ELEMENT_TYPE_INTERNAL);
2399
2400 if (type == ELEMENT_TYPE_VALUETYPE)
2401 {
2402 BEGIN_SO_INTOLERANT_CODE(GetThread());
2403 {
2404 // Everett C++ compiler can generate a TypeRef with RS=0
2405 // without respective TypeDef for unmanaged valuetypes,
2406 // referenced only by pointers to them.
2407 // In such case, GetTypeHandleThrowing returns null handle,
2408 // and we return E_T_VOID
2409 TypeHandle th = GetTypeHandleThrowing(pModule, pTypeContext, ClassLoader::LoadTypes, CLASS_LOAD_APPROXPARENTS, TRUE);
2410 if(th.IsNull())
2411 {
2412 th = TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_VOID));
2413 }
2414
2415 type = th.GetInternalCorElementType();
2416 if (pthValueType != NULL)
2417 *pthValueType = th;
2418 }
2419 END_SO_INTOLERANT_CODE;
2420 }
2421
2422 return(type);
2423}
2424
2425//---------------------------------------------------------------------------------------
2426//
2427CorElementType
2428SigPointer::PeekElemTypeClosed(
2429 Module * pModule,
2430 const SigTypeContext * pTypeContext) const
2431{
2432 CONTRACTL
2433 {
2434 INSTANCE_CHECK;
2435 NOTHROW;
2436 GC_NOTRIGGER;
2437 FORBID_FAULT;
2438 MODE_ANY;
2439 SO_TOLERANT;
2440 SUPPORTS_DAC;
2441 }
2442 CONTRACTL_END
2443
2444
2445 CorElementType type;
2446
2447 if (FAILED(PeekElemType(&type)))
2448 return ELEMENT_TYPE_END;
2449
2450 if ((type == ELEMENT_TYPE_GENERICINST) ||
2451 (type == ELEMENT_TYPE_VAR) ||
2452 (type == ELEMENT_TYPE_MVAR) ||
2453 (type == ELEMENT_TYPE_INTERNAL))
2454 {
2455 SigPointer sp(*this);
2456 if (FAILED(sp.GetElemType(NULL))) // skip over E_T_XXX
2457 return ELEMENT_TYPE_END;
2458
2459 switch (type)
2460 {
2461 case ELEMENT_TYPE_GENERICINST:
2462 {
2463 if (FAILED(sp.GetElemType(&type)))
2464 return ELEMENT_TYPE_END;
2465
2466 if (type != ELEMENT_TYPE_INTERNAL)
2467 return type;
2468 }
2469
2470 // intentionally fall through
2471 case ELEMENT_TYPE_INTERNAL:
2472 {
2473 TypeHandle th;
2474
2475 // this check is not functional in DAC and provides no security against a malicious dump
2476 // the DAC is prepared to receive an invalid type handle
2477#ifndef DACCESS_COMPILE
2478 if ((pModule != NULL) && pModule->IsSigInIL(m_ptr))
2479 {
2480 return ELEMENT_TYPE_END;
2481 }
2482#endif
2483
2484 if (FAILED(sp.GetPointer((void **)&th)))
2485 {
2486 return ELEMENT_TYPE_END;
2487 }
2488 _ASSERTE(!th.IsNull());
2489
2490 return th.GetSignatureCorElementType();
2491 }
2492 case ELEMENT_TYPE_VAR :
2493 case ELEMENT_TYPE_MVAR :
2494 {
2495 TypeHandle th = sp.GetTypeVariable(type, pTypeContext);
2496 if (th.IsNull())
2497 {
2498 BAD_FORMAT_NOTHROW_ASSERT(!"You either have bad signature or caller forget to pass valid type context");
2499 return ELEMENT_TYPE_END;
2500 }
2501
2502 return th.GetSignatureCorElementType();
2503 }
2504 default:
2505 UNREACHABLE();
2506 }
2507 }
2508
2509 return type;
2510} // SigPointer::PeekElemTypeClosed
2511
2512
2513//---------------------------------------------------------------------------------------
2514//
2515mdTypeRef SigPointer::PeekValueTypeTokenClosed(Module *pModule, const SigTypeContext *pTypeContext, Module **ppModuleOfToken) const
2516{
2517 CONTRACTL
2518 {
2519 INSTANCE_CHECK;
2520 NOTHROW;
2521 GC_NOTRIGGER;
2522 PRECONDITION(PeekElemTypeClosed(NULL, pTypeContext) == ELEMENT_TYPE_VALUETYPE);
2523 FORBID_FAULT;
2524 MODE_ANY;
2525 SO_TOLERANT;
2526 }
2527 CONTRACTL_END
2528
2529
2530 mdToken token;
2531 CorElementType type;
2532
2533 *ppModuleOfToken = pModule;
2534
2535 if (FAILED(PeekElemType(&type)))
2536 return mdTokenNil;
2537
2538 switch (type)
2539 {
2540 case ELEMENT_TYPE_GENERICINST:
2541 {
2542 SigPointer sp(*this);
2543 if (FAILED(sp.GetElemType(NULL)))
2544 return mdTokenNil;
2545
2546 CorElementType subtype;
2547 if (FAILED(sp.GetElemType(&subtype)))
2548 return mdTokenNil;
2549 if (subtype == ELEMENT_TYPE_INTERNAL)
2550 return mdTokenNil;
2551 _ASSERTE(subtype == ELEMENT_TYPE_VALUETYPE);
2552
2553 if (FAILED(sp.GetToken(&token)))
2554 return mdTokenNil;
2555
2556 return token;
2557 }
2558 case ELEMENT_TYPE_VAR :
2559 case ELEMENT_TYPE_MVAR :
2560 {
2561 SigPointer sp(*this);
2562
2563 if (FAILED(sp.GetElemType(NULL)))
2564 return mdTokenNil;
2565
2566 TypeHandle th = sp.GetTypeVariable(type, pTypeContext);
2567 *ppModuleOfToken = th.GetModule();
2568 _ASSERTE(!th.IsNull());
2569 return(th.GetCl());
2570 }
2571 case ELEMENT_TYPE_INTERNAL:
2572 // we have no way to give back a token for the E_T_INTERNAL so we return a null one
2573 // and make the caller deal with it
2574 return mdTokenNil;
2575
2576 default:
2577 {
2578 _ASSERTE(type == ELEMENT_TYPE_VALUETYPE);
2579 SigPointer sp(*this);
2580
2581 if (FAILED(sp.GetElemType(NULL)))
2582 return mdTokenNil;
2583
2584 if (FAILED(sp.GetToken(&token)))
2585 return mdTokenNil;
2586
2587 return token;
2588 }
2589 }
2590}
2591
2592//---------------------------------------------------------------------------------------
2593//
2594UINT MetaSig::GetElemSize(CorElementType etype, TypeHandle thValueType)
2595{
2596 CONTRACTL
2597 {
2598 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2599 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2600 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2601 MODE_ANY;
2602 SUPPORTS_DAC;
2603 }
2604 CONTRACTL_END
2605
2606 if ((UINT)etype >= COUNTOF(gElementTypeInfo))
2607 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_COMPLUS_SIG);
2608
2609 int cbsize = gElementTypeInfo[(UINT)etype].m_cbSize;
2610 if (cbsize != -1)
2611 return(cbsize);
2612
2613 if (!thValueType.IsNull())
2614 return thValueType.GetSize();
2615
2616 if (etype == ELEMENT_TYPE_VAR || etype == ELEMENT_TYPE_MVAR)
2617 {
2618 LOG((LF_ALWAYS, LL_INFO1000, "GENERICS: Warning: SizeOf on VAR without instantiation\n"));
2619 return(sizeof(LPVOID));
2620 }
2621
2622 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_ELEM_IN_SIZEOF);
2623}
2624
2625//---------------------------------------------------------------------------------------
2626//
2627// Assumes that the SigPointer points to the start of an element type.
2628// Returns size of that element in bytes. This is the minimum size that a
2629// field of this type would occupy inside an object.
2630//
2631UINT SigPointer::SizeOf(Module* pModule, const SigTypeContext *pTypeContext) const
2632{
2633 CONTRACTL
2634 {
2635 INSTANCE_CHECK;
2636 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2637 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2638 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2639 MODE_ANY;
2640 UNCHECKED(PRECONDITION(CheckPointer(pModule)));
2641 UNCHECKED(PRECONDITION(CheckPointer(pTypeContext, NULL_OK)));
2642 SUPPORTS_DAC;
2643 }
2644 CONTRACTL_END
2645
2646 TypeHandle thValueType;
2647 CorElementType etype = PeekElemTypeNormalized(pModule, pTypeContext, &thValueType);
2648 return MetaSig::GetElemSize(etype, thValueType);
2649}
2650
2651#ifndef DACCESS_COMPILE
2652
2653//---------------------------------------------------------------------------------------
2654//
2655// Determines if the current argument is System.String.
2656// Caller must determine first that the argument type is ELEMENT_TYPE_CLASS.
2657//
2658BOOL MetaSig::IsStringType() const
2659{
2660 WRAPPER_NO_CONTRACT
2661
2662 return m_pLastType.IsStringType(m_pModule, &m_typeContext);
2663}
2664
2665//---------------------------------------------------------------------------------------
2666//
2667// Determines if the current argument is a particular class.
2668// Caller must determine first that the argument type is ELEMENT_TYPE_CLASS.
2669//
2670BOOL MetaSig::IsClass(LPCUTF8 szClassName) const
2671{
2672 WRAPPER_NO_CONTRACT
2673
2674 return m_pLastType.IsClass(m_pModule, szClassName, &m_typeContext);
2675}
2676
2677//---------------------------------------------------------------------------------------
2678//
2679// Return the type of an reference if the array is the param type
2680// The arg type must be an ELEMENT_TYPE_BYREF
2681// ref to array needs additional arg
2682//
2683CorElementType MetaSig::GetByRefType(TypeHandle *pTy) const
2684{
2685 CONTRACTL
2686 {
2687 INSTANCE_CHECK;
2688 THROWS;
2689 GC_TRIGGERS;
2690 INJECT_FAULT(COMPlusThrowOM());
2691 MODE_ANY;
2692 }
2693 CONTRACTL_END
2694
2695 SigPointer sigptr(m_pLastType);
2696
2697 CorElementType typ = ELEMENT_TYPE_END;
2698 IfFailThrowBF(sigptr.GetElemType(&typ), BFA_BAD_SIGNATURE, GetModule());
2699
2700 _ASSERTE(typ == ELEMENT_TYPE_BYREF);
2701 typ = (CorElementType)sigptr.PeekElemTypeClosed(GetModule(), &m_typeContext);
2702
2703 if (!CorIsPrimitiveType(typ))
2704 {
2705 if (typ == ELEMENT_TYPE_TYPEDBYREF)
2706 THROW_BAD_FORMAT(BFA_TYPEDBYREFCANNOTHAVEBYREF, GetModule());
2707 TypeHandle th = sigptr.GetTypeHandleThrowing(m_pModule, &m_typeContext);
2708 *pTy = th;
2709 return(th.GetSignatureCorElementType());
2710 }
2711 return(typ);
2712}
2713
2714//---------------------------------------------------------------------------------------
2715//
2716HRESULT CompareTypeTokensNT(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModule2)
2717{
2718 STATIC_CONTRACT_NOTHROW;
2719
2720 HRESULT hr = S_OK;
2721 EX_TRY
2722 {
2723 if (CompareTypeTokens(tk1, tk2, pModule1, pModule2))
2724 hr = S_OK;
2725 else
2726 hr = S_FALSE;
2727 }
2728 EX_CATCH_HRESULT_NO_ERRORINFO(hr);
2729 return hr;
2730}
2731
2732#ifdef FEATURE_TYPEEQUIVALENCE
2733
2734//---------------------------------------------------------------------------------------
2735//
2736// Returns S_FALSE if the type is not decorated with TypeIdentifierAttribute.
2737//
2738HRESULT TypeIdentifierData::Init(Module *pModule, mdToken tk)
2739{
2740 CONTRACTL
2741 {
2742 NOTHROW;
2743 GC_NOTRIGGER;
2744 MODE_ANY;
2745 PRECONDITION(CheckPointer(pModule));
2746 PRECONDITION(TypeFromToken(tk) == mdtTypeDef);
2747 }
2748 CONTRACTL_END
2749
2750 IMDInternalImport *pInternalImport = pModule->GetMDImport();
2751 HRESULT hr = S_OK;
2752
2753 DWORD dwAttrType;
2754 IfFailRet(pInternalImport->GetTypeDefProps(tk, &dwAttrType, NULL));
2755
2756 if (IsTdWindowsRuntime(dwAttrType))
2757 {
2758 // no type equivalence support for WinRT types
2759 return S_FALSE;
2760 }
2761
2762 ULONG cbData;
2763 const BYTE *pData;
2764
2765 IfFailRet(pInternalImport->GetCustomAttributeByName(
2766 tk,
2767 g_TypeIdentifierAttributeClassName,
2768 (const void **)&pData,
2769 &cbData));
2770
2771 if (hr == S_OK)
2772 {
2773 CustomAttributeParser caType(pData, cbData);
2774
2775 if (cbData > 4)
2776 {
2777 // parameterless blob is 01 00 00 00 which means that the two arguments must follow now
2778 CaArg args[2];
2779
2780 args[0].Init(SERIALIZATION_TYPE_STRING, 0);
2781 args[1].Init(SERIALIZATION_TYPE_STRING, 0);
2782 IfFailRet(ParseKnownCaArgs(caType, args, lengthof(args)));
2783
2784 m_cbScope = args[0].val.str.cbStr;
2785 m_pchScope = args[0].val.str.pStr;
2786 m_cbIdentifierName = args[1].val.str.cbStr;
2787 m_pchIdentifierName = args[1].val.str.pStr;
2788 }
2789 else
2790 {
2791 // no arguments follow but we should still verify the blob
2792 IfFailRet(caType.ValidateProlog());
2793 }
2794 }
2795 else
2796 {
2797 // no TypeIdentifierAttribute -> the assembly must be a type library
2798 bool has_eq = !pModule->GetAssembly()->IsDynamic();
2799
2800#ifdef FEATURE_COMINTEROP
2801 has_eq = has_eq && pModule->GetAssembly()->IsPIAOrImportedFromTypeLib();
2802#endif // FEATURE_COMINTEROP
2803
2804 if (!has_eq)
2805 {
2806 // this type is not opted into type equivalence
2807 return S_FALSE;
2808 }
2809 }
2810
2811 if (m_pchIdentifierName == NULL)
2812 {
2813 // we have got no data from the TypeIdentifier attribute -> we have to get it elsewhere
2814 if (IsTdInterface(dwAttrType) && IsTdImport(dwAttrType))
2815 {
2816 // ComImport interfaces get scope from their GUID
2817 hr = pInternalImport->GetCustomAttributeByName(tk, INTEROP_GUID_TYPE, (const void **)&pData, &cbData);
2818 }
2819 else
2820 {
2821 // other equivalent types get it from the declaring assembly
2822 IMDInternalImport *pAssemblyImport = pModule->GetAssembly()->GetManifestImport();
2823 hr = pAssemblyImport->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly), INTEROP_GUID_TYPE, (const void **)&pData, &cbData);
2824 }
2825
2826 if (hr != S_OK)
2827 {
2828 // no GUID is available
2829 return hr;
2830 }
2831
2832 CustomAttributeParser caType(pData, cbData);
2833 CaArg guidarg;
2834
2835 guidarg.Init(SERIALIZATION_TYPE_STRING, 0);
2836 IfFailRet(ParseKnownCaArgs(caType, &guidarg, 1));
2837
2838 m_cbScope = guidarg.val.str.cbStr;
2839 m_pchScope = guidarg.val.str.pStr;
2840
2841 // all types get their identifier from their namespace and name
2842 LPCUTF8 pszName;
2843 LPCUTF8 pszNamespace;
2844 IfFailRet(pInternalImport->GetNameOfTypeDef(tk, &pszName, &pszNamespace));
2845
2846 m_cbIdentifierNamespace = (pszNamespace != NULL ? strlen(pszNamespace) : 0);
2847 m_pchIdentifierNamespace = pszNamespace;
2848
2849 m_cbIdentifierName = strlen(pszName);
2850 m_pchIdentifierName = pszName;
2851
2852 hr = S_OK;
2853 }
2854
2855 return hr;
2856}
2857
2858//---------------------------------------------------------------------------------------
2859//
2860BOOL TypeIdentifierData::IsEqual(const TypeIdentifierData & data) const
2861{
2862 LIMITED_METHOD_CONTRACT;
2863
2864 // scope needs to be the same
2865 if (m_cbScope != data.m_cbScope || _strnicmp(m_pchScope, data.m_pchScope, m_cbScope) != 0)
2866 return FALSE;
2867
2868 // identifier needs to be the same
2869 if (m_cbIdentifierNamespace == 0 && data.m_cbIdentifierNamespace == 0)
2870 {
2871 // we are comparing only m_pchIdentifierName
2872 return (m_cbIdentifierName == data.m_cbIdentifierName) &&
2873 (memcmp(m_pchIdentifierName, data.m_pchIdentifierName, m_cbIdentifierName) == 0);
2874 }
2875
2876 if (m_cbIdentifierNamespace != 0 && data.m_cbIdentifierNamespace != 0)
2877 {
2878 // we are comparing both m_pchIdentifierNamespace and m_pchIdentifierName
2879 return (m_cbIdentifierName == data.m_cbIdentifierName) &&
2880 (m_cbIdentifierNamespace == data.m_cbIdentifierNamespace) &&
2881 (memcmp(m_pchIdentifierName, data.m_pchIdentifierName, m_cbIdentifierName) == 0) &&
2882 (memcmp(m_pchIdentifierNamespace, data.m_pchIdentifierNamespace, m_cbIdentifierNamespace) == 0);
2883 }
2884
2885 if (m_cbIdentifierNamespace == 0 && data.m_cbIdentifierNamespace != 0)
2886 {
2887 // we are comparing m_cbIdentifierName with (data.m_pchIdentifierNamespace + '.' + data.m_pchIdentifierName)
2888 if (m_cbIdentifierName != data.m_cbIdentifierNamespace + 1 + data.m_cbIdentifierName)
2889 return FALSE;
2890
2891 return (memcmp(m_pchIdentifierName, data.m_pchIdentifierNamespace, data.m_cbIdentifierNamespace) == 0) &&
2892 (m_pchIdentifierName[data.m_cbIdentifierNamespace] == NAMESPACE_SEPARATOR_CHAR) &&
2893 (memcmp(m_pchIdentifierName + data.m_cbIdentifierNamespace + 1, data.m_pchIdentifierName, data.m_cbIdentifierName) == 0);
2894 }
2895
2896 _ASSERTE(m_cbIdentifierNamespace != 0 && data.m_cbIdentifierNamespace == 0);
2897
2898 // we are comparing (m_pchIdentifierNamespace + '.' + m_pchIdentifierName) with data.m_cbIdentifierName
2899 if (m_cbIdentifierNamespace + 1 + m_cbIdentifierName != data.m_cbIdentifierName)
2900 return FALSE;
2901
2902 return (memcmp(m_pchIdentifierNamespace, data.m_pchIdentifierName, m_cbIdentifierNamespace) == 0) &&
2903 (data.m_pchIdentifierName[m_cbIdentifierNamespace] == NAMESPACE_SEPARATOR_CHAR) &&
2904 (memcmp(m_pchIdentifierName, data.m_pchIdentifierName + m_cbIdentifierNamespace + 1, m_cbIdentifierName) == 0);
2905}
2906
2907//---------------------------------------------------------------------------------------
2908//
2909static BOOL CompareStructuresForEquivalence(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModule2, BOOL fEnumMode, TokenPairList *pVisited)
2910{
2911 CONTRACTL
2912 {
2913 THROWS;
2914 GC_TRIGGERS;
2915 MODE_ANY;
2916 }
2917 CONTRACTL_END
2918
2919 // make sure the types don't declare any methods
2920 IMDInternalImport *pInternalImport1 = pModule1->GetMDImport();
2921 IMDInternalImport *pInternalImport2 = pModule2->GetMDImport();
2922
2923 HENUMInternalHolder hMethodEnum1(pInternalImport1);
2924 HENUMInternalHolder hMethodEnum2(pInternalImport2);
2925
2926 hMethodEnum1.EnumInit(mdtMethodDef, tk1);
2927 hMethodEnum2.EnumInit(mdtMethodDef, tk2);
2928
2929 if (hMethodEnum1.EnumGetCount() != 0 || hMethodEnum2.EnumGetCount() != 0)
2930 return FALSE;
2931
2932 // compare field types for equivalence
2933 HENUMInternalHolder hFieldEnum1(pInternalImport1);
2934 HENUMInternalHolder hFieldEnum2(pInternalImport2);
2935
2936 hFieldEnum1.EnumInit(mdtFieldDef, tk1);
2937 hFieldEnum2.EnumInit(mdtFieldDef, tk2);
2938
2939 while (true)
2940 {
2941 mdToken tkField1, tkField2;
2942
2943 DWORD dwAttrField1, dwAttrField2;
2944 bool res1, res2;
2945
2946 while ((res1 = hFieldEnum1.EnumNext(&tkField1)) == true)
2947 {
2948 IfFailThrow(pInternalImport1->GetFieldDefProps(tkField1, &dwAttrField1));
2949
2950 if (IsFdPublic(dwAttrField1) && !IsFdStatic(dwAttrField1))
2951 break;
2952
2953 if (!fEnumMode || !IsFdLiteral(dwAttrField1)) // ignore literals in enums
2954 return FALSE;
2955 }
2956
2957 while ((res2 = hFieldEnum2.EnumNext(&tkField2)) == true)
2958 {
2959 IfFailThrow(pInternalImport2->GetFieldDefProps(tkField2, &dwAttrField2));
2960
2961 if (IsFdPublic(dwAttrField2) && !IsFdStatic(dwAttrField2))
2962 break;
2963
2964 if (!fEnumMode || !IsFdLiteral(dwAttrField2)) // ignore literals in enums
2965 return FALSE;
2966 }
2967
2968 if (!res1 && !res2)
2969 {
2970 // we ran out of fields in both types
2971 break;
2972 }
2973
2974 if (res1 != res2)
2975 {
2976 // we ran out of fields in one type
2977 return FALSE;
2978 }
2979
2980 // now we have tokens of two instance fields that need to be compared for equivalence
2981 PCCOR_SIGNATURE pSig1, pSig2;
2982 DWORD cbSig1, cbSig2;
2983
2984 IfFailThrow(pInternalImport1->GetSigOfFieldDef(tkField1, &cbSig1, &pSig1));
2985 IfFailThrow(pInternalImport2->GetSigOfFieldDef(tkField2, &cbSig2, &pSig2));
2986
2987 if (!MetaSig::CompareFieldSigs(pSig1, cbSig1, pModule1, pSig2, cbSig2, pModule2, pVisited))
2988 return FALSE;
2989 }
2990
2991 if (!fEnumMode)
2992 {
2993 // compare layout (layout kind, charset, packing, size, offsets, marshaling)
2994 if (!CompareTypeLayout(tk1, tk2, pModule1, pModule2))
2995 return FALSE;
2996 }
2997
2998 return TRUE;
2999}
3000
3001//---------------------------------------------------------------------------------------
3002//
3003static void GetDelegateInvokeMethodSignature(mdToken tkDelegate, Module *pModule, DWORD *pcbSig, PCCOR_SIGNATURE *ppSig)
3004{
3005 CONTRACTL
3006 {
3007 THROWS;
3008 GC_NOTRIGGER;
3009 MODE_ANY;
3010 }
3011 CONTRACTL_END
3012
3013 IMDInternalImport *pInternalImport = pModule->GetMDImport();
3014
3015 HENUMInternalHolder hEnum(pInternalImport);
3016 hEnum.EnumInit(mdtMethodDef, tkDelegate);
3017
3018 mdToken tkMethod;
3019 while (hEnum.EnumNext(&tkMethod))
3020 {
3021 LPCUTF8 pszName;
3022 IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tkMethod, ppSig, pcbSig, &pszName));
3023
3024 if (strcmp(pszName, "Invoke") == 0)
3025 return;
3026 }
3027
3028 ThrowHR(COR_E_BADIMAGEFORMAT);
3029}
3030
3031static BOOL CompareDelegatesForEquivalence(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModule2, TokenPairList *pVisited)
3032{
3033 CONTRACTL
3034 {
3035 THROWS;
3036 GC_TRIGGERS;
3037 MODE_ANY;
3038 }
3039 CONTRACTL_END
3040
3041 PCCOR_SIGNATURE pSig1;
3042 PCCOR_SIGNATURE pSig2;
3043 DWORD cbSig1;
3044 DWORD cbSig2;
3045
3046 // find the Invoke methods
3047 GetDelegateInvokeMethodSignature(tk1, pModule1, &cbSig1, &pSig1);
3048 GetDelegateInvokeMethodSignature(tk2, pModule2, &cbSig2, &pSig2);
3049
3050 return MetaSig::CompareMethodSigs(pSig1, cbSig1, pModule1, NULL, pSig2, cbSig2, pModule2, NULL, pVisited);
3051}
3052
3053#endif // FEATURE_TYPEEQUIVALENCE
3054#endif // #ifndef DACCESS_COMPILE
3055
3056#ifndef DACCESS_COMPILE
3057//---------------------------------------------------------------------------------------
3058//
3059BOOL IsTypeDefExternallyVisible(mdToken tk, Module *pModule, DWORD dwAttrClass)
3060{
3061 CONTRACTL
3062 {
3063 NOTHROW;
3064 MODE_ANY;
3065 GC_NOTRIGGER;
3066 SO_INTOLERANT;
3067 }
3068 CONTRACTL_END;
3069
3070 BOOL bIsVisible = TRUE;
3071
3072 if (!IsTdPublic(dwAttrClass))
3073 {
3074 if (!IsTdNestedPublic(dwAttrClass))
3075 return FALSE;
3076
3077 IMDInternalImport *pInternalImport = pModule->GetMDImport();
3078
3079 DWORD dwAttrEnclosing;
3080
3081 mdTypeDef tdCurrent = tk;
3082 do
3083 {
3084 mdTypeDef tdEnclosing = mdTypeDefNil;
3085
3086 if (FAILED(pInternalImport->GetNestedClassProps(tdCurrent, &tdEnclosing)))
3087 return FALSE;
3088
3089 tdCurrent = tdEnclosing;
3090
3091 // We stop searching as soon as we hit the first non NestedPublic type.
3092 // So logically, we can't possibly fall off the top of the hierarchy.
3093 _ASSERTE(tdEnclosing != mdTypeDefNil);
3094
3095 mdToken tkJunk = mdTokenNil;
3096
3097 if (FAILED(pInternalImport->GetTypeDefProps(tdEnclosing, &dwAttrEnclosing, &tkJunk)))
3098 {
3099 return FALSE;
3100 }
3101 }
3102 while (IsTdNestedPublic(dwAttrEnclosing));
3103
3104 bIsVisible = IsTdPublic(dwAttrEnclosing);
3105 }
3106
3107 return bIsVisible;
3108}
3109#endif
3110
3111#ifndef FEATURE_TYPEEQUIVALENCE
3112#ifndef DACCESS_COMPILE
3113BOOL IsTypeDefEquivalent(mdToken tk, Module *pModule)
3114{
3115 LIMITED_METHOD_CONTRACT;
3116 return FALSE;
3117}
3118#endif
3119#endif
3120
3121#ifdef FEATURE_TYPEEQUIVALENCE
3122#ifndef DACCESS_COMPILE
3123BOOL IsTypeDefEquivalent(mdToken tk, Module *pModule)
3124{
3125 CONTRACTL
3126 {
3127 THROWS;
3128 GC_TRIGGERS;
3129 INJECT_FAULT(COMPlusThrowOM());
3130 MODE_ANY;
3131 }
3132 CONTRACTL_END;
3133
3134
3135 IMDInternalImport *pInternalImport = pModule->GetMDImport();
3136
3137 if (tk == mdTypeDefNil)
3138 return FALSE;
3139
3140 DWORD dwAttrType;
3141 mdToken tkExtends;
3142
3143 IfFailThrow(pInternalImport->GetTypeDefProps(tk, &dwAttrType, &tkExtends));
3144
3145 if (IsTdWindowsRuntime(dwAttrType))
3146 {
3147 // no type equivalence support for WinRT types
3148 return FALSE;
3149 }
3150
3151 // Check for the TypeIdentifierAttribute and auto opt-in
3152 HRESULT hr = pInternalImport->GetCustomAttributeByName(tk, g_TypeIdentifierAttributeClassName, NULL, NULL);
3153 IfFailThrow(hr);
3154
3155 // 1. Type is within assembly marked with ImportedFromTypeLibAttribute or PrimaryInteropAssemblyAttribute
3156 if (hr != S_OK)
3157 {
3158 // no TypeIdentifierAttribute -> the assembly must be a type library
3159 bool has_eq = !pModule->GetAssembly()->IsDynamic();
3160
3161#ifdef FEATURE_COMINTEROP
3162 has_eq = has_eq && pModule->GetAssembly()->IsPIAOrImportedFromTypeLib();
3163#endif // FEATURE_COMINTEROP
3164
3165 if (!has_eq)
3166 return FALSE;
3167 }
3168 else if (hr == S_OK)
3169 {
3170 // Type has TypeIdentifierAttribute. It is marked as type equivalent.
3171 return TRUE;
3172 }
3173
3174 mdToken tdEnum = g_pEnumClass->GetCl();
3175 Module *pSystemModule = g_pEnumClass->GetModule();
3176 mdToken tdValueType = g_pValueTypeClass->GetCl();
3177 _ASSERTE(pSystemModule == g_pValueTypeClass->GetModule());
3178 mdToken tdMCDelegate = g_pMulticastDelegateClass->GetCl();
3179 _ASSERTE(pSystemModule == g_pMulticastDelegateClass->GetModule());
3180
3181 // 2. Type is a COMImport/COMEvent interface, enum, struct, or delegate
3182 BOOL fIsCOMInterface = FALSE;
3183 if (IsTdInterface(dwAttrType))
3184 {
3185 if (IsTdImport(dwAttrType))
3186 {
3187 // COMImport
3188 fIsCOMInterface = TRUE;
3189 }
3190 else
3191 {
3192 // COMEvent
3193 hr = pInternalImport->GetCustomAttributeByName(tk, INTEROP_COMEVENTINTERFACE_TYPE, NULL, NULL);
3194 IfFailThrow(hr);
3195
3196 if (hr == S_OK)
3197 fIsCOMInterface = TRUE;
3198 }
3199 }
3200
3201 if (fIsCOMInterface ||
3202 (!IsTdInterface(dwAttrType) && (tkExtends != mdTypeDefNil) &&
3203 ((CompareTypeTokens(tkExtends, tdEnum, pModule, pSystemModule)) ||
3204 (CompareTypeTokens(tkExtends, tdValueType, pModule, pSystemModule) && (tk != tdEnum || pModule != pSystemModule)) ||
3205 (CompareTypeTokens(tkExtends, tdMCDelegate, pModule, pSystemModule)))))
3206 {
3207 HENUMInternal hEnumGenericPars;
3208 IfFailThrow(pInternalImport->EnumInit(mdtGenericParam, tk, &hEnumGenericPars));
3209 DWORD numGenericArgs = pInternalImport->EnumGetCount(&hEnumGenericPars);
3210
3211 // 3. Type is not generic
3212 if (numGenericArgs > 0)
3213 return FALSE;
3214
3215 // 4. Type is externally visible (i.e. public)
3216 if (!IsTypeDefExternallyVisible(tk, pModule, dwAttrType))
3217 return FALSE;
3218
3219 // since the token has not been loaded yet,
3220 // its module might be not fully initialized in this domain
3221 // take care of that possibility
3222 pModule->EnsureAllocated();
3223
3224 // 6. If type is nested, nesting type must be equivalent.
3225 if (IsTdNested(dwAttrType))
3226 {
3227 mdTypeDef tdEnclosing = mdTypeDefNil;
3228
3229 IfFailThrow(pInternalImport->GetNestedClassProps(tk, &tdEnclosing));
3230
3231 if (!IsTypeDefEquivalent(tdEnclosing, pModule))
3232 return FALSE;
3233 }
3234
3235 // Type meets all of the requirements laid down above. Type is considered to be marked as equivalent.
3236 return TRUE;
3237 }
3238 else
3239 {
3240 return FALSE;
3241 }
3242}
3243#endif
3244#endif // FEATURE_TYPEEQUIVALENCE
3245
3246BOOL CompareTypeDefsForEquivalence(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModule2, TokenPairList *pVisited)
3247{
3248#if !defined(DACCESS_COMPILE) && defined(FEATURE_TYPEEQUIVALENCE)
3249 CONTRACTL
3250 {
3251 THROWS;
3252 GC_TRIGGERS;
3253 INJECT_FAULT(COMPlusThrowOM());
3254 MODE_ANY;
3255 }
3256 CONTRACTL_END;
3257
3258 if (TokenPairList::InTypeEquivalenceForbiddenScope(pVisited))
3259 {
3260 // we limit variance on generics only to interfaces
3261 return FALSE;
3262 }
3263 if (TokenPairList::Exists(pVisited, tk1, pModule1, tk2, pModule2))
3264 {
3265 // we are in the process of comparing these tokens already
3266 return TRUE;
3267 }
3268 TokenPairList newVisited(tk1, pModule1, tk2, pModule2, pVisited);
3269
3270 DWORD dwAttrType1;
3271 DWORD dwAttrType2;
3272 mdToken tkExtends1;
3273 mdToken tkExtends2;
3274 IMDInternalImport *pInternalImport1 = pModule1->GetMDImport();
3275 IMDInternalImport *pInternalImport2 = pModule2->GetMDImport();
3276
3277 // *************************************************************************
3278 // 1. both types must opt into type equivalence and be able to acquire their equivalence set
3279 // *************************************************************************
3280 TypeIdentifierData data1;
3281 TypeIdentifierData data2;
3282 HRESULT hr;
3283
3284 IfFailThrow(hr = data1.Init(pModule1, tk1));
3285 BOOL has_eq1 = (hr == S_OK);
3286
3287 IfFailThrow(hr = data2.Init(pModule2, tk2));
3288 BOOL has_eq2 = (hr == S_OK);
3289
3290 if (!has_eq1 || !has_eq2)
3291 return FALSE;
3292
3293 // Check to ensure that the types are actually opted into equivalence.
3294 if (!IsTypeDefEquivalent(tk1, pModule1) || !IsTypeDefEquivalent(tk2, pModule2))
3295 return FALSE;
3296
3297 // *************************************************************************
3298 // 2. the two types have the same type identity
3299 // *************************************************************************
3300 if (!data1.IsEqual(data2))
3301 return FALSE;
3302
3303 IfFailThrow(pInternalImport1->GetTypeDefProps(tk1, &dwAttrType1, &tkExtends1));
3304 IfFailThrow(pInternalImport2->GetTypeDefProps(tk2, &dwAttrType2, &tkExtends2));
3305
3306 // *************************************************************************
3307 // 2a. the two types have the same name and namespace
3308 // *************************************************************************
3309 {
3310 LPCUTF8 pszName1;
3311 LPCUTF8 pszNamespace1;
3312 LPCUTF8 pszName2;
3313 LPCUTF8 pszNamespace2;
3314
3315 IfFailThrow(pInternalImport1->GetNameOfTypeDef(tk1, &pszName1, &pszNamespace1));
3316 IfFailThrow(pInternalImport2->GetNameOfTypeDef(tk2, &pszName2, &pszNamespace2));
3317
3318 if (strcmp(pszName1, pszName2) != 0 || strcmp(pszNamespace1, pszNamespace2) != 0)
3319 {
3320 return FALSE;
3321 }
3322 }
3323
3324 // *************************************************************************
3325 // 2b. the two types must not be nested... or they must have an equivalent enclosing type
3326 // *************************************************************************
3327 {
3328 if (!!IsTdNested(dwAttrType1) != !!IsTdNested(dwAttrType2))
3329 {
3330 return FALSE;
3331 }
3332
3333 if (IsTdNested(dwAttrType1))
3334 {
3335 mdToken tkEnclosing1;
3336 mdToken tkEnclosing2;
3337
3338 IfFailThrow(pInternalImport1->GetNestedClassProps(tk1, &tkEnclosing1));
3339 IfFailThrow(pInternalImport2->GetNestedClassProps(tk2, &tkEnclosing2));
3340
3341 if (!CompareTypeDefsForEquivalence(tkEnclosing1, tkEnclosing2, pModule1, pModule2, pVisited))
3342 {
3343 return FALSE;
3344 }
3345 }
3346 }
3347
3348 // *************************************************************************
3349 // 3. type is an interface, struct, enum, or delegate
3350 // *************************************************************************
3351 if (IsTdInterface(dwAttrType1))
3352 {
3353 // interface
3354 if (!IsTdInterface(dwAttrType2))
3355 return FALSE;
3356 }
3357 else
3358 {
3359 mdToken tdEnum = g_pEnumClass->GetCl();
3360 Module *pSystemModule = g_pEnumClass->GetModule();
3361
3362 if (CompareTypeTokens(tkExtends1, tdEnum, pModule1, pSystemModule, &newVisited))
3363 {
3364 // enum (extends System.Enum)
3365 if (!CompareTypeTokens(tkExtends2, tdEnum, pModule2, pSystemModule, &newVisited))
3366 return FALSE;
3367
3368 if (!CompareStructuresForEquivalence(tk1, tk2, pModule1, pModule2, TRUE, &newVisited))
3369 return FALSE;
3370 }
3371 else
3372 {
3373 mdToken tdValueType = g_pValueTypeClass->GetCl();
3374 _ASSERTE(pSystemModule == g_pValueTypeClass->GetModule());
3375
3376 if (CompareTypeTokens(tkExtends1, tdValueType, pModule1, pSystemModule, &newVisited) &&
3377 (tk1 != tdEnum || pModule1 != pSystemModule))
3378 {
3379 // struct (extends System.ValueType but is not System.Enum)
3380 if (!CompareTypeTokens(tkExtends2, tdValueType, pModule2, pSystemModule, &newVisited) ||
3381 (tk2 == tdEnum && pModule2 == pSystemModule))
3382 return FALSE;
3383
3384 if (!CompareStructuresForEquivalence(tk1, tk2, pModule1, pModule2, FALSE, &newVisited))
3385 return FALSE;
3386 }
3387 else
3388 {
3389 mdToken tdMCDelegate = g_pMulticastDelegateClass->GetCl();
3390 _ASSERTE(pSystemModule == g_pMulticastDelegateClass->GetModule());
3391
3392 if (CompareTypeTokens(tkExtends1, tdMCDelegate, pModule1, pSystemModule, &newVisited))
3393 {
3394 // delegate (extends System.MulticastDelegate)
3395 if (!CompareTypeTokens(tkExtends2, tdMCDelegate, pModule2, pSystemModule, &newVisited))
3396 return FALSE;
3397
3398 if (!CompareDelegatesForEquivalence(tk1, tk2, pModule1, pModule2, &newVisited))
3399 return FALSE;
3400 }
3401 else
3402 {
3403 // the type is neither interface, struct, enum, nor delegate
3404 return FALSE;
3405 }
3406 }
3407 }
3408 }
3409 return TRUE;
3410
3411#else //!defined(DACCESS_COMPILE) && defined(FEATURE_TYPEEQUIVALENCE)
3412
3413#ifdef DACCESS_COMPILE
3414 // We shouldn't execute this code in dac builds.
3415 _ASSERTE(FALSE);
3416#endif
3417 return (tk1 == tk2) && (pModule1 == pModule2);
3418#endif //!defined(DACCESS_COMPILE) && defined(FEATURE_COMINTEROP)
3419}
3420
3421
3422BOOL CompareTypeTokens(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModule2, TokenPairList *pVisited /*= NULL*/)
3423{
3424 CONTRACTL
3425 {
3426 THROWS;
3427 GC_TRIGGERS;
3428 INJECT_FAULT(COMPlusThrowOM());
3429 MODE_ANY;
3430 }
3431 CONTRACTL_END
3432
3433 HRESULT hr;
3434 IMDInternalImport *pInternalImport1;
3435 IMDInternalImport *pInternalImport2;
3436 LPCUTF8 pszName1;
3437 LPCUTF8 pszNamespace1;
3438 LPCUTF8 pszName2;
3439 LPCUTF8 pszNamespace2;
3440 mdToken enclosingTypeTk1;
3441 mdToken enclosingTypeTk2;
3442
3443 if (dac_cast<TADDR>(pModule1) == dac_cast<TADDR>(pModule2) &&
3444 tk1 == tk2)
3445 {
3446 return TRUE;
3447 }
3448
3449 pInternalImport1 = pModule1->GetMDImport();
3450 if (!pInternalImport1->IsValidToken(tk1))
3451 {
3452 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid token");
3453 IfFailGo(COR_E_BADIMAGEFORMAT);
3454 }
3455
3456 pInternalImport2 = pModule2->GetMDImport();
3457 if (!pInternalImport2->IsValidToken(tk2))
3458 {
3459 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid token");
3460 IfFailGo(COR_E_BADIMAGEFORMAT);
3461 }
3462
3463 pszName1 = NULL;
3464 pszNamespace1 = NULL;
3465 if (TypeFromToken(tk1) == mdtTypeRef)
3466 {
3467 IfFailGo(pInternalImport1->GetNameOfTypeRef(tk1, &pszNamespace1, &pszName1));
3468 }
3469 else if (TypeFromToken(tk1) == mdtTypeDef)
3470 {
3471 if (TypeFromToken(tk2) == mdtTypeDef)
3472 {
3473#ifdef FEATURE_TYPEEQUIVALENCE
3474 // two type defs can't be the same unless they are identical or resolve to
3475 // equivalent types (equivalence based on GUID and TypeIdentifierAttribute)
3476 return CompareTypeDefsForEquivalence(tk1, tk2, pModule1, pModule2, pVisited);
3477#else // FEATURE_TYPEEQUIVALENCE
3478 // two type defs can't be the same unless they are identical
3479 return FALSE;
3480#endif // FEATURE_TYPEEQUIVALENCE
3481 }
3482 IfFailGo(pInternalImport1->GetNameOfTypeDef(tk1, &pszName1, &pszNamespace1));
3483 }
3484 else
3485 {
3486 return FALSE; // comparing a type against a module or assemblyref, no match
3487 }
3488
3489 pszName2 = NULL;
3490 pszNamespace2 = NULL;
3491 if (TypeFromToken(tk2) == mdtTypeRef)
3492 {
3493 IfFailGo(pInternalImport2->GetNameOfTypeRef(tk2, &pszNamespace2, &pszName2));
3494 }
3495 else if (TypeFromToken(tk2) == mdtTypeDef)
3496 {
3497 IfFailGo(pInternalImport2->GetNameOfTypeDef(tk2, &pszName2, &pszNamespace2));
3498 }
3499 else
3500 {
3501 return FALSE; // comparing a type against a module or assemblyref, no match
3502 }
3503
3504 _ASSERTE((pszNamespace1 != NULL) && (pszNamespace2 != NULL));
3505 if (strcmp(pszName1, pszName2) != 0 || strcmp(pszNamespace1, pszNamespace2) != 0)
3506 {
3507 return FALSE;
3508 }
3509
3510 //////////////////////////////////////////////////////////////////////
3511 // OK names pass, see if it is nested, and if so that the nested classes are the same
3512
3513 enclosingTypeTk1 = mdTokenNil;
3514 if (TypeFromToken(tk1) == mdtTypeRef)
3515 {
3516 IfFailGo(pInternalImport1->GetResolutionScopeOfTypeRef(tk1, &enclosingTypeTk1));
3517 if (enclosingTypeTk1 == mdTypeRefNil)
3518 {
3519 enclosingTypeTk1 = mdTokenNil;
3520 }
3521 }
3522 else
3523 {
3524 if (FAILED(hr = pInternalImport1->GetNestedClassProps(tk1, &enclosingTypeTk1)))
3525 {
3526 if (hr != CLDB_E_RECORD_NOTFOUND)
3527 {
3528 IfFailGo(hr);
3529 }
3530 enclosingTypeTk1 = mdTokenNil;
3531 }
3532 }
3533
3534 enclosingTypeTk2 = mdTokenNil;
3535 if (TypeFromToken(tk2) == mdtTypeRef)
3536 {
3537 IfFailGo(pInternalImport2->GetResolutionScopeOfTypeRef(tk2, &enclosingTypeTk2));
3538 if (enclosingTypeTk2 == mdTypeRefNil)
3539 {
3540 enclosingTypeTk2 = mdTokenNil;
3541 }
3542 }
3543 else
3544 {
3545 if (FAILED(hr = pInternalImport2->GetNestedClassProps(tk2, &enclosingTypeTk2)))
3546 {
3547 if (hr != CLDB_E_RECORD_NOTFOUND)
3548 {
3549 IfFailGo(hr);
3550 }
3551 enclosingTypeTk2 = mdTokenNil;
3552 }
3553 }
3554
3555 if (TypeFromToken(enclosingTypeTk1) == mdtTypeRef || TypeFromToken(enclosingTypeTk1) == mdtTypeDef)
3556 {
3557 if (!CompareTypeTokens(enclosingTypeTk1, enclosingTypeTk2, pModule1, pModule2, pVisited))
3558 return FALSE;
3559
3560 // TODO: We could return TRUE if we knew that type equivalence was not exercised during the previous call.
3561 }
3562 else
3563 {
3564 // Check if tk1 is non-nested, but tk2 is nested
3565 if (TypeFromToken(enclosingTypeTk2) == mdtTypeRef || TypeFromToken(enclosingTypeTk2) == mdtTypeDef)
3566 return FALSE;
3567 }
3568
3569 //////////////////////////////////////////////////////////////////////
3570 // OK, we have non-nested types or the the enclosing types are equivalent
3571
3572
3573 // Do not load the type! (Or else you may run into circular dependency loading problems.)
3574 Module* pFoundModule1;
3575 mdToken foundTypeDefToken1;
3576 if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule1,
3577 tk1,
3578 &pFoundModule1,
3579 &foundTypeDefToken1))
3580 {
3581 return FALSE;
3582 }
3583 _ASSERTE(TypeFromToken(foundTypeDefToken1) == mdtTypeDef);
3584
3585 Module* pFoundModule2;
3586 mdToken foundTypeDefToken2;
3587 if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule2,
3588 tk2,
3589 &pFoundModule2,
3590 &foundTypeDefToken2))
3591 {
3592 return FALSE;
3593 }
3594 _ASSERTE(TypeFromToken(foundTypeDefToken2) == mdtTypeDef);
3595
3596 _ASSERTE(TypeFromToken(foundTypeDefToken1) == mdtTypeDef && TypeFromToken(foundTypeDefToken2) == mdtTypeDef);
3597 return CompareTypeTokens(foundTypeDefToken1, foundTypeDefToken2, pFoundModule1, pFoundModule2, pVisited);
3598
3599ErrExit:
3600#ifdef DACCESS_COMPILE
3601 ThrowHR(hr);
3602#else
3603 EEFileLoadException::Throw(pModule2->GetFile(), hr);
3604#endif //!DACCESS_COMPILE
3605} // CompareTypeTokens
3606
3607#ifdef _PREFAST_
3608#pragma warning(push)
3609#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
3610#endif
3611//---------------------------------------------------------------------------------------
3612//
3613// Compare the next elements in two sigs.
3614//
3615// static
3616BOOL
3617MetaSig::CompareElementType(
3618 PCCOR_SIGNATURE & pSig1,
3619 PCCOR_SIGNATURE & pSig2,
3620 PCCOR_SIGNATURE pEndSig1,
3621 PCCOR_SIGNATURE pEndSig2,
3622 Module * pModule1,
3623 Module * pModule2,
3624 const Substitution * pSubst1,
3625 const Substitution * pSubst2,
3626 TokenPairList * pVisited) // = NULL
3627{
3628 CONTRACTL
3629 {
3630 THROWS;
3631 GC_TRIGGERS;
3632 INJECT_FAULT(COMPlusThrowOM());
3633 MODE_ANY;
3634 }
3635 CONTRACTL_END
3636
3637 redo:
3638 // We jump here if the Type was a ET_CMOD prefix.
3639 // The caller expects us to handle CMOD's but not present them as types on their own.
3640
3641 if ((pSig1 >= pEndSig1) || (pSig2 >= pEndSig2))
3642 { // End of sig encountered prematurely
3643 return FALSE;
3644 }
3645
3646 if ((*pSig2 == ELEMENT_TYPE_VAR) && (pSubst2 != NULL) && !pSubst2->GetInst().IsNull())
3647 {
3648 SigPointer inst = pSubst2->GetInst();
3649 pSig2++;
3650 DWORD index;
3651 IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &index));
3652
3653 for (DWORD i = 0; i < index; i++)
3654 {
3655 IfFailThrow(inst.SkipExactlyOne());
3656 }
3657 PCCOR_SIGNATURE pSig3 = inst.GetPtr();
3658 IfFailThrow(inst.SkipExactlyOne());
3659 PCCOR_SIGNATURE pEndSig3 = inst.GetPtr();
3660
3661 return CompareElementType(
3662 pSig1,
3663 pSig3,
3664 pEndSig1,
3665 pEndSig3,
3666 pModule1,
3667 pSubst2->GetModule(),
3668 pSubst1,
3669 pSubst2->GetNext(),
3670 pVisited);
3671 }
3672
3673 if ((*pSig1 == ELEMENT_TYPE_VAR) && (pSubst1 != NULL) && !pSubst1->GetInst().IsNull())
3674 {
3675 SigPointer inst = pSubst1->GetInst();
3676 pSig1++;
3677 DWORD index;
3678 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &index));
3679
3680 for (DWORD i = 0; i < index; i++)
3681 {
3682 IfFailThrow(inst.SkipExactlyOne());
3683 }
3684 PCCOR_SIGNATURE pSig3 = inst.GetPtr();
3685 IfFailThrow(inst.SkipExactlyOne());
3686 PCCOR_SIGNATURE pEndSig3 = inst.GetPtr();
3687
3688 return CompareElementType(
3689 pSig3,
3690 pSig2,
3691 pEndSig3,
3692 pEndSig2,
3693 pSubst1->GetModule(),
3694 pModule2,
3695 pSubst1->GetNext(),
3696 pSubst2,
3697 pVisited);
3698 }
3699
3700 CorElementType Type1 = ELEMENT_TYPE_MAX; // initialize to illegal
3701 CorElementType Type2 = ELEMENT_TYPE_MAX; // initialize to illegal
3702
3703 IfFailThrow(CorSigUncompressElementType_EndPtr(pSig1, pEndSig1, &Type1));
3704 IfFailThrow(CorSigUncompressElementType_EndPtr(pSig2, pEndSig2, &Type2));
3705
3706 if (Type1 == ELEMENT_TYPE_INTERNAL)
3707 {
3708 // this check is not functional in DAC and provides no security against a malicious dump
3709 // the DAC is prepared to receive an invalid type handle
3710#ifndef DACCESS_COMPILE
3711 if (pModule1->IsSigInIL(pSig1))
3712 {
3713 THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module *)pModule1);
3714 }
3715#endif
3716
3717 }
3718
3719 if (Type2 == ELEMENT_TYPE_INTERNAL)
3720 {
3721 // this check is not functional in DAC and provides no security against a malicious dump
3722 // the DAC is prepared to receive an invalid type handle
3723#ifndef DACCESS_COMPILE
3724 if (pModule2->IsSigInIL(pSig2))
3725 {
3726 THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module *)pModule2);
3727 }
3728#endif
3729 }
3730
3731 if (Type1 != Type2)
3732 {
3733 if ((Type1 == ELEMENT_TYPE_INTERNAL) || (Type2 == ELEMENT_TYPE_INTERNAL))
3734 {
3735 TypeHandle hInternal;
3736 CorElementType eOtherType;
3737 Module * pOtherModule;
3738
3739 // One type is already loaded, collect all the necessary information to identify the other type.
3740 if (Type1 == ELEMENT_TYPE_INTERNAL)
3741 {
3742 IfFailThrow(CorSigUncompressPointer_EndPtr(pSig1, pEndSig1, (void **)&hInternal));
3743
3744 eOtherType = Type2;
3745 pOtherModule = pModule2;
3746 }
3747 else
3748 {
3749 IfFailThrow(CorSigUncompressPointer_EndPtr(pSig2, pEndSig2, (void **)&hInternal));
3750
3751 eOtherType = Type1;
3752 pOtherModule = pModule1;
3753 }
3754
3755 // Internal types can only correspond to types or value types.
3756 switch (eOtherType)
3757 {
3758 case ELEMENT_TYPE_OBJECT:
3759 {
3760 return (hInternal.AsMethodTable() == g_pObjectClass);
3761 }
3762 case ELEMENT_TYPE_STRING:
3763 {
3764 return (hInternal.AsMethodTable() == g_pStringClass);
3765 }
3766 case ELEMENT_TYPE_VALUETYPE:
3767 case ELEMENT_TYPE_CLASS:
3768 {
3769 mdToken tkOther;
3770 if (Type1 == ELEMENT_TYPE_INTERNAL)
3771 {
3772 IfFailThrow(CorSigUncompressToken_EndPtr(pSig2, pEndSig2, &tkOther));
3773 }
3774 else
3775 {
3776 IfFailThrow(CorSigUncompressToken_EndPtr(pSig1, pEndSig1, &tkOther));
3777 }
3778 TypeHandle hOtherType;
3779
3780 hOtherType = ClassLoader::LoadTypeDefOrRefThrowing(
3781 pOtherModule,
3782 tkOther,
3783 ClassLoader::ReturnNullIfNotFound,
3784 ClassLoader::FailIfUninstDefOrRef);
3785
3786 return (hInternal == hOtherType);
3787 }
3788 default:
3789 {
3790 return FALSE;
3791 }
3792 }
3793 }
3794 else
3795 {
3796 return FALSE; // types must be the same
3797 }
3798 }
3799
3800 switch (Type1)
3801 {
3802 default:
3803 {
3804 // Unknown type!
3805 THROW_BAD_FORMAT(BFA_BAD_COMPLUS_SIG, pModule1);
3806 }
3807
3808 case ELEMENT_TYPE_U:
3809 case ELEMENT_TYPE_I:
3810 case ELEMENT_TYPE_VOID:
3811 case ELEMENT_TYPE_I1:
3812 case ELEMENT_TYPE_U1:
3813 case ELEMENT_TYPE_I2:
3814 case ELEMENT_TYPE_U2:
3815 case ELEMENT_TYPE_I4:
3816 case ELEMENT_TYPE_U4:
3817 case ELEMENT_TYPE_I8:
3818 case ELEMENT_TYPE_U8:
3819 case ELEMENT_TYPE_R4:
3820 case ELEMENT_TYPE_R8:
3821 case ELEMENT_TYPE_BOOLEAN:
3822 case ELEMENT_TYPE_CHAR:
3823 case ELEMENT_TYPE_TYPEDBYREF:
3824 case ELEMENT_TYPE_STRING:
3825 case ELEMENT_TYPE_OBJECT:
3826 {
3827 return TRUE;
3828 }
3829
3830 case ELEMENT_TYPE_VAR:
3831 case ELEMENT_TYPE_MVAR:
3832 {
3833 DWORD varNum1;
3834 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &varNum1));
3835 DWORD varNum2;
3836 IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &varNum2));
3837
3838 return (varNum1 == varNum2);
3839 }
3840
3841 case ELEMENT_TYPE_CMOD_REQD:
3842 case ELEMENT_TYPE_CMOD_OPT:
3843 {
3844 mdToken tk1, tk2;
3845
3846 IfFailThrow(CorSigUncompressToken_EndPtr(pSig1, pEndSig1, &tk1));
3847 IfFailThrow(CorSigUncompressToken_EndPtr(pSig2, pEndSig2, &tk2));
3848
3849#ifndef DACCESS_COMPILE
3850 if (!CompareTypeDefOrRefOrSpec(
3851 pModule1,
3852 tk1,
3853 pSubst1,
3854 pModule2,
3855 tk2,
3856 pSubst2,
3857 pVisited))
3858 {
3859 return FALSE;
3860 }
3861#endif //!DACCESS_COMPILE
3862
3863 goto redo;
3864 }
3865
3866 // These take an additional argument, which is the element type
3867 case ELEMENT_TYPE_SZARRAY:
3868 case ELEMENT_TYPE_PTR:
3869 case ELEMENT_TYPE_BYREF:
3870 {
3871 if (!CompareElementType(
3872 pSig1,
3873 pSig2,
3874 pEndSig1,
3875 pEndSig2,
3876 pModule1,
3877 pModule2,
3878 pSubst1,
3879 pSubst2,
3880 pVisited))
3881 {
3882 return FALSE;
3883 }
3884 return TRUE;
3885 }
3886
3887 case ELEMENT_TYPE_VALUETYPE:
3888 case ELEMENT_TYPE_CLASS:
3889 {
3890 mdToken tk1, tk2;
3891
3892 IfFailThrow(CorSigUncompressToken_EndPtr(pSig1, pEndSig1, &tk1));
3893 IfFailThrow(CorSigUncompressToken_EndPtr(pSig2, pEndSig2, &tk2));
3894
3895 return CompareTypeTokens(tk1, tk2, pModule1, pModule2, pVisited);
3896 }
3897
3898 case ELEMENT_TYPE_FNPTR:
3899 {
3900 // Compare calling conventions
3901 // Note: We used to read them as compressed integers, which is wrong, but works for correct
3902 // signatures as the highest bit is always 0 for calling conventions
3903 CorElementType callingConvention1 = ELEMENT_TYPE_MAX; // initialize to illegal
3904 IfFailThrow(CorSigUncompressElementType_EndPtr(pSig1, pEndSig1, &callingConvention1));
3905 CorElementType callingConvention2 = ELEMENT_TYPE_MAX; // initialize to illegal
3906 IfFailThrow(CorSigUncompressElementType_EndPtr(pSig2, pEndSig2, &callingConvention2));
3907 if (callingConvention1 != callingConvention2)
3908 {
3909 return FALSE;
3910 }
3911
3912 DWORD argCnt1;
3913 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &argCnt1));
3914 DWORD argCnt2;
3915 IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &argCnt2));
3916 if (argCnt1 != argCnt2)
3917 {
3918 return FALSE;
3919 }
3920
3921 // Compressed integer values can be only 0-0x1FFFFFFF
3922 _ASSERTE(argCnt1 < MAXDWORD);
3923 // Add return parameter into the parameter count (it cannot overflow)
3924 argCnt1++;
3925
3926 TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(pVisited);
3927 // Compare all parameters, incl. return parameter
3928 while (argCnt1 > 0)
3929 {
3930 if (!CompareElementType(
3931 pSig1,
3932 pSig2,
3933 pEndSig1,
3934 pEndSig2,
3935 pModule1,
3936 pModule2,
3937 pSubst1,
3938 pSubst2,
3939 &newVisited))
3940 {
3941 return FALSE;
3942 }
3943 --argCnt1;
3944 }
3945 return TRUE;
3946 }
3947
3948 case ELEMENT_TYPE_GENERICINST:
3949 {
3950 TokenPairList newVisited = TokenPairList::AdjustForTypeSpec(
3951 pVisited,
3952 pModule1,
3953 pSig1 - 1,
3954 (DWORD)(pEndSig1 - pSig1) + 1);
3955 TokenPairList newVisitedAlwaysForbidden = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(pVisited);
3956
3957 // Type constructors - The actual type is never permitted to participate in type equivalence.
3958 if (!CompareElementType(
3959 pSig1,
3960 pSig2,
3961 pEndSig1,
3962 pEndSig2,
3963 pModule1,
3964 pModule2,
3965 pSubst1,
3966 pSubst2,
3967 &newVisitedAlwaysForbidden))
3968 {
3969 return FALSE;
3970 }
3971
3972 DWORD argCnt1;
3973 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &argCnt1));
3974 DWORD argCnt2;
3975 IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &argCnt2));
3976 if (argCnt1 != argCnt2)
3977 {
3978 return FALSE;
3979 }
3980
3981 while (argCnt1 > 0)
3982 {
3983 if (!CompareElementType(
3984 pSig1,
3985 pSig2,
3986 pEndSig1,
3987 pEndSig2,
3988 pModule1,
3989 pModule2,
3990 pSubst1,
3991 pSubst2,
3992 &newVisited))
3993 {
3994 return FALSE;
3995 }
3996 --argCnt1;
3997 }
3998 return TRUE;
3999 }
4000
4001 case ELEMENT_TYPE_ARRAY:
4002 {
4003 // syntax: ARRAY <base type> rank <count n> <size 1> .... <size n> <lower bound m>
4004 // <lb 1> .... <lb m>
4005 DWORD rank1, rank2;
4006 DWORD dimension_sizes1, dimension_sizes2;
4007 DWORD dimension_lowerb1, dimension_lowerb2;
4008 DWORD i;
4009
4010 // element type
4011 if (!CompareElementType(
4012 pSig1,
4013 pSig2,
4014 pEndSig1,
4015 pEndSig2,
4016 pModule1,
4017 pModule2,
4018 pSubst1,
4019 pSubst2,
4020 pVisited))
4021 {
4022 return FALSE;
4023 }
4024
4025 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &rank1));
4026 IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &rank2));
4027 if (rank1 != rank2)
4028 {
4029 return FALSE;
4030 }
4031 // A zero ends the array spec
4032 if (rank1 == 0)
4033 {
4034 return TRUE;
4035 }
4036
4037 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &dimension_sizes1));
4038 IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &dimension_sizes2));
4039 if (dimension_sizes1 != dimension_sizes2)
4040 {
4041 return FALSE;
4042 }
4043
4044 for (i = 0; i < dimension_sizes1; i++)
4045 {
4046 DWORD size1, size2;
4047
4048 if (pSig1 == pEndSig1)
4049 { // premature end ok
4050 return TRUE;
4051 }
4052
4053 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &size1));
4054 IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &size2));
4055 if (size1 != size2)
4056 {
4057 return FALSE;
4058 }
4059 }
4060
4061 if (pSig1 == pEndSig1)
4062 { // premature end ok
4063 return TRUE;
4064 }
4065
4066 // # dimensions for lower bounds
4067 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &dimension_lowerb1));
4068 IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &dimension_lowerb2));
4069 if (dimension_lowerb1 != dimension_lowerb2)
4070 {
4071 return FALSE;
4072 }
4073
4074 for (i = 0; i < dimension_lowerb1; i++)
4075 {
4076 DWORD size1, size2;
4077
4078 if (pSig1 == pEndSig1)
4079 { // premature end ok
4080 return TRUE;
4081 }
4082
4083 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &size1));
4084 IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &size2));
4085 if (size1 != size2)
4086 {
4087 return FALSE;
4088 }
4089 }
4090 return TRUE;
4091 }
4092
4093 case ELEMENT_TYPE_INTERNAL:
4094 {
4095 TypeHandle hType1, hType2;
4096
4097 IfFailThrow(CorSigUncompressPointer_EndPtr(pSig1, pEndSig1, (void **)&hType1));
4098 IfFailThrow(CorSigUncompressPointer_EndPtr(pSig2, pEndSig2, (void **)&hType2));
4099
4100 return (hType1 == hType2);
4101 }
4102 } // switch
4103 // Unreachable
4104} // MetaSig::CompareElementType
4105#ifdef _PREFAST_
4106#pragma warning(pop)
4107#endif
4108
4109
4110//---------------------------------------------------------------------------------------
4111//
4112BOOL
4113MetaSig::CompareTypeDefsUnderSubstitutions(
4114 MethodTable * pTypeDef1,
4115 MethodTable * pTypeDef2,
4116 const Substitution * pSubst1,
4117 const Substitution * pSubst2,
4118 TokenPairList * pVisited)
4119{
4120 CONTRACTL
4121 {
4122 THROWS;
4123 GC_TRIGGERS;
4124 INJECT_FAULT(COMPlusThrowOM());
4125 MODE_ANY;
4126 }
4127 CONTRACTL_END
4128
4129 bool fSameTypeDef = (pTypeDef1->GetTypeDefRid() == pTypeDef2->GetTypeDefRid()) && (pTypeDef1->GetModule() == pTypeDef2->GetModule());
4130
4131 if (!fSameTypeDef)
4132 {
4133 if (!pTypeDef1->GetClass()->IsEquivalentType() || !pTypeDef2->GetClass()->IsEquivalentType() || TokenPairList::InTypeEquivalenceForbiddenScope(pVisited))
4134 {
4135 return FALSE;
4136 }
4137 else
4138 {
4139 if (!CompareTypeDefsForEquivalence(pTypeDef1->GetCl(), pTypeDef2->GetCl(), pTypeDef1->GetModule(), pTypeDef2->GetModule(), pVisited))
4140 {
4141 return FALSE;
4142 }
4143 }
4144 }
4145
4146 if (pTypeDef1->GetNumGenericArgs() != pTypeDef2->GetNumGenericArgs())
4147 return FALSE;
4148
4149 if (pTypeDef1->GetNumGenericArgs() == 0)
4150 return TRUE;
4151
4152 if ((pSubst1 == NULL) || (pSubst2 == NULL) || pSubst1->GetInst().IsNull() || pSubst2->GetInst().IsNull())
4153 return FALSE;
4154
4155 SigPointer inst1 = pSubst1->GetInst();
4156 SigPointer inst2 = pSubst2->GetInst();
4157 for (DWORD i = 0; i < pTypeDef1->GetNumGenericArgs(); i++)
4158 {
4159 PCCOR_SIGNATURE startInst1 = inst1.GetPtr();
4160 IfFailThrow(inst1.SkipExactlyOne());
4161 PCCOR_SIGNATURE endInst1ptr = inst1.GetPtr();
4162 PCCOR_SIGNATURE startInst2 = inst2.GetPtr();
4163 IfFailThrow(inst2.SkipExactlyOne());
4164 PCCOR_SIGNATURE endInst2ptr = inst2.GetPtr();
4165 if (!CompareElementType(
4166 startInst1,
4167 startInst2,
4168 endInst1ptr,
4169 endInst2ptr,
4170 pSubst1->GetModule(),
4171 pSubst2->GetModule(),
4172 pSubst1->GetNext(),
4173 pSubst2->GetNext(),
4174 pVisited))
4175 {
4176 return FALSE;
4177 }
4178 }
4179 return TRUE;
4180
4181} // MetaSig::CompareTypeDefsUnderSubstitutions
4182
4183//---------------------------------------------------------------------------------------
4184//
4185BOOL
4186TypeHandleCompareHelper(
4187 TypeHandle th1,
4188 TypeHandle th2)
4189{
4190 CONTRACTL
4191 {
4192 THROWS;
4193 GC_TRIGGERS;
4194 INJECT_FAULT(COMPlusThrowOM());
4195 MODE_ANY;
4196 }
4197 CONTRACTL_END
4198
4199#ifndef DACCESS_COMPILE
4200 return th1.IsEquivalentTo(th2);
4201#else
4202 return TRUE;
4203#endif // #ifndef DACCESS_COMPILE
4204}
4205
4206//---------------------------------------------------------------------------------------
4207//
4208//static
4209BOOL
4210MetaSig::CompareMethodSigs(
4211 MetaSig & msig1,
4212 MetaSig & msig2,
4213 BOOL ignoreCallconv)
4214{
4215 CONTRACTL
4216 {
4217 THROWS;
4218 GC_TRIGGERS;
4219 INJECT_FAULT(COMPlusThrowOM());
4220 MODE_ANY;
4221 }
4222 CONTRACTL_END
4223
4224 if (!ignoreCallconv &&
4225 ((msig1.GetCallingConventionInfo() & IMAGE_CEE_CS_CALLCONV_MASK)
4226 != (msig2.GetCallingConventionInfo() & IMAGE_CEE_CS_CALLCONV_MASK)))
4227 {
4228 return FALSE; // calling convention mismatch
4229 }
4230
4231 if (msig1.NumFixedArgs() != msig2.NumFixedArgs())
4232 return FALSE; // number of arguments don't match
4233
4234 // check that the argument types are equal
4235 for (DWORD i = 0; i<msig1.NumFixedArgs(); i++) //@GENERICSVER: does this really do the return type too?
4236 {
4237 CorElementType et1 = msig1.NextArg();
4238 CorElementType et2 = msig2.NextArg();
4239 if (et1 != et2)
4240 return FALSE;
4241 if (!CorTypeInfo::IsPrimitiveType(et1))
4242 {
4243 if (!TypeHandleCompareHelper(msig1.GetLastTypeHandleThrowing(), msig2.GetLastTypeHandleThrowing()))
4244 return FALSE;
4245 }
4246 }
4247
4248 CorElementType ret1 = msig1.GetReturnType();
4249 CorElementType ret2 = msig2.GetReturnType();
4250 if (ret1 != ret2)
4251 return FALSE;
4252
4253 if (!CorTypeInfo::IsPrimitiveType(ret1))
4254 {
4255 return TypeHandleCompareHelper(msig1.GetRetTypeHandleThrowing(), msig2.GetRetTypeHandleThrowing());
4256 }
4257
4258 return TRUE;
4259}
4260
4261//---------------------------------------------------------------------------------------
4262//
4263//static
4264HRESULT
4265MetaSig::CompareMethodSigsNT(
4266 PCCOR_SIGNATURE pSignature1,
4267 DWORD cSig1,
4268 Module * pModule1,
4269 const Substitution * pSubst1,
4270 PCCOR_SIGNATURE pSignature2,
4271 DWORD cSig2,
4272 Module * pModule2,
4273 const Substitution * pSubst2,
4274 TokenPairList * pVisited) //= NULL
4275{
4276 STATIC_CONTRACT_NOTHROW;
4277
4278 HRESULT hr = S_OK;
4279 EX_TRY
4280 {
4281 if (CompareMethodSigs(pSignature1, cSig1, pModule1, pSubst1, pSignature2, cSig2, pModule2, pSubst2, pVisited))
4282 hr = S_OK;
4283 else
4284 hr = S_FALSE;
4285 }
4286 EX_CATCH_HRESULT_NO_ERRORINFO(hr);
4287 return hr;
4288}
4289
4290//---------------------------------------------------------------------------------------
4291//
4292// Compare two method sigs and return whether they are the same.
4293// @GENERICS: instantiation of the type variables in the second signature
4294//
4295//static
4296BOOL
4297MetaSig::CompareMethodSigs(
4298 PCCOR_SIGNATURE pSignature1,
4299 DWORD cSig1,
4300 Module * pModule1,
4301 const Substitution * pSubst1,
4302 PCCOR_SIGNATURE pSignature2,
4303 DWORD cSig2,
4304 Module * pModule2,
4305 const Substitution * pSubst2,
4306 TokenPairList * pVisited) //= NULL
4307{
4308 CONTRACTL
4309 {
4310 THROWS;
4311 GC_TRIGGERS;
4312 INJECT_FAULT(COMPlusThrowOM());
4313 MODE_ANY;
4314 }
4315 CONTRACTL_END
4316
4317 PCCOR_SIGNATURE pSig1 = pSignature1;
4318 PCCOR_SIGNATURE pSig2 = pSignature2;
4319 PCCOR_SIGNATURE pEndSig1 = pSignature1 + cSig1;
4320 PCCOR_SIGNATURE pEndSig2 = pSignature2 + cSig2;
4321 DWORD ArgCount1;
4322 DWORD ArgCount2;
4323 DWORD i;
4324
4325 // If scopes are the same, and sigs are same, can return.
4326 // If the sigs aren't the same, but same scope, can't return yet, in
4327 // case there are two AssemblyRefs pointing to the same assembly or such.
4328 if ((pModule1 == pModule2) &&
4329 (cSig1 == cSig2) &&
4330 (pSubst1 == NULL) &&
4331 (pSubst2 == NULL) &&
4332 (memcmp(pSig1, pSig2, cSig1) == 0))
4333 {
4334 return TRUE;
4335 }
4336
4337 if ((*pSig1 & ~CORINFO_CALLCONV_PARAMTYPE) != (*pSig2 & ~CORINFO_CALLCONV_PARAMTYPE))
4338 { // Calling convention or hasThis mismatch
4339 return FALSE;
4340 }
4341
4342 __int8 callConv = *pSig1;
4343
4344 pSig1++;
4345 pSig2++;
4346
4347 if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
4348 {
4349 DWORD TyArgCount1;
4350 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &TyArgCount1));
4351 DWORD TyArgCount2;
4352 IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &TyArgCount2));
4353
4354 if (TyArgCount1 != TyArgCount2)
4355 return FALSE;
4356 }
4357
4358 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &ArgCount1));
4359 IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &ArgCount2));
4360
4361 if (ArgCount1 != ArgCount2)
4362 {
4363 if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) != IMAGE_CEE_CS_CALLCONV_VARARG)
4364 return FALSE;
4365
4366 // Signature #1 is the caller. We proceed until we hit the sentinel, or we hit
4367 // the end of the signature (which is an implied sentinel). We never worry about
4368 // what follows the sentinel, because that is the ... part, which is not
4369 // involved in matching.
4370 //
4371 // Theoretically, it's illegal for a sentinel to be the last element in the
4372 // caller's signature, because it's redundant. We don't waste our time checking
4373 // that case, but the metadata validator should. Also, it is always illegal
4374 // for a sentinel to appear in a callee's signature. We assert against this,
4375 // but in the shipping product the comparison would simply fail.
4376 //
4377 // Signature #2 is the callee. We must hit the exact end of the callee, because
4378 // we are trying to match on everything up to the variable part. This allows us
4379 // to correctly handle overloads, where there are a number of varargs methods
4380 // to pick from, like m1(int,...) and m2(int,int,...), etc.
4381
4382 // <= because we want to include a check of the return value!
4383 for (i = 0; i <= ArgCount1; i++)
4384 {
4385 // We may be just going out of bounds on the callee, but no further than that.
4386 _ASSERTE(i <= ArgCount2 + 1);
4387
4388 // If we matched all the way on the caller, is the callee now complete?
4389 if (*pSig1 == ELEMENT_TYPE_SENTINEL)
4390 return (i > ArgCount2);
4391
4392 // if we have more to compare on the caller side, but the callee side is
4393 // exhausted, this isn't our match
4394 if (i > ArgCount2)
4395 return FALSE;
4396
4397 // This would be a breaking change to make this throw... see comment above
4398 _ASSERT(*pSig2 != ELEMENT_TYPE_SENTINEL);
4399
4400 // We are in bounds on both sides. Compare the element.
4401 if (!CompareElementType(
4402 pSig1,
4403 pSig2,
4404 pEndSig1,
4405 pEndSig2,
4406 pModule1,
4407 pModule2,
4408 pSubst1,
4409 pSubst2,
4410 pVisited))
4411 {
4412 return FALSE;
4413 }
4414 }
4415
4416 // If we didn't consume all of the callee signature, then we failed.
4417 if (i <= ArgCount2)
4418 return FALSE;
4419
4420 return TRUE;
4421 }
4422
4423 // do return type as well
4424 for (i = 0; i <= ArgCount1; i++)
4425 {
4426 if (!CompareElementType(
4427 pSig1,
4428 pSig2,
4429 pEndSig1,
4430 pEndSig2,
4431 pModule1,
4432 pModule2,
4433 pSubst1,
4434 pSubst2,
4435 pVisited))
4436 {
4437 return FALSE;
4438 }
4439 }
4440
4441 return TRUE;
4442} // MetaSig::CompareMethodSigs
4443
4444//---------------------------------------------------------------------------------------
4445//
4446//static
4447BOOL MetaSig::CompareFieldSigs(
4448 PCCOR_SIGNATURE pSignature1,
4449 DWORD cSig1,
4450 Module * pModule1,
4451 PCCOR_SIGNATURE pSignature2,
4452 DWORD cSig2,
4453 Module * pModule2,
4454 TokenPairList * pVisited) //= NULL
4455{
4456 WRAPPER_NO_CONTRACT;
4457
4458 PCCOR_SIGNATURE pSig1 = pSignature1;
4459 PCCOR_SIGNATURE pSig2 = pSignature2;
4460 PCCOR_SIGNATURE pEndSig1;
4461 PCCOR_SIGNATURE pEndSig2;
4462
4463#if 0
4464 // <TODO>@TODO: If scopes are the same, use identity rule - for now, don't, so that we test the code paths</TODO>
4465 if (cSig1 != cSig2)
4466 return(FALSE); // sigs must be same size if they are in the same scope
4467#endif
4468
4469 if (*pSig1 != *pSig2)
4470 return(FALSE); // calling convention, must be IMAGE_CEE_CS_CALLCONV_FIELD
4471
4472 pEndSig1 = pSig1 + cSig1;
4473 pEndSig2 = pSig2 + cSig2;
4474
4475 return(CompareElementType(++pSig1, ++pSig2, pEndSig1, pEndSig2, pModule1, pModule2, NULL, NULL, pVisited));
4476}
4477
4478#ifndef DACCESS_COMPILE
4479
4480//---------------------------------------------------------------------------------------
4481//
4482//static
4483BOOL
4484MetaSig::CompareElementTypeToToken(
4485 PCCOR_SIGNATURE & pSig1,
4486 PCCOR_SIGNATURE pEndSig1, // end of sig1
4487 mdToken tk2,
4488 Module * pModule1,
4489 Module * pModule2,
4490 const Substitution * pSubst1,
4491 TokenPairList * pVisited)
4492{
4493 CONTRACTL
4494 {
4495 THROWS;
4496 GC_TRIGGERS;
4497 INJECT_FAULT(COMPlusThrowOM());
4498 MODE_ANY;
4499 }
4500 CONTRACTL_END
4501
4502 _ASSERTE((TypeFromToken(tk2) == mdtTypeDef) ||
4503 (TypeFromToken(tk2) == mdtTypeRef));
4504
4505 if (pSig1 >= pEndSig1)
4506 { // End of sig encountered prematurely
4507 return FALSE;
4508 }
4509
4510 if ((*pSig1 == ELEMENT_TYPE_VAR) && (pSubst1 != NULL) && !pSubst1->GetInst().IsNull())
4511 {
4512 SigPointer inst = pSubst1->GetInst();
4513 pSig1++;
4514 DWORD index;
4515 IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &index));
4516
4517 for (DWORD i = 0; i < index; i++)
4518 {
4519 IfFailThrow(inst.SkipExactlyOne());
4520 }
4521 PCCOR_SIGNATURE pSig3 = inst.GetPtr();
4522 IfFailThrow(inst.SkipExactlyOne());
4523 PCCOR_SIGNATURE pEndSig3 = inst.GetPtr();
4524
4525 return CompareElementTypeToToken(
4526 pSig3,
4527 pEndSig3,
4528 tk2,
4529 pSubst1->GetModule(),
4530 pModule2,
4531 pSubst1->GetNext(),
4532 pVisited);
4533 }
4534
4535 CorElementType Type1 = ELEMENT_TYPE_MAX; // initialize to illegal
4536
4537 IfFailThrow(CorSigUncompressElementType_EndPtr(pSig1, pEndSig1, &Type1));
4538 _ASSERTE(Type1 != ELEMENT_TYPE_INTERNAL);
4539
4540 if (Type1 == ELEMENT_TYPE_INTERNAL)
4541 {
4542 // this check is not functional in DAC and provides no security against a malicious dump
4543 // the DAC is prepared to receive an invalid type handle
4544#ifndef DACCESS_COMPILE
4545 if (pModule1->IsSigInIL(pSig1))
4546 {
4547 THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module*)pModule1);
4548 }
4549#endif
4550 }
4551
4552 switch (Type1)
4553 {
4554 default:
4555 { // Unknown type!
4556 THROW_BAD_FORMAT(BFA_BAD_COMPLUS_SIG, pModule1);
4557 }
4558
4559 case ELEMENT_TYPE_U:
4560 case ELEMENT_TYPE_I:
4561 case ELEMENT_TYPE_VOID:
4562 case ELEMENT_TYPE_I1:
4563 case ELEMENT_TYPE_U1:
4564 case ELEMENT_TYPE_I2:
4565 case ELEMENT_TYPE_U2:
4566 case ELEMENT_TYPE_I4:
4567 case ELEMENT_TYPE_U4:
4568 case ELEMENT_TYPE_I8:
4569 case ELEMENT_TYPE_U8:
4570 case ELEMENT_TYPE_R4:
4571 case ELEMENT_TYPE_R8:
4572 case ELEMENT_TYPE_BOOLEAN:
4573 case ELEMENT_TYPE_CHAR:
4574 case ELEMENT_TYPE_TYPEDBYREF:
4575 case ELEMENT_TYPE_STRING:
4576 case ELEMENT_TYPE_OBJECT:
4577 {
4578 break;
4579 }
4580
4581 case ELEMENT_TYPE_VAR:
4582 case ELEMENT_TYPE_MVAR:
4583 {
4584 return FALSE;
4585 }
4586 case ELEMENT_TYPE_CMOD_REQD:
4587 case ELEMENT_TYPE_CMOD_OPT:
4588 {
4589 return FALSE;
4590 }
4591 // These take an additional argument, which is the element type
4592 case ELEMENT_TYPE_SZARRAY:
4593 case ELEMENT_TYPE_PTR:
4594 case ELEMENT_TYPE_BYREF:
4595 {
4596 return FALSE;
4597 }
4598 case ELEMENT_TYPE_VALUETYPE:
4599 case ELEMENT_TYPE_CLASS:
4600 {
4601 mdToken tk1;
4602
4603 IfFailThrow(CorSigUncompressToken_EndPtr(pSig1, pEndSig1, &tk1));
4604
4605 return CompareTypeTokens(
4606 tk1,
4607 tk2,
4608 pModule1,
4609 pModule2,
4610 pVisited);
4611 }
4612 case ELEMENT_TYPE_FNPTR:
4613 {
4614 return FALSE;
4615 }
4616 case ELEMENT_TYPE_GENERICINST:
4617 {
4618 return FALSE;
4619 }
4620 case ELEMENT_TYPE_ARRAY:
4621 {
4622 return FALSE;
4623 }
4624 case ELEMENT_TYPE_INTERNAL:
4625 {
4626 return FALSE;
4627 }
4628 }
4629
4630 return CompareTypeTokens(
4631 MscorlibBinder::GetElementType(Type1)->GetCl(),
4632 tk2,
4633 MscorlibBinder::GetModule(),
4634 pModule2,
4635 pVisited);
4636} // MetaSig::CompareElementTypeToToken
4637
4638/* static */
4639BOOL MetaSig::CompareTypeSpecToToken(mdTypeSpec tk1,
4640 mdToken tk2,
4641 Module *pModule1,
4642 Module *pModule2,
4643 const Substitution *pSubst1,
4644 TokenPairList *pVisited)
4645{
4646 CONTRACTL
4647 {
4648 THROWS;
4649 GC_TRIGGERS;
4650 INJECT_FAULT(COMPlusThrowOM());
4651 MODE_ANY;
4652 }
4653 CONTRACTL_END
4654
4655 _ASSERTE(TypeFromToken(tk1) == mdtTypeSpec);
4656 _ASSERTE(TypeFromToken(tk2) == mdtTypeDef ||
4657 TypeFromToken(tk2) == mdtTypeRef);
4658
4659 IMDInternalImport *pInternalImport = pModule1->GetMDImport();
4660
4661 PCCOR_SIGNATURE pSig1;
4662 ULONG cSig1;
4663 IfFailThrow(pInternalImport->GetTypeSpecFromToken(tk1, &pSig1, &cSig1));
4664
4665 TokenPairList newVisited = TokenPairList::AdjustForTypeSpec(pVisited, pModule1, pSig1, cSig1);
4666
4667 return CompareElementTypeToToken(pSig1,pSig1+cSig1,tk2,pModule1,pModule2,pSubst1,&newVisited);
4668} // MetaSig::CompareTypeSpecToToken
4669
4670
4671/* static */
4672BOOL MetaSig::CompareTypeDefOrRefOrSpec(Module *pModule1, mdToken tok1,
4673 const Substitution *pSubst1,
4674 Module *pModule2, mdToken tok2,
4675 const Substitution *pSubst2,
4676 TokenPairList *pVisited)
4677{
4678 CONTRACTL
4679 {
4680 THROWS;
4681 GC_TRIGGERS;
4682 INJECT_FAULT(COMPlusThrowOM());
4683 MODE_ANY;
4684 }
4685 CONTRACTL_END
4686
4687 if (TypeFromToken(tok1) != mdtTypeSpec && TypeFromToken(tok2) != mdtTypeSpec)
4688 {
4689 _ASSERTE(TypeFromToken(tok1) == mdtTypeDef || TypeFromToken(tok1) == mdtTypeRef);
4690 _ASSERTE(TypeFromToken(tok2) == mdtTypeDef || TypeFromToken(tok2) == mdtTypeRef);
4691 return CompareTypeTokens(tok1,tok2,pModule1,pModule2,pVisited);
4692 }
4693
4694 if (TypeFromToken(tok1) != TypeFromToken(tok2))
4695 {
4696 if (TypeFromToken(tok1) == mdtTypeSpec)
4697 {
4698 return CompareTypeSpecToToken(tok1,tok2,pModule1,pModule2,pSubst1,pVisited);
4699 }
4700 else
4701 {
4702 _ASSERTE(TypeFromToken(tok2) == mdtTypeSpec);
4703 return CompareTypeSpecToToken(tok2,tok1,pModule2,pModule1,pSubst2,pVisited);
4704 }
4705 }
4706
4707 _ASSERTE(TypeFromToken(tok1) == mdtTypeSpec &&
4708 TypeFromToken(tok2) == mdtTypeSpec);
4709
4710 IMDInternalImport *pInternalImport1 = pModule1->GetMDImport();
4711 IMDInternalImport *pInternalImport2 = pModule2->GetMDImport();
4712
4713 PCCOR_SIGNATURE pSig1,pSig2;
4714 ULONG cSig1,cSig2;
4715 IfFailThrow(pInternalImport1->GetTypeSpecFromToken(tok1, &pSig1, &cSig1));
4716 IfFailThrow(pInternalImport2->GetTypeSpecFromToken(tok2, &pSig2, &cSig2));
4717 return MetaSig::CompareElementType(pSig1,pSig2,pSig1+cSig1,pSig2+cSig2,pModule1,pModule2,pSubst1,pSubst2,pVisited);
4718} // MetaSig::CompareTypeDefOrRefOrSpec
4719
4720/* static */
4721BOOL MetaSig::CompareVariableConstraints(const Substitution *pSubst1,
4722 Module *pModule1, mdGenericParam tok1, //overriding
4723 const Substitution *pSubst2,
4724 Module *pModule2, mdGenericParam tok2) //overridden
4725{
4726 CONTRACTL
4727 {
4728 THROWS;
4729 GC_TRIGGERS;
4730 INJECT_FAULT(COMPlusThrowOM());
4731 MODE_ANY;
4732 }
4733 CONTRACTL_END
4734
4735 IMDInternalImport *pInternalImport1 = pModule1->GetMDImport();
4736 IMDInternalImport *pInternalImport2 = pModule2->GetMDImport();
4737
4738 DWORD specialConstraints1,specialConstraints2;
4739
4740 // check special constraints
4741 {
4742 IfFailThrow(pInternalImport1->GetGenericParamProps(tok1, NULL, &specialConstraints1, NULL, NULL, NULL));
4743 IfFailThrow(pInternalImport2->GetGenericParamProps(tok2, NULL, &specialConstraints2, NULL, NULL, NULL));
4744 specialConstraints1 = specialConstraints1 & gpSpecialConstraintMask;
4745 specialConstraints2 = specialConstraints2 & gpSpecialConstraintMask;
4746
4747 if ((specialConstraints1 & gpNotNullableValueTypeConstraint) != 0)
4748 {
4749 if ((specialConstraints2 & gpNotNullableValueTypeConstraint) == 0)
4750 return FALSE;
4751 }
4752 if ((specialConstraints1 & gpReferenceTypeConstraint) != 0)
4753 {
4754 if ((specialConstraints2 & gpReferenceTypeConstraint) == 0)
4755 return FALSE;
4756 }
4757 if ((specialConstraints1 & gpDefaultConstructorConstraint) != 0)
4758 {
4759 if ((specialConstraints2 & (gpDefaultConstructorConstraint | gpNotNullableValueTypeConstraint)) == 0)
4760 return FALSE;
4761 }
4762 }
4763
4764
4765 HENUMInternalHolder hEnum1(pInternalImport1);
4766 mdGenericParamConstraint tkConstraint1;
4767 hEnum1.EnumInit(mdtGenericParamConstraint, tok1);
4768
4769 while (pInternalImport1->EnumNext(&hEnum1, &tkConstraint1))
4770 {
4771 mdToken tkConstraintType1, tkParam1;
4772 IfFailThrow(pInternalImport1->GetGenericParamConstraintProps(tkConstraint1, &tkParam1, &tkConstraintType1));
4773 _ASSERTE(tkParam1 == tok1);
4774
4775 // for each non-object constraint,
4776 // and, in the case of a notNullableValueType, each non-ValueType constraint,
4777 // find an equivalent constraint on tok2
4778 // NB: we do not attempt to match constraints equivalent to object (and ValueType when tok1 is notNullable)
4779 // because they
4780 // a) are vacuous, and
4781 // b) may be implicit (ie. absent) in the overriden variable's declaration
4782 if (!(CompareTypeDefOrRefOrSpec(pModule1, tkConstraintType1, NULL,
4783 MscorlibBinder::GetModule(), g_pObjectClass->GetCl(), NULL, NULL) ||
4784 (((specialConstraints1 & gpNotNullableValueTypeConstraint) != 0) &&
4785 (CompareTypeDefOrRefOrSpec(pModule1, tkConstraintType1, NULL,
4786 MscorlibBinder::GetModule(), g_pValueTypeClass->GetCl(), NULL, NULL)))))
4787 {
4788 HENUMInternalHolder hEnum2(pInternalImport2);
4789 mdGenericParamConstraint tkConstraint2;
4790 hEnum2.EnumInit(mdtGenericParamConstraint, tok2);
4791
4792 BOOL found = FALSE;
4793 while (!found && pInternalImport2->EnumNext(&hEnum2, &tkConstraint2) )
4794 {
4795 mdToken tkConstraintType2, tkParam2;
4796 IfFailThrow(pInternalImport2->GetGenericParamConstraintProps(tkConstraint2, &tkParam2, &tkConstraintType2));
4797 _ASSERTE(tkParam2 == tok2);
4798
4799 found = CompareTypeDefOrRefOrSpec(pModule1, tkConstraintType1, pSubst1, pModule2, tkConstraintType2, pSubst2, NULL);
4800 }
4801 if (!found)
4802 {
4803 //none of the constrains on tyvar2 match, exit early
4804 return FALSE;
4805 }
4806 }
4807 //check next constraint of tok1
4808 }
4809
4810 return TRUE;
4811}
4812
4813/* static */
4814BOOL MetaSig::CompareMethodConstraints(const Substitution *pSubst1,
4815 Module *pModule1,
4816 mdMethodDef tok1, //implementation
4817 const Substitution *pSubst2,
4818 Module *pModule2,
4819 mdMethodDef tok2) //declaration w.r.t subsitution
4820{
4821 CONTRACTL
4822 {
4823 THROWS;
4824 GC_TRIGGERS;
4825 INJECT_FAULT(COMPlusThrowOM());
4826 MODE_ANY;
4827 }
4828 CONTRACTL_END
4829
4830 IMDInternalImport *pInternalImport1 = pModule1->GetMDImport();
4831 IMDInternalImport *pInternalImport2 = pModule2->GetMDImport();
4832
4833 HENUMInternalHolder hEnumTyPars1(pInternalImport1);
4834 HENUMInternalHolder hEnumTyPars2(pInternalImport2);
4835
4836 hEnumTyPars1.EnumInit(mdtGenericParam, tok1);
4837 hEnumTyPars2.EnumInit(mdtGenericParam, tok2);
4838
4839 mdGenericParam tkTyPar1,tkTyPar2;
4840
4841 // enumerate the variables
4842 DWORD numTyPars1 = pInternalImport1->EnumGetCount(&hEnumTyPars1);
4843 DWORD numTyPars2 = pInternalImport2->EnumGetCount(&hEnumTyPars2);
4844
4845 _ASSERTE(numTyPars1 == numTyPars2);
4846 if (numTyPars1 != numTyPars2) //play it safe
4847 return FALSE; //throw bad format exception?
4848
4849 for(unsigned int i = 0; i < numTyPars1; i++)
4850 {
4851 pInternalImport1->EnumNext(&hEnumTyPars1, &tkTyPar1);
4852 pInternalImport2->EnumNext(&hEnumTyPars2, &tkTyPar2);
4853 if (!CompareVariableConstraints(pSubst1, pModule1, tkTyPar1, pSubst2, pModule2, tkTyPar2))
4854 {
4855 return FALSE;
4856 }
4857 }
4858 return TRUE;
4859}
4860
4861#endif // #ifndef DACCESS_COMPILE
4862
4863// PromoteCarefully
4864//
4865// Clients who know they MAY have an interior pointer should come through here. We
4866// can efficiently check whether our object lives on the current stack. If so, our
4867// reference to it is not an interior pointer. This is more efficient than asking
4868// the heap to verify whether our reference is interior, since it would have to
4869// check all the heap segments, including those containing large objects.
4870//
4871// Note that we only have to check against the thread we are currently crawling. It
4872// would be illegal for us to have a ByRef from someone else's stack. And this will
4873// be asserted if we pass this reference to the heap as a potentially interior pointer.
4874//
4875// But the thread we are currently crawling is not the currently executing thread (in
4876// the general case). We rely on fragile caching of the interesting thread, in our
4877// call to UpdateCachedStackInfo() where we initiate the crawl in GcScanRoots() above.
4878//
4879// The flags must indicate that the have an interior pointer GC_CALL_INTERIOR
4880// additionally the flags may indicate that we also have a pinned local byref
4881//
4882void PromoteCarefully(promote_func fn,
4883 PTR_PTR_Object ppObj,
4884 ScanContext* sc,
4885 uint32_t flags /* = GC_CALL_INTERIOR*/ )
4886{
4887 LIMITED_METHOD_CONTRACT;
4888
4889 //
4890 // Sanity check that the flags contain only these three values
4891 //
4892 assert((flags & ~(GC_CALL_INTERIOR|GC_CALL_PINNED|GC_CALL_CHECK_APP_DOMAIN)) == 0);
4893
4894 //
4895 // Sanity check that GC_CALL_INTERIOR FLAG is set
4896 //
4897 assert(flags & GC_CALL_INTERIOR);
4898
4899#if !defined(DACCESS_COMPILE)
4900
4901 //
4902 // Sanity check the stack scan limit
4903 //
4904 assert(sc->stack_limit != 0);
4905
4906 // Note that the base is at a higher address than the limit, since the stack
4907 // grows downwards.
4908 // To check whether the object is in the stack or not, we also need to check the sc->stack_limit.
4909 // The reason is that on Unix, the stack size can be unlimited. In such case, the system can
4910 // shrink the current reserved stack space. That causes the real limit of the stack to move up and
4911 // the range can be reused for other purposes. But the sc->stack_limit is stable during the scan.
4912 // Even on Windows, we care just about the stack above the stack_limit.
4913 if ((sc->thread_under_crawl->IsAddressInStack(*ppObj)) && (PTR_TO_TADDR(*ppObj) >= sc->stack_limit))
4914 {
4915 return;
4916 }
4917
4918#endif // !defined(DACCESS_COMPILE)
4919
4920 (*fn) (ppObj, sc, flags);
4921}
4922
4923void ReportPointersFromValueType(promote_func *fn, ScanContext *sc, PTR_MethodTable pMT, PTR_VOID pSrc)
4924{
4925 WRAPPER_NO_CONTRACT;
4926
4927 if (pMT->IsByRefLike())
4928 {
4929 FindByRefPointerOffsetsInByRefLikeObject(
4930 pMT,
4931 0 /* baseOffset */,
4932 [&](SIZE_T pointerOffset)
4933 {
4934 PTR_PTR_Object fieldRef = dac_cast<PTR_PTR_Object>(PTR_BYTE(pSrc) + pointerOffset);
4935 (*fn)(fieldRef, sc, GC_CALL_INTERIOR);
4936 });
4937 }
4938
4939 if (!pMT->ContainsPointers())
4940 return;
4941
4942 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
4943 CGCDescSeries* cur = map->GetHighestSeries();
4944 CGCDescSeries* last = map->GetLowestSeries();
4945 DWORD size = pMT->GetBaseSize();
4946 _ASSERTE(cur >= last);
4947
4948 do
4949 {
4950 // offset to embedded references in this series must be
4951 // adjusted by the VTable pointer, when in the unboxed state.
4952 size_t offset = cur->GetSeriesOffset() - TARGET_POINTER_SIZE;
4953 PTR_OBJECTREF srcPtr = dac_cast<PTR_OBJECTREF>(PTR_BYTE(pSrc) + offset);
4954 PTR_OBJECTREF srcPtrStop = dac_cast<PTR_OBJECTREF>(PTR_BYTE(srcPtr) + cur->GetSeriesSize() + size);
4955 while (srcPtr < srcPtrStop)
4956 {
4957 (*fn)(dac_cast<PTR_PTR_Object>(srcPtr), sc, 0);
4958 srcPtr = (PTR_OBJECTREF)(PTR_BYTE(srcPtr) + TARGET_POINTER_SIZE);
4959 }
4960 cur--;
4961 } while (cur >= last);
4962}
4963
4964void ReportPointersFromValueTypeArg(promote_func *fn, ScanContext *sc, PTR_MethodTable pMT, ArgDestination *pSrc)
4965{
4966 WRAPPER_NO_CONTRACT;
4967
4968 if (!pMT->ContainsPointers() && !pMT->IsByRefLike())
4969 {
4970 return;
4971 }
4972
4973#if defined(UNIX_AMD64_ABI)
4974 if (pSrc->IsStructPassedInRegs())
4975 {
4976 pSrc->ReportPointersFromStructInRegisters(fn, sc, pMT->GetNumInstanceFieldBytes());
4977 return;
4978 }
4979#endif // UNIX_AMD64_ABI
4980
4981 ReportPointersFromValueType(fn, sc, pMT, pSrc->GetDestinationAddress());
4982}
4983
4984//------------------------------------------------------------------
4985// Perform type-specific GC promotion on the value (based upon the
4986// last type retrieved by NextArg()).
4987//------------------------------------------------------------------
4988VOID MetaSig::GcScanRoots(ArgDestination *pValue,
4989 promote_func *fn,
4990 ScanContext* sc,
4991 promote_carefully_func *fnc)
4992{
4993
4994 CONTRACTL
4995 {
4996 INSTANCE_CHECK;
4997 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
4998 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
4999 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
5000 MODE_ANY;
5001 }
5002 CONTRACTL_END
5003
5004
5005 PTR_PTR_Object pArgPtr = (PTR_PTR_Object)pValue->GetDestinationAddress();
5006 if (fnc == NULL)
5007 fnc = &PromoteCarefully;
5008
5009 TypeHandle thValueType;
5010 CorElementType etype = m_pLastType.PeekElemTypeNormalized(m_pModule, &m_typeContext, &thValueType);
5011
5012 _ASSERTE(etype >= 0 && etype < ELEMENT_TYPE_MAX);
5013
5014#ifdef _DEBUG
5015 PTR_Object pOldLocation;
5016#endif
5017
5018 switch (gElementTypeInfo[etype].m_gc)
5019 {
5020 case TYPE_GC_NONE:
5021 // do nothing
5022 break;
5023
5024 case TYPE_GC_REF:
5025 LOG((LF_GC, INFO3,
5026 " Argument at" FMT_ADDR "causes promotion of " FMT_OBJECT "\n",
5027 DBG_ADDR(pArgPtr), DBG_ADDR(*pArgPtr) ));
5028#ifdef _DEBUG
5029 pOldLocation = *pArgPtr;
5030#endif
5031 (*fn)(pArgPtr, sc, GC_CALL_CHECK_APP_DOMAIN );
5032
5033 // !!! Do not cast to (OBJECTREF*)
5034 // !!! If we are in the relocate phase, we may have updated root,
5035 // !!! but we have not moved the GC heap yet.
5036 // !!! The root then points to bad locations until GC is done.
5037#ifdef LOGGING
5038 if (pOldLocation != *pArgPtr)
5039 LOG((LF_GC, INFO3,
5040 " Relocating from" FMT_ADDR "to " FMT_ADDR "\n",
5041 DBG_ADDR(pOldLocation), DBG_ADDR(*pArgPtr)));
5042#endif
5043 break;
5044
5045 case TYPE_GC_BYREF:
5046#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
5047 case_TYPE_GC_BYREF:
5048#endif // ENREGISTERED_PARAMTYPE_MAXSIZE
5049
5050 // value is an interior pointer
5051 LOG((LF_GC, INFO3,
5052 " Argument at" FMT_ADDR "causes promotion of interior pointer" FMT_ADDR "\n",
5053 DBG_ADDR(pArgPtr), DBG_ADDR(*pArgPtr) ));
5054
5055#ifdef _DEBUG
5056 pOldLocation = *pArgPtr;
5057#endif
5058
5059 (*fnc)(fn, pArgPtr, sc, GC_CALL_INTERIOR|GC_CALL_CHECK_APP_DOMAIN);
5060
5061 // !!! Do not cast to (OBJECTREF*)
5062 // !!! If we are in the relocate phase, we may have updated root,
5063 // !!! but we have not moved the GC heap yet.
5064 // !!! The root then points to bad locations until GC is done.
5065#ifdef LOGGING
5066 if (pOldLocation != *pArgPtr)
5067 LOG((LF_GC, INFO3,
5068 " Relocating from" FMT_ADDR "to " FMT_ADDR "\n",
5069 DBG_ADDR(pOldLocation), DBG_ADDR(*pArgPtr)));
5070#endif
5071 break;
5072
5073 case TYPE_GC_OTHER:
5074 // value is a ValueClass, generic type parameter
5075 // See one of the go_through_object() macros in
5076 // gc.cpp for the code we are emulating here. But note that the GCDesc
5077 // for value classes describes the state of the instance in its boxed
5078 // state. Here we are dealing with an unboxed instance, so we must adjust
5079 // the object size and series offsets appropriately.
5080 _ASSERTE(etype == ELEMENT_TYPE_VALUETYPE);
5081 {
5082 PTR_MethodTable pMT = thValueType.AsMethodTable();
5083
5084#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
5085 if (ArgIterator::IsArgPassedByRef(thValueType))
5086 {
5087 goto case_TYPE_GC_BYREF;
5088 }
5089#endif // ENREGISTERED_PARAMTYPE_MAXSIZE
5090
5091 ReportPointersFromValueTypeArg(fn, sc, pMT, pValue);
5092 }
5093 break;
5094
5095 default:
5096 _ASSERTE(0); // can't get here.
5097 }
5098}
5099
5100
5101#ifndef DACCESS_COMPILE
5102
5103void MetaSig::EnsureSigValueTypesLoaded(MethodDesc *pMD)
5104{
5105 CONTRACTL
5106 {
5107 THROWS;
5108 GC_TRIGGERS;
5109 INJECT_FAULT(COMPlusThrowOM());
5110 MODE_ANY;
5111 }
5112 CONTRACTL_END
5113
5114 SigTypeContext typeContext(pMD);
5115
5116 Module * pModule = pMD->GetModule();
5117
5118 // The signature format is approximately:
5119 // CallingConvention NumberOfArguments ReturnType Arg1 ...
5120 // There is also a blob length at pSig-1.
5121 SigPointer ptr(pMD->GetSig());
5122
5123 // Skip over calling convention.
5124 IfFailThrowBF(ptr.GetCallingConv(NULL), BFA_BAD_SIGNATURE, pModule);
5125
5126 ULONG numArgs = 0;
5127 IfFailThrowBF(ptr.GetData(&numArgs), BFA_BAD_SIGNATURE, pModule);
5128
5129 // Force a load of value type arguments.
5130 for(ULONG i=0; i <= numArgs; i++)
5131 {
5132 ptr.PeekElemTypeNormalized(pModule,&typeContext);
5133 // Move to next argument token.
5134 IfFailThrowBF(ptr.SkipExactlyOne(), BFA_BAD_SIGNATURE, pModule);
5135 }
5136}
5137
5138// this walks the sig and checks to see if all types in the sig can be loaded
5139
5140// This is used by ComCallableWrapper to give good error reporting
5141/*static*/
5142void MetaSig::CheckSigTypesCanBeLoaded(MethodDesc * pMD)
5143{
5144 CONTRACTL
5145 {
5146 THROWS;
5147 GC_TRIGGERS;
5148 INJECT_FAULT(COMPlusThrowOM());
5149 MODE_ANY;
5150 }
5151 CONTRACTL_END
5152
5153 SigTypeContext typeContext(pMD);
5154
5155 Module * pModule = pMD->GetModule();
5156
5157 // The signature format is approximately:
5158 // CallingConvention NumberOfArguments ReturnType Arg1 ...
5159 // There is also a blob length at pSig-1.
5160 SigPointer ptr(pMD->GetSig());
5161
5162 // Skip over calling convention.
5163 IfFailThrowBF(ptr.GetCallingConv(NULL), BFA_BAD_SIGNATURE, pModule);
5164
5165 ULONG numArgs = 0;
5166 IfFailThrowBF(ptr.GetData(&numArgs), BFA_BAD_SIGNATURE, pModule);
5167
5168 // must do a skip so we skip any class tokens associated with the return type
5169 IfFailThrowBF(ptr.SkipExactlyOne(), BFA_BAD_SIGNATURE, pModule);
5170
5171 // Force a load of value type arguments.
5172 for(ULONG i=0; i < numArgs; i++)
5173 {
5174 unsigned type = ptr.PeekElemTypeNormalized(pModule,&typeContext);
5175 if (type == ELEMENT_TYPE_VALUETYPE || type == ELEMENT_TYPE_CLASS)
5176 {
5177 ptr.GetTypeHandleThrowing(pModule, &typeContext);
5178 }
5179 // Move to next argument token.
5180 IfFailThrowBF(ptr.SkipExactlyOne(), BFA_BAD_SIGNATURE, pModule);
5181 }
5182}
5183
5184#endif // #ifndef DACCESS_COMPILE
5185
5186CorElementType MetaSig::GetReturnTypeNormalized(TypeHandle * pthValueType) const
5187{
5188 WRAPPER_NO_CONTRACT;
5189 SUPPORTS_DAC;
5190
5191 if ((m_flags & SIG_RET_TYPE_INITTED) &&
5192 ((pthValueType == NULL) || (m_corNormalizedRetType != ELEMENT_TYPE_VALUETYPE)))
5193 {
5194 return( m_corNormalizedRetType );
5195 }
5196
5197 MetaSig * pSig = const_cast<MetaSig *>(this);
5198 pSig->m_corNormalizedRetType = m_pRetType.PeekElemTypeNormalized(m_pModule, &m_typeContext, pthValueType);
5199 pSig->m_flags |= SIG_RET_TYPE_INITTED;
5200
5201 return( m_corNormalizedRetType );
5202}
5203
5204BOOL MetaSig::IsObjectRefReturnType()
5205{
5206 WRAPPER_NO_CONTRACT;
5207
5208 switch (GetReturnTypeNormalized())
5209 {
5210 case ELEMENT_TYPE_CLASS:
5211 case ELEMENT_TYPE_SZARRAY:
5212 case ELEMENT_TYPE_ARRAY:
5213 case ELEMENT_TYPE_STRING:
5214 case ELEMENT_TYPE_OBJECT:
5215 case ELEMENT_TYPE_VAR:
5216 return( TRUE );
5217 default:
5218 break;
5219 }
5220 return( FALSE );
5221}
5222
5223CorElementType MetaSig::GetReturnType() const
5224{
5225 WRAPPER_NO_CONTRACT;
5226 return m_pRetType.PeekElemTypeClosed(GetModule(), &m_typeContext);
5227}
5228
5229BOOL MetaSig::IsReturnTypeVoid() const
5230{
5231 WRAPPER_NO_CONTRACT;
5232 return (GetReturnType() == ELEMENT_TYPE_VOID);
5233}
5234
5235#ifndef DACCESS_COMPILE
5236
5237//----------------------------------------------------------
5238// Returns the unmanaged calling convention.
5239//----------------------------------------------------------
5240/*static*/
5241BOOL
5242MetaSig::GetUnmanagedCallingConvention(
5243 Module * pModule,
5244 PCCOR_SIGNATURE pSig,
5245 ULONG cSig,
5246 CorPinvokeMap * pPinvokeMapOut)
5247{
5248 CONTRACTL
5249 {
5250 NOTHROW;
5251 GC_NOTRIGGER;
5252 FORBID_FAULT;
5253 MODE_ANY;
5254 }
5255 CONTRACTL_END
5256
5257
5258 // Instantiations aren't relevant here
5259 MetaSig msig(pSig, cSig, pModule, NULL);
5260 PCCOR_SIGNATURE pWalk = msig.m_pRetType.GetPtr();
5261 _ASSERTE(pWalk <= pSig + cSig);
5262 while ((pWalk < (pSig + cSig)) && ((*pWalk == ELEMENT_TYPE_CMOD_OPT) || (*pWalk == ELEMENT_TYPE_CMOD_REQD)))
5263 {
5264 BOOL fIsOptional = (*pWalk == ELEMENT_TYPE_CMOD_OPT);
5265
5266 pWalk++;
5267 if (pWalk + CorSigUncompressedDataSize(pWalk) > pSig + cSig)
5268 {
5269 return FALSE; // Bad formatting
5270 }
5271 mdToken tk;
5272 pWalk += CorSigUncompressToken(pWalk, &tk);
5273
5274 if (fIsOptional)
5275 {
5276 if (IsTypeRefOrDef("System.Runtime.CompilerServices.CallConvCdecl", pModule, tk))
5277 {
5278 *pPinvokeMapOut = pmCallConvCdecl;
5279 return TRUE;
5280 }
5281 else if (IsTypeRefOrDef("System.Runtime.CompilerServices.CallConvStdcall", pModule, tk))
5282 {
5283 *pPinvokeMapOut = pmCallConvStdcall;
5284 return TRUE;
5285 }
5286 else if (IsTypeRefOrDef("System.Runtime.CompilerServices.CallConvThiscall", pModule, tk))
5287 {
5288 *pPinvokeMapOut = pmCallConvThiscall;
5289 return TRUE;
5290 }
5291 else if (IsTypeRefOrDef("System.Runtime.CompilerServices.CallConvFastcall", pModule, tk))
5292 {
5293 *pPinvokeMapOut = pmCallConvFastcall;
5294 return TRUE;
5295 }
5296 }
5297 }
5298
5299 *pPinvokeMapOut = (CorPinvokeMap)0;
5300 return TRUE;
5301}
5302
5303//---------------------------------------------------------------------------------------
5304//
5305// Substitution from a token (TypeDef and TypeRef have empty instantiation, TypeSpec gets it from MetaData).
5306//
5307Substitution::Substitution(
5308 mdToken parentTypeDefOrRefOrSpec,
5309 Module * pModule,
5310 const Substitution * pNext)
5311{
5312 LIMITED_METHOD_CONTRACT;
5313
5314 m_pModule = pModule;
5315 m_pNext = pNext;
5316
5317 if (IsNilToken(parentTypeDefOrRefOrSpec) ||
5318 (TypeFromToken(parentTypeDefOrRefOrSpec) != mdtTypeSpec))
5319 {
5320 return;
5321 }
5322
5323 ULONG cbSig;
5324 PCCOR_SIGNATURE pSig = NULL;
5325 if (FAILED(pModule->GetMDImport()->GetTypeSpecFromToken(
5326 parentTypeDefOrRefOrSpec,
5327 &pSig,
5328 &cbSig)))
5329 {
5330 return;
5331 }
5332 SigPointer sigptr = SigPointer(pSig, cbSig);
5333 CorElementType type;
5334
5335 if (FAILED(sigptr.GetElemType(&type)))
5336 return;
5337
5338 // The only kind of type specs that we recognise are instantiated types
5339 if (type != ELEMENT_TYPE_GENERICINST)
5340 return;
5341
5342 if (FAILED(sigptr.GetElemType(&type)))
5343 return;
5344
5345 if (type != ELEMENT_TYPE_CLASS)
5346 return;
5347
5348 /* mdToken genericTok = */
5349 if (FAILED(sigptr.GetToken(NULL)))
5350 return;
5351 /* DWORD ntypars = */
5352 if (FAILED(sigptr.GetData(NULL)))
5353 return;
5354
5355 m_sigInst = sigptr;
5356} // Substitution::Substitution
5357
5358//---------------------------------------------------------------------------------------
5359//
5360void
5361Substitution::CopyToArray(
5362 Substitution * pTarget) const
5363{
5364 LIMITED_METHOD_CONTRACT;
5365
5366 const Substitution * pChain = this;
5367 DWORD i = 0;
5368 for (; pChain != NULL; pChain = pChain->GetNext())
5369 {
5370 CONSISTENCY_CHECK(CheckPointer(pChain->GetModule()));
5371
5372 Substitution * pNext = (pChain->GetNext() != NULL) ? &pTarget[i + 1] : NULL;
5373 pTarget[i++] = Substitution(pChain->GetModule(), pChain->GetInst(), pNext);
5374 }
5375}
5376
5377//---------------------------------------------------------------------------------------
5378//
5379DWORD Substitution::GetLength() const
5380{
5381 LIMITED_METHOD_CONTRACT;
5382 DWORD res = 0;
5383 for (const Substitution * pChain = this; pChain != NULL; pChain = pChain->m_pNext)
5384 {
5385 res++;
5386 }
5387 return res;
5388}
5389
5390//---------------------------------------------------------------------------------------
5391//
5392void Substitution::DeleteChain()
5393{
5394 LIMITED_METHOD_CONTRACT;
5395 if (m_pNext != NULL)
5396 {
5397 ((Substitution *)m_pNext)->DeleteChain();
5398 }
5399 delete this;
5400}
5401
5402#endif // #ifndef DACCESS_COMPILE
5403
5404//---------------------------------------------------------------------------------------
5405//
5406// static
5407TokenPairList TokenPairList::AdjustForTypeSpec(TokenPairList *pTemplate, Module *pTypeSpecModule, PCCOR_SIGNATURE pTypeSpecSig, DWORD cbTypeSpecSig)
5408{
5409 CONTRACTL
5410 {
5411 THROWS;
5412 MODE_ANY;
5413 GC_TRIGGERS;
5414 }
5415 CONTRACTL_END
5416
5417 TokenPairList result(pTemplate);
5418
5419 if (InTypeEquivalenceForbiddenScope(&result))
5420 {
5421 // it cannot get any worse
5422 return result;
5423 }
5424
5425 SigParser sig(pTypeSpecSig, cbTypeSpecSig);
5426 CorElementType elemType;
5427
5428 IfFailThrow(sig.GetElemType(&elemType));
5429 if (elemType != ELEMENT_TYPE_GENERICINST)
5430 {
5431 // we don't care about anything else than generic instantiations
5432 return result;
5433 }
5434
5435 IfFailThrow(sig.GetElemType(&elemType));
5436
5437 if (elemType == ELEMENT_TYPE_CLASS)
5438 {
5439 mdToken tkType;
5440 IfFailThrow(sig.GetToken(&tkType));
5441
5442 Module *pModule;
5443 if (!ClassLoader::ResolveTokenToTypeDefThrowing(pTypeSpecModule,
5444 tkType,
5445 &pModule,
5446 &tkType))
5447 {
5448 // we couldn't prove otherwise so assume that this is not an interface
5449 result.m_bInTypeEquivalenceForbiddenScope = TRUE;
5450 }
5451 else
5452 {
5453 DWORD dwAttrType;
5454 IfFailThrow(pModule->GetMDImport()->GetTypeDefProps(tkType, &dwAttrType, NULL));
5455
5456 result.m_bInTypeEquivalenceForbiddenScope = !IsTdInterface(dwAttrType);
5457 }
5458 }
5459 else
5460 {
5461 _ASSERTE(elemType == ELEMENT_TYPE_VALUETYPE);
5462 result.m_bInTypeEquivalenceForbiddenScope = TRUE;
5463 }
5464
5465 return result;
5466}
5467
5468// static
5469TokenPairList TokenPairList::AdjustForTypeEquivalenceForbiddenScope(TokenPairList *pTemplate)
5470{
5471 CONTRACTL
5472 {
5473 THROWS;
5474 MODE_ANY;
5475 GC_TRIGGERS;
5476 }
5477 CONTRACTL_END
5478
5479 TokenPairList result(pTemplate);
5480 result.m_bInTypeEquivalenceForbiddenScope = TRUE;
5481 return result;
5482}
5483
5484// TRUE if the two TypeDefs have the same layout and field marshal information.
5485BOOL CompareTypeLayout(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModule2)
5486{
5487 CONTRACTL
5488 {
5489 THROWS;
5490 MODE_ANY;
5491 GC_NOTRIGGER;
5492 PRECONDITION(TypeFromToken(tk1) == mdtTypeDef);
5493 PRECONDITION(TypeFromToken(tk2) == mdtTypeDef);
5494 }
5495 CONTRACTL_END
5496
5497 DWORD dwAttr1, dwAttr2;
5498 IMDInternalImport *pInternalImport1 = pModule1->GetMDImport();
5499 IMDInternalImport *pInternalImport2 = pModule2->GetMDImport();
5500
5501 IfFailThrow(pInternalImport1->GetTypeDefProps(tk1, &dwAttr1, NULL));
5502 IfFailThrow(pInternalImport2->GetTypeDefProps(tk2, &dwAttr2, NULL));
5503
5504 // we need both to have sequential or explicit layout
5505 BOOL fExplicitLayout = FALSE;
5506 if (IsTdSequentialLayout(dwAttr1))
5507 {
5508 if (!IsTdSequentialLayout(dwAttr2))
5509 return FALSE;
5510 }
5511 else if (IsTdExplicitLayout(dwAttr1))
5512 {
5513 if (!IsTdExplicitLayout(dwAttr2))
5514 return FALSE;
5515
5516 fExplicitLayout = TRUE;
5517 }
5518 else
5519 {
5520 return FALSE;
5521 }
5522
5523 // they must have the same charset
5524 if ((dwAttr1 & tdStringFormatMask) != (dwAttr2 & tdStringFormatMask))
5525 return FALSE;
5526
5527 // they must have the same packing
5528 DWORD dwPackSize1, dwPackSize2;
5529 HRESULT hr1 = pInternalImport1->GetClassPackSize(tk1, &dwPackSize1);
5530 HRESULT hr2 = pInternalImport2->GetClassPackSize(tk2, &dwPackSize2);
5531
5532 if (hr1 == CLDB_E_RECORD_NOTFOUND)
5533 dwPackSize1 = 0;
5534 else
5535 IfFailThrow(hr1);
5536
5537 if (hr2 == CLDB_E_RECORD_NOTFOUND)
5538 dwPackSize2 = 0;
5539 else
5540 IfFailThrow(hr2);
5541
5542 if (dwPackSize1 != dwPackSize2)
5543 return FALSE;
5544
5545 // they must have the same explicit size
5546 DWORD dwTotalSize1, dwTotalSize2;
5547 hr1 = pInternalImport1->GetClassTotalSize(tk1, &dwTotalSize1);
5548 hr2 = pInternalImport2->GetClassTotalSize(tk2, &dwTotalSize2);
5549
5550 if (hr1 == CLDB_E_RECORD_NOTFOUND)
5551 dwTotalSize1 = 0;
5552 else
5553 IfFailThrow(hr1);
5554
5555 if (hr2 == CLDB_E_RECORD_NOTFOUND)
5556 dwTotalSize2 = 0;
5557 else
5558 IfFailThrow(hr2);
5559
5560 if (dwTotalSize1 != dwTotalSize2)
5561 return FALSE;
5562
5563 // same offsets, same field marshal
5564 HENUMInternalHolder hFieldEnum1(pInternalImport1);
5565 HENUMInternalHolder hFieldEnum2(pInternalImport2);
5566
5567 hFieldEnum1.EnumInit(mdtFieldDef, tk1);
5568 hFieldEnum2.EnumInit(mdtFieldDef, tk2);
5569
5570 mdToken tkField1, tkField2;
5571
5572 while (hFieldEnum1.EnumNext(&tkField1))
5573 {
5574 if (!hFieldEnum2.EnumNext(&tkField2))
5575 return FALSE;
5576
5577 // check for same offsets
5578 if (fExplicitLayout)
5579 {
5580 ULONG uOffset1, uOffset2;
5581 IfFailThrow(pInternalImport1->GetFieldOffset(tkField1, &uOffset1));
5582 IfFailThrow(pInternalImport2->GetFieldOffset(tkField2, &uOffset2));
5583
5584 if (uOffset1 != uOffset2)
5585 return FALSE;
5586 }
5587
5588 // check for same field marshal
5589 DWORD dwAttrField1, dwAttrField2;
5590 IfFailThrow(pInternalImport1->GetFieldDefProps(tkField1, &dwAttrField1));
5591 IfFailThrow(pInternalImport2->GetFieldDefProps(tkField2, &dwAttrField2));
5592
5593 if (IsFdHasFieldMarshal(dwAttrField1) != IsFdHasFieldMarshal(dwAttrField2))
5594 return FALSE;
5595
5596 if (IsFdHasFieldMarshal(dwAttrField1))
5597 {
5598 // both fields have field marshal info - make sure it's same
5599 PCCOR_SIGNATURE pNativeSig1, pNativeSig2;
5600 ULONG cbNativeSig1, cbNativeSig2;
5601
5602 IfFailThrow(pInternalImport1->GetFieldMarshal(tkField1, &pNativeSig1, &cbNativeSig1));
5603 IfFailThrow(pInternalImport2->GetFieldMarshal(tkField2, &pNativeSig2, &cbNativeSig2));
5604
5605 // just check if the blobs are identical
5606 if (cbNativeSig1 != cbNativeSig2 || memcmp(pNativeSig1, pNativeSig2, cbNativeSig1) != 0)
5607 return FALSE;
5608 }
5609 }
5610
5611 return TRUE;
5612}
5613