Merge pull request #24232 from janvorli/fix-large-version-bubble-2
[platform/upstream/coreclr.git] / src / vm / clsload.cpp
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 // File: clsload.cpp
6 //
7 // ============================================================================
8
9 #include "common.h"
10 #include "winwrap.h"
11 #include "ceeload.h"
12 #include "siginfo.hpp"
13 #include "vars.hpp"
14 #include "clsload.hpp"
15 #include "classhash.inl"
16 #include "class.h"
17 #include "method.hpp"
18 #include "ecall.h"
19 #include "stublink.h"
20 #include "object.h"
21 #include "excep.h"
22 #include "threads.h"
23 #include "comsynchronizable.h"
24 #include "threads.h"
25 #include "dllimport.h"
26 #include "dbginterface.h"
27 #include "log.h"
28 #include "eeconfig.h"
29 #include "fieldmarshaler.h"
30 #include "jitinterface.h"
31 #include "vars.hpp"
32 #include "assembly.hpp"
33 #include "eeprofinterfaces.h"
34 #include "eehash.h"
35 #include "typehash.h"
36 #include "comdelegate.h"
37 #include "array.h"
38 #include "posterror.h"
39 #include "wrappers.h"
40 #include "generics.h"
41 #include "typestring.h"
42 #include "typedesc.h"
43 #include "cgencpu.h"
44 #include "eventtrace.h"
45 #include "typekey.h"
46 #include "pendingload.h"
47 #include "proftoeeinterfaceimpl.h"
48 #include "mdaassistants.h"
49 #include "virtualcallstub.h"
50 #include "stringarraylist.h"
51
52
53 // This method determines the "loader module" for an instantiated type
54 // or method. The rule must ensure that any types involved in the
55 // instantiated type or method do not outlive the loader module itself
56 // with respect to app-domain unloading (e.g. MyList<MyType> can't be
57 // put in the module of MyList if MyList's assembly is
58 // app-domain-neutral but MyType's assembly is app-domain-specific).
59 // The rule we use is:
60 //
61 // * Pick the first type in the class instantiation, followed by
62 //   method instantiation, whose loader module is non-shared (app-domain-bound)
63 // * If no type is app-domain-bound, return the module containing the generic type itself
64 //
65 // Some useful effects of this rule (for ngen purposes) are:
66 //
67 // * G<object,...,object> lives in the module defining G
68 // * non-mscorlib instantiations of mscorlib-defined generic types live in the module
69 //   of the instantiation (when only one module is invloved in the instantiation)
70 //
71
72 /* static */
73 PTR_Module ClassLoader::ComputeLoaderModuleWorker(
74     Module *     pDefinitionModule,  // the module that declares the generic type or method
75     mdToken      token,              // method or class token for this item
76     Instantiation classInst,         // the type arguments to the type (if any)
77     Instantiation methodInst)        // the type arguments to the method (if any)
78 {
79     CONTRACT(Module*)
80     {
81         NOTHROW;
82         GC_NOTRIGGER;
83         FORBID_FAULT;
84         MODE_ANY;
85         PRECONDITION(CheckPointer(pDefinitionModule, NULL_OK));
86         POSTCONDITION(CheckPointer(RETVAL));
87         SUPPORTS_DAC;
88     }
89     CONTRACT_END
90
91     if (classInst.IsEmpty() && methodInst.IsEmpty())
92         RETURN PTR_Module(pDefinitionModule);
93
94 #ifndef DACCESS_COMPILE
95 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
96     //
97     // Use special loader module placement during compilation of fragile native images.
98     //
99     // ComputeLoaderModuleForCompilation algorithm assumes that we are using fragile native image
100     // for CoreLib (or compiling CoreLib itself). It is not the case for ReadyToRun compilation because
101     // CoreLib as always treated as IL there (see code:PEFile::ShouldTreatNIAsMSIL for details).
102     //
103     if (IsCompilationProcess() && !IsReadyToRunCompilation())
104     {
105         RETURN(ComputeLoaderModuleForCompilation(pDefinitionModule, token, classInst, methodInst));
106     }
107 #endif // FEATURE_PREJIT
108 #endif // #ifndef DACCESS_COMPILE
109
110     Module *pLoaderModule = NULL;
111
112     if (pDefinitionModule)
113     {
114         if (pDefinitionModule->IsCollectible())
115             goto ComputeCollectibleLoaderModule;
116         pLoaderModule = pDefinitionModule;
117     }
118
119     for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
120     {
121         TypeHandle classArg = classInst[i];
122         _ASSERTE(!classArg.IsEncodedFixup());
123         Module* pModule = classArg.GetLoaderModule();
124         if (pModule->IsCollectible())
125             goto ComputeCollectibleLoaderModule;
126         if (pLoaderModule == NULL)
127             pLoaderModule = pModule;
128     }
129
130     for (DWORD i = 0; i < methodInst.GetNumArgs(); i++)
131     {
132         TypeHandle methodArg = methodInst[i];
133         _ASSERTE(!methodArg.IsEncodedFixup());
134         Module *pModule = methodArg.GetLoaderModule();
135         if (pModule->IsCollectible())
136             goto ComputeCollectibleLoaderModule;
137         if (pLoaderModule == NULL)
138             pLoaderModule = pModule;
139     }
140
141     if (pLoaderModule == NULL)
142     {
143         CONSISTENCY_CHECK(MscorlibBinder::GetModule() && MscorlibBinder::GetModule()->IsSystem());
144
145         pLoaderModule = MscorlibBinder::GetModule();
146     }
147
148     if (FALSE)
149     {
150 ComputeCollectibleLoaderModule:
151         LoaderAllocator *pLoaderAllocatorOfDefiningType = NULL;
152         LoaderAllocator *pOldestLoaderAllocator = NULL;
153         Module *pOldestLoaderModule = NULL;
154         UINT64 oldestFoundAge = 0;
155         DWORD classArgsCount = classInst.GetNumArgs();
156         DWORD totalArgsCount = classArgsCount + methodInst.GetNumArgs();
157
158         if (pDefinitionModule != NULL) pLoaderAllocatorOfDefiningType = pDefinitionModule->GetLoaderAllocator();
159
160         for (DWORD i = 0; i < totalArgsCount; i++) {
161
162             TypeHandle arg;
163
164             if (i < classArgsCount)
165                 arg = classInst[i];
166             else
167                 arg = methodInst[i - classArgsCount];
168
169             Module *pModuleCheck = arg.GetLoaderModule();
170             LoaderAllocator *pLoaderAllocatorCheck = pModuleCheck->GetLoaderAllocator();
171
172             if (pLoaderAllocatorCheck != pLoaderAllocatorOfDefiningType &&
173                 pLoaderAllocatorCheck->IsCollectible() && 
174                 pLoaderAllocatorCheck->GetCreationNumber() > oldestFoundAge)
175             {
176                 pOldestLoaderModule = pModuleCheck;
177                 pOldestLoaderAllocator = pLoaderAllocatorCheck;
178                 oldestFoundAge = pLoaderAllocatorCheck->GetCreationNumber();
179             }
180         }
181
182         // Only if we didn't find a different loader allocator than the defining loader allocator do we
183         // use the defining loader allocator
184         if (pOldestLoaderModule != NULL)
185             pLoaderModule = pOldestLoaderModule;
186         else
187             pLoaderModule = pDefinitionModule;
188     }
189     RETURN PTR_Module(pLoaderModule);
190 }
191
192 #ifndef DACCESS_COMPILE
193 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
194 /* static */
195 PTR_Module ClassLoader::ComputeLoaderModuleForCompilation(
196     Module *     pDefinitionModule,  // the module that declares the generic type or method
197     mdToken      token,              // method or class token for this item
198     Instantiation classInst,         // the type arguments to the type (if any)
199     Instantiation methodInst)        // the type arguments to the method (if any)
200 {
201     CONTRACT(Module*)
202     {
203         NOTHROW;
204         GC_NOTRIGGER;
205         FORBID_FAULT;
206         MODE_ANY;
207         PRECONDITION(CheckPointer(pDefinitionModule, NULL_OK));
208         POSTCONDITION(CheckPointer(RETVAL));
209     }
210     CONTRACT_END
211
212     // The NGEN rule for compiling constructed types and instantiated methods
213     // into modules other than their "natural" LoaderModule. This is at the heart of
214     // "full generics NGEN".
215     //
216     // If this instantiation doesn't have a unique home then use the ngen module 
217
218     // OK, we're certainly NGEN'ing.  And if we're NGEN'ing then we're not on the debugger thread.
219     CONSISTENCY_CHECK(((GetThread() && GetAppDomain()) || IsGCThread()) &&
220         "unexpected: running a load on debug thread but IsCompilationProcess() returned TRUE");
221
222     // Save it into its PreferredZapModule if it's always going to be saved there.
223     // This is a stable choice - no need to record it in the table (as we do for others below)
224     if (Module::IsAlwaysSavedInPreferredZapModule(classInst, methodInst))
225     {
226         RETURN (Module::ComputePreferredZapModule(pDefinitionModule, classInst, methodInst));
227     }
228
229     // Check if this compilation process has already decided on an adjustment.  Once we decide
230     // on the LoaderModule for an item it must be stable for the duration of a
231     // compilation process, no matter how many modules get NGEN'd.
232     
233     ZapperLoaderModuleTableKey key(pDefinitionModule, 
234                                    token, 
235                                    classInst, 
236                                    methodInst);
237
238     Module * pZapperLoaderModule = g_pCEECompileInfo->LookupZapperLoaderModule(&key);
239     if (pZapperLoaderModule != NULL)
240     {
241         RETURN (pZapperLoaderModule);
242     }
243
244     // OK, we need to compute a non-standard zapping module.
245
246     Module * pPreferredZapModule = Module::ComputePreferredZapModule(pDefinitionModule, classInst, methodInst);
247
248     // Check if we're NGEN'ing but where perhaps the compilation domain 
249     // isn't set up yet.  This can happen in following situations:
250     // - Managed code running during startup before compilation domain is setup.
251     // - Exceptions (e.g. invalid program exceptions) thrown from compilation domain and caught in default domain
252
253     // We're a little stuck - we can't force the item into an NGEN image at this point.  So just bail out
254     // and use the loader module we've computed without recording the choice. The loader module should always 
255     // be mscorlib in this case.
256     AppDomain * pAppDomain = GetAppDomain();
257     if (!pAppDomain->IsCompilationDomain() ||
258         !pAppDomain->ToCompilationDomain()->GetTargetModule())
259     {
260         _ASSERTE(pPreferredZapModule->IsSystem() || IsNgenPDBCompilationProcess());
261         RETURN (pPreferredZapModule);
262     }
263
264     Module * pTargetModule = pAppDomain->ToCompilationDomain()->GetTargetModule();
265
266     // If it is multi-module assembly and we have not saved PZM yet, do not create
267     // speculative instantiation - just save it in PZM.
268     if (pTargetModule->GetAssembly() == pPreferredZapModule->GetAssembly() && 
269         !pPreferredZapModule->IsModuleSaved())
270     {
271         pZapperLoaderModule = pPreferredZapModule;
272     }
273     else
274     {
275         // Everything else can be saved into the current module.
276         pZapperLoaderModule = pTargetModule;
277     }
278
279     // If generating WinMD resilient code and we so far choose to use the target module,
280     // we need to check if the definition module or any of the instantiation type can
281     // cause version resilient problems.
282     if (g_fNGenWinMDResilient && pZapperLoaderModule == pTargetModule)
283     {
284         if (pDefinitionModule != NULL && !pDefinitionModule->IsInCurrentVersionBubble())
285         {
286             pZapperLoaderModule = pDefinitionModule;
287             goto ModuleAdjustedForVersionResiliency;
288         }
289
290         for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
291         {
292             Module * pModule = classInst[i].GetLoaderModule();
293             if (!pModule->IsInCurrentVersionBubble())
294             {
295                 pZapperLoaderModule = pModule;
296                 goto ModuleAdjustedForVersionResiliency;
297             }
298         }
299
300         for (DWORD i = 0; i < methodInst.GetNumArgs(); i++)
301         {
302             Module * pModule = methodInst[i].GetLoaderModule();
303             if (!pModule->IsInCurrentVersionBubble())
304             {
305                 pZapperLoaderModule = pModule;
306                 goto ModuleAdjustedForVersionResiliency;
307             }
308         }
309 ModuleAdjustedForVersionResiliency: ;
310     }
311
312     // Record this choice just in case we're NGEN'ing multiple modules
313     // to make sure we always do the same thing if we're asked to compute 
314     // the loader module again.
315
316     // Note this whole code path only happens while NGEN'ing, so this violation
317     // is not so bad.  It is needed since we allocate stuff on the heap.
318     CONTRACT_VIOLATION(ThrowsViolation|FaultViolation);
319
320     // Copy the instantiation arrays so they can escape the scope of this method.
321     // Since this is a permanent entry in a table for this compilation process
322     // we do not need to collect these.  If we did have to we would do it when we deleteed the
323     // ZapperLoaderModuleTable.
324     NewArrayHolder<TypeHandle> pClassArgs = NULL;
325     if (!classInst.IsEmpty())
326     {
327         pClassArgs = new TypeHandle[classInst.GetNumArgs()];
328         for (unsigned int i = 0; i < classInst.GetNumArgs(); i++)
329             pClassArgs[i] = classInst[i];
330     }
331
332     NewArrayHolder<TypeHandle> pMethodArgs = NULL;
333     if (!methodInst.IsEmpty())
334     {
335         pMethodArgs = new TypeHandle[methodInst.GetNumArgs()];
336         for (unsigned int i = 0; i < methodInst.GetNumArgs(); i++)
337             pMethodArgs[i] = methodInst[i];
338     }
339
340     ZapperLoaderModuleTableKey key2(pDefinitionModule, 
341                                     token, 
342                                     Instantiation(pClassArgs, classInst.GetNumArgs()),
343                                     Instantiation(pMethodArgs, methodInst.GetNumArgs()));
344     g_pCEECompileInfo->RecordZapperLoaderModule(&key2, pZapperLoaderModule);
345
346     pClassArgs.SuppressRelease();
347     pMethodArgs.SuppressRelease();
348
349     RETURN (pZapperLoaderModule);
350 }
351 #endif // FEATURE_NATIVE_IMAGE_GENERATION
352 #endif // #ifndef DACCESS_COMPILE
353
354 /*static*/
355 Module * ClassLoader::ComputeLoaderModule(MethodTable * pMT, 
356                                           mdToken       token, 
357                                           Instantiation methodInst)
358 {
359     CONTRACTL
360     {
361         NOTHROW;
362         GC_NOTRIGGER;
363         MODE_ANY;
364         SUPPORTS_DAC;
365     }
366     CONTRACTL_END;
367
368     return ComputeLoaderModuleWorker(pMT->GetModule(), 
369                                token,
370                                pMT->GetInstantiation(),
371                                methodInst);
372 }
373 /*static*/
374 Module *ClassLoader::ComputeLoaderModule(TypeKey *typeKey)
375 {
376     CONTRACTL
377     {
378         NOTHROW;
379         GC_NOTRIGGER;
380         MODE_ANY;
381         SUPPORTS_DAC;
382     }
383     CONTRACTL_END;
384
385
386     if (typeKey->GetKind() == ELEMENT_TYPE_CLASS)
387         return ComputeLoaderModuleWorker(typeKey->GetModule(),
388                                    typeKey->GetTypeToken(),
389                                    typeKey->GetInstantiation(),
390                                    Instantiation());
391     else if (typeKey->GetKind() == ELEMENT_TYPE_FNPTR)
392         return ComputeLoaderModuleForFunctionPointer(typeKey->GetRetAndArgTypes(), typeKey->GetNumArgs() + 1);
393     else                                                    
394         return ComputeLoaderModuleForParamType(typeKey->GetElementType());
395 }
396
397 /*static*/ 
398 BOOL ClassLoader::IsTypicalInstantiation(Module *pModule, mdToken token, Instantiation inst)
399 {
400     CONTRACTL
401     {
402         NOTHROW;
403         GC_NOTRIGGER;
404         FORBID_FAULT;
405         PRECONDITION(CheckPointer(pModule));
406         PRECONDITION(TypeFromToken(token) == mdtTypeDef || TypeFromToken(token) == mdtMethodDef);
407         SUPPORTS_DAC;
408     }
409     CONTRACTL_END
410
411     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
412     {
413         TypeHandle thArg = inst[i];
414
415         if (thArg.IsGenericVariable())
416         {
417             TypeVarTypeDesc* tyvar = thArg.AsGenericVariable();
418
419             PREFIX_ASSUME(tyvar!=NULL);
420             if ((tyvar->GetTypeOrMethodDef() != token) ||
421                 (tyvar->GetModule() != dac_cast<PTR_Module>(pModule)) ||
422                 (tyvar->GetIndex() != i))
423                 return FALSE;
424         }
425         else
426         {
427             return FALSE;
428         }
429     }
430     return TRUE;
431 }
432
433 // External class loader entry point: load a type by name
434 /*static*/
435 TypeHandle ClassLoader::LoadTypeByNameThrowing(Assembly *pAssembly,
436                                                LPCUTF8 nameSpace,
437                                                LPCUTF8 name,
438                                                NotFoundAction fNotFound,
439                                                ClassLoader::LoadTypesFlag fLoadTypes,
440                                                ClassLoadLevel level)
441 {
442     CONTRACT(TypeHandle)
443     {
444         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
445         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
446         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
447         MODE_ANY;
448
449         if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
450
451         PRECONDITION(CheckPointer(pAssembly));
452         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
453         POSTCONDITION(CheckPointer(RETVAL, 
454                      (fNotFound == ThrowIfNotFound && fLoadTypes == LoadTypes )? NULL_NOT_OK : NULL_OK));
455         POSTCONDITION(RETVAL.IsNull() || RETVAL.CheckLoadLevel(level));
456         SUPPORTS_DAC;
457 #ifdef DACCESS_COMPILE
458         PRECONDITION((fNotFound == ClassLoader::ReturnNullIfNotFound) && (fLoadTypes == DontLoadTypes));
459 #endif
460     }
461     CONTRACT_END
462
463     NameHandle nameHandle(nameSpace, name);
464     if (fLoadTypes == DontLoadTypes)
465         nameHandle.SetTokenNotToLoad(tdAllTypes);
466     if (fNotFound == ThrowIfNotFound)
467         RETURN pAssembly->GetLoader()->LoadTypeHandleThrowIfFailed(&nameHandle, level);
468     else
469         RETURN pAssembly->GetLoader()->LoadTypeHandleThrowing(&nameHandle, level);
470 }
471
472 #ifndef DACCESS_COMPILE
473
474 #define DAC_LOADS_TYPE(level, expression) \
475     if (FORBIDGC_LOADER_USE_ENABLED() || (expression)) \
476         { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); } 
477 #else 
478
479 #define DAC_LOADS_TYPE(level, expression) { LOADS_TYPE(CLASS_LOAD_BEGIN); } 
480 #endif // #ifndef DACCESS_COMPILE
481
482 //
483 // Find a class given name, using the classloader's global list of known classes.
484 // If the type is found, it will be restored unless pName->GetTokenNotToLoad() prohibits that
485 // Returns NULL if class not found AND pName->OKToLoad returns false
486 TypeHandle ClassLoader::LoadTypeHandleThrowIfFailed(NameHandle* pName, ClassLoadLevel level,
487                                                     Module* pLookInThisModuleOnly/*=NULL*/)
488 {
489     CONTRACT(TypeHandle)
490     {
491         INSTANCE_CHECK;
492         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
493         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
494         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
495         DAC_LOADS_TYPE(level, !pName->OKToLoad());
496         MODE_ANY;
497         PRECONDITION(CheckPointer(pName));
498         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
499         POSTCONDITION(CheckPointer(RETVAL, pName->OKToLoad() ? NULL_NOT_OK : NULL_OK));
500         POSTCONDITION(RETVAL.IsNull() || RETVAL.CheckLoadLevel(level));
501         SUPPORTS_DAC;
502     }
503     CONTRACT_END;
504
505     // Lookup in the classes that this class loader knows about
506     TypeHandle typeHnd = LoadTypeHandleThrowing(pName, level, pLookInThisModuleOnly);
507
508     if(typeHnd.IsNull()) {
509
510         if ( pName->OKToLoad() ) {
511 #ifdef _DEBUG_IMPL
512             {
513                 LPCUTF8 szName = pName->GetName();
514                 if (szName == NULL)
515                     szName = "<UNKNOWN>";
516                 
517                 StackSString codeBase;
518                 GetAssembly()->GetCodeBase(codeBase);
519
520                 LOG((LF_CLASSLOADER, LL_INFO10, "Failed to find class \"%s\" in the manifest for assembly \"%ws\"\n", szName, (LPCWSTR)codeBase));
521             }
522 #endif
523
524 #ifndef DACCESS_COMPILE
525             m_pAssembly->ThrowTypeLoadException(pName, IDS_CLASSLOAD_GENERAL);
526 #else
527             DacNotImpl();
528 #endif
529         }
530     }
531
532     RETURN(typeHnd);
533 }
534
535 #ifndef DACCESS_COMPILE
536
537 //<TODO>@TODO: Need to allow exceptions to be thrown when classloader is cleaned up</TODO>
538 EEClassHashEntry_t* ClassLoader::InsertValue(EEClassHashTable *pClassHash, EEClassHashTable *pClassCaseInsHash, LPCUTF8 pszNamespace, LPCUTF8 pszClassName, HashDatum Data, EEClassHashEntry_t *pEncloser, AllocMemTracker *pamTracker)
539 {
540     CONTRACTL
541     {
542         INSTANCE_CHECK;
543         THROWS;
544         GC_NOTRIGGER;
545         MODE_ANY;
546         INJECT_FAULT(COMPlusThrowOM(););
547     }
548     CONTRACTL_END
549
550     LPUTF8 pszLowerCaseNS = NULL;
551     LPUTF8 pszLowerCaseName = NULL;
552     EEClassHashEntry_t *pCaseInsEntry = NULL;
553
554     EEClassHashEntry_t *pEntry = pClassHash->AllocNewEntry(pamTracker);
555    
556     if (pClassCaseInsHash) {
557         CreateCanonicallyCasedKey(pszNamespace, pszClassName, &pszLowerCaseNS, &pszLowerCaseName);
558         pCaseInsEntry = pClassCaseInsHash->AllocNewEntry(pamTracker);
559     }
560
561
562     {
563         // ! We cannot fail after this point.
564         CANNOTTHROWCOMPLUSEXCEPTION();
565         FAULT_FORBID();
566
567
568         pClassHash->InsertValueUsingPreallocatedEntry(pEntry, pszNamespace, pszClassName, Data, pEncloser);
569     
570         //If we're keeping a table for case-insensitive lookup, keep that up to date
571         if (pClassCaseInsHash)
572             pClassCaseInsHash->InsertValueUsingPreallocatedEntry(pCaseInsEntry, pszLowerCaseNS, pszLowerCaseName, pEntry, pEncloser);
573         
574         return pEntry;
575     }
576
577 }
578
579 #endif // #ifndef DACCESS_COMPILE
580
581 BOOL ClassLoader::CompareNestedEntryWithExportedType(IMDInternalImport *  pImport,
582                                                      mdExportedType       mdCurrent,
583                                                      EEClassHashTable *   pClassHash,
584                                                      PTR_EEClassHashEntry pEntry)
585 {
586     CONTRACTL
587     {
588         INSTANCE_CHECK;
589         NOTHROW;
590         GC_NOTRIGGER;
591         MODE_ANY;
592         FORBID_FAULT;
593         SUPPORTS_DAC;
594     }
595     CONTRACTL_END;
596
597     LPCUTF8 Key[2];
598
599     do
600     {
601         if (FAILED(pImport->GetExportedTypeProps(
602             mdCurrent, 
603             &Key[0], 
604             &Key[1], 
605             &mdCurrent, 
606             NULL,   //binding (type def)
607             NULL))) //flags
608         {
609             return FALSE;
610         }
611         
612         if (pClassHash->CompareKeys(pEntry, Key))
613         {
614             // Reached top level class for mdCurrent - return whether
615             // or not pEntry is a top level class
616             // (pEntry is a top level class if its pEncloser is NULL)
617             if ((TypeFromToken(mdCurrent) != mdtExportedType) ||
618                 (mdCurrent == mdExportedTypeNil))
619             {
620                 return pEntry->GetEncloser() == NULL;
621             }
622         }
623         else // Keys don't match - wrong entry
624         {
625             return FALSE;
626         }
627     }
628     while ((pEntry = pEntry->GetEncloser()) != NULL);
629
630     // Reached the top level class for pEntry, but mdCurrent is nested
631     return FALSE;
632 }
633
634
635 BOOL ClassLoader::CompareNestedEntryWithTypeDef(IMDInternalImport *  pImport,
636                                                 mdTypeDef            mdCurrent,
637                                                 EEClassHashTable *   pClassHash,
638                                                 PTR_EEClassHashEntry pEntry)
639 {
640     CONTRACTL
641     {
642         INSTANCE_CHECK;
643         NOTHROW;
644         GC_NOTRIGGER;
645         MODE_ANY;
646         FORBID_FAULT;
647         SUPPORTS_DAC;
648     }
649     CONTRACTL_END;
650
651     LPCUTF8 Key[2];
652
653     do {
654         if (FAILED(pImport->GetNameOfTypeDef(mdCurrent, &Key[1], &Key[0])))
655         {
656             return FALSE;
657         }
658         
659         if (pClassHash->CompareKeys(pEntry, Key)) {
660             // Reached top level class for mdCurrent - return whether
661             // or not pEntry is a top level class
662             // (pEntry is a top level class if its pEncloser is NULL)
663             if (FAILED(pImport->GetNestedClassProps(mdCurrent, &mdCurrent)))
664                 return pEntry->GetEncloser() == NULL;
665         }
666         else // Keys don't match - wrong entry
667             return FALSE;
668     }
669     while ((pEntry = pEntry->GetEncloser()) != NULL);
670
671     // Reached the top level class for pEntry, but mdCurrent is nested
672     return FALSE;
673 }
674
675
676 BOOL ClassLoader::CompareNestedEntryWithTypeRef(IMDInternalImport *  pImport,
677                                                 mdTypeRef            mdCurrent,
678                                                 EEClassHashTable *   pClassHash,
679                                                 PTR_EEClassHashEntry pEntry)
680 {
681     CONTRACTL
682     {
683         INSTANCE_CHECK;
684         NOTHROW;
685         GC_NOTRIGGER;
686         MODE_ANY;
687         FORBID_FAULT;
688         SUPPORTS_DAC;
689     }
690     CONTRACTL_END;
691
692     LPCUTF8 Key[2];
693
694     do {
695         if (FAILED(pImport->GetNameOfTypeRef(mdCurrent, &Key[0], &Key[1])))
696         {
697             return FALSE;
698         }
699         
700         if (pClassHash->CompareKeys(pEntry, Key))
701         {
702             if (FAILED(pImport->GetResolutionScopeOfTypeRef(mdCurrent, &mdCurrent)))
703             {
704                 return FALSE;
705             }
706             // Reached top level class for mdCurrent - return whether
707             // or not pEntry is a top level class
708             // (pEntry is a top level class if its pEncloser is NULL)
709             if ((TypeFromToken(mdCurrent) != mdtTypeRef) ||
710                 (mdCurrent == mdTypeRefNil))
711                 return pEntry->GetEncloser() == NULL;
712         }
713         else // Keys don't match - wrong entry
714             return FALSE;
715     }
716     while ((pEntry = pEntry->GetEncloser())!=NULL);
717
718     // Reached the top level class for pEntry, but mdCurrent is nested
719     return FALSE;
720 }
721
722
723 /*static*/
724 BOOL ClassLoader::IsNested(Module *pModule, mdToken token, mdToken *mdEncloser)
725 {
726     CONTRACTL
727     {
728         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
729         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
730         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
731         MODE_ANY;
732         SUPPORTS_DAC;
733     }
734     CONTRACTL_END;
735
736     switch(TypeFromToken(token)) {
737         case mdtTypeDef:
738             return (SUCCEEDED(pModule->GetMDImport()->GetNestedClassProps(token, mdEncloser)));
739
740         case mdtTypeRef:
741             IfFailThrow(pModule->GetMDImport()->GetResolutionScopeOfTypeRef(token, mdEncloser));
742             return ((TypeFromToken(*mdEncloser) == mdtTypeRef) &&
743                     (*mdEncloser != mdTypeRefNil));
744
745         case mdtExportedType:
746             IfFailThrow(pModule->GetAssembly()->GetManifestImport()->GetExportedTypeProps(
747                 token,
748                 NULL,   // namespace
749                 NULL,   // name
750                 mdEncloser, 
751                 NULL,   //binding (type def)
752                 NULL)); //flags
753             return ((TypeFromToken(*mdEncloser) == mdtExportedType) &&
754                     (*mdEncloser != mdExportedTypeNil));
755
756         default:
757             ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE);
758     }
759 }
760
761 BOOL ClassLoader::IsNested(NameHandle* pName, mdToken *mdEncloser)
762 {
763     CONTRACTL
764     {
765         INSTANCE_CHECK;
766         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
767         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
768         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
769         MODE_ANY;
770         SUPPORTS_DAC;
771     }
772     CONTRACTL_END;
773
774     if (pName->GetTypeModule()) {
775         if (TypeFromToken(pName->GetTypeToken()) == mdtBaseType)
776         {
777             if (!pName->GetBucket().IsNull())
778                 return TRUE;
779             return FALSE;
780         }
781         else
782             return IsNested(pName->GetTypeModule(), pName->GetTypeToken(), mdEncloser);
783     }
784     else
785         return FALSE;
786 }
787
788 void ClassLoader::GetClassValue(NameHandleTable nhTable,
789                                     NameHandle *pName,
790                                     HashDatum *pData,
791                                     EEClassHashTable **ppTable,
792                                     Module* pLookInThisModuleOnly,
793                                     HashedTypeEntry* pFoundEntry,
794                                     Loader::LoadFlag loadFlag,
795                                     BOOL& needsToBuildHashtable)
796 {
797     CONTRACTL
798     {
799         INSTANCE_CHECK;
800         MODE_ANY;
801         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
802         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
803         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
804         PRECONDITION(CheckPointer(pName));
805         SUPPORTS_DAC;
806     }
807     CONTRACTL_END
808
809
810     mdToken             mdEncloser;
811     EEClassHashEntry_t  *pBucket = NULL;
812
813     needsToBuildHashtable = FALSE;
814
815 #if _DEBUG
816     if (pName->GetName()) {
817         if (pName->GetNameSpace() == NULL)
818             LOG((LF_CLASSLOADER, LL_INFO1000, "Looking up %s by name.\n",
819                  pName->GetName()));
820         else
821             LOG((LF_CLASSLOADER, LL_INFO1000, "Looking up %s.%s by name.\n",
822                  pName->GetNameSpace(), pName->GetName()));
823     }
824 #endif
825
826     BOOL isNested = IsNested(pName, &mdEncloser);
827
828     PTR_Assembly assembly = GetAssembly();
829     PREFIX_ASSUME(assembly != NULL);
830     ModuleIterator i = assembly->IterateModules();
831
832     while (i.Next()) 
833     {
834         Module * pCurrentClsModule = i.GetModule();
835         PREFIX_ASSUME(pCurrentClsModule != NULL);
836
837         if (pCurrentClsModule->IsResource())
838             continue;
839         if (pLookInThisModuleOnly && (pCurrentClsModule != pLookInThisModuleOnly))
840             continue;
841
842 #ifdef FEATURE_READYTORUN
843         if (nhTable == nhCaseSensitive && pCurrentClsModule->IsReadyToRun() && pCurrentClsModule->GetReadyToRunInfo()->HasHashtableOfTypes() &&
844             pCurrentClsModule->GetAvailableClassHash() == NULL)
845         {
846             // For R2R modules, we only search the hashtable of token types stored in the module's image, and don't fallback
847             // to searching m_pAvailableClasses or m_pAvailableClassesCaseIns (in fact, we don't even allocate them for R2R modules).
848             // Also note that type lookups in R2R modules only support case sensitive lookups.
849
850             mdToken mdFoundTypeToken;
851             if (pCurrentClsModule->GetReadyToRunInfo()->TryLookupTypeTokenFromName(pName, &mdFoundTypeToken))
852             {
853                 if (TypeFromToken(mdFoundTypeToken) == mdtExportedType)
854                 {
855                     mdToken mdUnused;
856                     Module * pTargetModule = GetAssembly()->FindModuleByExportedType(mdFoundTypeToken, loadFlag, mdTypeDefNil, &mdUnused);
857
858                     pFoundEntry->SetTokenBasedEntryValue(mdFoundTypeToken, pTargetModule);
859                 }
860                 else
861                 {
862                     pFoundEntry->SetTokenBasedEntryValue(mdFoundTypeToken, pCurrentClsModule);
863                 }
864
865                 return; // Return on the first success
866             }
867         }
868         else
869 #endif
870         {
871             EEClassHashTable* pTable = NULL;
872             if (nhTable == nhCaseSensitive)
873             {
874                 *ppTable = pTable = pCurrentClsModule->GetAvailableClassHash();
875
876 #ifdef FEATURE_READYTORUN
877                 if (pTable == NULL && pCurrentClsModule->IsReadyToRun() && !pCurrentClsModule->GetReadyToRunInfo()->HasHashtableOfTypes())
878                 {
879                     // Old R2R image generated without the hashtable of types.
880                     // We fallback to the slow path of creating the hashtable dynamically 
881                     // at execution time in that scenario. The caller will handle
882                     pFoundEntry->SetClassHashBasedEntryValue(NULL);
883                     needsToBuildHashtable = TRUE;
884                     return;
885                 }
886 #endif
887             }
888             else
889             {
890                 // currently we expect only these two kinds--for DAC builds, nhTable will be nhCaseSensitive
891                 _ASSERTE(nhTable == nhCaseInsensitive);
892                 *ppTable = pTable = pCurrentClsModule->GetAvailableClassCaseInsHash();
893
894                 if (pTable == NULL)
895                 {
896                     // We have not built the table yet - the caller will handle
897                     pFoundEntry->SetClassHashBasedEntryValue(NULL);
898                     needsToBuildHashtable = TRUE;
899                     return;
900                 }
901             }
902             _ASSERTE(pTable);
903
904             if (isNested)
905             {
906                 Module *pNameModule = pName->GetTypeModule();
907                 PREFIX_ASSUME(pNameModule != NULL);
908
909                 EEClassHashTable::LookupContext sContext;
910                 if ((pBucket = pTable->GetValue(pName, pData, TRUE, &sContext)) != NULL)
911                 {
912                     switch (TypeFromToken(pName->GetTypeToken()))
913                     {
914                     case mdtTypeDef:
915                         while ((!CompareNestedEntryWithTypeDef(pNameModule->GetMDImport(),
916                                                                mdEncloser,
917                                                                pCurrentClsModule->GetAvailableClassHash(),
918                                                                pBucket->GetEncloser())) &&
919                                                                (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
920                         break;
921                     case mdtTypeRef:
922                         while ((!CompareNestedEntryWithTypeRef(pNameModule->GetMDImport(),
923                                                                mdEncloser,
924                                                                pCurrentClsModule->GetAvailableClassHash(),
925                                                                pBucket->GetEncloser())) &&
926                                                                (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
927                         break;
928                     case mdtExportedType:
929                         while ((!CompareNestedEntryWithExportedType(pNameModule->GetAssembly()->GetManifestImport(),
930                                                                     mdEncloser,
931                                                                     pCurrentClsModule->GetAvailableClassHash(),
932                                                                     pBucket->GetEncloser())) &&
933                                                                     (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
934                         break;
935                     default:
936                         while ((pBucket->GetEncloser() != pName->GetBucket().GetClassHashBasedEntryValue()) &&
937                             (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
938                     }
939                 }
940             }
941             else
942             {
943                 pBucket = pTable->GetValue(pName, pData, FALSE, NULL);
944             }
945
946             if (pBucket) // Return on the first success
947             {
948                 pFoundEntry->SetClassHashBasedEntryValue(pBucket);
949                 return;
950             }
951         }
952     }
953
954     // No results found: default to a NULL EEClassHashEntry_t result
955     pFoundEntry->SetClassHashBasedEntryValue(NULL);
956 }
957
958 #ifndef DACCESS_COMPILE
959
960 VOID ClassLoader::PopulateAvailableClassHashTable(Module* pModule,
961                                                   AllocMemTracker *pamTracker)
962 {
963     CONTRACTL
964     {
965         INSTANCE_CHECK;
966         THROWS;
967         GC_TRIGGERS;
968         MODE_ANY;
969         INJECT_FAULT(COMPlusThrowOM(););
970     }
971     CONTRACTL_END;
972
973     mdTypeDef           td;
974     HENUMInternal       hTypeDefEnum;
975     IMDInternalImport * pImport = pModule->GetMDImport();
976
977     LPCSTR szWinRtNamespacePrefix = NULL;
978     DWORD  cchWinRtNamespacePrefix = 0;
979
980 #ifdef FEATURE_COMINTEROP
981     SString            ssFileName;
982     StackScratchBuffer ssFileNameBuffer;
983     
984     if (pModule->GetAssembly()->IsWinMD())
985     {   // WinMD file in execution context (not ReflectionOnly context) - use its file name as WinRT namespace prefix 
986         //  (Windows requirement)
987         // Note: Reflection can work on 'unfinished' WinMD files where the types are in 'wrong' WinMD file (i.e. 
988         //  type namespace does not start with the file name)
989         
990         _ASSERTE(pModule->GetFile()->IsAssembly()); // No multi-module WinMD file support
991         _ASSERTE(!pModule->GetFile()->GetPath().IsEmpty());
992         
993         SplitPath(
994             pModule->GetFile()->GetPath(),
995             NULL,   // Drive
996             NULL,   // Directory
997             &ssFileName, 
998             NULL);  // Extension
999         
1000         szWinRtNamespacePrefix = ssFileName.GetUTF8(ssFileNameBuffer);
1001         cchWinRtNamespacePrefix = (DWORD)strlen(szWinRtNamespacePrefix);
1002     }
1003 #endif //FEATURE_COMINTEROP
1004
1005     IfFailThrow(pImport->EnumTypeDefInit(&hTypeDefEnum));
1006
1007     // Now loop through all the classdefs adding the CVID and scope to the hash
1008     while(pImport->EnumTypeDefNext(&hTypeDefEnum, &td)) {
1009         
1010         AddAvailableClassHaveLock(pModule,
1011                                   td,
1012                                   pamTracker,
1013                                   szWinRtNamespacePrefix,
1014                                   cchWinRtNamespacePrefix);
1015     }
1016     pImport->EnumTypeDefClose(&hTypeDefEnum);
1017 }
1018
1019
1020 void ClassLoader::LazyPopulateCaseSensitiveHashTables()
1021 {
1022     CONTRACTL
1023     {
1024         INSTANCE_CHECK;
1025         THROWS;
1026         GC_TRIGGERS;
1027         MODE_ANY;
1028         INJECT_FAULT(COMPlusThrowOM());
1029     }
1030     CONTRACTL_END;
1031
1032     AllocMemTracker amTracker;
1033     ModuleIterator i = GetAssembly()->IterateModules();
1034
1035     // Create a case-sensitive hashtable for each module, and fill it with the module's typedef entries
1036     while (i.Next())
1037     {
1038         Module *pModule = i.GetModule();
1039         PREFIX_ASSUME(pModule != NULL);
1040         if (pModule->IsResource())
1041             continue;
1042
1043         // Lazy construction of the case-sensitive hashtable of types is *only* a scenario for ReadyToRun images
1044         // (either images compiled with an old version of crossgen, or for case-insensitive type lookups in R2R modules)
1045         _ASSERT(pModule->IsReadyToRun());
1046
1047         EEClassHashTable * pNewClassHash = EEClassHashTable::Create(pModule, AVAILABLE_CLASSES_HASH_BUCKETS, FALSE /* bCaseInsensitive */, &amTracker);
1048         pModule->SetAvailableClassHash(pNewClassHash);
1049
1050         PopulateAvailableClassHashTable(pModule, &amTracker);
1051     }
1052
1053     // Add exported types of the manifest module to the hashtable
1054     if (!GetAssembly()->GetManifestModule()->IsResource())
1055     {
1056         IMDInternalImport * pManifestImport = GetAssembly()->GetManifestImport();
1057         HENUMInternalHolder phEnum(pManifestImport);
1058         phEnum.EnumInit(mdtExportedType, mdTokenNil);
1059
1060         mdToken mdExportedType;
1061         while (pManifestImport->EnumNext(&phEnum, &mdExportedType))
1062             AddExportedTypeHaveLock(GetAssembly()->GetManifestModule(), mdExportedType, &amTracker);
1063     }
1064
1065     amTracker.SuppressRelease();
1066 }
1067
1068 void ClassLoader::LazyPopulateCaseInsensitiveHashTables()
1069 {
1070     CONTRACTL
1071     {
1072         INSTANCE_CHECK;
1073         THROWS;
1074         GC_TRIGGERS;
1075         MODE_ANY;
1076         INJECT_FAULT(COMPlusThrowOM());
1077     }
1078     CONTRACTL_END;
1079
1080     if (!GetAssembly()->GetManifestModule()->IsResource() && GetAssembly()->GetManifestModule()->GetAvailableClassHash() == NULL)
1081     {
1082         // This is a R2R assembly, and a case insensitive type lookup was triggered. 
1083         // Construct the case-sensitive table first, since the case-insensitive table 
1084         // create piggy-backs on the first.
1085         LazyPopulateCaseSensitiveHashTables();
1086     }
1087
1088     // Add any unhashed modules into our hash tables, and try again.
1089     
1090     AllocMemTracker amTracker;
1091     ModuleIterator i = GetAssembly()->IterateModules();
1092
1093     while (i.Next()) 
1094     {
1095         Module *pModule = i.GetModule();
1096         if (pModule->IsResource())
1097             continue;
1098
1099         if (pModule->GetAvailableClassCaseInsHash() == NULL) 
1100         {
1101             EEClassHashTable *pNewClassCaseInsHash = pModule->GetAvailableClassHash()->MakeCaseInsensitiveTable(pModule, &amTracker);
1102
1103             LOG((LF_CLASSLOADER, LL_INFO10, "%s's classes being added to case insensitive hash table\n",
1104                  pModule->GetSimpleName()));
1105
1106             {
1107                 CANNOTTHROWCOMPLUSEXCEPTION();
1108                 FAULT_FORBID();
1109                 
1110                 amTracker.SuppressRelease();
1111                 pModule->SetAvailableClassCaseInsHash(pNewClassCaseInsHash);
1112                 FastInterlockDecrement((LONG*)&m_cUnhashedModules);
1113             }
1114         }
1115     }
1116 }
1117
1118 /*static*/
1119 void DECLSPEC_NORETURN ClassLoader::ThrowTypeLoadException(TypeKey *pKey,
1120                                                            UINT resIDWhy)
1121 {
1122     STATIC_CONTRACT_THROWS;
1123
1124     StackSString fullName;
1125     StackSString assemblyName;
1126     TypeString::AppendTypeKey(fullName, pKey);
1127     pKey->GetModule()->GetAssembly()->GetDisplayName(assemblyName);
1128     ::ThrowTypeLoadException(fullName, assemblyName, NULL, resIDWhy);        
1129 }
1130
1131 #endif
1132
1133
1134 TypeHandle ClassLoader::LoadConstructedTypeThrowing(TypeKey *pKey,
1135                                                     LoadTypesFlag fLoadTypes /*= LoadTypes*/,
1136                                                     ClassLoadLevel level /*=CLASS_LOADED*/,
1137                                                     const InstantiationContext *pInstContext /*=NULL*/)
1138 {
1139     CONTRACT(TypeHandle)
1140     {
1141         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1142         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1143         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1144         if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
1145         PRECONDITION(CheckPointer(pKey));
1146         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1147         PRECONDITION(CheckPointer(pInstContext, NULL_OK));
1148         POSTCONDITION(CheckPointer(RETVAL, fLoadTypes==DontLoadTypes ? NULL_OK : NULL_NOT_OK));
1149         POSTCONDITION(RETVAL.IsNull() || RETVAL.GetLoadLevel() >= level);
1150         MODE_ANY;
1151         SUPPORTS_DAC;
1152     }
1153     CONTRACT_END
1154
1155     TypeHandle typeHnd;
1156     ClassLoadLevel existingLoadLevel = CLASS_LOAD_BEGIN;
1157
1158     // Lookup in the classes that this class loader knows about
1159
1160     if (pKey->HasInstantiation() && ClassLoader::IsTypicalSharedInstantiation(pKey->GetInstantiation()))
1161     {
1162         _ASSERTE(pKey->GetModule() == ComputeLoaderModule(pKey));
1163         typeHnd = pKey->GetModule()->LookupFullyCanonicalInstantiation(pKey->GetTypeToken(), &existingLoadLevel);
1164     }
1165
1166     if (typeHnd.IsNull())
1167     {
1168         typeHnd = LookupTypeHandleForTypeKey(pKey);
1169         if (!typeHnd.IsNull())
1170         {
1171             existingLoadLevel = typeHnd.GetLoadLevel();
1172             if (existingLoadLevel >= level)
1173                 g_IBCLogger.LogTypeHashTableAccess(&typeHnd);
1174         }
1175     }
1176
1177     // If something has been published in the tables, and it's at the right level, just return it
1178     if (!typeHnd.IsNull() && existingLoadLevel >= level)
1179     {
1180         RETURN typeHnd;
1181     }
1182
1183 #ifndef DACCESS_COMPILE
1184     if (typeHnd.IsNull() && pKey->HasInstantiation())
1185     {
1186         if (!Generics::CheckInstantiation(pKey->GetInstantiation()))
1187             pKey->GetModule()->GetAssembly()->ThrowTypeLoadException(pKey->GetModule()->GetMDImport(), pKey->GetTypeToken(), IDS_CLASSLOAD_INVALIDINSTANTIATION);
1188     }
1189 #endif
1190
1191     // If we're not loading any types at all, then we're not creating
1192     // instantiations either because we're in FORBIDGC_LOADER_USE mode, so
1193     // we should bail out here.
1194     if (fLoadTypes == DontLoadTypes)
1195         RETURN TypeHandle();
1196
1197 #ifndef DACCESS_COMPILE
1198     // If we got here, we now have to allocate a new parameterized type.
1199     // By definition, forbidgc-users aren't allowed to reach this point.
1200     CONSISTENCY_CHECK(!FORBIDGC_LOADER_USE_ENABLED());
1201
1202     Module *pLoaderModule = ComputeLoaderModule(pKey);
1203     RETURN(pLoaderModule->GetClassLoader()->LoadTypeHandleForTypeKey(pKey, typeHnd, level, pInstContext));
1204 #else
1205     DacNotImpl();
1206     RETURN(typeHnd);
1207 #endif
1208 }
1209
1210
1211 /*static*/
1212 void ClassLoader::EnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level)
1213 {
1214     CONTRACTL
1215     {
1216         PRECONDITION(CheckPointer(typeHnd));
1217         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1218         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1219         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1220         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1221         if (FORBIDGC_LOADER_USE_ENABLED()) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); } 
1222         SUPPORTS_DAC;
1223
1224         MODE_ANY;
1225     }
1226     CONTRACTL_END
1227
1228 #ifndef DACCESS_COMPILE // Nothing to do for the DAC case
1229
1230     if (typeHnd.GetLoadLevel() < level)
1231     {
1232 #ifdef FEATURE_PREJIT
1233         if (typeHnd.GetLoadLevel() == CLASS_LOAD_UNRESTOREDTYPEKEY)
1234         {
1235             typeHnd.DoRestoreTypeKey();
1236         }        
1237 #endif
1238         if (level > CLASS_LOAD_UNRESTORED)
1239         {
1240             TypeKey typeKey = typeHnd.GetTypeKey();
1241             
1242             Module *pLoaderModule = ComputeLoaderModule(&typeKey);
1243             pLoaderModule->GetClassLoader()->LoadTypeHandleForTypeKey(&typeKey, typeHnd, level);
1244         }
1245     }
1246
1247 #endif // DACCESS_COMPILE
1248 }
1249
1250 /*static*/
1251 void ClassLoader::TryEnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level)
1252 {
1253     WRAPPER_NO_CONTRACT;
1254
1255 #ifndef DACCESS_COMPILE // Nothing to do for the DAC case
1256
1257     EX_TRY
1258     {
1259         ClassLoader::EnsureLoaded(typeHnd, level);
1260     }
1261     EX_CATCH
1262     {
1263         // Some type may not load successfully. For eg. generic instantiations
1264         // that do not satisfy the constraints of the type arguments.
1265     }
1266     EX_END_CATCH(RethrowTerminalExceptions);
1267
1268 #endif // DACCESS_COMPILE
1269 }
1270
1271 // This is separated out to avoid the overhead of C++ exception handling in the non-locking case.
1272 /* static */
1273 TypeHandle ClassLoader::LookupTypeKeyUnderLock(TypeKey *pKey,
1274                                                EETypeHashTable *pTable,
1275                                                CrstBase *pLock)
1276 {
1277     WRAPPER_NO_CONTRACT;
1278     SUPPORTS_DAC;
1279
1280     // m_AvailableTypesLock has to be taken in cooperative mode to avoid deadlocks during GC
1281     GCX_MAYBE_COOP_NO_THREAD_BROKEN(!IsGCThread());
1282
1283     CrstHolder ch(pLock);
1284     return pTable->GetValue(pKey);
1285 }
1286
1287 /* static */
1288 TypeHandle ClassLoader::LookupTypeKey(TypeKey *pKey,
1289                                       EETypeHashTable *pTable,
1290                                       CrstBase *pLock,
1291                                       BOOL fCheckUnderLock)
1292 {
1293     CONTRACTL {
1294         NOTHROW;
1295         GC_NOTRIGGER; 
1296         FORBID_FAULT;
1297         PRECONDITION(CheckPointer(pKey));
1298         PRECONDITION(pKey->IsConstructed());
1299         PRECONDITION(CheckPointer(pTable));
1300         PRECONDITION(!fCheckUnderLock || CheckPointer(pLock));
1301         MODE_ANY;
1302         SUPPORTS_DAC;
1303     } CONTRACTL_END;
1304
1305     TypeHandle th;
1306
1307     if (fCheckUnderLock)
1308     {
1309         th = LookupTypeKeyUnderLock(pKey, pTable, pLock);
1310     }
1311     else
1312     {
1313         th = pTable->GetValue(pKey);
1314     }
1315     return th;
1316 }
1317
1318
1319 #ifdef FEATURE_PREJIT
1320 /* static */
1321 TypeHandle ClassLoader::LookupInPreferredZapModule(TypeKey *pKey, BOOL fCheckUnderLock)
1322 {
1323     CONTRACTL {
1324         NOTHROW;
1325         GC_NOTRIGGER; 
1326         FORBID_FAULT;
1327         PRECONDITION(CheckPointer(pKey));
1328         PRECONDITION(pKey->IsConstructed());
1329         MODE_ANY;
1330         SUPPORTS_DAC;
1331     } CONTRACTL_END;
1332
1333     // First look for an NGEN'd type in the preferred ngen module
1334     TypeHandle th;
1335     PTR_Module pPreferredZapModule = Module::ComputePreferredZapModule(pKey);
1336     
1337     if (pPreferredZapModule != NULL && pPreferredZapModule->HasNativeImage())
1338     {
1339         th = LookupTypeKey(pKey,
1340                            pPreferredZapModule->GetAvailableParamTypes(),
1341                            &pPreferredZapModule->GetClassLoader()->m_AvailableTypesLock,
1342                            fCheckUnderLock);
1343     }
1344
1345     return th;
1346 }
1347 #endif // FEATURE_PREJIT
1348
1349
1350 /* static */
1351 TypeHandle ClassLoader::LookupInLoaderModule(TypeKey *pKey, BOOL fCheckUnderLock)
1352 {
1353     CONTRACTL {
1354         NOTHROW;
1355         GC_NOTRIGGER; 
1356         FORBID_FAULT;
1357         PRECONDITION(CheckPointer(pKey));
1358         PRECONDITION(pKey->IsConstructed());
1359         MODE_ANY;
1360         SUPPORTS_DAC;
1361     } CONTRACTL_END;
1362
1363     Module *pLoaderModule = ComputeLoaderModule(pKey);
1364     PREFIX_ASSUME(pLoaderModule!=NULL);
1365     
1366     return LookupTypeKey(pKey,
1367                          pLoaderModule->GetAvailableParamTypes(),
1368                          &pLoaderModule->GetClassLoader()->m_AvailableTypesLock,
1369                          fCheckUnderLock);
1370 }
1371
1372
1373 /* static */
1374 TypeHandle ClassLoader::LookupTypeHandleForTypeKey(TypeKey *pKey)
1375 {
1376     WRAPPER_NO_CONTRACT;
1377     SUPPORTS_DAC;
1378
1379     // Make an initial lookup without taking any locks.
1380     TypeHandle th = LookupTypeHandleForTypeKeyInner(pKey, FALSE);
1381
1382     // A non-null TypeHandle for the above lookup indicates success
1383     // A null TypeHandle only indicates "well, it might have been there,
1384     // try again with a lock".  This kind of negative result will
1385     // only happen while accessing the underlying EETypeHashTable 
1386     // during a resize, i.e. very rarely. In such a case, we just
1387     // perform the lookup again, but indicate that appropriate locks
1388     // should be taken.
1389
1390     if (th.IsNull())
1391     {
1392         th = LookupTypeHandleForTypeKeyInner(pKey, TRUE);
1393     }
1394
1395     return th;
1396 }
1397 /* static */
1398 TypeHandle ClassLoader::LookupTypeHandleForTypeKeyInner(TypeKey *pKey, BOOL fCheckUnderLock)
1399 {
1400     CONTRACTL
1401     {
1402         NOTHROW;
1403         GC_NOTRIGGER; 
1404         FORBID_FAULT;
1405         PRECONDITION(CheckPointer(pKey));
1406         MODE_ANY;
1407         SUPPORTS_DAC;
1408     }
1409     CONTRACTL_END
1410
1411     // Check if it's the typical instantiation.  In this case it's not stored in the same
1412     // way as other constructed types.
1413     if (!pKey->IsConstructed() || 
1414         (pKey->GetKind() == ELEMENT_TYPE_CLASS && ClassLoader::IsTypicalInstantiation(pKey->GetModule(), 
1415                                                                                       pKey->GetTypeToken(),
1416                                                                                       pKey->GetInstantiation())))
1417     {
1418         return TypeHandle(pKey->GetModule()->LookupTypeDef(pKey->GetTypeToken()));
1419     }
1420
1421 #ifdef FEATURE_PREJIT
1422     // The following ways of finding a constructed type should be mutually exclusive!
1423     //  1. Look for a zapped item in the PreferredZapModule
1424     //  2. Look for a unzapped (JIT-loaded) item in the LoaderModule
1425
1426     TypeHandle thPZM = LookupInPreferredZapModule(pKey, fCheckUnderLock);
1427     if (!thPZM.IsNull())
1428     {
1429         return thPZM;
1430     }
1431 #endif // FEATURE_PREJIT
1432
1433     // Next look in the loader module.  This is where the item is guaranteed to live if
1434     // it is not latched from an NGEN image, i.e. if it is JIT loaded. 
1435     // If the thing is not NGEN'd then this may
1436     // be different to pPreferredZapModule.  If they are the same then 
1437     // we can reuse the results of the lookup above.
1438     TypeHandle thLM = LookupInLoaderModule(pKey, fCheckUnderLock);
1439     if (!thLM.IsNull())
1440     {
1441         return thLM;
1442     }
1443
1444     return TypeHandle();
1445 }
1446
1447 // FindClassModuleThrowing discovers which module the type you're looking for is in and loads the Module if necessary.
1448 // Basically, it iterates through all of the assembly's modules until a name match is found in a module's
1449 // AvailableClassHashTable.
1450 //
1451 // The possible outcomes are:
1452 //
1453 //    - Function returns TRUE   - class exists and we successfully found/created the containing Module. See below
1454 //                                for how to deconstruct the results.
1455 //    - Function returns FALSE  - class affirmatively NOT found (that means it doesn't exist as a regular type although
1456 //                                  it could also be a parameterized type)
1457 //    - Function throws         - OOM or some other reason we couldn't do the job (if it's a case-sensitive search
1458 //                                  and you're looking for already loaded type or you've set the TokenNotToLoad.
1459 //                                  we are guaranteed not to find a reason to throw.)
1460 //
1461 //
1462 // If it succeeds (returns TRUE), one of the following will occur. Check (*pType)->IsNull() to discriminate.
1463 //
1464 //     1. *pType: set to the null TypeHandle()
1465 //        *ppModule: set to the owning Module
1466 //        *pmdClassToken: set to the typedef
1467 //        *pmdFoundExportedType: if this name bound to an ExportedType, this contains the mdtExportedType token (otherwise,
1468 //                               it's set to mdTokenNil.) You need this because in this case, *pmdClassToken is just
1469 //                               a best guess and you need to verify it. (The division of labor between this
1470 //                               and LoadTypeHandle could definitely be better!)
1471 //
1472 //     2. *pType: set to non-null TypeHandle()
1473 //        This means someone else had already done this same lookup before you and caused the actual
1474 //        TypeHandle to be cached. Since we know that's what you *really* wanted, we'll just forget the
1475 //        Module/typedef stuff and give you the actual TypeHandle.
1476 //
1477 //
1478 BOOL ClassLoader::FindClassModuleThrowing(
1479     const NameHandle *    pOriginalName, 
1480     TypeHandle *          pType, 
1481     mdToken *             pmdClassToken, 
1482     Module **             ppModule, 
1483     mdToken *             pmdFoundExportedType, 
1484     HashedTypeEntry *     pFoundEntry,
1485     Module *              pLookInThisModuleOnly, 
1486     Loader::LoadFlag      loadFlag)
1487 {
1488     CONTRACTL
1489     {
1490         INSTANCE_CHECK;
1491         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1492         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1493         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1494         PRECONDITION(CheckPointer(pOriginalName));
1495         PRECONDITION(CheckPointer(ppModule));
1496         MODE_ANY;
1497         SUPPORTS_DAC;
1498     }
1499     CONTRACTL_END
1500
1501     NameHandleTable nhTable = nhCaseSensitive; // just to initialize this ...
1502     
1503     // Make a copy of the original name which we can modify (to lowercase)
1504     NameHandle   localName = *pOriginalName;
1505     NameHandle * pName = &localName;
1506
1507     switch (pName->GetTable()) 
1508     {
1509       case nhCaseInsensitive:
1510       {
1511 #ifndef DACCESS_COMPILE
1512         // GC-type users should only be loading types through tokens.
1513 #ifdef _DEBUG_IMPL
1514         _ASSERTE(!FORBIDGC_LOADER_USE_ENABLED());
1515 #endif
1516
1517         // Use the case insensitive table
1518         nhTable = nhCaseInsensitive;
1519
1520         // Create a low case version of the namespace and name
1521         LPUTF8 pszLowerNameSpace = NULL;
1522         LPUTF8 pszLowerClassName = NULL;
1523         int allocLen;
1524
1525         if (pName->GetNameSpace())
1526         {
1527             allocLen = InternalCasingHelper::InvariantToLower(
1528                 NULL, 
1529                 0, 
1530                 pName->GetNameSpace());
1531             if (allocLen == 0)
1532             {
1533                 return FALSE;
1534             }
1535
1536             pszLowerNameSpace = (LPUTF8)_alloca(allocLen);
1537             if (allocLen == 1)
1538             {
1539                 *pszLowerNameSpace = '\0';
1540             }
1541             else if (!InternalCasingHelper::InvariantToLower(
1542                         pszLowerNameSpace, 
1543                         allocLen, 
1544                         pName->GetNameSpace()))
1545             {
1546                 return FALSE;
1547             }
1548         }
1549
1550         _ASSERTE(pName->GetName() != NULL);
1551         allocLen = InternalCasingHelper::InvariantToLower(NULL, 0, pName->GetName());
1552         if (allocLen == 0)
1553         {
1554             return FALSE;
1555         }
1556
1557         pszLowerClassName = (LPUTF8)_alloca(allocLen);
1558         if (!InternalCasingHelper::InvariantToLower(
1559                 pszLowerClassName, 
1560                 allocLen, 
1561                 pName->GetName()))
1562         {
1563             return FALSE;
1564         }
1565
1566         // Substitute the lower case version of the name.
1567         // The field are will be released when we leave this scope
1568         pName->SetName(pszLowerNameSpace, pszLowerClassName);
1569         break;
1570 #else
1571         DacNotImpl();
1572         break;
1573 #endif // #ifndef DACCESS_COMPILE
1574       }
1575       case nhCaseSensitive:
1576         nhTable = nhCaseSensitive;
1577         break;
1578     }
1579
1580     // Remember if there are any unhashed modules.  We must do this before
1581     // the actual look to avoid a race condition with other threads doing lookups.
1582 #ifdef LOGGING
1583     BOOL incomplete = (m_cUnhashedModules > 0);
1584 #endif
1585
1586     HashDatum Data;
1587     EEClassHashTable * pTable = NULL;
1588     HashedTypeEntry foundEntry;
1589     BOOL needsToBuildHashtable;
1590     GetClassValue(nhTable, pName, &Data, &pTable, pLookInThisModuleOnly, &foundEntry, loadFlag, needsToBuildHashtable);
1591
1592     // In the case of R2R modules, the search is only performed in the hashtable saved in the 
1593     // R2R image, and this is why we return (whether we found a valid typedef token or not).
1594     // Note: case insensitive searches are not used/supported in R2R images.
1595     if (foundEntry.GetEntryType() == HashedTypeEntry::EntryType::IsHashedTokenEntry)
1596     {
1597         *pType = TypeHandle();
1598         HashedTypeEntry::TokenTypeEntry tokenAndModulePair = foundEntry.GetTokenBasedEntryValue();
1599         switch (TypeFromToken(tokenAndModulePair.m_TypeToken))
1600         {
1601         case mdtTypeDef:
1602             *pmdClassToken = tokenAndModulePair.m_TypeToken;
1603             *pmdFoundExportedType = mdTokenNil;
1604             break;
1605         case mdtExportedType:
1606             *pmdClassToken = mdTokenNil;
1607             *pmdFoundExportedType = tokenAndModulePair.m_TypeToken;
1608             break;
1609         default:
1610             _ASSERT(false);
1611             return FALSE;
1612         }
1613         *ppModule = tokenAndModulePair.m_pModule;
1614         if (pFoundEntry != NULL)
1615             *pFoundEntry = foundEntry;
1616
1617         return TRUE;
1618     }
1619
1620     EEClassHashEntry_t * pBucket = foundEntry.GetClassHashBasedEntryValue();
1621
1622     if (pBucket == NULL)
1623     {
1624         AvailableClasses_LockHolder lh(this);
1625
1626         // Try again with the lock.  This will protect against another thread reallocating
1627         // the hash table underneath us
1628         GetClassValue(nhTable, pName, &Data, &pTable, pLookInThisModuleOnly, &foundEntry, loadFlag, needsToBuildHashtable);
1629         pBucket = foundEntry.GetClassHashBasedEntryValue();
1630
1631 #ifndef DACCESS_COMPILE
1632         if (needsToBuildHashtable && (pBucket == NULL) && (m_cUnhashedModules > 0))
1633         {
1634             _ASSERT(needsToBuildHashtable);
1635
1636             if (nhTable == nhCaseInsensitive)
1637             {
1638                 LazyPopulateCaseInsensitiveHashTables();
1639             }
1640             else
1641             {
1642                 // Note: This codepath is only valid for R2R scenarios
1643                 LazyPopulateCaseSensitiveHashTables();
1644             }
1645
1646             // Try yet again with the new classes added
1647             GetClassValue(nhTable, pName, &Data, &pTable, pLookInThisModuleOnly, &foundEntry, loadFlag, needsToBuildHashtable);
1648             pBucket = foundEntry.GetClassHashBasedEntryValue();
1649             _ASSERT(!needsToBuildHashtable);
1650         }
1651 #endif
1652     }
1653
1654     // Same check as above, but this time we've checked with the lock so the table will be populated
1655     if (pBucket == NULL)
1656     {
1657 #if defined(_DEBUG_IMPL) && !defined(DACCESS_COMPILE)
1658         LPCUTF8 szName = pName->GetName();
1659         if (szName == NULL)
1660             szName = "<UNKNOWN>";
1661         LOG((LF_CLASSLOADER, LL_INFO10, "Failed to find type \"%s\", assembly \"%ws\" in hash table. Incomplete = %d\n",
1662             szName, GetAssembly()->GetDebugName(), incomplete));
1663 #endif
1664         return FALSE;
1665     }
1666
1667     if (pName->GetTable() == nhCaseInsensitive)
1668     {
1669         _ASSERTE(Data);
1670         pBucket = PTR_EEClassHashEntry(Data);
1671         Data = pBucket->GetData();
1672     }
1673
1674     // Lower bit is a discriminator.  If the lower bit is NOT SET, it means we have
1675     // a TypeHandle. Otherwise, we have a Module/CL.
1676     if ((dac_cast<TADDR>(Data) & EECLASSHASH_TYPEHANDLE_DISCR) == 0)
1677     {
1678         TypeHandle t = TypeHandle::FromPtr(Data);
1679         _ASSERTE(!t.IsNull());
1680
1681         *pType = t;
1682         if (pFoundEntry != NULL)
1683         {
1684             pFoundEntry->SetClassHashBasedEntryValue(pBucket);
1685         }
1686         return TRUE;
1687     }
1688
1689     // We have a Module/CL
1690     if (!pTable->UncompressModuleAndClassDef(Data, 
1691                                              loadFlag, 
1692                                              ppModule, 
1693                                              pmdClassToken, 
1694                                              pmdFoundExportedType))
1695     {
1696         _ASSERTE(loadFlag != Loader::Load);
1697         return FALSE;
1698     }
1699
1700     *pType = TypeHandle();
1701     if (pFoundEntry != NULL)
1702     {
1703         pFoundEntry->SetClassHashBasedEntryValue(pBucket);
1704     }
1705     return TRUE;
1706 } // ClassLoader::FindClassModuleThrowing
1707
1708 #ifndef DACCESS_COMPILE
1709 // Returns true if the full name (namespace+name) of pName matches that
1710 // of typeHnd; otherwise false. Because this is nothrow, it will default
1711 // to false for all exceptions (such as OOM).
1712 bool CompareNameHandleWithTypeHandleNoThrow(
1713     const NameHandle * pName, 
1714     TypeHandle         typeHnd)
1715 {
1716     bool fRet = false;
1717     
1718     EX_TRY
1719     {
1720         // This block is specifically designed to handle transient faults such
1721         // as OOM exceptions.
1722         CONTRACT_VIOLATION(FaultViolation | ThrowsViolation);
1723         StackSString ssBuiltName;
1724         ns::MakePath(ssBuiltName,
1725                      StackSString(SString::Utf8, pName->GetNameSpace()),
1726                      StackSString(SString::Utf8, pName->GetName()));
1727         StackSString ssName;
1728         typeHnd.GetName(ssName);
1729         fRet = ssName.Equals(ssBuiltName) == TRUE;
1730     }
1731     EX_CATCH
1732     {
1733         // Technically, the above operations should never result in a non-OOM
1734         // exception, but we'll put the rethrow line in there just in case.
1735         CONSISTENCY_CHECK(!GET_EXCEPTION()->IsTerminal());
1736         RethrowTerminalExceptions;
1737     }
1738     EX_END_CATCH(SwallowAllExceptions);
1739     
1740     return fRet;
1741 }
1742 #endif // #ifndef DACCESS_COMPILE
1743
1744 // 1024 seems like a good bet at detecting a loop in the type forwarding.
1745 static const UINT32 const_cMaxTypeForwardingChainSize = 1024;
1746
1747 // Does not throw an exception if the type was not found.  Use LoadTypeHandleThrowIfFailed()
1748 // instead if you need that.
1749 // 
1750 // Returns:
1751 //  pName->m_pBucket 
1752 //    Will be set to the 'final' TypeDef bucket if pName->GetTokenType() is mdtBaseType.
1753 // 
1754 TypeHandle 
1755 ClassLoader::LoadTypeHandleThrowing(
1756     NameHandle *   pName, 
1757     ClassLoadLevel level, 
1758     Module *       pLookInThisModuleOnly /*=NULL*/)
1759 {
1760     CONTRACT(TypeHandle) {
1761         INSTANCE_CHECK;
1762         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1763         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1764         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1765         DAC_LOADS_TYPE(level, !pName->OKToLoad()); 
1766         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1767         PRECONDITION(CheckPointer(pName));
1768         POSTCONDITION(RETVAL.IsNull() || RETVAL.GetLoadLevel() >= level);
1769         MODE_ANY;
1770         SUPPORTS_DAC;
1771     } CONTRACT_END
1772
1773     TypeHandle typeHnd;
1774     Module * pFoundModule = NULL;
1775     mdToken FoundCl;
1776     HashedTypeEntry foundEntry;
1777     mdExportedType FoundExportedType = mdTokenNil;
1778
1779     UINT32 cLoopIterations = 0;
1780
1781     ClassLoader * pClsLdr = this;
1782
1783     while (true)
1784     {
1785         if (cLoopIterations++ >= const_cMaxTypeForwardingChainSize)
1786         {   // If we've looped too many times due to type forwarding, return null TypeHandle
1787             // Would prefer to return a format exception, but the original behaviour
1788             // was to detect a stack overflow possibility and return a null, and
1789             // so we need to maintain this.
1790             typeHnd = TypeHandle();
1791             break;
1792         }
1793         
1794         // Look outside the lock (though we're actually still a long way from the
1795         // lock at this point...).  This may discover that the type is actually
1796         // defined in another module...
1797         
1798         if (!pClsLdr->FindClassModuleThrowing(
1799                 pName, 
1800                 &typeHnd, 
1801                 &FoundCl, 
1802                 &pFoundModule, 
1803                 &FoundExportedType, 
1804                 &foundEntry,
1805                 pLookInThisModuleOnly, 
1806                 pName->OKToLoad() ? Loader::Load 
1807                                   : Loader::DontLoad))
1808         {   // Didn't find anything, no point looping indefinitely
1809             break;
1810         }
1811         _ASSERTE(!foundEntry.IsNull());
1812
1813         if (pName->GetTypeToken() == mdtBaseType)
1814         {   // We should return the found bucket in the pName
1815             pName->SetBucket(foundEntry);
1816         }
1817
1818         if (!typeHnd.IsNull())
1819         {   // Found the cached value, or a constructedtype
1820             if (typeHnd.GetLoadLevel() < level)
1821             {
1822                 typeHnd = pClsLdr->LoadTypeDefThrowing(
1823                     typeHnd.GetModule(),
1824                     typeHnd.GetCl(),
1825                     ClassLoader::ReturnNullIfNotFound, 
1826                     ClassLoader::PermitUninstDefOrRef, // When loading by name we always permit naked type defs/refs
1827                     pName->GetTokenNotToLoad(), 
1828                     level);
1829             }
1830             break;
1831         }
1832         
1833         // Found a cl, pModule pair            
1834         
1835         // If the found module's class loader is not the same as the current class loader,
1836         // then this is a forwarded type and we want to do something else (see 
1837         // code:#LoadTypeHandle_TypeForwarded).
1838         if (pFoundModule->GetClassLoader() == pClsLdr)
1839         {
1840             BOOL fTrustTD = TRUE;
1841 #ifndef DACCESS_COMPILE
1842             CONTRACT_VIOLATION(ThrowsViolation);
1843             BOOL fVerifyTD = FALSE;
1844             
1845             // If this is an exported type with a mdTokenNil class token, then then
1846             // exported type did not give a typedefID hint. We won't be able to trust the typedef
1847             // here.
1848             if ((FoundExportedType != mdTokenNil) && (FoundCl == mdTokenNil))
1849             {
1850                 fVerifyTD = TRUE;
1851                 fTrustTD = FALSE;
1852             }
1853             // verify that FoundCl is a valid token for pFoundModule, because
1854             // it may be just the hint saved in an ExportedType in another scope
1855             else if (fVerifyTD)
1856             {
1857                 fTrustTD = pFoundModule->GetMDImport()->IsValidToken(FoundCl);
1858             }                    
1859 #endif // #ifndef DACCESS_COMPILE
1860                 
1861             if (fTrustTD)
1862             {
1863                 typeHnd = pClsLdr->LoadTypeDefThrowing(
1864                     pFoundModule, 
1865                     FoundCl, 
1866                     ClassLoader::ReturnNullIfNotFound, 
1867                     ClassLoader::PermitUninstDefOrRef, // when loading by name we always permit naked type defs/refs
1868                     pName->GetTokenNotToLoad(), 
1869                     level);
1870             }                
1871 #ifndef DACCESS_COMPILE
1872             // If we used a TypeDef saved in a ExportedType, if we didn't verify
1873             // the hash for this internal module, don't trust the TD value.
1874             if (fVerifyTD)
1875             {
1876                 if (typeHnd.IsNull() || !CompareNameHandleWithTypeHandleNoThrow(pName, typeHnd))
1877                 {
1878                     if (SUCCEEDED(pClsLdr->FindTypeDefByExportedType(
1879                             pClsLdr->GetAssembly()->GetManifestImport(), 
1880                             FoundExportedType, 
1881                             pFoundModule->GetMDImport(), 
1882                             &FoundCl)))
1883                     {
1884                         typeHnd = pClsLdr->LoadTypeDefThrowing(
1885                             pFoundModule, 
1886                             FoundCl, 
1887                             ClassLoader::ReturnNullIfNotFound, 
1888                             ClassLoader::PermitUninstDefOrRef, 
1889                             pName->GetTokenNotToLoad(), 
1890                             level);
1891                     }
1892                     else
1893                     {
1894                         typeHnd = TypeHandle();
1895                     }
1896                 }
1897             }
1898 #endif // #ifndef DACCESS_COMPILE
1899             break;
1900         }
1901         else
1902         {   //#LoadTypeHandle_TypeForwarded
1903             // pName is a host instance so it's okay to set fields in it in a DAC build
1904             HashedTypeEntry& bucket = pName->GetBucket();
1905
1906             // Reset pName's bucket entry
1907             if (bucket.GetEntryType() == HashedTypeEntry::IsHashedClassEntry && bucket.GetClassHashBasedEntryValue()->GetEncloser())
1908             {
1909                 // We will be searching for the type name again, so set the nesting/context type to the 
1910                 // encloser of just found type
1911                 pName->SetBucket(HashedTypeEntry().SetClassHashBasedEntryValue(bucket.GetClassHashBasedEntryValue()->GetEncloser()));
1912             }
1913             else
1914             {
1915                 pName->SetBucket(HashedTypeEntry());
1916             }
1917
1918             // Update the class loader for the new module/token pair.
1919             pClsLdr = pFoundModule->GetClassLoader();
1920             pLookInThisModuleOnly = NULL;
1921         }
1922
1923 #ifndef DACCESS_COMPILE
1924         // Replace AvailableClasses Module entry with found TypeHandle
1925         if (!typeHnd.IsNull() && 
1926             typeHnd.IsRestored() && 
1927             foundEntry.GetEntryType() == HashedTypeEntry::EntryType::IsHashedClassEntry &&
1928             (foundEntry.GetClassHashBasedEntryValue() != NULL) && 
1929             (foundEntry.GetClassHashBasedEntryValue()->GetData() != typeHnd.AsPtr()))
1930         {
1931             foundEntry.GetClassHashBasedEntryValue()->SetData(typeHnd.AsPtr());
1932         }
1933 #endif // !DACCESS_COMPILE
1934     }
1935
1936     RETURN typeHnd;
1937 } // ClassLoader::LoadTypeHandleThrowing
1938
1939 /* static */
1940 TypeHandle ClassLoader::LoadPointerOrByrefTypeThrowing(CorElementType typ, 
1941                                                        TypeHandle baseType,
1942                                                        LoadTypesFlag fLoadTypes/*=LoadTypes*/, 
1943                                                        ClassLoadLevel level/*=CLASS_LOADED*/)
1944 {
1945     CONTRACT(TypeHandle)
1946     {
1947         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1948         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1949         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1950         if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
1951         MODE_ANY;
1952         PRECONDITION(CheckPointer(baseType));
1953         PRECONDITION(typ == ELEMENT_TYPE_BYREF || typ == ELEMENT_TYPE_PTR);
1954         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1955         POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
1956         SUPPORTS_DAC;
1957     }
1958     CONTRACT_END
1959
1960     TypeKey key(typ, baseType);
1961     RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level));
1962 }
1963
1964 /* static */
1965 TypeHandle ClassLoader::LoadNativeValueTypeThrowing(TypeHandle baseType,
1966                                                     LoadTypesFlag fLoadTypes/*=LoadTypes*/, 
1967                                                     ClassLoadLevel level/*=CLASS_LOADED*/)
1968 {
1969     CONTRACT(TypeHandle)
1970     {
1971         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1972         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1973         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1974         MODE_ANY;
1975         PRECONDITION(CheckPointer(baseType));
1976         PRECONDITION(baseType.AsMethodTable()->IsValueType());
1977         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1978         POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
1979     }
1980     CONTRACT_END
1981
1982     TypeKey key(ELEMENT_TYPE_VALUETYPE, baseType);
1983     RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level));
1984 }
1985
1986 /* static */
1987 TypeHandle ClassLoader::LoadFnptrTypeThrowing(BYTE callConv,
1988                                               DWORD ntypars,
1989                                               TypeHandle* inst, 
1990                                               LoadTypesFlag fLoadTypes/*=LoadTypes*/,
1991                                               ClassLoadLevel level/*=CLASS_LOADED*/)
1992 {
1993     CONTRACT(TypeHandle)
1994     {
1995         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1996         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1997         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1998         if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
1999         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
2000         POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
2001         MODE_ANY;
2002         SUPPORTS_DAC;
2003     }
2004     CONTRACT_END
2005
2006     TypeKey key(callConv, ntypars, inst);
2007     RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level));
2008 }
2009
2010 // Find an instantiation of a generic type if it has already been created.
2011 // If typeDef is not a generic type or is already instantiated then throw an exception.
2012 // If its arity does not match ntypars then throw an exception.
2013 // Value will be non-null if we're loading types.
2014 /* static */
2015 TypeHandle ClassLoader::LoadGenericInstantiationThrowing(Module *pModule,
2016                                                          mdTypeDef typeDef,
2017                                                          Instantiation inst,
2018                                                          LoadTypesFlag fLoadTypes/*=LoadTypes*/,
2019                                                          ClassLoadLevel level/*=CLASS_LOADED*/,
2020                                                          const InstantiationContext *pInstContext/*=NULL*/,
2021                                                          BOOL fFromNativeImage /*=FALSE*/)
2022 {
2023     // This can be called in FORBIDGC_LOADER_USE mode by the debugger to find
2024     // a particular generic type instance that is already loaded.
2025     CONTRACT(TypeHandle)
2026     {
2027         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2028         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2029         if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
2030         PRECONDITION(CheckPointer(pModule));
2031         MODE_ANY;
2032         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
2033         PRECONDITION(CheckPointer(pInstContext, NULL_OK));
2034         POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
2035         SUPPORTS_DAC;
2036     }
2037     CONTRACT_END
2038
2039     // Essentially all checks to determine if a generic instantiation of a type
2040     // is well-formed go in this method, i.e. this is the 
2041     // "choke" point through which all attempts
2042     // to create an instantiation flow.  There is a similar choke point for generic
2043     // methods in genmeth.cpp.
2044
2045     if (inst.IsEmpty() || ClassLoader::IsTypicalInstantiation(pModule, typeDef, inst))
2046     {
2047         TypeHandle th = LoadTypeDefThrowing(pModule, typeDef, 
2048                                             ThrowIfNotFound,
2049                                             PermitUninstDefOrRef,
2050                                             fLoadTypes == DontLoadTypes ? tdAllTypes : tdNoTypes, 
2051                                             level, 
2052                                             fFromNativeImage ? NULL : &inst);
2053         _ASSERTE(th.GetNumGenericArgs() == inst.GetNumArgs());
2054         RETURN th;
2055     }
2056
2057     if (!fFromNativeImage)
2058     {
2059         TypeHandle th = ClassLoader::LoadTypeDefThrowing(pModule, typeDef, 
2060                                          ThrowIfNotFound,
2061                                          PermitUninstDefOrRef,
2062                                          fLoadTypes == DontLoadTypes ? tdAllTypes : tdNoTypes, 
2063                                          level, 
2064                                          fFromNativeImage ? NULL : &inst);
2065         _ASSERTE(th.GetNumGenericArgs() == inst.GetNumArgs());
2066     }
2067
2068     TypeKey key(pModule, typeDef, inst);
2069
2070 #ifndef DACCESS_COMPILE
2071     // To avoid loading useless shared instantiations, normalize shared instantiations to the canonical form 
2072     // (e.g. Dictionary<String,_Canon> -> Dictionary<_Canon,_Canon>)
2073     // The denormalized shared instantiations should be needed only during JITing, so it is fine to skip this
2074     // for DACCESS_COMPILE.
2075     if (TypeHandle::IsCanonicalSubtypeInstantiation(inst) && !IsCanonicalGenericInstantiation(inst))
2076     {
2077         RETURN(ClassLoader::LoadCanonicalGenericInstantiation(&key, fLoadTypes, level));
2078     }
2079 #endif
2080
2081     RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level, pInstContext));
2082 }
2083
2084 //   For non-nested classes, gets the ExportedType name and finds the corresponding
2085 // TypeDef.
2086 //   For nested classes, gets the name of the ExportedType and its encloser.
2087 // Recursively gets and keeps the name for each encloser until we have the top
2088 // level one.  Gets the TypeDef token for that.  Then, returns from the
2089 // recursion, using the last found TypeDef token in order to find the
2090 // next nested level down TypeDef token.  Finally, returns the TypeDef
2091 // token for the type we care about.
2092 /*static*/
2093 HRESULT ClassLoader::FindTypeDefByExportedType(IMDInternalImport *pCTImport, mdExportedType mdCurrent,
2094                                                IMDInternalImport *pTDImport, mdTypeDef *mtd)
2095 {
2096     CONTRACTL
2097     {
2098         NOTHROW;
2099         GC_NOTRIGGER;
2100         FORBID_FAULT;
2101         MODE_ANY;
2102         SUPPORTS_DAC;
2103     }
2104     CONTRACTL_END
2105     
2106     mdToken mdImpl;
2107     LPCSTR szcNameSpace;
2108     LPCSTR szcName;
2109     HRESULT hr;
2110     
2111     IfFailRet(pCTImport->GetExportedTypeProps(
2112         mdCurrent,
2113         &szcNameSpace,
2114         &szcName,
2115         &mdImpl,
2116         NULL, //binding
2117         NULL)); //flags
2118     
2119     if ((TypeFromToken(mdImpl) == mdtExportedType) &&
2120         (mdImpl != mdExportedTypeNil)) {
2121         // mdCurrent is a nested ExportedType
2122         IfFailRet(FindTypeDefByExportedType(pCTImport, mdImpl, pTDImport, mtd));
2123         
2124         // Get TypeDef token for this nested type
2125         return pTDImport->FindTypeDef(szcNameSpace, szcName, *mtd, mtd);
2126     }
2127     
2128     // Get TypeDef token for this top-level type
2129     return pTDImport->FindTypeDef(szcNameSpace, szcName, mdTokenNil, mtd);
2130 }
2131
2132 #ifndef DACCESS_COMPILE
2133
2134 VOID ClassLoader::CreateCanonicallyCasedKey(LPCUTF8 pszNameSpace, LPCUTF8 pszName, __out LPUTF8 *ppszOutNameSpace, __out LPUTF8 *ppszOutName)
2135 {
2136     CONTRACTL
2137     {
2138         INSTANCE_CHECK;
2139         THROWS;
2140         GC_NOTRIGGER;
2141         INJECT_FAULT(COMPlusThrowOM(););
2142         MODE_ANY;
2143     }
2144     CONTRACTL_END
2145
2146     // We can use the NoThrow versions here because we only call this routine if we're maintaining
2147     // a case-insensitive hash table, and the creation of that table initialized the
2148     // CasingHelper system.
2149     INT32 iNSLength = InternalCasingHelper::InvariantToLowerNoThrow(NULL, 0, pszNameSpace);
2150     if (!iNSLength)
2151     {
2152         COMPlusThrowOM();
2153     }
2154
2155     INT32 iNameLength = InternalCasingHelper::InvariantToLowerNoThrow(NULL, 0, pszName);
2156     if (!iNameLength)
2157     {
2158         COMPlusThrowOM();
2159     }
2160
2161     {
2162         //Calc & allocate path length
2163         //Includes terminating null
2164         S_SIZE_T allocSize = S_SIZE_T(iNSLength) + S_SIZE_T(iNameLength);
2165         if (allocSize.IsOverflow())
2166         {
2167             ThrowHR(COR_E_OVERFLOW);
2168         }
2169
2170         AllocMemHolder<char> pszOutNameSpace (GetAssembly()->GetHighFrequencyHeap()->AllocMem(allocSize));
2171         *ppszOutNameSpace = pszOutNameSpace;
2172     
2173         if (iNSLength == 1)
2174         {
2175             **ppszOutNameSpace = '\0';
2176         }
2177         else
2178         {
2179             if (!InternalCasingHelper::InvariantToLowerNoThrow(*ppszOutNameSpace, iNSLength, pszNameSpace))
2180             {
2181                 COMPlusThrowOM();
2182             }
2183         }
2184
2185         *ppszOutName = *ppszOutNameSpace + iNSLength;
2186     
2187         if (!InternalCasingHelper::InvariantToLowerNoThrow(*ppszOutName, iNameLength, pszName))
2188         {
2189             COMPlusThrowOM();
2190         }
2191
2192         pszOutNameSpace.SuppressRelease();
2193     }
2194 }
2195
2196 #endif // #ifndef DACCESS_COMPILE
2197
2198
2199 //
2200 // Return a class that is already loaded
2201 // Only for type refs and type defs (not type specs)
2202 //
2203 /*static*/
2204 TypeHandle ClassLoader::LookupTypeDefOrRefInModule(Module *pModule, mdToken cl, ClassLoadLevel *pLoadLevel)
2205 {
2206     CONTRACT(TypeHandle)
2207     {
2208         NOTHROW;
2209         GC_NOTRIGGER;
2210         FORBID_FAULT;
2211         MODE_ANY;
2212         PRECONDITION(CheckPointer(pModule));
2213         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2214         SUPPORTS_DAC;
2215     }
2216     CONTRACT_END
2217
2218     BAD_FORMAT_NOTHROW_ASSERT((TypeFromToken(cl) == mdtTypeRef ||
2219                        TypeFromToken(cl) == mdtTypeDef ||
2220                        TypeFromToken(cl) == mdtTypeSpec));
2221
2222     TypeHandle typeHandle;
2223
2224     if (TypeFromToken(cl) == mdtTypeDef)
2225         typeHandle = pModule->LookupTypeDef(cl, pLoadLevel);
2226     else if (TypeFromToken(cl) == mdtTypeRef)
2227     {
2228         typeHandle = pModule->LookupTypeRef(cl);
2229
2230         if (pLoadLevel && !typeHandle.IsNull())
2231         {
2232             *pLoadLevel = typeHandle.GetLoadLevel();
2233         }
2234     }
2235
2236     RETURN(typeHandle);
2237 }
2238
2239 DomainAssembly *ClassLoader::GetDomainAssembly()
2240 {
2241     WRAPPER_NO_CONTRACT;
2242     return GetAssembly()->GetDomainAssembly();
2243 }
2244
2245 #ifndef DACCESS_COMPILE
2246
2247 //
2248 // Free all modules associated with this loader
2249 //
2250 void ClassLoader::FreeModules()
2251 {
2252     CONTRACTL
2253     {
2254         INSTANCE_CHECK;
2255         NOTHROW;
2256         GC_TRIGGERS;
2257         MODE_PREEMPTIVE;
2258         DISABLED(FORBID_FAULT);  //Lots of crud to clean up to make this work
2259     }
2260     CONTRACTL_END;
2261
2262     Module *pManifest = NULL;
2263     if (GetAssembly() && (NULL != (pManifest = GetAssembly()->GetManifestModule()))) {
2264         // Unload the manifest last, since it contains the module list in its rid map
2265         ModuleIterator i = GetAssembly()->IterateModules();
2266         while (i.Next()) {
2267             // Have the module free its various tables and some of the EEClass links
2268             if (i.GetModule() != pManifest)
2269                 i.GetModule()->Destruct();
2270         }
2271         
2272         // Now do the manifest module.
2273         pManifest->Destruct();
2274     }
2275
2276 }
2277
2278 ClassLoader::~ClassLoader()
2279 {
2280     CONTRACTL
2281     {
2282         NOTHROW;
2283         DESTRUCTOR_CHECK;
2284         GC_TRIGGERS;
2285         MODE_PREEMPTIVE;
2286         DISABLED(FORBID_FAULT);  //Lots of crud to clean up to make this work
2287     }
2288     CONTRACTL_END
2289
2290 #ifdef _DEBUG
2291     // Do not walk m_pUnresolvedClassHash at destruct time as it is loaderheap allocated memory
2292     // and may already have been deallocated via an AllocMemTracker.
2293     m_pUnresolvedClassHash = (PendingTypeLoadTable*)(UINT_PTR)0xcccccccc;
2294 #endif
2295
2296 #ifdef _DEBUG
2297 //     LOG((
2298 //         LF_CLASSLOADER,
2299 //         INFO3,
2300 //         "Deleting classloader %x\n"
2301 //         "  >EEClass data:     %10d bytes\n"
2302 //         "  >Classname hash:   %10d bytes\n"
2303 //         "  >FieldDesc data:   %10d bytes\n"
2304 //         "  >MethodDesc data:  %10d bytes\n"
2305 //         "  >GCInfo:           %10d bytes\n"
2306 //         "  >Interface maps:   %10d bytes\n"
2307 //         "  >MethodTables:     %10d bytes\n"
2308 //         "  >Vtables:          %10d bytes\n"
2309 //         "  >Static fields:    %10d bytes\n"
2310 //         "# methods:           %10d\n"
2311 //         "# field descs:       %10d\n"
2312 //         "# classes:           %10d\n"
2313 //         "# dup intf slots:    %10d\n"
2314 //         "# array classrefs:   %10d\n"
2315 //         "Array class overhead:%10d bytes\n",
2316 //         this,
2317 //             m_dwEEClassData,
2318 //             m_pAvailableClasses->m_dwDebugMemory,
2319 //             m_dwFieldDescData,
2320 //             m_dwMethodDescData,
2321 //             m_dwGCSize,
2322 //             m_dwInterfaceMapSize,
2323 //             m_dwMethodTableSize,
2324 //             m_dwVtableData,
2325 //             m_dwStaticFieldData,
2326 //         m_dwDebugMethods,
2327 //         m_dwDebugFieldDescs,
2328 //         m_dwDebugClasses,
2329 //         m_dwDebugDuplicateInterfaceSlots,
2330 //     ));
2331 #endif
2332
2333     FreeModules();
2334
2335     m_UnresolvedClassLock.Destroy();
2336     m_AvailableClassLock.Destroy();
2337     m_AvailableTypesLock.Destroy();
2338 }
2339
2340
2341 //----------------------------------------------------------------------------
2342 // The constructor should only initialize enough to ensure that the destructor doesn't
2343 // crash. It cannot allocate or do anything that might fail as that would leave
2344 // the ClassLoader undestructable. Any such tasks should be done in ClassLoader::Init().
2345 //----------------------------------------------------------------------------
2346 ClassLoader::ClassLoader(Assembly *pAssembly)
2347 {
2348     CONTRACTL
2349     {
2350         CONSTRUCTOR_CHECK;
2351         NOTHROW;
2352         GC_NOTRIGGER;
2353         MODE_ANY;
2354         FORBID_FAULT;
2355     }
2356     CONTRACTL_END
2357
2358     m_pAssembly = pAssembly;
2359
2360     m_pUnresolvedClassHash          = NULL;
2361     m_cUnhashedModules              = 0;
2362
2363 #ifdef _DEBUG
2364     m_dwDebugMethods        = 0;
2365     m_dwDebugFieldDescs     = 0;
2366     m_dwDebugClasses        = 0;
2367     m_dwDebugDuplicateInterfaceSlots = 0;
2368     m_dwGCSize              = 0;
2369     m_dwInterfaceMapSize    = 0;
2370     m_dwMethodTableSize     = 0;
2371     m_dwVtableData          = 0;
2372     m_dwStaticFieldData     = 0;
2373     m_dwFieldDescData       = 0;
2374     m_dwMethodDescData      = 0;
2375     m_dwEEClassData         = 0;
2376 #endif
2377 }
2378
2379
2380 //----------------------------------------------------------------------------
2381 // This function completes the initialization of the ClassLoader. It can
2382 // assume the constructor is run and that the function is entered with
2383 // ClassLoader in a safely destructable state. This function can throw
2384 // but whether it throws or succeeds, it must leave the ClassLoader in a safely
2385 // destructable state.
2386 //----------------------------------------------------------------------------
2387 VOID ClassLoader::Init(AllocMemTracker *pamTracker)
2388 {
2389     STANDARD_VM_CONTRACT;
2390
2391     m_pUnresolvedClassHash = PendingTypeLoadTable::Create(GetAssembly()->GetLowFrequencyHeap(), 
2392                                                           UNRESOLVED_CLASS_HASH_BUCKETS, 
2393                                                           pamTracker);
2394
2395     m_UnresolvedClassLock.Init(CrstUnresolvedClassLock);
2396
2397     // This lock is taken within the classloader whenever we have to enter a
2398     // type in one of the modules governed by the loader.
2399     // The process of creating these types may be reentrant.  The ordering has
2400     // not yet been sorted out, and when we sort it out we should also modify the
2401     // ordering for m_AvailableTypesLock in BaseDomain.
2402     m_AvailableClassLock.Init(
2403                              CrstAvailableClass,
2404                              CRST_REENTRANCY);
2405
2406     // This lock is taken within the classloader whenever we have to insert a new param. type into the table
2407     // This lock also needs to be taken for a read operation in a GC_NOTRIGGER scope, thus the ANYMODE flag.
2408     m_AvailableTypesLock.Init(
2409                                   CrstAvailableParamTypes,
2410                                   (CrstFlags)(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD));
2411
2412 #ifdef _DEBUG
2413     CorTypeInfo::CheckConsistency();
2414 #endif
2415
2416 }
2417
2418 #endif // #ifndef DACCESS_COMPILE
2419
2420 /*static*/
2421 TypeHandle ClassLoader::LoadTypeDefOrRefOrSpecThrowing(Module *pModule,
2422                                                        mdToken typeDefOrRefOrSpec,
2423                                                        const SigTypeContext *pTypeContext,
2424                                                        NotFoundAction fNotFoundAction /* = ThrowIfNotFound */ ,
2425                                                        PermitUninstantiatedFlag fUninstantiated /* = FailIfUninstDefOrRef */,
2426                                                        LoadTypesFlag fLoadTypes/*=LoadTypes*/ ,
2427                                                        ClassLoadLevel level /* = CLASS_LOADED */,
2428                                                        BOOL dropGenericArgumentLevel /* = FALSE */,
2429                                                        const Substitution *pSubst)
2430 {
2431     CONTRACT(TypeHandle)
2432     {
2433         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2434         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2435         MODE_ANY;
2436         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2437         if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
2438         PRECONDITION(CheckPointer(pModule));
2439         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
2440         PRECONDITION(FORBIDGC_LOADER_USE_ENABLED() || GetAppDomain()->CheckCanLoadTypes(pModule->GetAssembly()));
2441         POSTCONDITION(CheckPointer(RETVAL, (fNotFoundAction == ThrowIfNotFound)? NULL_NOT_OK : NULL_OK));
2442     }
2443     CONTRACT_END
2444
2445     if (TypeFromToken(typeDefOrRefOrSpec) == mdtTypeSpec) 
2446     {
2447         ULONG cSig;
2448         PCCOR_SIGNATURE pSig;
2449         
2450         IMDInternalImport *pInternalImport = pModule->GetMDImport();
2451         if (FAILED(pInternalImport->GetTypeSpecFromToken(typeDefOrRefOrSpec, &pSig, &cSig)))
2452         {
2453 #ifndef DACCESS_COMPILE
2454             if (fNotFoundAction == ThrowIfNotFound)
2455             {
2456                 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, typeDefOrRefOrSpec, IDS_CLASSLOAD_BADFORMAT);
2457             }
2458 #endif //!DACCESS_COMPILE
2459             RETURN (TypeHandle());
2460         }
2461         SigPointer sigptr(pSig, cSig);
2462         TypeHandle typeHnd = sigptr.GetTypeHandleThrowing(pModule, pTypeContext, fLoadTypes, 
2463                                                           level, dropGenericArgumentLevel, pSubst);
2464 #ifndef DACCESS_COMPILE
2465         if ((fNotFoundAction == ThrowIfNotFound) && typeHnd.IsNull())
2466             pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, typeDefOrRefOrSpec,
2467                                                            IDS_CLASSLOAD_GENERAL);
2468 #endif
2469         RETURN (typeHnd);
2470     }
2471     else
2472     {
2473         RETURN (LoadTypeDefOrRefThrowing(pModule, typeDefOrRefOrSpec, 
2474                                          fNotFoundAction, 
2475                                          fUninstantiated,
2476                                          ((fLoadTypes == LoadTypes) ? tdNoTypes : tdAllTypes), 
2477                                          level));
2478     }
2479 } // ClassLoader::LoadTypeDefOrRefOrSpecThrowing
2480
2481 // Given a token specifying a typeDef, and a module in which to
2482 // interpret that token, find or load the corresponding type handle.
2483 //
2484 //
2485 /*static*/
2486 TypeHandle ClassLoader::LoadTypeDefThrowing(Module *pModule,
2487                                             mdToken typeDef,
2488                                             NotFoundAction fNotFoundAction /* = ThrowIfNotFound */ ,
2489                                             PermitUninstantiatedFlag fUninstantiated /* = FailIfUninstDefOrRef */,
2490                                             mdToken tokenNotToLoad,
2491                                             ClassLoadLevel level, 
2492                                             Instantiation * pTargetInstantiation)
2493 {
2494
2495     CONTRACT(TypeHandle)
2496     {
2497         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2498         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2499         MODE_ANY;
2500         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2501         DAC_LOADS_TYPE(level, !NameHandle::OKToLoad(typeDef, tokenNotToLoad));
2502         PRECONDITION(CheckPointer(pModule));
2503         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
2504         PRECONDITION(FORBIDGC_LOADER_USE_ENABLED()
2505                      || GetAppDomain()->CheckCanLoadTypes(pModule->GetAssembly()));
2506
2507         POSTCONDITION(CheckPointer(RETVAL, NameHandle::OKToLoad(typeDef, tokenNotToLoad) && (fNotFoundAction == ThrowIfNotFound) ? NULL_NOT_OK : NULL_OK));
2508         POSTCONDITION(RETVAL.IsNull() || RETVAL.GetCl() == typeDef);
2509         SUPPORTS_DAC;
2510     }
2511     CONTRACT_END;
2512
2513     TypeHandle typeHnd;
2514
2515     // First, attempt to find the class if it is already loaded
2516     ClassLoadLevel existingLoadLevel = CLASS_LOAD_BEGIN;
2517     typeHnd = pModule->LookupTypeDef(typeDef, &existingLoadLevel);
2518     if (!typeHnd.IsNull())
2519     {
2520 #ifndef DACCESS_COMPILE
2521         // If the type is loaded, we can do cheap arity verification
2522         if (pTargetInstantiation != NULL && pTargetInstantiation->GetNumArgs() != typeHnd.AsMethodTable()->GetNumGenericArgs())
2523             pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), typeDef, IDS_CLASSLOAD_TYPEWRONGNUMGENERICARGS);
2524 #endif
2525
2526         if (existingLoadLevel >= level)
2527             RETURN(typeHnd);
2528     }
2529
2530     IMDInternalImport *pInternalImport = pModule->GetMDImport();
2531
2532 #ifndef DACCESS_COMPILE
2533     if (typeHnd.IsNull() && pTargetInstantiation != NULL)
2534     {
2535         // If the type is not loaded yet, we have to do heavy weight arity verification based on metadata
2536         HENUMInternal hEnumGenericPars;
2537         HRESULT hr = pInternalImport->EnumInit(mdtGenericParam, typeDef, &hEnumGenericPars);
2538         if (FAILED(hr))
2539             pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, typeDef, IDS_CLASSLOAD_BADFORMAT);
2540         DWORD nGenericClassParams = pInternalImport->EnumGetCount(&hEnumGenericPars);
2541         pInternalImport->EnumClose(&hEnumGenericPars);
2542
2543         if (pTargetInstantiation->GetNumArgs() != nGenericClassParams)
2544             pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, typeDef, IDS_CLASSLOAD_TYPEWRONGNUMGENERICARGS);
2545     }
2546 #endif
2547
2548     if (IsNilToken(typeDef) || TypeFromToken(typeDef) != mdtTypeDef || !pInternalImport->IsValidToken(typeDef) )
2549     {
2550         LOG((LF_CLASSLOADER, LL_INFO10, "Bogus class token to load: 0x%08x\n", typeDef));
2551         typeHnd = TypeHandle();
2552     }
2553     else 
2554     {
2555         // *****************************************************************************
2556         //
2557         //             Important invariant:
2558         //
2559         // The rule here is that we never go to LoadTypeHandleForTypeKey if a Find should succeed.
2560         // This is vital, because otherwise a stack crawl will open up opportunities for
2561         // GC.  Since operations like setting up a GCFrame will trigger a crawl in stress
2562         // mode, a GC at that point would be disastrous.  We can't assert this, because
2563         // of race conditions.  (In other words, the type could suddently be find-able
2564         // because another thread loaded it while we were in this method.
2565
2566         // Not found - try to load it unless we are told not to
2567
2568 #ifndef DACCESS_COMPILE
2569         if ( !NameHandle::OKToLoad(typeDef, tokenNotToLoad) )
2570         {
2571             typeHnd = TypeHandle();
2572         }
2573         else
2574         {
2575             // Anybody who puts himself in a FORBIDGC_LOADER state has promised
2576             // to use us only for resolving, not loading. We are now transitioning into
2577             // loading.
2578 #ifdef _DEBUG_IMPL
2579             _ASSERTE(!FORBIDGC_LOADER_USE_ENABLED());
2580 #endif
2581             TRIGGERSGC();
2582
2583             if (pModule->IsReflection())
2584             {
2585                 // Don't try to load types that are not in available table, when this
2586                 // is an in-memory module.  Raise the type-resolve event instead.
2587                 typeHnd = TypeHandle();
2588
2589                 // Avoid infinite recursion
2590                 if (tokenNotToLoad != tdAllAssemblies)
2591                 {
2592                     AppDomain* pDomain = SystemDomain::GetCurrentDomain();
2593
2594                     LPUTF8 pszFullName;
2595                     LPCUTF8 className;
2596                     LPCUTF8 nameSpace;
2597                     if (FAILED(pInternalImport->GetNameOfTypeDef(typeDef, &className, &nameSpace)))
2598                     {
2599                         LOG((LF_CLASSLOADER, LL_INFO10, "Bogus TypeDef record while loading: 0x%08x\n", typeDef));
2600                         typeHnd = TypeHandle();
2601                     }
2602                     else
2603                     {
2604                         MAKE_FULL_PATH_ON_STACK_UTF8(pszFullName,
2605                                                         nameSpace,
2606                                                         className);
2607                         GCX_COOP();
2608                         ASSEMBLYREF asmRef = NULL;
2609                         DomainAssembly *pDomainAssembly = NULL;
2610                         GCPROTECT_BEGIN(asmRef);
2611
2612                         pDomainAssembly = pDomain->RaiseTypeResolveEventThrowing(
2613                             pModule->GetAssembly()->GetDomainAssembly(), 
2614                             pszFullName, &asmRef);
2615
2616                         if (asmRef != NULL)
2617                         {
2618                             _ASSERTE(pDomainAssembly != NULL);
2619                             if (pDomainAssembly->GetAssembly()->GetLoaderAllocator()->IsCollectible())
2620                             {
2621                                 if (!pModule->GetLoaderAllocator()->IsCollectible())
2622                                 {
2623                                     LOG((LF_CLASSLOADER, LL_INFO10, "Bad result from TypeResolveEvent while loader TypeDef record: 0x%08x\n", typeDef));
2624                                     COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
2625                                 }
2626
2627                                 pModule->GetLoaderAllocator()->EnsureReference(pDomainAssembly->GetAssembly()->GetLoaderAllocator());
2628                             }
2629                         }
2630                         GCPROTECT_END();
2631                         if (pDomainAssembly != NULL)
2632                         {
2633                             Assembly *pAssembly = pDomainAssembly->GetAssembly();
2634                                 
2635                             NameHandle name(nameSpace, className);
2636                             name.SetTypeToken(pModule, typeDef);
2637                             name.SetTokenNotToLoad(tdAllAssemblies);
2638                             typeHnd = pAssembly->GetLoader()->LoadTypeHandleThrowing(&name, level);
2639                         }
2640                     }
2641                 }
2642             }
2643             else
2644             {
2645                 TypeKey typeKey(pModule, typeDef);
2646                 typeHnd = pModule->GetClassLoader()->LoadTypeHandleForTypeKey(&typeKey, 
2647                                                                               typeHnd,
2648                                                                               level);
2649             }
2650         }
2651 #endif // !DACCESS_COMPILE
2652     }
2653
2654 #ifndef DACCESS_COMPILE
2655     if ((fUninstantiated == FailIfUninstDefOrRef) && !typeHnd.IsNull() && typeHnd.IsGenericTypeDefinition())
2656     {
2657         typeHnd = TypeHandle();
2658     }
2659
2660     if ((fNotFoundAction == ThrowIfNotFound) && typeHnd.IsNull() && (tokenNotToLoad != tdAllTypes))
2661     {
2662         pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), 
2663                                                        typeDef,
2664                                                        IDS_CLASSLOAD_GENERAL);
2665     }
2666 #endif
2667     ;
2668     
2669     RETURN(typeHnd);
2670 }
2671
2672 // Given a token specifying a typeDef or typeRef, and a module in
2673 // which to interpret that token, find or load the corresponding type
2674 // handle.
2675 //
2676 /*static*/
2677 TypeHandle ClassLoader::LoadTypeDefOrRefThrowing(Module *pModule,
2678                                                  mdToken typeDefOrRef,
2679                                                  NotFoundAction fNotFoundAction /* = ThrowIfNotFound */ ,
2680                                                  PermitUninstantiatedFlag fUninstantiated /* = FailIfUninstDefOrRef */,
2681                                                  mdToken tokenNotToLoad,
2682                                                  ClassLoadLevel level)
2683 {
2684
2685     CONTRACT(TypeHandle)
2686     {
2687         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2688         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2689         MODE_ANY;
2690         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2691         PRECONDITION(CheckPointer(pModule));
2692         PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
2693         PRECONDITION(FORBIDGC_LOADER_USE_ENABLED()
2694                      || GetAppDomain()->CheckCanLoadTypes(pModule->GetAssembly()));
2695
2696         POSTCONDITION(CheckPointer(RETVAL, NameHandle::OKToLoad(typeDefOrRef, tokenNotToLoad) && (fNotFoundAction == ThrowIfNotFound) ? NULL_NOT_OK : NULL_OK));
2697         POSTCONDITION(level <= CLASS_LOAD_UNRESTORED || RETVAL.IsNull() || RETVAL.IsRestored());
2698         SUPPORTS_DAC;
2699     }
2700     CONTRACT_END;
2701
2702     // NotFoundAction could be the bizarre 'ThrowButNullV11McppWorkaround', 
2703     //  which means ThrowIfNotFound EXCEPT if this might be the Everett MCPP 
2704     //  Nil-token ResolutionScope for value type.  In that case, it means 
2705     //  ReturnNullIfNotFound.
2706     // If we have ThrowButNullV11McppWorkaround, remember that NULL *might*
2707     //  be OK if there is no resolution scope, but change the value to
2708     //  ThrowIfNotFound.
2709     BOOLEAN bReturnNullOkWhenNoResolutionScope = false;
2710     if (fNotFoundAction == ThrowButNullV11McppWorkaround)
2711     {
2712         bReturnNullOkWhenNoResolutionScope = true;
2713         fNotFoundAction = ThrowIfNotFound;
2714     }
2715
2716     // First, attempt to find the class if it is already loaded
2717     ClassLoadLevel existingLoadLevel = CLASS_LOAD_BEGIN;
2718     TypeHandle typeHnd = LookupTypeDefOrRefInModule(pModule, typeDefOrRef, &existingLoadLevel);
2719     if (!typeHnd.IsNull())
2720     {
2721         if (existingLoadLevel < level)
2722         {
2723             pModule = typeHnd.GetModule();
2724             typeDefOrRef = typeHnd.GetCl();
2725         }
2726     }
2727
2728     if (!typeHnd.IsNull() && existingLoadLevel >= level)
2729     {
2730         // perform the check that it's not an uninstantiated TypeDef/TypeRef
2731         // being used inappropriately.
2732         if (!((fUninstantiated == FailIfUninstDefOrRef) && !typeHnd.IsNull() && typeHnd.IsGenericTypeDefinition()))
2733         {
2734             RETURN(typeHnd);
2735         }
2736     }
2737     else
2738     {
2739         // otherwise try to resolve the TypeRef and/or load the corresponding TypeDef
2740         IMDInternalImport *pInternalImport = pModule->GetMDImport();
2741         mdToken tokType = TypeFromToken(typeDefOrRef);
2742         
2743         if (IsNilToken(typeDefOrRef) || ((tokType != mdtTypeDef)&&(tokType != mdtTypeRef))
2744             || !pInternalImport->IsValidToken(typeDefOrRef) ) 
2745         {
2746 #ifdef _DEBUG
2747             LOG((LF_CLASSLOADER, LL_INFO10, "Bogus class token to load: 0x%08x\n", typeDefOrRef));
2748 #endif
2749             
2750             typeHnd = TypeHandle();
2751         }
2752         
2753         else if (tokType == mdtTypeRef) 
2754         {
2755             BOOL fNoResolutionScope;
2756             Module *pFoundModule = Assembly::FindModuleByTypeRef(pModule, typeDefOrRef,
2757                                                                   tokenNotToLoad==tdAllTypes ? 
2758                                                                                   Loader::DontLoad :
2759                                                                                   Loader::Load,
2760                                                                  &fNoResolutionScope);
2761
2762             if (pFoundModule != NULL)
2763             {
2764                 
2765                 // Not in my module, have to look it up by name.  This is the primary path
2766                 // taken by the TypeRef case, i.e. we've resolve a TypeRef to a TypeDef/Module
2767                 // pair.
2768                 LPCUTF8 pszNameSpace;
2769                 LPCUTF8 pszClassName;
2770                 if (FAILED(pInternalImport->GetNameOfTypeRef(
2771                     typeDefOrRef, 
2772                     &pszNameSpace, 
2773                     &pszClassName)))
2774                 {
2775                     typeHnd = TypeHandle();
2776                 }
2777                 else
2778                 {
2779                     if (fNoResolutionScope)
2780                     {
2781                         // Everett C++ compiler can generate a TypeRef with RS=0
2782                         // without respective TypeDef for unmanaged valuetypes,
2783                         // referenced only by pointers to them,
2784                         // so we can fail to load legally w/ no exception
2785                         typeHnd = ClassLoader::LoadTypeByNameThrowing(pFoundModule->GetAssembly(),
2786                                                                       pszNameSpace,
2787                                                                       pszClassName,
2788                                                                       ClassLoader::ReturnNullIfNotFound,
2789                                                                       tokenNotToLoad==tdAllTypes ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes,
2790                                                                       level);
2791                         
2792                         if(typeHnd.IsNull() && bReturnNullOkWhenNoResolutionScope)
2793                         {
2794                             fNotFoundAction = ReturnNullIfNotFound;
2795                             RETURN(typeHnd);
2796                         }
2797                     }
2798                     else
2799                     {
2800                         NameHandle nameHandle(pModule, typeDefOrRef);
2801                         nameHandle.SetName(pszNameSpace, pszClassName);
2802                         nameHandle.SetTokenNotToLoad(tokenNotToLoad);
2803                         typeHnd = pFoundModule->GetClassLoader()->
2804                             LoadTypeHandleThrowIfFailed(&nameHandle, level,
2805                                                         pFoundModule->IsReflection() ? NULL : pFoundModule);
2806                     }
2807                 }
2808                 
2809 #ifndef DACCESS_COMPILE
2810                 if (!(typeHnd.IsNull()))
2811                     pModule->StoreTypeRef(typeDefOrRef, typeHnd);
2812 #endif
2813             }
2814         }
2815         else
2816         {
2817             // This is the mdtTypeDef case...
2818             typeHnd = LoadTypeDefThrowing(pModule, typeDefOrRef, 
2819                                           fNotFoundAction, 
2820                                           fUninstantiated, 
2821                                           tokenNotToLoad, 
2822                                           level);
2823         }
2824     }
2825     TypeHandle thRes = typeHnd;
2826     
2827     // reject the load if it's an uninstantiated TypeDef/TypeRef
2828     // being used inappropriately.  
2829     if ((fUninstantiated == FailIfUninstDefOrRef) && !typeHnd.IsNull() && typeHnd.IsGenericTypeDefinition())
2830         thRes = TypeHandle();
2831
2832     // perform the check to throw when the thing is not found
2833     if ((fNotFoundAction == ThrowIfNotFound) && thRes.IsNull() && (tokenNotToLoad != tdAllTypes))
2834     {
2835 #ifndef DACCESS_COMPILE
2836         pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(),
2837                                                        typeDefOrRef,
2838                                                        IDS_CLASSLOAD_GENERAL);
2839 #else
2840         DacNotImpl();
2841 #endif
2842     }
2843
2844     RETURN(thRes);
2845 }
2846
2847 /*static*/
2848 BOOL 
2849 ClassLoader::ResolveTokenToTypeDefThrowing(
2850     Module *         pTypeRefModule, 
2851     mdTypeRef        typeRefToken, 
2852     Module **        ppTypeDefModule, 
2853     mdTypeDef *      pTypeDefToken, 
2854     Loader::LoadFlag loadFlag,
2855     BOOL *           pfUsesTypeForwarder) // The semantic of this parameter: TRUE if a type forwarder is found. It is never set to FALSE.
2856 {
2857     CONTRACT(BOOL)
2858     {
2859         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2860         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2861         MODE_ANY;
2862         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2863         PRECONDITION(CheckPointer(pTypeRefModule));
2864         SUPPORTS_DAC;
2865     }
2866     CONTRACT_END;
2867     
2868     // It's a TypeDef already
2869     if (TypeFromToken(typeRefToken) == mdtTypeDef)
2870     {
2871         if (ppTypeDefModule != NULL)
2872             *ppTypeDefModule = pTypeRefModule;
2873         if (pTypeDefToken != NULL)
2874             *pTypeDefToken = typeRefToken;
2875         RETURN TRUE;
2876     }
2877     
2878     TypeHandle typeHnd = pTypeRefModule->LookupTypeRef(typeRefToken);
2879     
2880     // Type is already (partially) loaded and cached in the module's TypeRef table
2881     // Do not return here if we are checking for type forwarders
2882     if (!typeHnd.IsNull() && (pfUsesTypeForwarder == NULL))
2883     {
2884         if (ppTypeDefModule != NULL)
2885             *ppTypeDefModule = typeHnd.GetModule();
2886         if (pTypeDefToken != NULL)
2887             *pTypeDefToken = typeHnd.GetCl();
2888         RETURN TRUE;
2889     }
2890     
2891     BOOL fNoResolutionScope; //not used
2892     Module * pFoundRefModule = Assembly::FindModuleByTypeRef(
2893         pTypeRefModule, 
2894         typeRefToken, 
2895         loadFlag, 
2896         &fNoResolutionScope);
2897     
2898     if (pFoundRefModule == NULL) 
2899     {   // We didn't find the TypeRef anywhere
2900         RETURN FALSE;
2901     }
2902     
2903     // If checking for type forwarders, then we can see if a type forwarder was used based on the output of 
2904     // pFoundRefModule and typeHnd (if typeHnd is set)
2905     if (!typeHnd.IsNull() && (pfUsesTypeForwarder != NULL))
2906     {
2907         if (typeHnd.GetModule() != pFoundRefModule)
2908         {
2909             *pfUsesTypeForwarder = TRUE;
2910         }
2911
2912         if (ppTypeDefModule != NULL)
2913             *ppTypeDefModule = typeHnd.GetModule();
2914         if (pTypeDefToken != NULL)
2915             *pTypeDefToken = typeHnd.GetCl();
2916         RETURN TRUE;
2917     }
2918
2919     // Not in my module, have to look it up by name
2920     LPCUTF8 pszNameSpace;
2921     LPCUTF8 pszClassName;
2922     if (FAILED(pTypeRefModule->GetMDImport()->GetNameOfTypeRef(typeRefToken, &pszNameSpace, &pszClassName)))
2923     {
2924         RETURN FALSE;
2925     }
2926     NameHandle nameHandle(pTypeRefModule, typeRefToken);
2927     nameHandle.SetName(pszNameSpace, pszClassName);
2928     if (loadFlag != Loader::Load)
2929     {
2930         nameHandle.SetTokenNotToLoad(tdAllTypes);
2931     }
2932
2933     return ResolveNameToTypeDefThrowing(pFoundRefModule, &nameHandle, ppTypeDefModule, pTypeDefToken, loadFlag, pfUsesTypeForwarder);
2934 }
2935
2936 /*static*/
2937 BOOL
2938 ClassLoader::ResolveNameToTypeDefThrowing(
2939     Module *         pModule,
2940     NameHandle *     pName,
2941     Module **        ppTypeDefModule,
2942     mdTypeDef *      pTypeDefToken,
2943     Loader::LoadFlag loadFlag,
2944     BOOL *           pfUsesTypeForwarder) // The semantic of this parameter: TRUE if a type forwarder is found. It is never set to FALSE.
2945 {    
2946     CONTRACT(BOOL)
2947     {
2948         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2949         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2950         MODE_ANY;
2951         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2952         PRECONDITION(CheckPointer(pModule));
2953         PRECONDITION(CheckPointer(pName));
2954         SUPPORTS_DAC;
2955     }
2956     CONTRACT_END;
2957
2958     TypeHandle typeHnd;
2959     mdToken  foundTypeDef;
2960     Module * pFoundModule;
2961     mdExportedType foundExportedType;
2962     Module * pSourceModule = pModule;
2963     Module * pFoundRefModule = pModule;
2964     
2965     for (UINT32 nTypeForwardingChainSize = 0; nTypeForwardingChainSize < const_cMaxTypeForwardingChainSize; nTypeForwardingChainSize++)
2966     {
2967         foundTypeDef = mdTokenNil;
2968         pFoundModule = NULL;
2969         foundExportedType = mdTokenNil;
2970         if (!pSourceModule->GetClassLoader()->FindClassModuleThrowing(
2971             pName,
2972             &typeHnd, 
2973             &foundTypeDef, 
2974             &pFoundModule, 
2975             &foundExportedType, 
2976             NULL, 
2977             pSourceModule->IsReflection() ? NULL : pSourceModule, 
2978             loadFlag))
2979         {
2980             RETURN FALSE;
2981         }
2982         
2983         // Type is already loaded and cached in the loader's by-name table
2984         if (!typeHnd.IsNull())
2985         {
2986             if ((typeHnd.GetModule() != pFoundRefModule) && (pfUsesTypeForwarder != NULL))
2987             {   // We followed at least one type forwarder to resolve the type
2988                 *pfUsesTypeForwarder = TRUE;
2989             }
2990             if (ppTypeDefModule != NULL)
2991                 *ppTypeDefModule = typeHnd.GetModule();
2992             if (pTypeDefToken != NULL)
2993                 *pTypeDefToken = typeHnd.GetCl();
2994             RETURN TRUE;
2995         }
2996         
2997         if (pFoundModule == NULL)
2998         {   // Module was probably not loaded
2999             RETURN FALSE;
3000         }
3001         
3002         if (TypeFromToken(foundExportedType) != mdtExportedType)
3003         {   // It's not exported type
3004             _ASSERTE(foundExportedType == mdTokenNil);
3005             
3006             if ((pFoundModule != pFoundRefModule) && (pfUsesTypeForwarder != NULL))
3007             {   // We followed at least one type forwarder to resolve the type
3008                 *pfUsesTypeForwarder = TRUE;
3009             }
3010             if (pTypeDefToken != NULL)
3011                 *pTypeDefToken = foundTypeDef;
3012             if (ppTypeDefModule != NULL)
3013                 *ppTypeDefModule = pFoundModule;
3014             RETURN TRUE;
3015         }
3016         // It's exported type
3017         
3018         // Repeat the search for the type in the newly found module
3019         pSourceModule = pFoundModule;
3020     }
3021     // Type forwarding chain is too long
3022     RETURN FALSE;
3023 } // ClassLoader::ResolveTokenToTypeDefThrowing
3024
3025 #ifndef DACCESS_COMPILE
3026
3027 //---------------------------------------------------------------------------------------
3028 // 
3029 //static
3030 VOID 
3031 ClassLoader::GetEnclosingClassThrowing(
3032     IMDInternalImport * pInternalImport, 
3033     Module *            pModule, 
3034     mdTypeDef           cl, 
3035     mdTypeDef *         tdEnclosing)
3036 {
3037     CONTRACTL
3038     {
3039         THROWS;
3040         GC_TRIGGERS;
3041         INJECT_FAULT(COMPlusThrowOM());
3042         MODE_ANY;
3043     }
3044     CONTRACTL_END;
3045
3046     _ASSERTE(tdEnclosing);
3047     *tdEnclosing = mdTypeDefNil;
3048
3049     HRESULT hr = pInternalImport->GetNestedClassProps(cl, tdEnclosing);
3050
3051     if (FAILED(hr))
3052     {
3053         if (hr != CLDB_E_RECORD_NOTFOUND)
3054             COMPlusThrowHR(hr);
3055         return;
3056     }
3057
3058     if (TypeFromToken(*tdEnclosing) != mdtTypeDef)
3059         pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_ENCLOSING);
3060 } // ClassLoader::GetEnclosingClassThrowing
3061
3062
3063 //---------------------------------------------------------------------------------------
3064 // 
3065 // Load a parent type or implemented interface type.
3066 //
3067 // If this is an instantiated type represented by a type spec, then instead of attempting to load the
3068 // exact type, load an approximate instantiation in which all reference types are replaced by Object.
3069 // The exact instantiated types will be loaded later by LoadInstantiatedInfo.
3070 // We do this to avoid cycles early in class loading caused by definitions such as
3071 //   struct M : ICloneable<M>                     // load ICloneable<object>
3072 //   class C<T> : D<C<T>,int> for any T           // load D<object,int>
3073 // 
3074 //static
3075 TypeHandle 
3076 ClassLoader::LoadApproxTypeThrowing(
3077     Module *               pModule, 
3078     mdToken                tok, 
3079     SigPointer *           pSigInst, 
3080     const SigTypeContext * pClassTypeContext)
3081 {
3082     CONTRACT(TypeHandle)
3083     {
3084         THROWS;
3085         GC_TRIGGERS;
3086         INJECT_FAULT(COMPlusThrowOM());
3087         MODE_ANY;
3088         PRECONDITION(CheckPointer(pSigInst, NULL_OK));
3089         PRECONDITION(CheckPointer(pModule));
3090         POSTCONDITION(CheckPointer(RETVAL));
3091     }
3092     CONTRACT_END;
3093
3094     IMDInternalImport * pInternalImport = pModule->GetMDImport();
3095
3096     if (TypeFromToken(tok) == mdtTypeSpec)
3097     {
3098         ULONG cSig;
3099         PCCOR_SIGNATURE pSig;
3100         IfFailThrowBF(pInternalImport->GetTypeSpecFromToken(tok, &pSig, &cSig), BFA_METADATA_CORRUPT, pModule);
3101
3102         SigPointer sigptr = SigPointer(pSig, cSig);
3103         CorElementType type = ELEMENT_TYPE_END;
3104         IfFailThrowBF(sigptr.GetElemType(&type), BFA_BAD_SIGNATURE, pModule);
3105
3106         // The only kind of type specs that we recognise are instantiated types
3107         if (type != ELEMENT_TYPE_GENERICINST)
3108             pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, tok, IDS_CLASSLOAD_GENERAL);
3109
3110         // Of these, we outlaw instantiated value classes (they can't be interfaces and can't be subclassed)
3111         IfFailThrowBF(sigptr.GetElemType(&type), BFA_BAD_SIGNATURE, pModule);
3112      
3113         if (type != ELEMENT_TYPE_CLASS)
3114             pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, tok, IDS_CLASSLOAD_GENERAL);
3115
3116         mdToken genericTok = 0;
3117         IfFailThrowBF(sigptr.GetToken(&genericTok), BFA_BAD_SIGNATURE, pModule);
3118         IfFailThrowBF(sigptr.GetData(NULL), BFA_BAD_SIGNATURE, pModule);
3119
3120         if (pSigInst != NULL)
3121             *pSigInst = sigptr;
3122
3123         // Try to load the generic type itself
3124         THROW_BAD_FORMAT_MAYBE(
3125             ((TypeFromToken(genericTok) == mdtTypeRef) || (TypeFromToken(genericTok) == mdtTypeDef)), 
3126             BFA_UNEXPECTED_GENERIC_TOKENTYPE, 
3127             pModule);
3128         TypeHandle genericTypeTH = LoadTypeDefOrRefThrowing(
3129             pModule, 
3130             genericTok, 
3131             ClassLoader::ThrowIfNotFound, 
3132             ClassLoader::PermitUninstDefOrRef, 
3133             tdNoTypes, 
3134             CLASS_LOAD_APPROXPARENTS);
3135
3136         // We load interfaces at very approximate types - the generic
3137         // interface itself.  We fix this up in LoadInstantiatedInfo.
3138         // This allows us to load recursive interfaces on structs such
3139         // as "struct VC : I<VC>".  The details of the interface
3140         // are not currently needed during the first phase
3141         // of setting up the method table.
3142         if (genericTypeTH.IsInterface())
3143         {
3144             RETURN genericTypeTH;
3145         }
3146         else            
3147         {
3148             // approxTypes, i.e. approximate reference types by Object, i.e. load the canonical type
3149             RETURN SigPointer(pSig, cSig).GetTypeHandleThrowing(
3150                 pModule, 
3151                 pClassTypeContext, 
3152                 ClassLoader::LoadTypes, 
3153                 CLASS_LOAD_APPROXPARENTS, 
3154                 TRUE /*dropGenericArgumentLevel*/);
3155         }
3156     }
3157     else 
3158     {
3159         if (pSigInst != NULL)
3160             *pSigInst = SigPointer();
3161         RETURN LoadTypeDefOrRefThrowing(
3162             pModule, 
3163             tok, 
3164             ClassLoader::ThrowIfNotFound, 
3165             ClassLoader::FailIfUninstDefOrRef, 
3166             tdNoTypes, 
3167             CLASS_LOAD_APPROXPARENTS);
3168     }
3169 } // ClassLoader::LoadApproxTypeThrowing
3170
3171
3172 //---------------------------------------------------------------------------------------
3173 // 
3174 //static
3175 MethodTable * 
3176 ClassLoader::LoadApproxParentThrowing(
3177     Module *               pModule, 
3178     mdToken                cl, 
3179     SigPointer *           pParentInst, 
3180     const SigTypeContext * pClassTypeContext)
3181 {
3182     CONTRACTL
3183     {
3184         THROWS;
3185         GC_TRIGGERS;
3186         INJECT_FAULT(COMPlusThrowOM());
3187         MODE_ANY;
3188     }
3189     CONTRACTL_END;
3190
3191     mdTypeRef     crExtends;
3192     MethodTable * pParentMethodTable = NULL;
3193     TypeHandle    parentType;
3194     DWORD         dwAttrClass;
3195     Assembly *    pAssembly = pModule->GetAssembly();
3196     IMDInternalImport * pInternalImport = pModule->GetMDImport();
3197     
3198     // Initialize the return value;
3199     *pParentInst = SigPointer();
3200     
3201     // Now load all dependencies of this class
3202     if (FAILED(pInternalImport->GetTypeDefProps(
3203         cl,
3204         &dwAttrClass, // AttrClass
3205         &crExtends)))
3206     {
3207         pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
3208     }
3209     
3210     if (RidFromToken(crExtends) != mdTokenNil)
3211     {
3212         // Do an "approximate" load of the parent, replacing reference types in the instantiation by Object
3213         // This is to avoid cycles in the loader e.g. on class C : D<C> or class C<T> : D<C<T>>
3214         // We fix up the exact parent later in LoadInstantiatedInfo
3215         parentType = LoadApproxTypeThrowing(pModule, crExtends, pParentInst, pClassTypeContext);
3216
3217         pParentMethodTable = parentType.GetMethodTable();
3218
3219         if (pParentMethodTable == NULL)
3220             pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_PARENTNULL);
3221
3222         // cannot inherit from an interface
3223         if (pParentMethodTable->IsInterface())
3224             pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_PARENTINTERFACE);
3225
3226         if (IsTdInterface(dwAttrClass))
3227         {
3228             // Interfaces must extend from Object
3229             if (! pParentMethodTable->IsObjectClass())
3230                 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_INTERFACEOBJECT);
3231         }
3232     }
3233
3234     return pParentMethodTable;
3235 } // ClassLoader::LoadApproxParentThrowing
3236
3237 // Perform a single phase of class loading
3238 // It is the caller's responsibility to lock
3239 /*static*/
3240 TypeHandle ClassLoader::DoIncrementalLoad(TypeKey *pTypeKey, TypeHandle typeHnd, ClassLoadLevel currentLevel)
3241 {
3242     CONTRACTL
3243     {
3244         STANDARD_VM_CHECK;
3245         PRECONDITION(CheckPointer(pTypeKey));
3246         PRECONDITION(currentLevel >= CLASS_LOAD_BEGIN && currentLevel < CLASS_LOADED);
3247         MODE_ANY;
3248     }
3249     CONTRACTL_END;
3250
3251 #ifdef _DEBUG
3252     if (LoggingOn(LF_CLASSLOADER, LL_INFO10000))
3253     {
3254         SString name;
3255         TypeString::AppendTypeKeyDebug(name, pTypeKey);
3256         LOG((LF_CLASSLOADER, LL_INFO10000, "PHASEDLOAD: About to do incremental load of type %S (%p) from level %s\n", name.GetUnicode(), typeHnd.AsPtr(), classLoadLevelName[currentLevel]));
3257     }
3258 #endif
3259
3260     // Level is BEGIN if and only if type handle is null
3261     CONSISTENCY_CHECK((currentLevel == CLASS_LOAD_BEGIN) == typeHnd.IsNull());
3262
3263     switch (currentLevel)
3264     {
3265         // Attain at least level CLASS_LOAD_UNRESTORED (if just locating type in ngen image)
3266         // or at least level CLASS_LOAD_APPROXPARENTS (if creating type for the first time)
3267         case CLASS_LOAD_BEGIN :
3268             {
3269                 IBCLoggerAwareAllocMemTracker amTracker;
3270                 typeHnd = CreateTypeHandleForTypeKey(pTypeKey, &amTracker);
3271                 CONSISTENCY_CHECK(!typeHnd.IsNull());
3272                 TypeHandle published = PublishType(pTypeKey, typeHnd);
3273                 if (published == typeHnd)
3274                     amTracker.SuppressRelease();
3275                 typeHnd = published;
3276             }
3277             break;
3278
3279         case CLASS_LOAD_UNRESTOREDTYPEKEY :
3280 #ifdef FEATURE_PREJIT
3281             typeHnd.DoRestoreTypeKey();
3282 #endif
3283             break;
3284
3285         // Attain level CLASS_LOAD_APPROXPARENTS, starting with unrestored class
3286         case CLASS_LOAD_UNRESTORED :
3287 #ifdef FEATURE_PREJIT
3288             {
3289                 CONSISTENCY_CHECK(!typeHnd.IsRestored_NoLogging());
3290                 if (typeHnd.IsTypeDesc())
3291                     typeHnd.AsTypeDesc()->Restore();
3292                 else
3293                     typeHnd.AsMethodTable()->Restore();
3294             }
3295 #endif
3296             break;
3297
3298         // Attain level CLASS_LOAD_EXACTPARENTS
3299         case CLASS_LOAD_APPROXPARENTS :
3300             if (!typeHnd.IsTypeDesc())
3301             {
3302                 LoadExactParents(typeHnd.AsMethodTable());
3303             }
3304             break;
3305
3306         case CLASS_LOAD_EXACTPARENTS :
3307         case CLASS_DEPENDENCIES_LOADED :
3308         case CLASS_LOADED :
3309             break;
3310
3311     }
3312
3313     if (typeHnd.GetLoadLevel() >= CLASS_LOAD_EXACTPARENTS)
3314     {
3315         Notify(typeHnd);
3316     }
3317
3318     return typeHnd;
3319 }
3320
3321 /*static*/
3322 // For non-canonical instantiations of generic types, create a fresh type by replicating the canonical instantiation
3323 // For canonical instantiations of generic types, create a brand new method table
3324 // For other constructed types, create a type desc and template method table if necessary
3325 // For all other types, create a method table
3326 TypeHandle ClassLoader::CreateTypeHandleForTypeKey(TypeKey* pKey, AllocMemTracker* pamTracker)
3327 {
3328     CONTRACT(TypeHandle)
3329     {
3330         STANDARD_VM_CHECK;
3331         PRECONDITION(CheckPointer(pKey));
3332       
3333         POSTCONDITION(RETVAL.CheckMatchesKey(pKey));
3334         MODE_ANY;
3335     }
3336     CONTRACT_END
3337
3338     TypeHandle typeHnd = TypeHandle();
3339     
3340     if (!pKey->IsConstructed())
3341     {
3342         typeHnd = CreateTypeHandleForTypeDefThrowing(pKey->GetModule(),
3343                                                      pKey->GetTypeToken(),
3344                                                      pKey->GetInstantiation(),
3345                                                      pamTracker);
3346     }
3347     else if (pKey->HasInstantiation())
3348     {
3349         if (IsCanonicalGenericInstantiation(pKey->GetInstantiation()))
3350         {
3351             typeHnd = CreateTypeHandleForTypeDefThrowing(pKey->GetModule(),
3352                                                             pKey->GetTypeToken(),
3353                                                             pKey->GetInstantiation(),
3354                                                             pamTracker);
3355         }
3356         else 
3357         {
3358             typeHnd = CreateTypeHandleForNonCanonicalGenericInstantiation(pKey,
3359                                                                                         pamTracker);
3360         }
3361 #if defined(_DEBUG) && !defined(CROSSGEN_COMPILE)
3362         if (Nullable::IsNullableType(typeHnd)) 
3363             Nullable::CheckFieldOffsets(typeHnd);
3364 #endif
3365     }
3366     else if (pKey->GetKind() == ELEMENT_TYPE_FNPTR) 
3367     {
3368         Module *pLoaderModule = ComputeLoaderModule(pKey);
3369         pLoaderModule->GetLoaderAllocator()->EnsureInstantiation(NULL, Instantiation(pKey->GetRetAndArgTypes(), pKey->GetNumArgs() + 1));
3370
3371         PREFIX_ASSUME(pLoaderModule!=NULL);
3372         DWORD numArgs = pKey->GetNumArgs();
3373         BYTE* mem = (BYTE*) pamTracker->Track(pLoaderModule->GetAssembly()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(FnPtrTypeDesc)) + S_SIZE_T(sizeof(TypeHandle)) * S_SIZE_T(numArgs)));
3374             
3375         typeHnd = TypeHandle(new(mem)  FnPtrTypeDesc(pKey->GetCallConv(), numArgs, pKey->GetRetAndArgTypes()));
3376     }
3377     else
3378     {
3379         Module *pLoaderModule = ComputeLoaderModule(pKey);
3380         PREFIX_ASSUME(pLoaderModule!=NULL);
3381
3382         CorElementType kind = pKey->GetKind();
3383         TypeHandle paramType = pKey->GetElementType();
3384         MethodTable *templateMT;
3385
3386         // Create a new type descriptor and insert into constructed type table
3387         if (CorTypeInfo::IsArray(kind)) 
3388         {
3389             DWORD rank = pKey->GetRank();
3390             THROW_BAD_FORMAT_MAYBE((kind != ELEMENT_TYPE_ARRAY) || rank > 0, BFA_MDARRAY_BADRANK, pLoaderModule);
3391             THROW_BAD_FORMAT_MAYBE((kind != ELEMENT_TYPE_SZARRAY) || rank == 1, BFA_SDARRAY_BADRANK, pLoaderModule);
3392
3393             // Arrays of BYREFS not allowed
3394             if (paramType.GetInternalCorElementType() == ELEMENT_TYPE_BYREF)
3395             {
3396                 ThrowTypeLoadException(pKey, IDS_CLASSLOAD_BYREFARRAY);
3397             }
3398
3399             // Arrays of ByRefLike types not allowed
3400             MethodTable* pMT = paramType.GetMethodTable();
3401             if (pMT != NULL)
3402             {
3403                 if (pMT->IsByRefLike())
3404                 {
3405                     ThrowTypeLoadException(pKey, IDS_CLASSLOAD_BYREFLIKEARRAY);
3406                 }
3407             }
3408
3409             // We really don't need this check anymore.
3410             if (rank > MAX_RANK)
3411             {
3412                 ThrowTypeLoadException(pKey, IDS_CLASSLOAD_RANK_TOOLARGE);
3413             }
3414
3415             templateMT = pLoaderModule->CreateArrayMethodTable(paramType, kind, rank, pamTracker);
3416
3417             BYTE* mem = (BYTE*) pamTracker->Track(pLoaderModule->GetAssembly()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(ArrayTypeDesc))));
3418             typeHnd = TypeHandle(new(mem)  ArrayTypeDesc(templateMT, paramType));
3419         }
3420         else 
3421         {
3422             // no parameterized type allowed on a reference
3423             if (paramType.GetInternalCorElementType() == ELEMENT_TYPE_BYREF ||
3424                 paramType.GetInternalCorElementType() == ELEMENT_TYPE_TYPEDBYREF)
3425             {
3426                 ThrowTypeLoadException(pKey, IDS_CLASSLOAD_GENERAL);
3427             }
3428
3429             // We do allow parametrized types of ByRefLike types. Languages may restrict them to produce safe or verifiable code, 
3430             // but there is not a good reason for restricting them in the runtime.
3431
3432             // let <Type>* type have a method table
3433             // System.UIntPtr's method table is used for types like int*, void *, string * etc.
3434             if (kind == ELEMENT_TYPE_PTR)
3435                 templateMT = MscorlibBinder::GetElementType(ELEMENT_TYPE_U);
3436             else 
3437                 templateMT = NULL;
3438
3439             BYTE* mem = (BYTE*) pamTracker->Track(pLoaderModule->GetAssembly()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(ParamTypeDesc))));
3440             typeHnd = TypeHandle(new(mem)  ParamTypeDesc(kind, templateMT, paramType));
3441         }
3442     }
3443
3444     RETURN typeHnd;
3445 }
3446
3447 // Publish a type (and possibly member information) in the loader's
3448 // tables Types are published before they are fully loaded. In
3449 // particular, exact parent info (base class and interfaces) is loaded
3450 // in a later phase
3451 /*static*/
3452 TypeHandle ClassLoader::PublishType(TypeKey *pTypeKey, TypeHandle typeHnd)
3453 {
3454     CONTRACTL
3455     {
3456         STANDARD_VM_CHECK;
3457         PRECONDITION(CheckPointer(typeHnd));
3458         PRECONDITION(CheckPointer(pTypeKey));
3459
3460         // Key must match that of the handle
3461         PRECONDITION(typeHnd.CheckMatchesKey(pTypeKey));
3462
3463         // Don't publish array template method tables; these are accessed only through type descs
3464         PRECONDITION(typeHnd.IsTypeDesc() || !typeHnd.AsMethodTable()->IsArray());
3465     }
3466     CONTRACTL_END;
3467
3468
3469     if (pTypeKey->IsConstructed())
3470     {
3471         Module *pLoaderModule = ComputeLoaderModule(pTypeKey);
3472         EETypeHashTable *pTable = pLoaderModule->GetAvailableParamTypes();
3473
3474         // m_AvailableTypesLock has to be taken in cooperative mode to avoid deadlocks during GC
3475         GCX_COOP();
3476
3477         CrstHolder ch(&pLoaderModule->GetClassLoader()->m_AvailableTypesLock);
3478
3479         // The type could have been loaded by a different thread as side-effect of avoiding deadlocks caused by LoadsTypeViolation
3480         TypeHandle existing = pTable->GetValue(pTypeKey);
3481         if (!existing.IsNull())
3482             return existing;
3483
3484         pTable->InsertValue(typeHnd);
3485
3486 #ifdef _DEBUG
3487         // Checks to help ensure that the CoreLib in the ngen process does not get contaminated with pointers to the compilation domains.
3488         if (pLoaderModule->IsSystem() && IsCompilationProcess() && pLoaderModule->HasNativeImage())
3489         {
3490             CorElementType kind = pTypeKey->GetKind();
3491             MethodTable *typeHandleMethodTable = typeHnd.GetMethodTable();
3492             if ((typeHandleMethodTable != NULL) && (typeHandleMethodTable->GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator()))
3493             {
3494                 _ASSERTE(!"MethodTable of type loaded into CoreLib during NGen is not from CoreLib!");
3495             }
3496             if ((kind != ELEMENT_TYPE_FNPTR) && (kind != ELEMENT_TYPE_VAR) && (kind != ELEMENT_TYPE_MVAR))
3497             {
3498                 if ((kind == ELEMENT_TYPE_SZARRAY) || (kind == ELEMENT_TYPE_ARRAY) || (kind == ELEMENT_TYPE_BYREF) || (kind == ELEMENT_TYPE_PTR) || (kind == ELEMENT_TYPE_VALUETYPE))
3499                 {
3500                     // Check to ensure param value is also part of CoreLib.
3501                     if (pTypeKey->GetElementType().GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator())
3502                     {
3503                         _ASSERTE(!"Param value of type key used to load type during NGEN not located within CoreLib yet type is placed into CoreLib");
3504                     }
3505                 }
3506                 else if (kind == ELEMENT_TYPE_FNPTR)
3507                 {
3508                     // Check to ensure the parameter types of fnptr are in CoreLib
3509                     for (DWORD i = 0; i <= pTypeKey->GetNumArgs(); i++)
3510                     {
3511                         if (pTypeKey->GetRetAndArgTypes()[i].GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator())
3512                         {
3513                             _ASSERTE(!"Ret or Arg type of function pointer type key used to load type during NGEN not located within CoreLib yet type is placed into CoreLib");
3514                         }
3515                     }
3516                 }
3517                 else if (kind == ELEMENT_TYPE_CLASS)
3518                 {
3519                     // Check to ensure that the generic parameters are all within CoreLib
3520                     for (DWORD i = 0; i < pTypeKey->GetNumGenericArgs(); i++)
3521                     {
3522                         if (pTypeKey->GetInstantiation()[i].GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator())
3523                         {
3524                             _ASSERTE(!"Instantiation parameter of generic class type key used to load type during NGEN not located within CoreLib yet type is placed into CoreLib");
3525                         }
3526                     }
3527                 }
3528                 else
3529                 {
3530                     // Should not be able to get here
3531                     _ASSERTE(!"Unknown type key type");
3532                 }
3533             }
3534         }
3535 #endif // DEBUG 
3536     }
3537     else
3538     {
3539         Module *pModule = pTypeKey->GetModule();
3540         mdTypeDef typeDef = pTypeKey->GetTypeToken();
3541
3542         // m_AvailableTypesLock has to be taken in cooperative mode to avoid deadlocks during GC
3543         GCX_COOP();
3544
3545         CrstHolder ch(&pModule->GetClassLoader()->m_AvailableTypesLock);
3546
3547         // ! We cannot fail after this point.
3548         CANNOTTHROWCOMPLUSEXCEPTION();
3549         FAULT_FORBID();
3550
3551         // The type could have been loaded by a different thread as side-effect of avoiding deadlocks caused by LoadsTypeViolation
3552         TypeHandle existing = pModule->LookupTypeDef(typeDef);
3553         if (!existing.IsNull())
3554             return existing;
3555
3556         MethodTable *pMT = typeHnd.AsMethodTable();
3557
3558         MethodTable::IntroducedMethodIterator it(pMT);
3559         for (; it.IsValid(); it.Next())
3560         {
3561             MethodDesc * pMD = it.GetMethodDesc();
3562             CONSISTENCY_CHECK(pMD != NULL && pMD->GetMethodTable() == pMT);
3563             if (!pMD->IsUnboxingStub())
3564             {
3565                 pModule->EnsuredStoreMethodDef(pMD->GetMemberDef(), pMD);
3566             }
3567         }
3568
3569         ApproxFieldDescIterator fdIterator(pMT, ApproxFieldDescIterator::ALL_FIELDS);
3570         FieldDesc* pFD;
3571
3572         while ((pFD = fdIterator.Next()) != NULL)
3573         {
3574             if (pFD->GetEnclosingMethodTable() == pMT)
3575             {
3576                 pModule->EnsuredStoreFieldDef(pFD->GetMemberDef(), pFD);
3577             }
3578         }
3579
3580         // Publish the type last - to ensure that nobody can see it until all the method and field RID maps are filled in
3581         pModule->EnsuredStoreTypeDef(typeDef, typeHnd);
3582     }
3583
3584     return typeHnd;
3585 }
3586
3587 // Notify profiler and debugger that a type load has completed
3588 // Also adjust perf counters
3589 /*static*/
3590 void ClassLoader::Notify(TypeHandle typeHnd)
3591 {
3592     CONTRACTL
3593     {
3594         STANDARD_VM_CHECK;
3595         PRECONDITION(CheckPointer(typeHnd));
3596     }
3597     CONTRACTL_END;
3598
3599     LOG((LF_CLASSLOADER, LL_INFO1000, "Notify: %p %s\n", typeHnd.AsPtr(), typeHnd.IsTypeDesc() ? "typedesc" : typeHnd.AsMethodTable()->GetDebugClassName()));
3600
3601     if (typeHnd.IsTypeDesc())
3602         return;
3603
3604     MethodTable * pMT = typeHnd.AsMethodTable();
3605
3606 #ifdef PROFILING_SUPPORTED
3607     {
3608         BEGIN_PIN_PROFILER(CORProfilerTrackClasses());
3609         // We don't tell profilers about typedescs, as per IF above.  Also, we don't
3610         // tell profilers about:
3611         if (
3612             // ...generics with unbound variables
3613             (!pMT->ContainsGenericVariables()) &&
3614             // ...or array method tables
3615             // (This check is mainly for NGEN restore, as JITted code won't hit
3616             // this code path for array method tables anyway)
3617             (!pMT->IsArray()))
3618         {
3619             LOG((LF_CLASSLOADER, LL_INFO1000, "Notifying profiler of Started1 %p %s\n", pMT, pMT->GetDebugClassName()));
3620             // Record successful load of the class for the profiler
3621             g_profControlBlock.pProfInterface->ClassLoadStarted(TypeHandleToClassID(typeHnd));
3622
3623             //
3624             // Profiler can turn off TrackClasses during the Started() callback.  Need to
3625             // retest the flag here.
3626             //
3627             if (CORProfilerTrackClasses()) 
3628             {
3629                 LOG((LF_CLASSLOADER, LL_INFO1000, "Notifying profiler of Finished1 %p %s\n", pMT, pMT->GetDebugClassName()));
3630                 g_profControlBlock.pProfInterface->ClassLoadFinished(TypeHandleToClassID(typeHnd),
3631                     S_OK);
3632             }
3633         }
3634         END_PIN_PROFILER();
3635     }
3636 #endif //PROFILING_SUPPORTED
3637
3638     g_IBCLogger.LogMethodTableAccess(pMT);
3639
3640     if (pMT->IsTypicalTypeDefinition())
3641     {
3642         LOG((LF_CLASSLOADER, LL_INFO100, "Successfully loaded class %s\n", pMT->GetDebugClassName()));
3643
3644 #ifdef DEBUGGING_SUPPORTED
3645         {
3646             Module * pModule = pMT->GetModule();
3647             // Update metadata for dynamic module.
3648             pModule->UpdateDynamicMetadataIfNeeded();
3649         }
3650
3651         if (CORDebuggerAttached()) 
3652         {
3653             LOG((LF_CORDB, LL_EVERYTHING, "NotifyDebuggerLoad clsload 2239 class %s\n", pMT->GetDebugClassName()));
3654             typeHnd.NotifyDebuggerLoad(NULL, FALSE);
3655         }
3656 #endif // DEBUGGING_SUPPORTED
3657     }
3658 }
3659
3660
3661 //-----------------------------------------------------------------------------
3662 // Common helper for LoadTypeHandleForTypeKey and LoadTypeHandleForTypeKeyNoLock.
3663 // Makes the root level call to kick off the transitive closure walk for
3664 // the final level pushes.
3665 //-----------------------------------------------------------------------------
3666 static void PushFinalLevels(TypeHandle typeHnd, ClassLoadLevel targetLevel, const InstantiationContext *pInstContext)
3667 {
3668     CONTRACTL
3669     {
3670         STANDARD_VM_CHECK;
3671         LOADS_TYPE(targetLevel);
3672     }
3673     CONTRACTL_END
3674
3675
3676     // This phase brings the type and all its transitive dependencies to their
3677     // final state, sans the IsFullyLoaded bit.
3678     if (targetLevel >= CLASS_DEPENDENCIES_LOADED)
3679     {
3680         BOOL fBailed = FALSE;
3681         typeHnd.DoFullyLoad(NULL, CLASS_DEPENDENCIES_LOADED, NULL, &fBailed, pInstContext);
3682     }
3683
3684     // This phase does access/constraint and other type-safety checks on the type
3685     // and on its transitive dependencies.
3686     if (targetLevel == CLASS_LOADED)
3687     {
3688         DFLPendingList pendingList;
3689         BOOL           fBailed = FALSE;
3690     
3691         typeHnd.DoFullyLoad(NULL, CLASS_LOADED, &pendingList, &fBailed, pInstContext);
3692
3693
3694         // In the case of a circular dependency, one or more types will have
3695         // had their promotions deferred.
3696         //
3697         // If we got to this point, all checks have successfully passed on
3698         // the transitive closure (otherwise, DoFullyLoad would have thrown.)
3699         //
3700         // So we can go ahead and mark everyone as fully loaded.
3701         //
3702         UINT numTH = pendingList.Count();
3703         TypeHandle *pTHPending = pendingList.Table();
3704         for (UINT i = 0; i < numTH; i++)
3705         {
3706             // NOTE: It is possible for duplicates to appear in this list so
3707             // don't do any operation that isn't idempodent.
3708
3709             pTHPending[i].SetIsFullyLoaded();
3710         }
3711     }
3712 }
3713
3714
3715 // 
3716 TypeHandle ClassLoader::LoadTypeHandleForTypeKey(TypeKey *pTypeKey,
3717                                                  TypeHandle typeHnd,
3718                                                  ClassLoadLevel targetLevel/*=CLASS_LOADED*/,
3719                                                  const InstantiationContext *pInstContext/*=NULL*/)
3720 {
3721
3722     CONTRACTL
3723     {
3724         INSTANCE_CHECK;
3725         THROWS;
3726         GC_TRIGGERS;
3727         MODE_ANY;
3728         LOADS_TYPE(targetLevel);
3729     }
3730     CONTRACTL_END
3731
3732     GCX_PREEMP();
3733
3734 #ifdef _DEBUG
3735     if (LoggingOn(LF_CLASSLOADER, LL_INFO1000))
3736     {
3737         SString name;
3738         TypeString::AppendTypeKeyDebug(name, pTypeKey);
3739         LOG((LF_CLASSLOADER, LL_INFO10000, "PHASEDLOAD: LoadTypeHandleForTypeKey for type %S to level %s\n", name.GetUnicode(), classLoadLevelName[targetLevel]));
3740         CrstHolder unresolvedClassLockHolder(&m_UnresolvedClassLock);
3741         m_pUnresolvedClassHash->Dump();
3742     }
3743 #endif
3744
3745     // When using domain neutral assemblies (and not eagerly propagating dependency loads), 
3746     // it's possible to get here without having injected the module into the current app domain.
3747     // GetDomainFile will accomplish that.
3748     
3749     if (!pTypeKey->IsConstructed())
3750     {
3751         pTypeKey->GetModule()->GetDomainFile();
3752     }
3753     
3754     ClassLoadLevel currentLevel = typeHnd.IsNull() ? CLASS_LOAD_BEGIN : typeHnd.GetLoadLevel();
3755     ClassLoadLevel targetLevelUnderLock = targetLevel < CLASS_DEPENDENCIES_LOADED ? targetLevel : (ClassLoadLevel) (CLASS_DEPENDENCIES_LOADED-1);
3756     if (currentLevel < targetLevelUnderLock)
3757     {
3758         typeHnd = LoadTypeHandleForTypeKey_Body(pTypeKey, 
3759                                                 typeHnd,
3760                                                 targetLevelUnderLock);
3761         _ASSERTE(!typeHnd.IsNull());
3762     }
3763     _ASSERTE(typeHnd.GetLoadLevel() >= targetLevelUnderLock);
3764
3765     PushFinalLevels(typeHnd, targetLevel, pInstContext);
3766
3767     return typeHnd;
3768 }
3769
3770 // 
3771 TypeHandle ClassLoader::LoadTypeHandleForTypeKeyNoLock(TypeKey *pTypeKey,
3772                                                        ClassLoadLevel targetLevel/*=CLASS_LOADED*/,
3773                                                        const InstantiationContext *pInstContext/*=NULL*/)
3774 {
3775
3776     CONTRACTL
3777     {
3778         INSTANCE_CHECK;
3779         THROWS;
3780         GC_TRIGGERS;
3781         MODE_ANY;
3782         LOADS_TYPE(targetLevel);
3783         PRECONDITION(CheckPointer(pTypeKey));
3784         PRECONDITION(targetLevel >= 0 && targetLevel <= CLASS_LOADED);
3785     }
3786     CONTRACTL_END
3787
3788     GCX_PREEMP();
3789
3790     TypeHandle typeHnd = TypeHandle();
3791
3792     ClassLoadLevel currentLevel = CLASS_LOAD_BEGIN;
3793     ClassLoadLevel targetLevelUnderLock = targetLevel < CLASS_DEPENDENCIES_LOADED ? targetLevel : (ClassLoadLevel) (CLASS_DEPENDENCIES_LOADED-1);
3794     while (currentLevel < targetLevelUnderLock)
3795     {
3796         typeHnd = DoIncrementalLoad(pTypeKey, typeHnd, currentLevel);
3797         CONSISTENCY_CHECK(typeHnd.GetLoadLevel() > currentLevel);
3798         currentLevel = typeHnd.GetLoadLevel();
3799     }
3800
3801     PushFinalLevels(typeHnd, targetLevel, pInstContext);
3802
3803     return typeHnd;
3804 }
3805
3806 //---------------------------------------------------------------------------------------
3807 // 
3808 class PendingTypeLoadHolder
3809 {
3810     Thread * m_pThread;
3811     PendingTypeLoadEntry * m_pEntry;
3812     PendingTypeLoadHolder * m_pPrevious;
3813
3814 public:
3815     PendingTypeLoadHolder(PendingTypeLoadEntry * pEntry)
3816     {
3817         LIMITED_METHOD_CONTRACT;
3818
3819         m_pThread = GetThread();
3820         m_pEntry = pEntry;
3821
3822         m_pPrevious = m_pThread->GetPendingTypeLoad();
3823         m_pThread->SetPendingTypeLoad(this);
3824     }
3825
3826     ~PendingTypeLoadHolder()
3827     {
3828         LIMITED_METHOD_CONTRACT;
3829
3830         _ASSERTE(m_pThread->GetPendingTypeLoad() == this);
3831         m_pThread->SetPendingTypeLoad(m_pPrevious);
3832     }
3833
3834     static bool CheckForDeadLockOnCurrentThread(PendingTypeLoadEntry * pEntry)
3835     {
3836         LIMITED_METHOD_CONTRACT;
3837
3838         PendingTypeLoadHolder * pCurrent = GetThread()->GetPendingTypeLoad();
3839
3840         while (pCurrent != NULL)
3841         {
3842             if (pCurrent->m_pEntry == pEntry)
3843                 return true;
3844
3845             pCurrent = pCurrent->m_pPrevious;
3846         }
3847
3848         return false;
3849     }
3850 };
3851
3852 //---------------------------------------------------------------------------------------
3853 // 
3854 TypeHandle 
3855 ClassLoader::LoadTypeHandleForTypeKey_Body(
3856     TypeKey *                         pTypeKey, 
3857     TypeHandle                        typeHnd, 
3858     ClassLoadLevel                    targetLevel)
3859 {
3860     CONTRACT(TypeHandle)
3861     {
3862         STANDARD_VM_CHECK;
3863         POSTCONDITION(!typeHnd.IsNull() && typeHnd.GetLoadLevel() >= targetLevel);
3864     }
3865     CONTRACT_END
3866
3867     if (!pTypeKey->IsConstructed())
3868     {
3869         Module *pModule = pTypeKey->GetModule();
3870         mdTypeDef cl = pTypeKey->GetTypeToken();
3871
3872         STRESS_LOG2(LF_CLASSLOADER,  LL_INFO100000, "LoadTypeHandle: Loading Class from Module %p token %x\n", pModule, cl);
3873
3874 #ifdef _DEBUG
3875         IMDInternalImport* pInternalImport = pModule->GetMDImport();
3876         LPCUTF8 className;
3877         LPCUTF8 nameSpace;
3878         if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &className, &nameSpace)))
3879         {
3880             className = nameSpace = "Invalid TypeDef record";
3881         }
3882         if (g_pConfig->ShouldBreakOnClassLoad(className))
3883             CONSISTENCY_CHECK_MSGF(false, ("BreakOnClassLoad: typename '%s' ", className));
3884 #endif
3885     }
3886
3887     ReleaseHolder<PendingTypeLoadEntry> pLoadingEntry;
3888     CrstHolderWithState unresolvedClassLockHolder(&m_UnresolvedClassLock, false);
3889
3890 retry:
3891     unresolvedClassLockHolder.Acquire();    
3892
3893     // Is it in the hash of classes currently being loaded?
3894     pLoadingEntry = m_pUnresolvedClassHash->GetValue(pTypeKey);
3895     if (pLoadingEntry)
3896     {
3897         pLoadingEntry->AddRef();
3898
3899         // It is in the hash, which means that another thread is waiting for it (or that we are
3900         // already loading this class on this thread, which should never happen, since that implies
3901         // a recursive dependency).
3902         unresolvedClassLockHolder.Release();
3903
3904         //
3905         // Check one last time before waiting that the type handle is not sufficiently loaded to 
3906         // prevent deadlocks
3907         //
3908         {
3909             if (typeHnd.IsNull())
3910             {
3911                 typeHnd = LookupTypeHandleForTypeKey(pTypeKey);
3912             }
3913
3914             if (!typeHnd.IsNull())
3915             {
3916                 if (typeHnd.GetLoadLevel() >= targetLevel)
3917                     RETURN typeHnd;
3918             }
3919         }
3920
3921         if (PendingTypeLoadHolder::CheckForDeadLockOnCurrentThread(pLoadingEntry))
3922         {
3923             // Attempting recursive load
3924             ClassLoader::ThrowTypeLoadException(pTypeKey, IDS_CLASSLOAD_GENERAL);
3925         }
3926
3927         //
3928         // Violation of type loadlevel ordering rules depends on type load failing in case of cyclic dependency that would
3929         // otherwise lead to deadlock. We will speculatively proceed with the type load to make it fail in the right spot,
3930         // in backward compatible way. In case the type load succeeds, we will only let one type win in PublishType.
3931         //
3932         if (typeHnd.IsNull() && GetThread()->HasThreadStateNC(Thread::TSNC_LoadsTypeViolation))
3933         {
3934             PendingTypeLoadHolder ptlh(pLoadingEntry);
3935             typeHnd = DoIncrementalLoad(pTypeKey, TypeHandle(), CLASS_LOAD_BEGIN);
3936             goto retry;
3937         }
3938
3939         {
3940             // Wait for class to be loaded by another thread.  This is where we start tracking the
3941             // entry, so there is an implicit Acquire in our use of Assign here.
3942             CrstHolder loadingEntryLockHolder(&pLoadingEntry->m_Crst);
3943             _ASSERTE(pLoadingEntry->HasLock());
3944         }
3945
3946         // Result of other thread loading the class
3947         HRESULT hr = pLoadingEntry->m_hrResult;
3948
3949         if (FAILED(hr)) {
3950
3951             //
3952             // Redo the lookup one more time and return a valid type if possible. The other thread could
3953             // have hit error while loading the type to higher level than we need.
3954             // 
3955             {
3956                 if (typeHnd.IsNull())
3957                 {
3958                     typeHnd = LookupTypeHandleForTypeKey(pTypeKey);
3959                 }
3960
3961                 if (!typeHnd.IsNull())
3962                 {
3963                     if (typeHnd.GetLoadLevel() >= targetLevel)
3964                         RETURN typeHnd;
3965                 }
3966             }
3967
3968             if (hr == E_ABORT) {
3969                 LOG((LF_CLASSLOADER, LL_INFO10, "need to retry LoadTypeHandle: %x\n", hr));
3970                 goto retry;
3971             }
3972
3973             LOG((LF_CLASSLOADER, LL_INFO10, "Failed to load in other entry: %x\n", hr));
3974
3975             if (hr == E_OUTOFMEMORY) {
3976                 COMPlusThrowOM();
3977             }
3978
3979             pLoadingEntry->ThrowException();
3980         }
3981
3982         // Get a pointer to the EEClass being loaded
3983         typeHnd = pLoadingEntry->m_typeHandle;
3984
3985         if (!typeHnd.IsNull())
3986         {
3987             // If the type load on the other thread loaded the type to the needed level, return it here.
3988             if (typeHnd.GetLoadLevel() >= targetLevel)
3989                 RETURN typeHnd;
3990         }
3991
3992         // The type load on the other thread did not load the type "enough". Begin the type load
3993         // process again to cause us to load to the needed level.
3994         goto retry;
3995     }
3996
3997     if (typeHnd.IsNull())
3998     {
3999         // The class was not being loaded.  However, it may have already been loaded after our
4000         // first LoadTypeHandleThrowIfFailed() and before taking the lock.
4001         typeHnd = LookupTypeHandleForTypeKey(pTypeKey);
4002     }
4003
4004     ClassLoadLevel currentLevel = CLASS_LOAD_BEGIN;
4005     if (!typeHnd.IsNull())
4006     {
4007         currentLevel = typeHnd.GetLoadLevel();
4008         if (currentLevel >= targetLevel)
4009             RETURN typeHnd;
4010     }
4011
4012     // It was not loaded, and it is not being loaded, so we must load it.  Create a new LoadingEntry
4013     // and acquire it immediately so that other threads will block. 
4014     pLoadingEntry = new PendingTypeLoadEntry(*pTypeKey, typeHnd);  // this atomically creates a crst and acquires it
4015
4016     if (!(m_pUnresolvedClassHash->InsertValue(pLoadingEntry)))
4017     {
4018         COMPlusThrowOM();
4019     }
4020
4021     // Leave the global lock, so that other threads may now start waiting on our class's lock
4022     unresolvedClassLockHolder.Release();
4023
4024     EX_TRY
4025     {
4026         PendingTypeLoadHolder ptlh(pLoadingEntry);
4027
4028         TRIGGERS_TYPELOAD();
4029
4030         while (currentLevel < targetLevel)
4031         {
4032             typeHnd = DoIncrementalLoad(pTypeKey, typeHnd, currentLevel);
4033             CONSISTENCY_CHECK(typeHnd.GetLoadLevel() > currentLevel);
4034             currentLevel = typeHnd.GetLoadLevel();
4035
4036             // If other threads are waiting for this load, unblock them as soon as possible to prevent deadlocks.
4037             if (pLoadingEntry->HasWaiters())
4038                 break;
4039         }
4040
4041         _ASSERTE(!typeHnd.IsNull());
4042         pLoadingEntry->SetResult(typeHnd);
4043     }
4044     EX_HOOK
4045     {
4046         LOG((LF_CLASSLOADER, LL_INFO10, "Caught an exception loading: %x, %0x (Module)\n", pTypeKey->GetTypeToken(), pTypeKey->GetModule()));
4047
4048         if (!GetThread()->HasThreadStateNC(Thread::TSNC_LoadsTypeViolation))
4049         {
4050             // Fix up the loading entry.
4051             Exception *pException = GET_EXCEPTION();
4052             pLoadingEntry->SetException(pException);
4053         }
4054
4055         // Unlink this class from the unresolved class list.
4056         unresolvedClassLockHolder.Acquire();
4057         m_pUnresolvedClassHash->DeleteValue(pTypeKey);
4058
4059         // Release the lock before proceeding. The unhandled exception filters take number of locks that
4060         // have ordering violations with this lock.
4061         unresolvedClassLockHolder.Release();
4062         
4063         // Unblock any thread waiting to load same type as in TypeLoadEntry
4064         pLoadingEntry->UnblockWaiters();
4065     }
4066     EX_END_HOOK;
4067
4068     // Unlink this class from the unresolved class list.
4069     unresolvedClassLockHolder.Acquire();
4070     m_pUnresolvedClassHash->DeleteValue(pTypeKey);
4071     unresolvedClassLockHolder.Release();
4072
4073     // Unblock any thread waiting to load same type as in TypeLoadEntry. This should be done
4074     // after pLoadingEntry is removed from m_pUnresolvedClassHash. Otherwise the other thread
4075     // (which was waiting) will keep spinning for a while after waking up, till the current thread removes 
4076     //  pLoadingEntry from m_pUnresolvedClassHash. This can cause hang in situation when the current 
4077     // thread is a background thread and so will get very less processor cycle to perform subsequent
4078     // operations to remove the entry from hash later. 
4079     pLoadingEntry->UnblockWaiters();
4080
4081     if (currentLevel < targetLevel)
4082         goto retry;
4083
4084     RETURN typeHnd;
4085 } // ClassLoader::LoadTypeHandleForTypeKey_Body
4086
4087 #endif //!DACCESS_COMPILE
4088
4089 //---------------------------------------------------------------------------------------
4090 // 
4091 //static
4092 TypeHandle 
4093 ClassLoader::LoadArrayTypeThrowing(
4094     TypeHandle     elemType, 
4095     CorElementType arrayKind, 
4096     unsigned       rank,        //=0
4097     LoadTypesFlag  fLoadTypes,  //=LoadTypes
4098     ClassLoadLevel level)
4099 {
4100     CONTRACT(TypeHandle)
4101     {
4102         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
4103         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
4104         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
4105         if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
4106         MODE_ANY;
4107         SUPPORTS_DAC;
4108         POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
4109     }
4110     CONTRACT_END
4111
4112     CorElementType predefinedElementType = ELEMENT_TYPE_END;
4113
4114     // Try finding it in our cache of primitive SD arrays
4115     if (arrayKind == ELEMENT_TYPE_SZARRAY) {
4116         predefinedElementType = elemType.GetSignatureCorElementType();
4117         if (predefinedElementType <= ELEMENT_TYPE_R8) {
4118             ArrayTypeDesc* typeDesc = g_pPredefinedArrayTypes[predefinedElementType];
4119             if (typeDesc != 0)
4120                 RETURN(TypeHandle(typeDesc));
4121         }
4122         // This call to AsPtr is somewhat bogus and only used
4123         // as an optimization.  If the TypeHandle is really a TypeDesc
4124         // then the equality checks for the optimizations below will 
4125         // fail.  Thus ArrayMT should not be used elsewhere in this function
4126         else if (elemType.AsPtr() == PTR_VOID(g_pObjectClass)) {
4127             // Code duplicated because Object[]'s SigCorElementType is E_T_CLASS, not OBJECT
4128             ArrayTypeDesc* typeDesc = g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT];
4129             if (typeDesc != 0)
4130                 RETURN(TypeHandle(typeDesc));
4131             predefinedElementType = ELEMENT_TYPE_OBJECT;
4132         }
4133         else if (elemType.AsPtr() == PTR_VOID(g_pStringClass)) {
4134             // Code duplicated because String[]'s SigCorElementType is E_T_CLASS, not STRING
4135             ArrayTypeDesc* typeDesc = g_pPredefinedArrayTypes[ELEMENT_TYPE_STRING];
4136             if (typeDesc != 0)
4137                 RETURN(TypeHandle(typeDesc));
4138             predefinedElementType = ELEMENT_TYPE_STRING;
4139         }
4140         else {
4141             predefinedElementType = ELEMENT_TYPE_END;
4142         }
4143         rank = 1;
4144     }
4145
4146 #ifndef DACCESS_COMPILE
4147     // To avoid loading useless shared instantiations, normalize shared instantiations to the canonical form 
4148     // (e.g. List<_Canon>[] -> _Canon[])
4149     // The denormalized shared instantiations should be needed only during JITing, so it is fine to skip this
4150     // for DACCESS_COMPILE.
4151     if (elemType.IsCanonicalSubtype())
4152     {
4153         elemType = ClassLoader::CanonicalizeGenericArg(elemType);
4154     }
4155 #endif
4156
4157     TypeKey key(arrayKind, elemType, FALSE, rank);
4158     TypeHandle th = LoadConstructedTypeThrowing(&key, fLoadTypes, level);
4159
4160     if (predefinedElementType != ELEMENT_TYPE_END && !th.IsNull() && th.IsFullyLoaded())
4161     {
4162         g_pPredefinedArrayTypes[predefinedElementType] = th.AsArray();
4163     }
4164
4165     RETURN(th);
4166 } // ClassLoader::LoadArrayTypeThrowing
4167
4168 #ifndef DACCESS_COMPILE
4169
4170 VOID ClassLoader::AddAvailableClassDontHaveLock(Module *pModule,
4171                                                 mdTypeDef classdef,
4172                                                 AllocMemTracker *pamTracker)
4173 {
4174     CONTRACTL
4175     {
4176         INSTANCE_CHECK;
4177         THROWS;
4178         GC_TRIGGERS;
4179         MODE_ANY;
4180         INJECT_FAULT(COMPlusThrowOM(););
4181     }
4182     CONTRACTL_END
4183     
4184 #ifdef FEATURE_COMINTEROP
4185     _ASSERTE(!pModule->GetAssembly()->IsWinMD());   // WinMD files should never get into this path, otherwise provide szWinRtNamespacePrefix
4186 #endif
4187
4188     CrstHolder ch(&m_AvailableClassLock);
4189
4190     // R2R pre-computes an export table and tries to avoid populating a class hash at runtime. However the profiler can
4191     // still add new types on the fly by calling here. If that occurs we fallback to the slower path of creating the
4192     // in memory hashtable as usual.
4193     if (!pModule->IsResource() && pModule->GetAvailableClassHash() == NULL)
4194     {
4195         LazyPopulateCaseSensitiveHashTables();
4196     }
4197
4198     AddAvailableClassHaveLock(
4199         pModule, 
4200         classdef, 
4201         pamTracker, 
4202         NULL,   // szWinRtNamespacePrefix
4203         0);     // cchWinRtNamespacePrefix
4204 }
4205
4206 // This routine must be single threaded!  The reason is that there are situations which allow
4207 // the same class name to have two different mdTypeDef tokens (for example, we load two different DLLs
4208 // simultaneously, and they have some common class files, or we convert the same class file
4209 // simultaneously on two threads).  The problem is that we do not want to overwrite the old
4210 // <classname> -> pModule mapping with the new one, because this may cause identity problems.
4211 //
4212 // This routine assumes you already have the lock.  Use AddAvailableClassDontHaveLock() if you
4213 // don't have it.
4214 // 
4215 // Also validates that TypeDef namespace begins with szWinRTNamespacePrefix (if it is not NULL).
4216 // The prefix should be NULL for normal non-WinRT .NET assemblies.
4217 // 
4218 VOID ClassLoader::AddAvailableClassHaveLock(
4219     Module *          pModule, 
4220     mdTypeDef         classdef, 
4221     AllocMemTracker * pamTracker, 
4222     LPCSTR            szWinRtNamespacePrefix, 
4223     DWORD             cchWinRtNamespacePrefix)  // Optimization for faster prefix comparison implementation
4224 {
4225     CONTRACTL
4226     {
4227         INSTANCE_CHECK;
4228         THROWS;
4229         GC_TRIGGERS;
4230         MODE_ANY;
4231         INJECT_FAULT(COMPlusThrowOM(););
4232     }
4233     CONTRACTL_END
4234
4235     EEClassHashTable *pClassHash = pModule->GetAvailableClassHash();
4236     EEClassHashTable *pClassCaseInsHash = pModule->GetAvailableClassCaseInsHash();
4237
4238     LPCUTF8        pszName;
4239     LPCUTF8        pszNameSpace;
4240     HashDatum      ThrowawayData;
4241     IMDInternalImport *pMDImport = pModule->GetMDImport();
4242     if (FAILED(pMDImport->GetNameOfTypeDef(classdef, &pszName, &pszNameSpace)))
4243     {
4244         pszName = pszNameSpace = "Invalid TypeDef token";
4245         pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4246     }
4247     
4248     EEClassHashEntry_t *pBucket;
4249     mdTypeDef      enclosing;
4250     if (SUCCEEDED(pMDImport->GetNestedClassProps(classdef, &enclosing))) {
4251         // nested type
4252
4253         LPCUTF8 pszEnclosingName;
4254         LPCUTF8 pszEnclosingNameSpace;
4255         mdTypeDef enclEnclosing;
4256
4257         // Find this type's encloser's entry in the available table.
4258         // We'll save a pointer to it in the new hash entry for this type.
4259         BOOL fNestedEncl = SUCCEEDED(pMDImport->GetNestedClassProps(enclosing, &enclEnclosing));
4260
4261         EEClassHashTable::LookupContext sContext;
4262         if (FAILED(pMDImport->GetNameOfTypeDef(enclosing, &pszEnclosingName, &pszEnclosingNameSpace)))
4263         {
4264             pszName = pszNameSpace = "Invalid TypeDef token";
4265             pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4266         }
4267         if ((pBucket = pClassHash->GetValue(pszEnclosingNameSpace,
4268                                             pszEnclosingName,
4269                                             &ThrowawayData,
4270                                             fNestedEncl,
4271                                             &sContext)) != NULL) {
4272             if (fNestedEncl) {
4273                 // Find entry for enclosing class - NOTE, this assumes that the
4274                 // enclosing class's TypeDef or ExportedType was inserted previously,
4275                 // which assumes that, when enuming TD's, we get the enclosing class first
4276                 while ((!CompareNestedEntryWithTypeDef(pMDImport,
4277                                                        enclEnclosing,
4278                                                        pClassHash,
4279                                                        pBucket->GetEncloser())) &&
4280                        (pBucket = pClassHash->FindNextNestedClass(pszEnclosingNameSpace,
4281                                                                   pszEnclosingName,
4282                                                                   &ThrowawayData,
4283                                                                   &sContext)) != NULL);
4284             }
4285
4286             if (!pBucket) // Enclosing type not found in hash table
4287                 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_ENCLOSING_TYPE_NOT_FOUND);
4288
4289             // In this hash table, if the lower bit is set, it means a Module, otherwise it means EEClass*
4290             ThrowawayData = EEClassHashTable::CompressClassDef(classdef);
4291             InsertValue(pClassHash, pClassCaseInsHash, pszNameSpace, pszName, ThrowawayData, pBucket, pamTracker);
4292         }
4293     }
4294     else {
4295         // Don't add duplicate top-level classes.  Top-level classes are
4296         // added to the beginning of the bucket, while nested classes are
4297         // added to the end.  So, a duplicate top-level class could hide
4298         // the previous type's EEClass* entry in the hash table.
4299         EEClassHashEntry_t *pCaseInsEntry = NULL;
4300         LPUTF8 pszLowerCaseNS = NULL;
4301         LPUTF8 pszLowerCaseName = NULL;
4302
4303         if (pClassCaseInsHash) {
4304             CreateCanonicallyCasedKey(pszNameSpace, pszName, &pszLowerCaseNS, &pszLowerCaseName);
4305             pCaseInsEntry = pClassCaseInsHash->AllocNewEntry(pamTracker);
4306         }
4307
4308         EEClassHashEntry_t *pEntry = pClassHash->FindItem(pszNameSpace, pszName, FALSE, NULL);
4309         if (pEntry) {
4310             HashDatum Data = pEntry->GetData();
4311
4312             if (((size_t)Data & EECLASSHASH_TYPEHANDLE_DISCR) &&
4313                 ((size_t)Data & EECLASSHASH_MDEXPORT_DISCR)) {
4314
4315                 // it's an ExportedType - check the 'already seen' bit and if on, report a class loading exception
4316                 // otherwise, set it
4317                 if ((size_t)Data & EECLASSHASH_ALREADYSEEN)
4318                     pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_MULT_TYPE_SAME_NAME);
4319                 else {
4320                     Data = (HashDatum)((size_t)Data | EECLASSHASH_ALREADYSEEN);
4321                     pEntry->SetData(Data);
4322                 }
4323             }
4324             else {
4325                 // We want to throw an exception for a duplicate typedef.
4326                 // However, this used to be allowed in 1.0/1.1, and some third-party DLLs have
4327                 // been obfuscated so that they have duplicate private typedefs.
4328                 // We must allow this for old assemblies for app compat reasons
4329                 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_MULT_TYPE_SAME_NAME);
4330             }
4331         }
4332         else {
4333             pEntry = pClassHash->AllocNewEntry(pamTracker);
4334
4335             CANNOTTHROWCOMPLUSEXCEPTION();
4336             FAULT_FORBID();
4337
4338             pClassHash->InsertValueUsingPreallocatedEntry(pEntry, pszNameSpace, pszName, EEClassHashTable::CompressClassDef(classdef), NULL);
4339
4340             if (pClassCaseInsHash)
4341                 pClassCaseInsHash->InsertValueUsingPreallocatedEntry(pCaseInsEntry, pszLowerCaseNS, pszLowerCaseName, pEntry, pEntry->GetEncloser());
4342         }
4343         
4344 #ifdef FEATURE_COMINTEROP
4345         // Check WinRT namespace prefix if required
4346         if (szWinRtNamespacePrefix != NULL)
4347         {
4348             DWORD dwAttr;
4349             if (FAILED(pMDImport->GetTypeDefProps(classdef, &dwAttr, NULL)))
4350             {
4351                 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4352             }
4353             
4354             // Check only public WinRT types that are not nested (i.e. only types available for binding, excluding NoPIA)
4355             if (IsTdPublic(dwAttr) && IsTdWindowsRuntime(dwAttr))
4356             {
4357                 // Guaranteed by the caller - code:ClassLoader::PopulateAvailableClassHashTable
4358                 _ASSERTE(cchWinRtNamespacePrefix == strlen(szWinRtNamespacePrefix));
4359                 
4360                 // Now make sure namespace is, or begins with the namespace-prefix (note: 'MyN' should not match namespace 'MyName')
4361                 // Note: Case insensitive comparison function has to be in sync with Win8 implementation 
4362                 // (ExtractExactCaseNamespaceSegmentFromMetadataFile in com\WinRT\WinTypes\TypeResolution\NamespaceResolution.cpp)
4363                 BOOL fIsNamespaceSubstring = (pszNameSpace != NULL) && 
4364                                               ((strncmp(pszNameSpace, szWinRtNamespacePrefix, cchWinRtNamespacePrefix) == 0) || 
4365                                                (_strnicmp(pszNameSpace, szWinRtNamespacePrefix, cchWinRtNamespacePrefix) == 0));
4366                 BOOL fIsSubNamespace = fIsNamespaceSubstring && 
4367                                        ((pszNameSpace[cchWinRtNamespacePrefix] == '\0') || 
4368                                         (pszNameSpace[cchWinRtNamespacePrefix] == '.'));
4369                 if (!fIsSubNamespace)
4370                 {
4371                     pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_WINRT_INVALID_NAMESPACE_FOR_TYPE);
4372                 }
4373             }
4374         }
4375 #endif // FEATURE_COMINTEROP
4376     }
4377 }
4378
4379 VOID ClassLoader::AddExportedTypeDontHaveLock(Module *pManifestModule,
4380     mdExportedType cl,
4381     AllocMemTracker *pamTracker)
4382 {
4383     CONTRACTL
4384     {
4385         INSTANCE_CHECK;
4386         THROWS;
4387         GC_TRIGGERS;
4388         MODE_ANY;
4389         INJECT_FAULT(COMPlusThrowOM(););
4390     }
4391     CONTRACTL_END
4392
4393     CrstHolder ch(&m_AvailableClassLock);
4394         
4395     // R2R pre-computes an export table and tries to avoid populating a class hash at runtime. However the profiler can
4396     // still add new types on the fly by calling here. If that occurs we fallback to the slower path of creating the
4397     // in memory hashtable as usual.
4398     if (!pManifestModule->IsResource() && pManifestModule->GetAvailableClassHash() == NULL)
4399     {
4400         LazyPopulateCaseSensitiveHashTables();
4401     }
4402
4403     AddExportedTypeHaveLock(
4404         pManifestModule,
4405         cl,
4406         pamTracker);
4407 }
4408
4409 VOID ClassLoader::AddExportedTypeHaveLock(Module *pManifestModule,
4410                                           mdExportedType cl,
4411                                           AllocMemTracker *pamTracker)
4412 {
4413     CONTRACTL
4414     {
4415         INSTANCE_CHECK;
4416         THROWS;
4417         GC_TRIGGERS;
4418         MODE_ANY;
4419         INJECT_FAULT(COMPlusThrowOM(););
4420     }
4421     CONTRACTL_END
4422
4423
4424     mdToken mdImpl;
4425     LPCSTR pszName;
4426     LPCSTR pszNameSpace;
4427     IMDInternalImport* pAsmImport = pManifestModule->GetMDImport();
4428     if (FAILED(pAsmImport->GetExportedTypeProps(
4429         cl,
4430         &pszNameSpace,
4431         &pszName,
4432         &mdImpl,
4433         NULL,   // type def
4434         NULL))) // flags
4435     {
4436         pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4437     }
4438     
4439     HashDatum ThrowawayData;
4440     
4441     if (TypeFromToken(mdImpl) == mdtExportedType)
4442     {
4443         // nested class
4444         LPCUTF8 pszEnclosingNameSpace;
4445         LPCUTF8 pszEnclosingName;
4446         mdToken nextImpl;
4447         if (FAILED(pAsmImport->GetExportedTypeProps(
4448             mdImpl, 
4449             &pszEnclosingNameSpace, 
4450             &pszEnclosingName, 
4451             &nextImpl, 
4452             NULL,   // type def
4453             NULL))) // flags
4454         {
4455             pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4456         }
4457         
4458         // Find entry for enclosing class - NOTE, this assumes that the
4459         // enclosing class's ExportedType was inserted previously, which assumes that,
4460         // when enuming ExportedTypes, we get the enclosing class first
4461         EEClassHashEntry_t *pBucket;
4462         EEClassHashTable::LookupContext sContext;
4463         if ((pBucket = pManifestModule->GetAvailableClassHash()->GetValue(pszEnclosingNameSpace,
4464                                                                           pszEnclosingName,
4465                                                                           &ThrowawayData,
4466                                                                           TypeFromToken(nextImpl) == mdtExportedType,
4467                                                                           &sContext)) != NULL) {
4468             do {
4469                 // check to see if this is the correct class
4470                 if (EEClassHashTable::UncompressModuleAndClassDef(ThrowawayData) == mdImpl) {
4471                     ThrowawayData = EEClassHashTable::CompressClassDef(cl);
4472
4473                     // we explicitly don't check for the case insensitive hash table because we know it can't have been created yet
4474                     pManifestModule->GetAvailableClassHash()->InsertValue(pszNameSpace, pszName, ThrowawayData, pBucket, pamTracker);
4475                 }
4476                 pBucket = pManifestModule->GetAvailableClassHash()->FindNextNestedClass(pszEnclosingNameSpace, pszEnclosingName, &ThrowawayData, &sContext);
4477             } while (pBucket);
4478         }
4479
4480         // If the encloser is not in the hash table, this nested class
4481         // was defined in the manifest module, so it doesn't need to be added
4482         return;
4483     }
4484     else {
4485         // Defined in the manifest module - add to the hash table by TypeDef instead
4486         if (mdImpl == mdFileNil)
4487             return;
4488
4489         // Don't add duplicate top-level classes
4490         // In this hash table, if the lower bit is set, it means a Module, otherwise it means EEClass*
4491         ThrowawayData = EEClassHashTable::CompressClassDef(cl);
4492         // ThrowawayData is an IN OUT param. Going in its the pointer to the new value if the entry needs
4493         // to be inserted. The OUT param points to the value stored in the hash table.
4494         BOOL bFound;
4495         pManifestModule->GetAvailableClassHash()->InsertValueIfNotFound(pszNameSpace, pszName, &ThrowawayData, NULL, FALSE, &bFound, pamTracker);
4496         if (bFound) {
4497
4498             // Check for duplicate ExportedTypes
4499             // Let it slide if it's pointing to the same type
4500             mdToken foundTypeImpl;
4501             if ((size_t)ThrowawayData & EECLASSHASH_MDEXPORT_DISCR)
4502             {
4503                 mdExportedType foundExportedType = EEClassHashTable::UncompressModuleAndClassDef(ThrowawayData);
4504                 if (FAILED(pAsmImport->GetExportedTypeProps(
4505                     foundExportedType,
4506                     NULL,   // namespace
4507                     NULL,   // name
4508                     &foundTypeImpl, 
4509                     NULL,   // TypeDef
4510                     NULL))) // flags
4511                 {
4512                     pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4513                 }
4514             }
4515             else
4516             {
4517                 foundTypeImpl = mdFileNil;
4518             }
4519
4520             if (mdImpl != foundTypeImpl)
4521             {
4522                 pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_MULT_TYPE_SAME_NAME);
4523             }
4524         }
4525     }
4526 }
4527
4528 static MethodTable* GetEnclosingMethodTable(MethodTable *pMT)
4529 {
4530     CONTRACT(MethodTable*)
4531     {
4532         THROWS;
4533         GC_TRIGGERS;
4534         INJECT_FAULT(COMPlusThrowOM(););
4535         MODE_ANY;
4536         PRECONDITION(CheckPointer(pMT));
4537         POSTCONDITION(RETVAL == NULL || RETVAL->IsTypicalTypeDefinition());
4538     }
4539     CONTRACT_END;
4540
4541     RETURN pMT->LoadEnclosingMethodTable();
4542 }
4543
4544 StaticAccessCheckContext::StaticAccessCheckContext(MethodDesc* pCallerMethod)
4545 {
4546     CONTRACTL
4547     {
4548         LIMITED_METHOD_CONTRACT;
4549         PRECONDITION(CheckPointer(pCallerMethod));
4550     }
4551     CONTRACTL_END;
4552
4553     m_pCallerMethod = pCallerMethod;
4554     m_pCallerMT = m_pCallerMethod->GetMethodTable();
4555     m_pCallerAssembly = m_pCallerMT->GetAssembly();
4556 }
4557
4558 StaticAccessCheckContext::StaticAccessCheckContext(MethodDesc* pCallerMethod, MethodTable* pCallerType)
4559 {
4560     CONTRACTL
4561     {
4562         LIMITED_METHOD_CONTRACT;
4563         PRECONDITION(CheckPointer(pCallerMethod, NULL_OK));
4564         PRECONDITION(CheckPointer(pCallerType));
4565     }
4566     CONTRACTL_END;
4567
4568     m_pCallerMethod = pCallerMethod;
4569     m_pCallerMT = pCallerType;
4570     m_pCallerAssembly = pCallerType->GetAssembly();
4571 }
4572
4573 //******************************************************************************
4574
4575 // static
4576 AccessCheckOptions* AccessCheckOptions::s_pNormalAccessChecks;
4577
4578 //******************************************************************************
4579
4580 void AccessCheckOptions::Startup()
4581 {
4582     STANDARD_VM_CONTRACT;
4583
4584     s_pNormalAccessChecks = new AccessCheckOptions(
4585                                     AccessCheckOptions::kNormalAccessibilityChecks, 
4586                                     NULL, 
4587                                     FALSE, 
4588                                     (MethodTable *)NULL);
4589 }
4590
4591 //******************************************************************************
4592 AccessCheckOptions::AccessCheckOptions(
4593     const AccessCheckOptions & templateOptions,
4594     BOOL                       throwIfTargetIsInaccessible) :
4595     m_pAccessContext(templateOptions.m_pAccessContext)
4596 {
4597     WRAPPER_NO_CONTRACT;
4598
4599     Initialize(
4600         templateOptions.m_accessCheckType,
4601         throwIfTargetIsInaccessible,
4602         templateOptions.m_pTargetMT,
4603         templateOptions.m_pTargetMethod, 
4604         templateOptions.m_pTargetField);
4605 }
4606
4607 //******************************************************************************
4608 // This function should only be called when normal accessibility is not possible.
4609 // It returns TRUE if the target can be accessed.
4610 // Otherwise, it either returns FALSE or throws an exception, depending on the value of throwIfTargetIsInaccessible.
4611
4612 BOOL AccessCheckOptions::DemandMemberAccess(AccessCheckContext *pContext, MethodTable * pTargetMT, BOOL visibilityCheck) const
4613 {
4614     CONTRACTL
4615     {
4616         THROWS;
4617         GC_TRIGGERS;
4618         MODE_ANY;
4619         PRECONDITION(m_accessCheckType != kNormalAccessibilityChecks);
4620         PRECONDITION(CheckPointer(pContext));
4621     }
4622     CONTRACTL_END;
4623
4624     _ASSERTE(m_accessCheckType != kNormalAccessibilityChecks);
4625
4626     if (NingenEnabled())
4627     {
4628         // NinGen should always perform normal accessibility checks
4629         _ASSERTE(false);
4630
4631         if (m_fThrowIfTargetIsInaccessible)
4632         {
4633             ThrowAccessException(pContext, pTargetMT, NULL);
4634         }
4635
4636         return FALSE;
4637     }
4638     
4639     if (pTargetMT && pTargetMT->GetAssembly()->IsDisabledPrivateReflection())
4640     {
4641         if (m_fThrowIfTargetIsInaccessible)
4642         {
4643             ThrowAccessException(pContext, pTargetMT, NULL);
4644         }
4645
4646         return FALSE;
4647     }
4648
4649     BOOL canAccessTarget = FALSE;
4650
4651 #ifndef CROSSGEN_COMPILE
4652
4653     // In CoreCLR kRestrictedMemberAccess means that one can access private/internal
4654     // classes/members in app code.
4655     if (m_accessCheckType != kMemberAccess && pTargetMT)
4656     {
4657         // We allow all transparency checks to succeed in LCG methods and reflection invocation.
4658         if (m_accessCheckType == kNormalAccessNoTransparency || m_accessCheckType == kRestrictedMemberAccessNoTransparency)
4659             return TRUE;
4660     }
4661
4662     // Always allow interop (NULL) callers full access.
4663     if (pContext->IsCalledFromInterop())
4664         return TRUE;
4665
4666     // No Access
4667     if (m_fThrowIfTargetIsInaccessible)
4668     {
4669         ThrowAccessException(pContext, pTargetMT, NULL);
4670     }
4671
4672 #endif // CROSSGEN_COMPILE
4673
4674     return canAccessTarget;
4675 }
4676
4677 //******************************************************************************
4678 // pFailureMT - the MethodTable that we were trying to access. It can be null
4679 //              if the failure is not because of a specific type. This will be a
4680 //              a component of the instantiation of m_pTargetMT/m_pTargetMethod/m_pTargetField.
4681
4682 void AccessCheckOptions::ThrowAccessException(
4683     AccessCheckContext* pContext,
4684     MethodTable*        pFailureMT,             /* = NULL  */
4685     Exception*          pInnerException         /* = NULL  */) const
4686 {
4687     CONTRACTL
4688     {
4689         THROWS;
4690         GC_TRIGGERS;
4691         MODE_ANY;
4692         PRECONDITION(CheckPointer(pContext));
4693         PRECONDITION(CheckPointer(pInnerException, NULL_OK));
4694         PRECONDITION(m_fThrowIfTargetIsInaccessible);
4695     }
4696     CONTRACTL_END;
4697
4698     GCX_COOP();
4699
4700     MethodDesc* pCallerMD = pContext->GetCallerMethod();
4701
4702     if (m_pTargetMT != NULL)
4703     {
4704         // If we know the specific type that caused the failure, display it.
4705         // Else display the whole type that we are trying to access.
4706         MethodTable * pMT = (pFailureMT != NULL) ? pFailureMT : m_pTargetMT;
4707         ThrowTypeAccessException(pContext, pMT, 0, pInnerException);
4708     }
4709     else if (m_pTargetMethod != NULL) 
4710     {
4711         // If the caller and target method are non-null and the same, then this means that we're checking to see
4712         // if the method has access to itself in order to validate that it has access to its parameter types,
4713         // containing type, and return type.  In this case, throw a more informative TypeAccessException to
4714         // describe the error that occurred (for instance, "this method doesn't have access to one of its
4715         // parameter types", rather than "this method doesn't have access to itself").
4716         // We only want to do this if we know the exact type that caused the problem, otherwise fall back to
4717         // throwing the standard MethodAccessException.
4718         if (pCallerMD != NULL && m_pTargetMethod == pCallerMD && pFailureMT != NULL)
4719         {
4720             ThrowTypeAccessException(pContext, pFailureMT, 0, pInnerException);
4721         }
4722         else
4723         {
4724             ThrowMethodAccessException(pContext, m_pTargetMethod, 0, pInnerException);
4725         }
4726     }
4727     else
4728     {
4729         _ASSERTE(m_pTargetField != NULL);
4730         ThrowFieldAccessException(pContext, m_pTargetField, 0, pInnerException);
4731     }
4732 }
4733
4734 //******************************************************************************
4735 // This will do a security demand if appropriate.
4736 // If access is not possible, this will either throw an exception or return FALSE
4737 BOOL AccessCheckOptions::DemandMemberAccessOrFail(AccessCheckContext *pContext, MethodTable * pTargetMT, BOOL visibilityCheck) const
4738 {
4739     CONTRACTL
4740     {
4741         THROWS;
4742         GC_TRIGGERS;
4743         MODE_ANY;
4744     }
4745     CONTRACTL_END;
4746
4747     if (DoNormalAccessibilityChecks())
4748     {
4749         if (pContext->GetCallerAssembly()->IgnoresAccessChecksTo(pTargetMT->GetAssembly()))
4750         {
4751             return TRUE;
4752         }
4753
4754         if (m_fThrowIfTargetIsInaccessible)
4755         {
4756             ThrowAccessException(pContext, pTargetMT);
4757         }
4758
4759         return FALSE;
4760     }
4761
4762     return DemandMemberAccess(pContext, pTargetMT, visibilityCheck);
4763 }
4764
4765 //******************************************************************************
4766 // This should be called if access to the target is not possible.
4767 // This will either throw an exception or return FALSE.
4768 BOOL AccessCheckOptions::FailOrThrow(AccessCheckContext *pContext) const
4769 {
4770     CONTRACTL
4771     {
4772         THROWS;
4773         GC_TRIGGERS;
4774         MODE_ANY;
4775         PRECONDITION(CheckPointer(pContext));
4776     }
4777     CONTRACTL_END;
4778
4779     if (m_fThrowIfTargetIsInaccessible)
4780     {
4781         ThrowAccessException(pContext);
4782     }
4783
4784     return FALSE;
4785 }
4786
4787 void DECLSPEC_NORETURN ThrowFieldAccessException(AccessCheckContext* pContext,
4788                                                  FieldDesc *pFD,
4789                                                  UINT messageID /* = 0 */,
4790                                                  Exception *pInnerException /* = NULL */)
4791 {
4792     CONTRACTL
4793     {
4794         THROWS;
4795         GC_TRIGGERS;
4796         MODE_ANY;
4797         PRECONDITION(CheckPointer(pContext));
4798         PRECONDITION(CheckPointer(pFD));
4799     }
4800     CONTRACTL_END;
4801
4802     MethodDesc* pCallerMD = pContext->GetCallerMethod();
4803     
4804     ThrowFieldAccessException(pCallerMD,
4805                               pFD,
4806                               messageID,
4807                               pInnerException);
4808 }
4809
4810 void DECLSPEC_NORETURN ThrowFieldAccessException(MethodDesc* pCallerMD,
4811                                                  FieldDesc *pFD,
4812                                                  UINT messageID /* = 0 */,
4813                                                  Exception *pInnerException /* = NULL */)
4814 {
4815     CONTRACTL
4816     {
4817         THROWS;
4818         GC_TRIGGERS;
4819         MODE_ANY;
4820         PRECONDITION(CheckPointer(pCallerMD, NULL_OK));
4821         PRECONDITION(CheckPointer(pFD));
4822     }
4823     CONTRACTL_END;
4824
4825     if (pCallerMD != NULL)
4826     {
4827         if (messageID == 0)
4828         {
4829             messageID = IDS_E_FIELDACCESS;
4830         }
4831
4832         EX_THROW_WITH_INNER(EEFieldException, (pFD, pCallerMD, SString::Empty(), messageID), pInnerException);
4833     }
4834     else
4835     {
4836         EX_THROW_WITH_INNER(EEFieldException, (pFD), pInnerException);
4837     }
4838 }
4839
4840 void DECLSPEC_NORETURN ThrowMethodAccessException(AccessCheckContext* pContext,
4841                                                   MethodDesc *pCalleeMD,
4842                                                   UINT messageID /* = 0 */,
4843                                                   Exception *pInnerException /* = NULL */)
4844 {
4845     CONTRACTL
4846     {
4847         THROWS;
4848         GC_TRIGGERS;
4849         MODE_ANY;
4850         PRECONDITION(CheckPointer(pContext));
4851         PRECONDITION(CheckPointer(pCalleeMD));
4852     }
4853     CONTRACTL_END;
4854
4855     MethodDesc* pCallerMD = pContext->GetCallerMethod();
4856     
4857     ThrowMethodAccessException(pCallerMD,
4858                                pCalleeMD,
4859                                messageID,
4860                                pInnerException);
4861 }
4862
4863 void DECLSPEC_NORETURN ThrowMethodAccessException(MethodDesc* pCallerMD,
4864                                                   MethodDesc *pCalleeMD,
4865                                                   UINT messageID /* = 0 */,
4866                                                   Exception *pInnerException /* = NULL */)
4867 {
4868     CONTRACTL
4869     {
4870         THROWS;
4871         GC_TRIGGERS;
4872         MODE_ANY;
4873         PRECONDITION(CheckPointer(pCallerMD, NULL_OK));
4874         PRECONDITION(CheckPointer(pCalleeMD));
4875     }
4876     CONTRACTL_END;
4877
4878     if (pCallerMD != NULL)
4879     {
4880         if (messageID == 0)
4881         {
4882             messageID = IDS_E_METHODACCESS;
4883         }
4884
4885         EX_THROW_WITH_INNER(EEMethodException, (pCalleeMD, pCallerMD, SString::Empty(), messageID), pInnerException);
4886     }
4887     else
4888     {
4889         EX_THROW_WITH_INNER(EEMethodException, (pCalleeMD), pInnerException);
4890     }
4891 }
4892
4893 void DECLSPEC_NORETURN ThrowTypeAccessException(AccessCheckContext* pContext,
4894                                                 MethodTable *pMT,
4895                                                 UINT messageID /* = 0 */,
4896                                                 Exception *pInnerException /* = NULL */)
4897 {
4898     CONTRACTL
4899     {
4900         THROWS;
4901         GC_TRIGGERS;
4902         MODE_ANY;
4903         PRECONDITION(CheckPointer(pContext));
4904         PRECONDITION(CheckPointer(pMT));
4905     }
4906     CONTRACTL_END;
4907
4908     MethodDesc* pCallerMD = pContext->GetCallerMethod();
4909     
4910     ThrowTypeAccessException(pCallerMD,
4911                              pMT,
4912                              messageID,
4913                              pInnerException);
4914 }
4915
4916 void DECLSPEC_NORETURN ThrowTypeAccessException(MethodDesc* pCallerMD,
4917                                                 MethodTable *pMT,
4918                                                 UINT messageID /* = 0 */,
4919                                                 Exception *pInnerException /* = NULL */)
4920 {
4921     CONTRACTL
4922     {
4923         THROWS;
4924         GC_TRIGGERS;
4925         MODE_ANY;
4926         PRECONDITION(CheckPointer(pCallerMD, NULL_OK));
4927         PRECONDITION(CheckPointer(pMT));
4928     }
4929     CONTRACTL_END;
4930
4931     if (pCallerMD != NULL)
4932     {
4933         if (messageID == 0)
4934         {
4935             messageID = IDS_E_TYPEACCESS;
4936         }
4937
4938         EX_THROW_WITH_INNER(EETypeAccessException, (pMT, pCallerMD, SString::Empty(), messageID), pInnerException);
4939     }
4940     else
4941     {
4942         EX_THROW_WITH_INNER(EETypeAccessException, (pMT), pInnerException);
4943     }
4944 }
4945
4946 //---------------------------------------------------------------------------------------
4947 //
4948 // Checks to see if access to a member with assembly visiblity is allowed.
4949 //
4950 // Arguments:
4951 //    pAccessingAssembly    - The assembly requesting access to the internal member
4952 //    pTargetAssembly       - The assembly which contains the target member
4953 //    pOptionalTargetField  - Internal field being accessed OR
4954 //    pOptionalTargetMethod - Internal type being accessed OR
4955 //    pOptionalTargetType   - Internal type being accessed
4956 //
4957 // Return Value:
4958 //    TRUE if pTargetAssembly is pAccessingAssembly, or if pTargetAssembly allows
4959 //    pAccessingAssembly friend access to the target. FALSE otherwise.
4960 //
4961
4962 static BOOL AssemblyOrFriendAccessAllowed(Assembly       *pAccessingAssembly,
4963                                           Assembly       *pTargetAssembly,
4964                                           FieldDesc      *pOptionalTargetField,
4965                                           MethodDesc     *pOptionalTargetMethod,
4966                                           MethodTable    *pOptionalTargetType)
4967 {
4968     CONTRACTL
4969     {
4970         THROWS;
4971         GC_TRIGGERS;
4972         PRECONDITION(CheckPointer(pAccessingAssembly));
4973         PRECONDITION(CheckPointer(pTargetAssembly));
4974         PRECONDITION(pOptionalTargetField != NULL || pOptionalTargetMethod != NULL || pOptionalTargetType != NULL);
4975         PRECONDITION(pOptionalTargetField == NULL || pOptionalTargetMethod == NULL);
4976     }
4977     CONTRACTL_END;
4978
4979     if (pAccessingAssembly == pTargetAssembly)
4980     {
4981         return TRUE;
4982     }
4983
4984     if (pAccessingAssembly->IgnoresAccessChecksTo(pTargetAssembly))
4985     {
4986         return TRUE;
4987     }
4988
4989     else if (pOptionalTargetField != NULL)
4990     {
4991         return pTargetAssembly->GrantsFriendAccessTo(pAccessingAssembly, pOptionalTargetField);
4992     }
4993     else if (pOptionalTargetMethod != NULL)
4994     {
4995         return pTargetAssembly->GrantsFriendAccessTo(pAccessingAssembly, pOptionalTargetMethod);
4996     }
4997     else
4998     {
4999         return pTargetAssembly->GrantsFriendAccessTo(pAccessingAssembly, pOptionalTargetType);
5000     }
5001 }
5002
5003 //******************************************************************************
5004 // This function determines whether a target class is accessible from 
5005 //  some given class.
5006 /* static */
5007 BOOL ClassLoader::CanAccessMethodInstantiation( // True if access is legal, false otherwise. 
5008     AccessCheckContext* pContext,
5009     MethodDesc*         pOptionalTargetMethod,  // The desired method; if NULL, return TRUE (or)
5010     const AccessCheckOptions & accessCheckOptions)
5011 {                                           
5012     CONTRACTL
5013     {
5014         THROWS;
5015         GC_TRIGGERS;
5016         INJECT_FAULT(COMPlusThrowOM(););
5017         MODE_ANY;
5018         PRECONDITION(CheckPointer(pContext));
5019     }
5020     CONTRACTL_END
5021
5022     // If there is no target method just allow access.
5023     // NB: the caller may just be checking access to a field or class, so we allow for NULL.
5024     if (!pOptionalTargetMethod)
5025         return TRUE;
5026
5027     // Is the desired target an instantiated generic method?
5028     if (pOptionalTargetMethod->HasMethodInstantiation())
5029     {   // check that the current class has access
5030         // to all of the instantiating classes.
5031         Instantiation inst = pOptionalTargetMethod->GetMethodInstantiation();
5032         for (DWORD i = 0; i < inst.GetNumArgs(); i++)
5033         {   
5034             TypeHandle th = inst[i];
5035
5036             MethodTable* pMT = th.GetMethodTableOfElementType();
5037
5038             // Either a TypeVarTypeDesc or a FnPtrTypeDesc. No access check needed.
5039             if (pMT == NULL)
5040                 continue;
5041
5042             if (!CanAccessClass(
5043                     pContext, 
5044                     pMT, 
5045                     th.GetAssembly(), 
5046                     accessCheckOptions))
5047             {
5048                 return FALSE;
5049             }
5050         }
5051         //  If we are here, the current class has access to all of the target's instantiating args,
5052     }
5053     return TRUE;
5054 }
5055
5056 //******************************************************************************
5057 // This function determines whether a target class is accessible from 
5058 //  some given class.
5059 // CanAccessClass does the following checks:
5060 //   1. Transparency check on the target class
5061 //   2. Recursively calls CanAccessClass on the generic arguments of the target class if it is generic.
5062 //   3. Visibility check on the target class, if the target class is nested, this will be translated
5063 //      to a member access check on the enclosing type (calling CanAccess with appropriate dwProtection.
5064 //
5065 /* static */
5066 BOOL ClassLoader::CanAccessClass(                   // True if access is legal, false otherwise. 
5067     AccessCheckContext* pContext,                   // The caller context
5068     MethodTable*        pTargetClass,               // The desired target class.
5069     Assembly*           pTargetAssembly,            // Assembly containing the target class.    
5070     const AccessCheckOptions & accessCheckOptions)// = TRUE
5071 {                                           
5072     CONTRACTL
5073     {
5074         THROWS;
5075         GC_TRIGGERS;
5076         INJECT_FAULT(COMPlusThrowOM(););
5077         MODE_ANY;
5078         PRECONDITION(CheckPointer(pContext));
5079         PRECONDITION(CheckPointer(pTargetClass));
5080     }
5081     CONTRACTL_END
5082
5083     // If there is no target class, allow access.
5084     // @todo: what does that mean?
5085     //if (!pTargetClass)
5086     //    return TRUE;
5087
5088     // Step 2: Recursively call CanAccessClass on the generic type arguments
5089     // Is the desired target a generic instantiation?
5090     if (pTargetClass->HasInstantiation())
5091     {   // Yes, so before going any further, check that the current class has access
5092         //  to all of the instantiating classes.
5093         Instantiation inst = pTargetClass->GetInstantiation();
5094         for (DWORD i = 0; i < inst.GetNumArgs(); i++)
5095         {   
5096             TypeHandle th = inst[i];
5097
5098             MethodTable* pMT = th.GetMethodTableOfElementType();
5099
5100             // Either a TypeVarTypeDesc or a FnPtrTypeDesc. No access check needed.
5101             if (pMT == NULL)
5102                 continue;
5103
5104             if (!CanAccessClass(
5105                     pContext, 
5106                     pMT, 
5107                     th.GetAssembly(), 
5108                     accessCheckOptions))
5109             {
5110                 // no need to call accessCheckOptions.DemandMemberAccessOrFail here because the base case in
5111                 // CanAccessClass does that already
5112                 return FALSE;
5113             }
5114         }
5115         // If we are here, the current class has access to all of the desired target's instantiating args.
5116         //  Now, check whether the current class has access to the desired target itself.
5117     }
5118
5119     // Step 3: Visibility Check
5120     if (!pTargetClass->GetClass()->IsNested()) 
5121     {   // a non-nested class can be either all public or accessible only from its own assembly (and friends).
5122         if (IsTdPublic(pTargetClass->GetClass()->GetProtection()))
5123         {
5124             return TRUE;
5125         }
5126         else
5127         {
5128             // Always allow interop callers full access.
5129             if (pContext->IsCalledFromInterop())
5130                 return TRUE;
5131
5132             Assembly* pCurrentAssembly = pContext->GetCallerAssembly();
5133             _ASSERTE(pCurrentAssembly != NULL);
5134
5135             if (AssemblyOrFriendAccessAllowed(pCurrentAssembly,
5136                                               pTargetAssembly,
5137                                               NULL,
5138                                               NULL,
5139                                               pTargetClass))
5140             {
5141                 return TRUE;
5142             }
5143             else
5144             {
5145                 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetClass, TRUE /*visibilityCheck*/);
5146             }
5147         }
5148     }
5149
5150     // If we are here, the desired target class is nested.  Translate the type flags 
5151     //  to corresponding method access flags. We need to make a note if friend access was allowed to the
5152     //  type being checked since we're not passing it directly to the recurisve call to CanAccess, and
5153     //  instead are just passing in the dwProtectionFlags.
5154     DWORD dwProtection = pTargetClass->GetClass()->GetProtection();
5155
5156     switch(dwProtection) {
5157         case tdNestedPublic:
5158             dwProtection = mdPublic;
5159             break;
5160         case tdNestedFamily:
5161             dwProtection = mdFamily;
5162             break;
5163         case tdNestedPrivate:
5164             dwProtection = mdPrivate;
5165             break;
5166         case tdNestedFamORAssem:
5167             // If we can access the class because we have assembly or friend access, we have satisfied the
5168             // FamORAssem accessibility, so we we can simplify it down to public. Otherwise we require that
5169             // family access be allowed to grant access.
5170         case tdNestedFamANDAssem:
5171             // If we don't grant assembly or friend access to the target class, then there is no way we
5172             // could satisfy the FamANDAssem requirement.  Otherwise, since we have satsified the Assm
5173             // portion, we only need to check for the Fam portion.
5174         case tdNestedAssembly:
5175             // If we don't grant assembly or friend access to the target class, and that class has assembly
5176             // protection, we can fail the request now.  Otherwise we can check to make sure a public member
5177             // of the outer class is allowed, since we have satisfied the target's accessibility rules.
5178
5179             // Always allow interop callers full access.
5180             if (pContext->IsCalledFromInterop())
5181                 return TRUE;
5182
5183             if (AssemblyOrFriendAccessAllowed(pContext->GetCallerAssembly(), pTargetAssembly, NULL, NULL, pTargetClass))
5184                 dwProtection = (dwProtection == tdNestedFamANDAssem) ? mdFamily : mdPublic;
5185             else if (dwProtection == tdNestedFamORAssem)
5186                 dwProtection = mdFamily;
5187             else
5188                 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetClass, TRUE /*visibilityCheck*/);
5189
5190             break;
5191
5192         default:
5193             THROW_BAD_FORMAT_MAYBE(!"Unexpected class visibility flag value", BFA_BAD_VISIBILITY, pTargetClass); 
5194     }
5195
5196     // The desired target class is nested, so translate the class access request into
5197     //  a member access request.  That is, if the current class is trying to access A::B, 
5198     //  check if it can access things in A with the visibility of B.
5199     // So, pass A as the desired target class and visibility of B within A as the member access
5200     // We've already done transparency check above. No need to do it again.
5201     return ClassLoader::CanAccess(
5202         pContext,
5203         GetEnclosingMethodTable(pTargetClass),
5204         pTargetAssembly,
5205         dwProtection,
5206         NULL,
5207         NULL,
5208         accessCheckOptions);
5209 } // BOOL ClassLoader::CanAccessClass()
5210
5211 //******************************************************************************
5212 // This is a front-end to CheckAccessMember that handles the nested class scope. If can't access
5213 // from the current point and are a nested class, then try from the enclosing class.
5214 // In addition to CanAccessMember, if the caller class doesn't have access to the caller, see if the enclosing class does.
5215 //
5216 /* static */
5217 BOOL ClassLoader::CanAccess(                            // TRUE if access is allowed, FALSE otherwise.
5218     AccessCheckContext* pContext,                       // The caller context
5219     MethodTable*        pTargetMT,                      // The class containing the desired target member.
5220     Assembly*           pTargetAssembly,                // Assembly containing that class.
5221     DWORD               dwMemberAccess,                 // Member access flags of the desired target member (as method bits).
5222     MethodDesc*         pOptionalTargetMethod,          // The target method; NULL if the target is a not a method or
5223                                                         // there is no need to check the method's instantiation.
5224     FieldDesc*          pOptionalTargetField,           // or The desired field; if NULL, return TRUE
5225     const AccessCheckOptions & accessCheckOptions)      // = s_NormalAccessChecks
5226 {
5227     CONTRACT(BOOL)
5228     {
5229         THROWS;
5230         GC_TRIGGERS;
5231         INJECT_FAULT(COMPlusThrowOM(););
5232         PRECONDITION(CheckPointer(pContext));
5233         MODE_ANY;
5234     }
5235     CONTRACT_END;
5236
5237     AccessCheckOptions accessCheckOptionsNoThrow(accessCheckOptions, FALSE);
5238
5239     if (!CheckAccessMember(pContext,
5240                            pTargetMT,
5241                            pTargetAssembly,
5242                            dwMemberAccess,
5243                            pOptionalTargetMethod,
5244                            pOptionalTargetField,
5245                            // Suppress exceptions for nested classes since this is not a hard-failure,
5246                            // and we can do additional checks
5247                            accessCheckOptionsNoThrow))
5248     {
5249         // If we're here, CheckAccessMember didn't allow access.
5250         BOOL canAccess = FALSE;
5251
5252         // If the current class is nested, there may be an enclosing class that might have access
5253         // to the target. And if the pCurrentMT == NULL, the current class is global, and so there 
5254         // is no enclosing class.
5255         MethodTable* pCurrentMT = pContext->GetCallerMT();
5256
5257         // if this is called from interop, the CheckAccessMember call above should have already succeeded.
5258         _ASSERTE(!pContext->IsCalledFromInterop());
5259         
5260         BOOL isNestedClass = (pCurrentMT && pCurrentMT->GetClass()->IsNested());
5261
5262         if (isNestedClass)
5263         {
5264             // A nested class also has access to anything that the enclosing class does, so 
5265             //  recursively check whether the enclosing class can access the desired target member.
5266             MethodTable * pEnclosingMT = GetEnclosingMethodTable(pCurrentMT);
5267
5268             StaticAccessCheckContext accessContext(pContext->GetCallerMethod(),
5269                                                    pEnclosingMT,
5270                                                    pContext->GetCallerAssembly());
5271
5272             // On failure, do not throw from inside this call since that will cause the exception message 
5273             // to refer to the enclosing type.
5274             canAccess = ClassLoader::CanAccess(
5275                                  &accessContext,
5276                                  pTargetMT,
5277                                  pTargetAssembly,
5278                                  dwMemberAccess,
5279                                  pOptionalTargetMethod,
5280                                  pOptionalTargetField,
5281                                  accessCheckOptionsNoThrow);
5282         }
5283
5284         if (!canAccess)
5285         {
5286             BOOL fail = accessCheckOptions.FailOrThrow(pContext);
5287             RETURN(fail);
5288         }
5289     }
5290
5291     RETURN(TRUE);
5292 } // BOOL ClassLoader::CanAccess()
5293
5294 //******************************************************************************
5295 // This is the helper function for the corresponding CanAccess()
5296 // It does the following checks:
5297 //   1. CanAccessClass on pTargetMT
5298 //   2. CanAccessMethodInstantiation if the pOptionalTargetMethod is provided and is generic.
5299 //   3. Transparency check on pTargetMT, pOptionalTargetMethod and pOptionalTargetField.
5300 //   4. Visibility check on dwMemberAccess (on pTargetMT)
5301
5302 /* static */
5303 BOOL ClassLoader::CheckAccessMember(                // TRUE if access is allowed, false otherwise.
5304     AccessCheckContext*     pContext,
5305     MethodTable*            pTargetMT,              // The class containing the desired target member.
5306     Assembly*               pTargetAssembly,        // Assembly containing that class.                                   
5307     DWORD                   dwMemberAccess,         // Member access flags of the desired target member (as method bits). 
5308     MethodDesc*             pOptionalTargetMethod,  // The target method; NULL if the target is a not a method or
5309                                                     // there is no need to check the method's instantiation.
5310     FieldDesc*              pOptionalTargetField,   // target field, NULL if there is no Target field
5311     const AccessCheckOptions & accessCheckOptions
5312     )             
5313 {
5314     CONTRACTL
5315     {
5316         THROWS;
5317         GC_TRIGGERS;
5318         INJECT_FAULT(COMPlusThrowOM(););
5319         PRECONDITION(CheckPointer(pContext));
5320         MODE_ANY;
5321     }
5322     CONTRACTL_END
5323
5324     // we're trying to access a member that is contained in the class pTargetClass, so need to
5325     // check if have access to pTargetClass itself from the current point before worry about
5326     // having access to the member within the class
5327     if (!CanAccessClass(pContext,
5328                         pTargetMT,
5329                         pTargetAssembly,
5330                         accessCheckOptions))
5331     {
5332         return FALSE;
5333     }
5334     
5335     // If we are trying to access a generic method, we have to ensure its instantiation is accessible.
5336     // Note that we need to perform transparency checks on the instantiation even if we have
5337     if (!CanAccessMethodInstantiation(
5338             pContext, 
5339             pOptionalTargetMethod, 
5340             accessCheckOptions))
5341     {
5342         return FALSE;
5343     }
5344
5345     // pOptionalTargetMethod and pOptionalTargetField can never be NULL at the same time.
5346     _ASSERTE(pOptionalTargetMethod == NULL || pOptionalTargetField == NULL);
5347
5348     // Perform transparency checks
5349     // We don't need to do transparency check against pTargetMT here because
5350     // it was already done in CanAccessClass above.
5351
5352     if (IsMdPublic(dwMemberAccess))
5353     {
5354         return TRUE;
5355     }
5356
5357     // Always allow interop callers full access.
5358     if (pContext->IsCalledFromInterop())
5359         return TRUE;
5360
5361     MethodTable* pCurrentMT = pContext->GetCallerMT();
5362
5363     if (IsMdPrivateScope(dwMemberAccess))
5364     {        
5365         if (pCurrentMT != NULL && pCurrentMT->GetModule() == pTargetMT->GetModule())
5366         {
5367             return TRUE;
5368         }
5369         else
5370         {
5371             return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
5372         }
5373     }
5374
5375
5376 #ifdef _DEBUG
5377     if (pTargetMT == NULL &&
5378         (IsMdFamORAssem(dwMemberAccess) ||
5379          IsMdFamANDAssem(dwMemberAccess) ||
5380          IsMdFamily(dwMemberAccess))) {
5381         THROW_BAD_FORMAT_MAYBE(!"Family flag is not allowed on global functions", BFA_FAMILY_ON_GLOBAL, pTargetMT); 
5382     }
5383 #endif
5384
5385     if (pTargetMT == NULL || 
5386         IsMdAssem(dwMemberAccess) || 
5387         IsMdFamORAssem(dwMemberAccess) || 
5388         IsMdFamANDAssem(dwMemberAccess))
5389     {
5390         // If the member has Assembly accessibility, grant access if the current
5391         //  class is in the same assembly as the desired target member, or if the
5392         //  desired target member's assembly grants friend access to the current 
5393         //  assembly.
5394         // @todo: What does it mean for the target class to be NULL?
5395
5396         Assembly* pCurrentAssembly = pContext->GetCallerAssembly();
5397
5398         // pCurrentAssembly should never be NULL, unless we are called from interop,
5399         // in which case we should have already returned TRUE.
5400         _ASSERTE(pCurrentAssembly != NULL);
5401         
5402         const BOOL fAssemblyOrFriendAccessAllowed = AssemblyOrFriendAccessAllowed(pCurrentAssembly,
5403                                                                                   pTargetAssembly,
5404                                                                                   pOptionalTargetField,
5405                                                                                   pOptionalTargetMethod,
5406                                                                                   pTargetMT);
5407
5408         if ((pTargetMT == NULL || IsMdAssem(dwMemberAccess) || IsMdFamORAssem(dwMemberAccess)) && 
5409             fAssemblyOrFriendAccessAllowed)
5410         {
5411             return TRUE;
5412         }
5413         else if (IsMdFamANDAssem(dwMemberAccess) && 
5414                  !fAssemblyOrFriendAccessAllowed)
5415         {
5416             return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
5417         }
5418     }
5419
5420     // Nested classes can access all members of the parent class.
5421     while(pCurrentMT != NULL)
5422     {
5423         //@GENERICSVER:
5424         if (pTargetMT->HasSameTypeDefAs(pCurrentMT))
5425             return TRUE;
5426
5427         if (IsMdPrivate(dwMemberAccess))
5428         {
5429             if (!pCurrentMT->GetClass()->IsNested())
5430             {
5431                 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
5432             }
5433         }
5434         else if (IsMdFamORAssem(dwMemberAccess) || IsMdFamily(dwMemberAccess) || IsMdFamANDAssem(dwMemberAccess))
5435         {
5436             if (CanAccessFamily(pCurrentMT, pTargetMT))
5437             {
5438                 return TRUE;
5439             }
5440         }
5441
5442         pCurrentMT = GetEnclosingMethodTable(pCurrentMT);
5443     }
5444
5445     return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
5446 }
5447
5448 // The family check is actually in two parts (Partition I, 8.5.3.2).  The first part:
5449 //
5450 //              ...accessible to referents that support the same type
5451 //              (i.e., an exact type and all of the types that inherit
5452 //              from it).
5453 //
5454 // Translation: pCurrentClass must be the same type as pTargetClass or a derived class.  (i.e. Derived
5455 // can access Base.protected but Unrelated cannot access Base.protected).
5456 //
5457 // The second part:
5458 //
5459 //              For verifiable code (see Section 8.8), there is an additional
5460 //              requirement that can require a runtime check: the reference
5461 //              shall be made through an item whose exact type supports
5462 //              the exact type of the referent. That is, the item whose
5463 //              member is being accessed shall inherit from the type
5464 //              performing the access.
5465 //
5466 // Translation: The C++ protected rule.  For those unfamiliar, it means that:
5467 //  if you have:
5468 //  GrandChild : Child
5469 //      and
5470 //  Child : Parent
5471 //      and
5472 //  Parent {
5473 //  protected:
5474 //      int protectedField;
5475 //  }
5476 //
5477 //  Child::function(GrandChild * o) {
5478 //      o->protectedField; //This access is legal.
5479 //  }
5480 //
5481 //  GrandChild:function2(Child * o) {
5482 //      o->protectedField; //This access is illegal.
5483 //  }
5484 //
5485 //  The reason for this rule is that if you had:
5486 //  Sibling : Parent
5487 //  
5488 //  Child::function3( Sibling * o ) {
5489 //      o->protectedField; //This access is illegal
5490 //  }
5491 //
5492 //  This is intuitively correct.  However, you need to prevent:
5493 //  Child::function4( Sibling * o ) {
5494 //      ((Parent*)o)->protectedField;
5495 //  }
5496 //
5497 //  Which means that you must access protected fields through a type that is yourself or one of your
5498 //  derived types.
5499
5500 //This checks the first part of the rule above.
5501 /* static */
5502 BOOL ClassLoader::CanAccessFamily(
5503                                  MethodTable *pCurrentClass,
5504                                  MethodTable *pTargetClass)
5505 {
5506     CONTRACTL
5507     {
5508         THROWS;
5509         GC_TRIGGERS;
5510         INJECT_FAULT(COMPlusThrowOM(););
5511         MODE_ANY;
5512         PRECONDITION(CheckPointer(pTargetClass));
5513     }
5514     CONTRACTL_END
5515
5516     _ASSERTE(pCurrentClass);
5517     _ASSERTE(pTargetClass);
5518
5519     BOOL bIsInterface = pTargetClass->IsInterface();
5520
5521     //Look to see if Current is a child of the Target.
5522     while (pCurrentClass) {
5523         if (bIsInterface)
5524         {
5525             // Calling a protected interface member
5526             MethodTable::InterfaceMapIterator it = pCurrentClass->IterateInterfaceMap();
5527             while (it.Next())
5528             {
5529                 // We only loosely check if they are of the same generic type
5530                 if (it.GetInterface()->HasSameTypeDefAs(pTargetClass))
5531                     return TRUE;
5532             }
5533         }
5534         else
5535         {
5536             MethodTable *pCurInstance = pCurrentClass;
5537
5538             while (pCurInstance) {
5539                 //This is correct.  csc is incredibly lax about generics.  Essentially if you are a subclass of
5540                 //any type of generic it lets you access it.  Since the standard is totally unclear, mirror that
5541                 //behavior here.
5542                 if (pCurInstance->HasSameTypeDefAs(pTargetClass)) {
5543                     return TRUE;
5544                 }
5545
5546                 pCurInstance = pCurInstance->GetParentMethodTable();
5547             }
5548         }
5549
5550         ///Looking at 8.5.3, it looks like a protected member of a nested class in a parent type is also
5551         //accessible.
5552         pCurrentClass = GetEnclosingMethodTable(pCurrentClass);
5553     }
5554
5555     return FALSE;
5556 }
5557
5558 //If instance is an inner class, this also succeeds if the outer class conforms to 8.5.3.2.  A nested class
5559 //is enclosed inside of the enclosing class' open type.  So we need to ignore generic variables.  That also
5560 //helps us with:
5561 /*
5562 class Base {
5563     protected int m_family;
5564 }
5565 class Derived<T> : Base {
5566     class Inner {
5567         public int function(Derived<T> d) {
5568             return d.m_family;
5569         }
5570     }
5571 }
5572 */
5573
5574 //Since the inner T is not the same T as the enclosing T (since accessing generic variables is a CLS rule,
5575 //not a CLI rule), we see that as a comparison between Derived<T> and Derived<T'>.  CanCastTo rejects that.
5576 //Instead we just check against the typedef of the two types.  This ignores all generic parameters (formal
5577 //or not).
5578
5579 BOOL CanAccessFamilyVerificationEnclosingHelper(MethodTable * pMTCurrentEnclosingClass,
5580                                                 TypeHandle thInstanceClass)
5581 {
5582     CONTRACTL
5583     {
5584         THROWS;
5585         GC_TRIGGERS;
5586         MODE_ANY;
5587     }
5588     CONTRACTL_END
5589
5590     _ASSERTE(pMTCurrentEnclosingClass);
5591
5592     if (thInstanceClass.IsGenericVariable())
5593     {
5594         //In this case it is a TypeVarTypeDesc (i.e. T).  If this access would be legal due to a
5595         //constraint:
5596         //
5597         /*
5598         public class My<T>
5599         {
5600             public class Inner<U> where U : My<T>
5601             {
5602                 public int foo(U u)
5603                 {
5604                     return u.field;
5605                 }
5606             }
5607             protected int field;
5608         }
5609         */
5610         //We need to find the generic class constraint.  (The above is legal because U must be a My<T> which makes this
5611         //legal by 8.5.3.2)
5612         // There may only be 1 class constraint on a generic parameter
5613
5614         // Get the constraints on this generic variable
5615         // At most 1 of them is a class constraint.
5616         // That class constraint methodtable can go through the normal search for matching typedef logic below
5617         TypeVarTypeDesc *tyvar = thInstanceClass.AsGenericVariable();
5618         DWORD numConstraints;
5619         TypeHandle *constraints = tyvar->GetConstraints(&numConstraints, CLASS_DEPENDENCIES_LOADED);
5620         if (constraints == NULL)
5621         {
5622             // If we did not find a class constraint, we cannot generate a methodtable to search for
5623             return FALSE;
5624         }
5625         else
5626         {
5627             for (DWORD i = 0; i < numConstraints; i++)
5628             {
5629                 if (!constraints[i].IsInterface())
5630                 {
5631                     // We have found the class constraint on this TypeVarTypeDesc
5632                     // Recurse on the found class constraint. It is possible that this constraint may also be a TypeVarTypeDesc
5633 //class Outer4<T>
5634 //{
5635 //    protected int field;
5636 //
5637 //    public class Inner<U,V> where V:U where U : Outer4<T>
5638 //    {
5639 //        public int Method(V param) { return (++param.field); }
5640 //    }
5641 //}
5642                     return CanAccessFamilyVerificationEnclosingHelper(pMTCurrentEnclosingClass, constraints[i]);
5643                 }
5644             }
5645             // If we did not find a class constraint, we cannot generate a methodtable to search for
5646             return FALSE;
5647         }
5648     }
5649     do
5650     {
5651         MethodTable * pAccessor = pMTCurrentEnclosingClass;
5652         //If thInstanceClass is a MethodTable, we should only be doing the TypeDef comparison (see
5653         //above).
5654         if (!thInstanceClass.IsTypeDesc())
5655         {
5656             MethodTable *pInstanceMT = thInstanceClass.AsMethodTable();
5657
5658             // This is a CanCastTo implementation for classes, assuming we should ignore generic instantiation parameters.
5659             do
5660             {
5661                 if (pAccessor->HasSameTypeDefAs(pInstanceMT))
5662                     return TRUE;
5663                 pInstanceMT = pInstanceMT->GetParentMethodTable();
5664             }while(pInstanceMT);
5665         }
5666         else
5667         {
5668             // Leave this logic in place for now, as I'm not fully confident it can't happen, and we are very close to RTM
5669             // This logic was originally written to handle TypeVarTypeDescs, but those are now handled above.
5670             _ASSERTE(FALSE);
5671             if (thInstanceClass.CanCastTo(TypeHandle(pAccessor)))
5672                 return TRUE;
5673         }
5674
5675         pMTCurrentEnclosingClass = GetEnclosingMethodTable(pMTCurrentEnclosingClass);
5676     }while(pMTCurrentEnclosingClass);
5677     return FALSE;
5678 }
5679
5680
5681 //This checks the verification only part of the rule above.
5682 //From the example above:
5683 //  GrandChild::function2(Child * o) {
5684 //      o->protectedField; //This access is illegal.
5685 //  }
5686 // pCurrentClass is GrandChild and pTargetClass is Child.  This check is completely unnecessary for statics,
5687 // but by legacy convention you can use GrandChild for pTargetClass in that case.
5688
5689 BOOL ClassLoader::CanAccessFamilyVerification(TypeHandle thCurrentClass,
5690                                               TypeHandle thInstanceClass)
5691 {
5692     CONTRACTL
5693     {
5694         THROWS;
5695         GC_TRIGGERS;
5696         INJECT_FAULT(COMPlusThrowOM(););
5697         MODE_ANY;
5698         PRECONDITION(!thCurrentClass.IsNull());
5699         PRECONDITION(!thCurrentClass.IsTypeDesc());
5700     }
5701     CONTRACTL_END
5702     
5703     //Check to see if Instance is equal to or derived from pCurrentClass.
5704     //
5705     //In some cases the type we have for the instance type is actually a TypeVarTypeDesc.  In those cases we
5706     //need to check against the constraints (You're accessing a member through a 'T' with a type constraint
5707     //that makes this legal).  For those cases, CanCastTo does what I want.  
5708     MethodTable * pAccessor = thCurrentClass.GetMethodTable();
5709     if (thInstanceClass.CanCastTo(TypeHandle(pAccessor)))
5710         return TRUE;
5711
5712     //ArrayTypeDescs are the only typedescs that have methods, and their methods don't have IL.  All other
5713     //TypeDescs don't need to be here.  So only run this on MethodTables.
5714     if (!thInstanceClass.IsNull())
5715     {
5716         return CanAccessFamilyVerificationEnclosingHelper(pAccessor, thInstanceClass);
5717     }
5718     return FALSE;
5719 }
5720
5721 #endif // #ifndef DACCESS_COMPILE
5722
5723 #ifdef DACCESS_COMPILE
5724
5725 void
5726 ClassLoader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
5727 {
5728     WRAPPER_NO_CONTRACT;
5729     SUPPORTS_DAC;
5730     DAC_ENUM_DTHIS();
5731
5732     EMEM_OUT(("MEM: %p ClassLoader\n", dac_cast<TADDR>(this)));
5733
5734     if (m_pAssembly.IsValid())
5735     {
5736         ModuleIterator modIter = GetAssembly()->IterateModules();
5737
5738         while (modIter.Next())
5739         {
5740             modIter.GetModule()->EnumMemoryRegions(flags, true);
5741         }
5742     }
5743 }
5744
5745 #endif // #ifdef DACCESS_COMPILE