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.
7 // ============================================================================
12 #include "siginfo.hpp"
14 #include "clsload.hpp"
15 #include "classhash.inl"
23 #include "comsynchronizable.h"
25 #include "dllimport.h"
26 #include "dbginterface.h"
29 #include "fieldmarshaler.h"
30 #include "jitinterface.h"
32 #include "assembly.hpp"
33 #include "eeprofinterfaces.h"
36 #include "comdelegate.h"
38 #include "posterror.h"
41 #include "typestring.h"
44 #include "eventtrace.h"
46 #include "pendingload.h"
47 #include "proftoeeinterfaceimpl.h"
48 #include "mdaassistants.h"
49 #include "virtualcallstub.h"
50 #include "stringarraylist.h"
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:
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
65 // Some useful effects of this rule (for ngen purposes) are:
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)
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)
85 PRECONDITION(CheckPointer(pDefinitionModule, NULL_OK));
86 POSTCONDITION(CheckPointer(RETVAL));
91 if (classInst.IsEmpty() && methodInst.IsEmpty())
92 RETURN PTR_Module(pDefinitionModule);
94 #ifndef DACCESS_COMPILE
95 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
97 // Use special loader module placement during compilation of fragile native images.
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).
103 if (IsCompilationProcess() && !IsReadyToRunCompilation())
105 RETURN(ComputeLoaderModuleForCompilation(pDefinitionModule, token, classInst, methodInst));
107 #endif // FEATURE_PREJIT
108 #endif // #ifndef DACCESS_COMPILE
110 Module *pLoaderModule = NULL;
112 if (pDefinitionModule)
114 if (pDefinitionModule->IsCollectible())
115 goto ComputeCollectibleLoaderModule;
116 pLoaderModule = pDefinitionModule;
119 for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
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;
130 for (DWORD i = 0; i < methodInst.GetNumArgs(); i++)
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;
141 if (pLoaderModule == NULL)
143 CONSISTENCY_CHECK(MscorlibBinder::GetModule() && MscorlibBinder::GetModule()->IsSystem());
145 pLoaderModule = MscorlibBinder::GetModule();
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();
158 if (pDefinitionModule != NULL) pLoaderAllocatorOfDefiningType = pDefinitionModule->GetLoaderAllocator();
160 for (DWORD i = 0; i < totalArgsCount; i++) {
164 if (i < classArgsCount)
167 arg = methodInst[i - classArgsCount];
169 Module *pModuleCheck = arg.GetLoaderModule();
170 LoaderAllocator *pLoaderAllocatorCheck = pModuleCheck->GetLoaderAllocator();
172 if (pLoaderAllocatorCheck != pLoaderAllocatorOfDefiningType &&
173 pLoaderAllocatorCheck->IsCollectible() &&
174 pLoaderAllocatorCheck->GetCreationNumber() > oldestFoundAge)
176 pOldestLoaderModule = pModuleCheck;
177 pOldestLoaderAllocator = pLoaderAllocatorCheck;
178 oldestFoundAge = pLoaderAllocatorCheck->GetCreationNumber();
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;
187 pLoaderModule = pDefinitionModule;
189 RETURN PTR_Module(pLoaderModule);
192 #ifndef DACCESS_COMPILE
193 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
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)
207 PRECONDITION(CheckPointer(pDefinitionModule, NULL_OK));
208 POSTCONDITION(CheckPointer(RETVAL));
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".
216 // If this instantiation doesn't have a unique home then use the ngen module
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");
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))
226 RETURN (Module::ComputePreferredZapModule(pDefinitionModule, classInst, methodInst));
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.
233 ZapperLoaderModuleTableKey key(pDefinitionModule,
238 Module * pZapperLoaderModule = g_pCEECompileInfo->LookupZapperLoaderModule(&key);
239 if (pZapperLoaderModule != NULL)
241 RETURN (pZapperLoaderModule);
244 // OK, we need to compute a non-standard zapping module.
246 Module * pPreferredZapModule = Module::ComputePreferredZapModule(pDefinitionModule, classInst, methodInst);
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
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())
260 _ASSERTE(pPreferredZapModule->IsSystem() || IsNgenPDBCompilationProcess());
261 RETURN (pPreferredZapModule);
264 Module * pTargetModule = pAppDomain->ToCompilationDomain()->GetTargetModule();
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())
271 pZapperLoaderModule = pPreferredZapModule;
275 // Everything else can be saved into the current module.
276 pZapperLoaderModule = pTargetModule;
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)
284 if (pDefinitionModule != NULL && !pDefinitionModule->IsInCurrentVersionBubble())
286 pZapperLoaderModule = pDefinitionModule;
287 goto ModuleAdjustedForVersionResiliency;
290 for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
292 Module * pModule = classInst[i].GetLoaderModule();
293 if (!pModule->IsInCurrentVersionBubble())
295 pZapperLoaderModule = pModule;
296 goto ModuleAdjustedForVersionResiliency;
300 for (DWORD i = 0; i < methodInst.GetNumArgs(); i++)
302 Module * pModule = methodInst[i].GetLoaderModule();
303 if (!pModule->IsInCurrentVersionBubble())
305 pZapperLoaderModule = pModule;
306 goto ModuleAdjustedForVersionResiliency;
309 ModuleAdjustedForVersionResiliency: ;
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.
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);
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())
327 pClassArgs = new TypeHandle[classInst.GetNumArgs()];
328 for (unsigned int i = 0; i < classInst.GetNumArgs(); i++)
329 pClassArgs[i] = classInst[i];
332 NewArrayHolder<TypeHandle> pMethodArgs = NULL;
333 if (!methodInst.IsEmpty())
335 pMethodArgs = new TypeHandle[methodInst.GetNumArgs()];
336 for (unsigned int i = 0; i < methodInst.GetNumArgs(); i++)
337 pMethodArgs[i] = methodInst[i];
340 ZapperLoaderModuleTableKey key2(pDefinitionModule,
342 Instantiation(pClassArgs, classInst.GetNumArgs()),
343 Instantiation(pMethodArgs, methodInst.GetNumArgs()));
344 g_pCEECompileInfo->RecordZapperLoaderModule(&key2, pZapperLoaderModule);
346 pClassArgs.SuppressRelease();
347 pMethodArgs.SuppressRelease();
349 RETURN (pZapperLoaderModule);
351 #endif // FEATURE_NATIVE_IMAGE_GENERATION
352 #endif // #ifndef DACCESS_COMPILE
355 Module * ClassLoader::ComputeLoaderModule(MethodTable * pMT,
357 Instantiation methodInst)
368 return ComputeLoaderModuleWorker(pMT->GetModule(),
370 pMT->GetInstantiation(),
374 Module *ClassLoader::ComputeLoaderModule(TypeKey *typeKey)
386 if (typeKey->GetKind() == ELEMENT_TYPE_CLASS)
387 return ComputeLoaderModuleWorker(typeKey->GetModule(),
388 typeKey->GetTypeToken(),
389 typeKey->GetInstantiation(),
391 else if (typeKey->GetKind() == ELEMENT_TYPE_FNPTR)
392 return ComputeLoaderModuleForFunctionPointer(typeKey->GetRetAndArgTypes(), typeKey->GetNumArgs() + 1);
394 return ComputeLoaderModuleForParamType(typeKey->GetElementType());
398 BOOL ClassLoader::IsTypicalInstantiation(Module *pModule, mdToken token, Instantiation inst)
405 PRECONDITION(CheckPointer(pModule));
406 PRECONDITION(TypeFromToken(token) == mdtTypeDef || TypeFromToken(token) == mdtMethodDef);
411 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
413 TypeHandle thArg = inst[i];
415 if (thArg.IsGenericVariable())
417 TypeVarTypeDesc* tyvar = thArg.AsGenericVariable();
419 PREFIX_ASSUME(tyvar!=NULL);
420 if ((tyvar->GetTypeOrMethodDef() != token) ||
421 (tyvar->GetModule() != dac_cast<PTR_Module>(pModule)) ||
422 (tyvar->GetIndex() != i))
433 // External class loader entry point: load a type by name
435 TypeHandle ClassLoader::LoadTypeByNameThrowing(Assembly *pAssembly,
438 NotFoundAction fNotFound,
439 ClassLoader::LoadTypesFlag fLoadTypes,
440 ClassLoadLevel level)
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()); }
449 if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
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));
457 #ifdef DACCESS_COMPILE
458 PRECONDITION((fNotFound == ClassLoader::ReturnNullIfNotFound) && (fLoadTypes == DontLoadTypes));
463 NameHandle nameHandle(nameSpace, name);
464 if (fLoadTypes == DontLoadTypes)
465 nameHandle.SetTokenNotToLoad(tdAllTypes);
466 if (fNotFound == ThrowIfNotFound)
467 RETURN pAssembly->GetLoader()->LoadTypeHandleThrowIfFailed(&nameHandle, level);
469 RETURN pAssembly->GetLoader()->LoadTypeHandleThrowing(&nameHandle, level);
472 #ifndef DACCESS_COMPILE
474 #define DAC_LOADS_TYPE(level, expression) \
475 if (FORBIDGC_LOADER_USE_ENABLED() || (expression)) \
476 { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
479 #define DAC_LOADS_TYPE(level, expression) { LOADS_TYPE(CLASS_LOAD_BEGIN); }
480 #endif // #ifndef DACCESS_COMPILE
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*/)
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());
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));
505 // Lookup in the classes that this class loader knows about
506 TypeHandle typeHnd = LoadTypeHandleThrowing(pName, level, pLookInThisModuleOnly);
508 if(typeHnd.IsNull()) {
510 if ( pName->OKToLoad() ) {
513 LPCUTF8 szName = pName->GetName();
515 szName = "<UNKNOWN>";
517 StackSString codeBase;
518 GetAssembly()->GetCodeBase(codeBase);
520 LOG((LF_CLASSLOADER, LL_INFO10, "Failed to find class \"%s\" in the manifest for assembly \"%ws\"\n", szName, (LPCWSTR)codeBase));
524 #ifndef DACCESS_COMPILE
525 m_pAssembly->ThrowTypeLoadException(pName, IDS_CLASSLOAD_GENERAL);
535 #ifndef DACCESS_COMPILE
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)
546 INJECT_FAULT(COMPlusThrowOM(););
550 LPUTF8 pszLowerCaseNS = NULL;
551 LPUTF8 pszLowerCaseName = NULL;
552 EEClassHashEntry_t *pCaseInsEntry = NULL;
554 EEClassHashEntry_t *pEntry = pClassHash->AllocNewEntry(pamTracker);
556 if (pClassCaseInsHash) {
557 CreateCanonicallyCasedKey(pszNamespace, pszClassName, &pszLowerCaseNS, &pszLowerCaseName);
558 pCaseInsEntry = pClassCaseInsHash->AllocNewEntry(pamTracker);
563 // ! We cannot fail after this point.
564 CANNOTTHROWCOMPLUSEXCEPTION();
568 pClassHash->InsertValueUsingPreallocatedEntry(pEntry, pszNamespace, pszClassName, Data, pEncloser);
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);
579 #endif // #ifndef DACCESS_COMPILE
581 BOOL ClassLoader::CompareNestedEntryWithExportedType(IMDInternalImport * pImport,
582 mdExportedType mdCurrent,
583 EEClassHashTable * pClassHash,
584 PTR_EEClassHashEntry pEntry)
601 if (FAILED(pImport->GetExportedTypeProps(
606 NULL, //binding (type def)
612 if (pClassHash->CompareKeys(pEntry, Key))
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))
620 return pEntry->GetEncloser() == NULL;
623 else // Keys don't match - wrong entry
628 while ((pEntry = pEntry->GetEncloser()) != NULL);
630 // Reached the top level class for pEntry, but mdCurrent is nested
635 BOOL ClassLoader::CompareNestedEntryWithTypeDef(IMDInternalImport * pImport,
637 EEClassHashTable * pClassHash,
638 PTR_EEClassHashEntry pEntry)
654 if (FAILED(pImport->GetNameOfTypeDef(mdCurrent, &Key[1], &Key[0])))
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;
666 else // Keys don't match - wrong entry
669 while ((pEntry = pEntry->GetEncloser()) != NULL);
671 // Reached the top level class for pEntry, but mdCurrent is nested
676 BOOL ClassLoader::CompareNestedEntryWithTypeRef(IMDInternalImport * pImport,
678 EEClassHashTable * pClassHash,
679 PTR_EEClassHashEntry pEntry)
695 if (FAILED(pImport->GetNameOfTypeRef(mdCurrent, &Key[0], &Key[1])))
700 if (pClassHash->CompareKeys(pEntry, Key))
702 if (FAILED(pImport->GetResolutionScopeOfTypeRef(mdCurrent, &mdCurrent)))
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;
713 else // Keys don't match - wrong entry
716 while ((pEntry = pEntry->GetEncloser())!=NULL);
718 // Reached the top level class for pEntry, but mdCurrent is nested
724 BOOL ClassLoader::IsNested(Module *pModule, mdToken token, mdToken *mdEncloser)
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()); }
736 switch(TypeFromToken(token)) {
738 return (SUCCEEDED(pModule->GetMDImport()->GetNestedClassProps(token, mdEncloser)));
741 IfFailThrow(pModule->GetMDImport()->GetResolutionScopeOfTypeRef(token, mdEncloser));
742 return ((TypeFromToken(*mdEncloser) == mdtTypeRef) &&
743 (*mdEncloser != mdTypeRefNil));
745 case mdtExportedType:
746 IfFailThrow(pModule->GetAssembly()->GetManifestImport()->GetExportedTypeProps(
751 NULL, //binding (type def)
753 return ((TypeFromToken(*mdEncloser) == mdtExportedType) &&
754 (*mdEncloser != mdExportedTypeNil));
757 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE);
761 BOOL ClassLoader::IsNested(NameHandle* pName, mdToken *mdEncloser)
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()); }
774 if (pName->GetTypeModule()) {
775 if (TypeFromToken(pName->GetTypeToken()) == mdtBaseType)
777 if (!pName->GetBucket().IsNull())
782 return IsNested(pName->GetTypeModule(), pName->GetTypeToken(), mdEncloser);
788 void ClassLoader::GetClassValue(NameHandleTable nhTable,
791 EEClassHashTable **ppTable,
792 Module* pLookInThisModuleOnly,
793 HashedTypeEntry* pFoundEntry,
794 Loader::LoadFlag loadFlag,
795 BOOL& needsToBuildHashtable)
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));
811 EEClassHashEntry_t *pBucket = NULL;
813 needsToBuildHashtable = FALSE;
816 if (pName->GetName()) {
817 if (pName->GetNameSpace() == NULL)
818 LOG((LF_CLASSLOADER, LL_INFO1000, "Looking up %s by name.\n",
821 LOG((LF_CLASSLOADER, LL_INFO1000, "Looking up %s.%s by name.\n",
822 pName->GetNameSpace(), pName->GetName()));
826 BOOL isNested = IsNested(pName, &mdEncloser);
828 PTR_Assembly assembly = GetAssembly();
829 PREFIX_ASSUME(assembly != NULL);
830 ModuleIterator i = assembly->IterateModules();
834 Module * pCurrentClsModule = i.GetModule();
835 PREFIX_ASSUME(pCurrentClsModule != NULL);
837 if (pCurrentClsModule->IsResource())
839 if (pLookInThisModuleOnly && (pCurrentClsModule != pLookInThisModuleOnly))
842 #ifdef FEATURE_READYTORUN
843 if (nhTable == nhCaseSensitive && pCurrentClsModule->IsReadyToRun() && pCurrentClsModule->GetReadyToRunInfo()->HasHashtableOfTypes() &&
844 pCurrentClsModule->GetAvailableClassHash() == NULL)
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.
850 mdToken mdFoundTypeToken;
851 if (pCurrentClsModule->GetReadyToRunInfo()->TryLookupTypeTokenFromName(pName, &mdFoundTypeToken))
853 if (TypeFromToken(mdFoundTypeToken) == mdtExportedType)
856 Module * pTargetModule = GetAssembly()->FindModuleByExportedType(mdFoundTypeToken, loadFlag, mdTypeDefNil, &mdUnused);
858 pFoundEntry->SetTokenBasedEntryValue(mdFoundTypeToken, pTargetModule);
862 pFoundEntry->SetTokenBasedEntryValue(mdFoundTypeToken, pCurrentClsModule);
865 return; // Return on the first success
871 EEClassHashTable* pTable = NULL;
872 if (nhTable == nhCaseSensitive)
874 *ppTable = pTable = pCurrentClsModule->GetAvailableClassHash();
876 #ifdef FEATURE_READYTORUN
877 if (pTable == NULL && pCurrentClsModule->IsReadyToRun() && !pCurrentClsModule->GetReadyToRunInfo()->HasHashtableOfTypes())
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;
890 // currently we expect only these two kinds--for DAC builds, nhTable will be nhCaseSensitive
891 _ASSERTE(nhTable == nhCaseInsensitive);
892 *ppTable = pTable = pCurrentClsModule->GetAvailableClassCaseInsHash();
896 // We have not built the table yet - the caller will handle
897 pFoundEntry->SetClassHashBasedEntryValue(NULL);
898 needsToBuildHashtable = TRUE;
906 Module *pNameModule = pName->GetTypeModule();
907 PREFIX_ASSUME(pNameModule != NULL);
909 EEClassHashTable::LookupContext sContext;
910 if ((pBucket = pTable->GetValue(pName, pData, TRUE, &sContext)) != NULL)
912 switch (TypeFromToken(pName->GetTypeToken()))
915 while ((!CompareNestedEntryWithTypeDef(pNameModule->GetMDImport(),
917 pCurrentClsModule->GetAvailableClassHash(),
918 pBucket->GetEncloser())) &&
919 (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
922 while ((!CompareNestedEntryWithTypeRef(pNameModule->GetMDImport(),
924 pCurrentClsModule->GetAvailableClassHash(),
925 pBucket->GetEncloser())) &&
926 (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
928 case mdtExportedType:
929 while ((!CompareNestedEntryWithExportedType(pNameModule->GetAssembly()->GetManifestImport(),
931 pCurrentClsModule->GetAvailableClassHash(),
932 pBucket->GetEncloser())) &&
933 (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
936 while ((pBucket->GetEncloser() != pName->GetBucket().GetClassHashBasedEntryValue()) &&
937 (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
943 pBucket = pTable->GetValue(pName, pData, FALSE, NULL);
946 if (pBucket) // Return on the first success
948 pFoundEntry->SetClassHashBasedEntryValue(pBucket);
954 // No results found: default to a NULL EEClassHashEntry_t result
955 pFoundEntry->SetClassHashBasedEntryValue(NULL);
958 #ifndef DACCESS_COMPILE
960 VOID ClassLoader::PopulateAvailableClassHashTable(Module* pModule,
961 AllocMemTracker *pamTracker)
969 INJECT_FAULT(COMPlusThrowOM(););
974 HENUMInternal hTypeDefEnum;
975 IMDInternalImport * pImport = pModule->GetMDImport();
977 LPCSTR szWinRtNamespacePrefix = NULL;
978 DWORD cchWinRtNamespacePrefix = 0;
980 #ifdef FEATURE_COMINTEROP
982 StackScratchBuffer ssFileNameBuffer;
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)
990 _ASSERTE(pModule->GetFile()->IsAssembly()); // No multi-module WinMD file support
991 _ASSERTE(!pModule->GetFile()->GetPath().IsEmpty());
994 pModule->GetFile()->GetPath(),
1000 szWinRtNamespacePrefix = ssFileName.GetUTF8(ssFileNameBuffer);
1001 cchWinRtNamespacePrefix = (DWORD)strlen(szWinRtNamespacePrefix);
1003 #endif //FEATURE_COMINTEROP
1005 IfFailThrow(pImport->EnumTypeDefInit(&hTypeDefEnum));
1007 // Now loop through all the classdefs adding the CVID and scope to the hash
1008 while(pImport->EnumTypeDefNext(&hTypeDefEnum, &td)) {
1010 AddAvailableClassHaveLock(pModule,
1013 szWinRtNamespacePrefix,
1014 cchWinRtNamespacePrefix);
1016 pImport->EnumTypeDefClose(&hTypeDefEnum);
1020 void ClassLoader::LazyPopulateCaseSensitiveHashTables()
1028 INJECT_FAULT(COMPlusThrowOM());
1032 AllocMemTracker amTracker;
1033 ModuleIterator i = GetAssembly()->IterateModules();
1035 // Create a case-sensitive hashtable for each module, and fill it with the module's typedef entries
1038 Module *pModule = i.GetModule();
1039 PREFIX_ASSUME(pModule != NULL);
1040 if (pModule->IsResource())
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());
1047 EEClassHashTable * pNewClassHash = EEClassHashTable::Create(pModule, AVAILABLE_CLASSES_HASH_BUCKETS, FALSE /* bCaseInsensitive */, &amTracker);
1048 pModule->SetAvailableClassHash(pNewClassHash);
1050 PopulateAvailableClassHashTable(pModule, &amTracker);
1053 // Add exported types of the manifest module to the hashtable
1054 if (!GetAssembly()->GetManifestModule()->IsResource())
1056 IMDInternalImport * pManifestImport = GetAssembly()->GetManifestImport();
1057 HENUMInternalHolder phEnum(pManifestImport);
1058 phEnum.EnumInit(mdtExportedType, mdTokenNil);
1060 mdToken mdExportedType;
1061 while (pManifestImport->EnumNext(&phEnum, &mdExportedType))
1062 AddExportedTypeHaveLock(GetAssembly()->GetManifestModule(), mdExportedType, &amTracker);
1065 amTracker.SuppressRelease();
1068 void ClassLoader::LazyPopulateCaseInsensitiveHashTables()
1076 INJECT_FAULT(COMPlusThrowOM());
1080 if (!GetAssembly()->GetManifestModule()->IsResource() && GetAssembly()->GetManifestModule()->GetAvailableClassHash() == NULL)
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();
1088 // Add any unhashed modules into our hash tables, and try again.
1090 AllocMemTracker amTracker;
1091 ModuleIterator i = GetAssembly()->IterateModules();
1095 Module *pModule = i.GetModule();
1096 if (pModule->IsResource())
1099 if (pModule->GetAvailableClassCaseInsHash() == NULL)
1101 EEClassHashTable *pNewClassCaseInsHash = pModule->GetAvailableClassHash()->MakeCaseInsensitiveTable(pModule, &amTracker);
1103 LOG((LF_CLASSLOADER, LL_INFO10, "%s's classes being added to case insensitive hash table\n",
1104 pModule->GetSimpleName()));
1107 CANNOTTHROWCOMPLUSEXCEPTION();
1110 amTracker.SuppressRelease();
1111 pModule->SetAvailableClassCaseInsHash(pNewClassCaseInsHash);
1112 FastInterlockDecrement((LONG*)&m_cUnhashedModules);
1119 void DECLSPEC_NORETURN ClassLoader::ThrowTypeLoadException(TypeKey *pKey,
1122 STATIC_CONTRACT_THROWS;
1124 StackSString fullName;
1125 StackSString assemblyName;
1126 TypeString::AppendTypeKey(fullName, pKey);
1127 pKey->GetModule()->GetAssembly()->GetDisplayName(assemblyName);
1128 ::ThrowTypeLoadException(fullName, assemblyName, NULL, resIDWhy);
1134 TypeHandle ClassLoader::LoadConstructedTypeThrowing(TypeKey *pKey,
1135 LoadTypesFlag fLoadTypes /*= LoadTypes*/,
1136 ClassLoadLevel level /*=CLASS_LOADED*/,
1137 const InstantiationContext *pInstContext /*=NULL*/)
1139 CONTRACT(TypeHandle)
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);
1156 ClassLoadLevel existingLoadLevel = CLASS_LOAD_BEGIN;
1158 // Lookup in the classes that this class loader knows about
1160 if (pKey->HasInstantiation() && ClassLoader::IsTypicalSharedInstantiation(pKey->GetInstantiation()))
1162 _ASSERTE(pKey->GetModule() == ComputeLoaderModule(pKey));
1163 typeHnd = pKey->GetModule()->LookupFullyCanonicalInstantiation(pKey->GetTypeToken(), &existingLoadLevel);
1166 if (typeHnd.IsNull())
1168 typeHnd = LookupTypeHandleForTypeKey(pKey);
1169 if (!typeHnd.IsNull())
1171 existingLoadLevel = typeHnd.GetLoadLevel();
1172 if (existingLoadLevel >= level)
1173 g_IBCLogger.LogTypeHashTableAccess(&typeHnd);
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)
1183 #ifndef DACCESS_COMPILE
1184 if (typeHnd.IsNull() && pKey->HasInstantiation())
1186 if (!Generics::CheckInstantiation(pKey->GetInstantiation()))
1187 pKey->GetModule()->GetAssembly()->ThrowTypeLoadException(pKey->GetModule()->GetMDImport(), pKey->GetTypeToken(), IDS_CLASSLOAD_INVALIDINSTANTIATION);
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();
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());
1202 Module *pLoaderModule = ComputeLoaderModule(pKey);
1203 RETURN(pLoaderModule->GetClassLoader()->LoadTypeHandleForTypeKey(pKey, typeHnd, level, pInstContext));
1212 void ClassLoader::EnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level)
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); }
1228 #ifndef DACCESS_COMPILE // Nothing to do for the DAC case
1230 if (typeHnd.GetLoadLevel() < level)
1232 #ifdef FEATURE_PREJIT
1233 if (typeHnd.GetLoadLevel() == CLASS_LOAD_UNRESTOREDTYPEKEY)
1235 typeHnd.DoRestoreTypeKey();
1238 if (level > CLASS_LOAD_UNRESTORED)
1240 TypeKey typeKey = typeHnd.GetTypeKey();
1242 Module *pLoaderModule = ComputeLoaderModule(&typeKey);
1243 pLoaderModule->GetClassLoader()->LoadTypeHandleForTypeKey(&typeKey, typeHnd, level);
1247 #endif // DACCESS_COMPILE
1251 void ClassLoader::TryEnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level)
1253 WRAPPER_NO_CONTRACT;
1255 #ifndef DACCESS_COMPILE // Nothing to do for the DAC case
1259 ClassLoader::EnsureLoaded(typeHnd, level);
1263 // Some type may not load successfully. For eg. generic instantiations
1264 // that do not satisfy the constraints of the type arguments.
1266 EX_END_CATCH(RethrowTerminalExceptions);
1268 #endif // DACCESS_COMPILE
1271 // This is separated out to avoid the overhead of C++ exception handling in the non-locking case.
1273 TypeHandle ClassLoader::LookupTypeKeyUnderLock(TypeKey *pKey,
1274 EETypeHashTable *pTable,
1277 WRAPPER_NO_CONTRACT;
1280 // m_AvailableTypesLock has to be taken in cooperative mode to avoid deadlocks during GC
1281 GCX_MAYBE_COOP_NO_THREAD_BROKEN(!IsGCThread());
1283 CrstHolder ch(pLock);
1284 return pTable->GetValue(pKey);
1288 TypeHandle ClassLoader::LookupTypeKey(TypeKey *pKey,
1289 EETypeHashTable *pTable,
1291 BOOL fCheckUnderLock)
1297 PRECONDITION(CheckPointer(pKey));
1298 PRECONDITION(pKey->IsConstructed());
1299 PRECONDITION(CheckPointer(pTable));
1300 PRECONDITION(!fCheckUnderLock || CheckPointer(pLock));
1307 if (fCheckUnderLock)
1309 th = LookupTypeKeyUnderLock(pKey, pTable, pLock);
1313 th = pTable->GetValue(pKey);
1319 #ifdef FEATURE_PREJIT
1321 TypeHandle ClassLoader::LookupInPreferredZapModule(TypeKey *pKey, BOOL fCheckUnderLock)
1327 PRECONDITION(CheckPointer(pKey));
1328 PRECONDITION(pKey->IsConstructed());
1333 // First look for an NGEN'd type in the preferred ngen module
1335 PTR_Module pPreferredZapModule = Module::ComputePreferredZapModule(pKey);
1337 if (pPreferredZapModule != NULL && pPreferredZapModule->HasNativeImage())
1339 th = LookupTypeKey(pKey,
1340 pPreferredZapModule->GetAvailableParamTypes(),
1341 &pPreferredZapModule->GetClassLoader()->m_AvailableTypesLock,
1347 #endif // FEATURE_PREJIT
1351 TypeHandle ClassLoader::LookupInLoaderModule(TypeKey *pKey, BOOL fCheckUnderLock)
1357 PRECONDITION(CheckPointer(pKey));
1358 PRECONDITION(pKey->IsConstructed());
1363 Module *pLoaderModule = ComputeLoaderModule(pKey);
1364 PREFIX_ASSUME(pLoaderModule!=NULL);
1366 return LookupTypeKey(pKey,
1367 pLoaderModule->GetAvailableParamTypes(),
1368 &pLoaderModule->GetClassLoader()->m_AvailableTypesLock,
1374 TypeHandle ClassLoader::LookupTypeHandleForTypeKey(TypeKey *pKey)
1376 WRAPPER_NO_CONTRACT;
1379 // Make an initial lookup without taking any locks.
1380 TypeHandle th = LookupTypeHandleForTypeKeyInner(pKey, FALSE);
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
1392 th = LookupTypeHandleForTypeKeyInner(pKey, TRUE);
1398 TypeHandle ClassLoader::LookupTypeHandleForTypeKeyInner(TypeKey *pKey, BOOL fCheckUnderLock)
1405 PRECONDITION(CheckPointer(pKey));
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())))
1418 return TypeHandle(pKey->GetModule()->LookupTypeDef(pKey->GetTypeToken()));
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
1426 TypeHandle thPZM = LookupInPreferredZapModule(pKey, fCheckUnderLock);
1427 if (!thPZM.IsNull())
1431 #endif // FEATURE_PREJIT
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);
1444 return TypeHandle();
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.
1451 // The possible outcomes are:
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.)
1462 // If it succeeds (returns TRUE), one of the following will occur. Check (*pType)->IsNull() to discriminate.
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!)
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.
1478 BOOL ClassLoader::FindClassModuleThrowing(
1479 const NameHandle * pOriginalName,
1481 mdToken * pmdClassToken,
1483 mdToken * pmdFoundExportedType,
1484 HashedTypeEntry * pFoundEntry,
1485 Module * pLookInThisModuleOnly,
1486 Loader::LoadFlag loadFlag)
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));
1501 NameHandleTable nhTable = nhCaseSensitive; // just to initialize this ...
1503 // Make a copy of the original name which we can modify (to lowercase)
1504 NameHandle localName = *pOriginalName;
1505 NameHandle * pName = &localName;
1507 switch (pName->GetTable())
1509 case nhCaseInsensitive:
1511 #ifndef DACCESS_COMPILE
1512 // GC-type users should only be loading types through tokens.
1514 _ASSERTE(!FORBIDGC_LOADER_USE_ENABLED());
1517 // Use the case insensitive table
1518 nhTable = nhCaseInsensitive;
1520 // Create a low case version of the namespace and name
1521 LPUTF8 pszLowerNameSpace = NULL;
1522 LPUTF8 pszLowerClassName = NULL;
1525 if (pName->GetNameSpace())
1527 allocLen = InternalCasingHelper::InvariantToLower(
1530 pName->GetNameSpace());
1536 pszLowerNameSpace = (LPUTF8)_alloca(allocLen);
1539 *pszLowerNameSpace = '\0';
1541 else if (!InternalCasingHelper::InvariantToLower(
1544 pName->GetNameSpace()))
1550 _ASSERTE(pName->GetName() != NULL);
1551 allocLen = InternalCasingHelper::InvariantToLower(NULL, 0, pName->GetName());
1557 pszLowerClassName = (LPUTF8)_alloca(allocLen);
1558 if (!InternalCasingHelper::InvariantToLower(
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);
1573 #endif // #ifndef DACCESS_COMPILE
1575 case nhCaseSensitive:
1576 nhTable = nhCaseSensitive;
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.
1583 BOOL incomplete = (m_cUnhashedModules > 0);
1587 EEClassHashTable * pTable = NULL;
1588 HashedTypeEntry foundEntry;
1589 BOOL needsToBuildHashtable;
1590 GetClassValue(nhTable, pName, &Data, &pTable, pLookInThisModuleOnly, &foundEntry, loadFlag, needsToBuildHashtable);
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)
1597 *pType = TypeHandle();
1598 HashedTypeEntry::TokenTypeEntry tokenAndModulePair = foundEntry.GetTokenBasedEntryValue();
1599 switch (TypeFromToken(tokenAndModulePair.m_TypeToken))
1602 *pmdClassToken = tokenAndModulePair.m_TypeToken;
1603 *pmdFoundExportedType = mdTokenNil;
1605 case mdtExportedType:
1606 *pmdClassToken = mdTokenNil;
1607 *pmdFoundExportedType = tokenAndModulePair.m_TypeToken;
1613 *ppModule = tokenAndModulePair.m_pModule;
1614 if (pFoundEntry != NULL)
1615 *pFoundEntry = foundEntry;
1620 EEClassHashEntry_t * pBucket = foundEntry.GetClassHashBasedEntryValue();
1622 if (pBucket == NULL)
1624 AvailableClasses_LockHolder lh(this);
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();
1631 #ifndef DACCESS_COMPILE
1632 if (needsToBuildHashtable && (pBucket == NULL) && (m_cUnhashedModules > 0))
1634 _ASSERT(needsToBuildHashtable);
1636 if (nhTable == nhCaseInsensitive)
1638 LazyPopulateCaseInsensitiveHashTables();
1642 // Note: This codepath is only valid for R2R scenarios
1643 LazyPopulateCaseSensitiveHashTables();
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);
1654 // Same check as above, but this time we've checked with the lock so the table will be populated
1655 if (pBucket == NULL)
1657 #if defined(_DEBUG_IMPL) && !defined(DACCESS_COMPILE)
1658 LPCUTF8 szName = pName->GetName();
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));
1667 if (pName->GetTable() == nhCaseInsensitive)
1670 pBucket = PTR_EEClassHashEntry(Data);
1671 Data = pBucket->GetData();
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)
1678 TypeHandle t = TypeHandle::FromPtr(Data);
1679 _ASSERTE(!t.IsNull());
1682 if (pFoundEntry != NULL)
1684 pFoundEntry->SetClassHashBasedEntryValue(pBucket);
1689 // We have a Module/CL
1690 if (!pTable->UncompressModuleAndClassDef(Data,
1694 pmdFoundExportedType))
1696 _ASSERTE(loadFlag != Loader::Load);
1700 *pType = TypeHandle();
1701 if (pFoundEntry != NULL)
1703 pFoundEntry->SetClassHashBasedEntryValue(pBucket);
1706 } // ClassLoader::FindClassModuleThrowing
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,
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;
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;
1738 EX_END_CATCH(SwallowAllExceptions);
1742 #endif // #ifndef DACCESS_COMPILE
1744 // 1024 seems like a good bet at detecting a loop in the type forwarding.
1745 static const UINT32 const_cMaxTypeForwardingChainSize = 1024;
1747 // Does not throw an exception if the type was not found. Use LoadTypeHandleThrowIfFailed()
1748 // instead if you need that.
1752 // Will be set to the 'final' TypeDef bucket if pName->GetTokenType() is mdtBaseType.
1755 ClassLoader::LoadTypeHandleThrowing(
1757 ClassLoadLevel level,
1758 Module * pLookInThisModuleOnly /*=NULL*/)
1760 CONTRACT(TypeHandle) {
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);
1774 Module * pFoundModule = NULL;
1776 HashedTypeEntry foundEntry;
1777 mdExportedType FoundExportedType = mdTokenNil;
1779 UINT32 cLoopIterations = 0;
1781 ClassLoader * pClsLdr = this;
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();
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...
1798 if (!pClsLdr->FindClassModuleThrowing(
1805 pLookInThisModuleOnly,
1806 pName->OKToLoad() ? Loader::Load
1807 : Loader::DontLoad))
1808 { // Didn't find anything, no point looping indefinitely
1811 _ASSERTE(!foundEntry.IsNull());
1813 if (pName->GetTypeToken() == mdtBaseType)
1814 { // We should return the found bucket in the pName
1815 pName->SetBucket(foundEntry);
1818 if (!typeHnd.IsNull())
1819 { // Found the cached value, or a constructedtype
1820 if (typeHnd.GetLoadLevel() < level)
1822 typeHnd = pClsLdr->LoadTypeDefThrowing(
1823 typeHnd.GetModule(),
1825 ClassLoader::ReturnNullIfNotFound,
1826 ClassLoader::PermitUninstDefOrRef, // When loading by name we always permit naked type defs/refs
1827 pName->GetTokenNotToLoad(),
1833 // Found a cl, pModule pair
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)
1840 BOOL fTrustTD = TRUE;
1841 #ifndef DACCESS_COMPILE
1842 CONTRACT_VIOLATION(ThrowsViolation);
1843 BOOL fVerifyTD = FALSE;
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
1848 if ((FoundExportedType != mdTokenNil) && (FoundCl == mdTokenNil))
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
1857 fTrustTD = pFoundModule->GetMDImport()->IsValidToken(FoundCl);
1859 #endif // #ifndef DACCESS_COMPILE
1863 typeHnd = pClsLdr->LoadTypeDefThrowing(
1866 ClassLoader::ReturnNullIfNotFound,
1867 ClassLoader::PermitUninstDefOrRef, // when loading by name we always permit naked type defs/refs
1868 pName->GetTokenNotToLoad(),
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.
1876 if (typeHnd.IsNull() || !CompareNameHandleWithTypeHandleNoThrow(pName, typeHnd))
1878 if (SUCCEEDED(pClsLdr->FindTypeDefByExportedType(
1879 pClsLdr->GetAssembly()->GetManifestImport(),
1881 pFoundModule->GetMDImport(),
1884 typeHnd = pClsLdr->LoadTypeDefThrowing(
1887 ClassLoader::ReturnNullIfNotFound,
1888 ClassLoader::PermitUninstDefOrRef,
1889 pName->GetTokenNotToLoad(),
1894 typeHnd = TypeHandle();
1898 #endif // #ifndef DACCESS_COMPILE
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();
1906 // Reset pName's bucket entry
1907 if (bucket.GetEntryType() == HashedTypeEntry::IsHashedClassEntry && bucket.GetClassHashBasedEntryValue()->GetEncloser())
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()));
1915 pName->SetBucket(HashedTypeEntry());
1918 // Update the class loader for the new module/token pair.
1919 pClsLdr = pFoundModule->GetClassLoader();
1920 pLookInThisModuleOnly = NULL;
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()))
1931 foundEntry.GetClassHashBasedEntryValue()->SetData(typeHnd.AsPtr());
1933 #endif // !DACCESS_COMPILE
1937 } // ClassLoader::LoadTypeHandleThrowing
1940 TypeHandle ClassLoader::LoadPointerOrByrefTypeThrowing(CorElementType typ,
1941 TypeHandle baseType,
1942 LoadTypesFlag fLoadTypes/*=LoadTypes*/,
1943 ClassLoadLevel level/*=CLASS_LOADED*/)
1945 CONTRACT(TypeHandle)
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); }
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)));
1960 TypeKey key(typ, baseType);
1961 RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level));
1965 TypeHandle ClassLoader::LoadNativeValueTypeThrowing(TypeHandle baseType,
1966 LoadTypesFlag fLoadTypes/*=LoadTypes*/,
1967 ClassLoadLevel level/*=CLASS_LOADED*/)
1969 CONTRACT(TypeHandle)
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()); }
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)));
1982 TypeKey key(ELEMENT_TYPE_VALUETYPE, baseType);
1983 RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level));
1987 TypeHandle ClassLoader::LoadFnptrTypeThrowing(BYTE callConv,
1990 LoadTypesFlag fLoadTypes/*=LoadTypes*/,
1991 ClassLoadLevel level/*=CLASS_LOADED*/)
1993 CONTRACT(TypeHandle)
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)));
2006 TypeKey key(callConv, ntypars, inst);
2007 RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level));
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.
2015 TypeHandle ClassLoader::LoadGenericInstantiationThrowing(Module *pModule,
2018 LoadTypesFlag fLoadTypes/*=LoadTypes*/,
2019 ClassLoadLevel level/*=CLASS_LOADED*/,
2020 const InstantiationContext *pInstContext/*=NULL*/,
2021 BOOL fFromNativeImage /*=FALSE*/)
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)
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));
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)));
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.
2045 if (inst.IsEmpty() || ClassLoader::IsTypicalInstantiation(pModule, typeDef, inst))
2047 TypeHandle th = LoadTypeDefThrowing(pModule, typeDef,
2049 PermitUninstDefOrRef,
2050 fLoadTypes == DontLoadTypes ? tdAllTypes : tdNoTypes,
2052 fFromNativeImage ? NULL : &inst);
2053 _ASSERTE(th.GetNumGenericArgs() == inst.GetNumArgs());
2057 if (!fFromNativeImage)
2059 TypeHandle th = ClassLoader::LoadTypeDefThrowing(pModule, typeDef,
2061 PermitUninstDefOrRef,
2062 fLoadTypes == DontLoadTypes ? tdAllTypes : tdNoTypes,
2064 fFromNativeImage ? NULL : &inst);
2065 _ASSERTE(th.GetNumGenericArgs() == inst.GetNumArgs());
2068 TypeKey key(pModule, typeDef, inst);
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))
2077 RETURN(ClassLoader::LoadCanonicalGenericInstantiation(&key, fLoadTypes, level));
2081 RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level, pInstContext));
2084 // For non-nested classes, gets the ExportedType name and finds the corresponding
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.
2093 HRESULT ClassLoader::FindTypeDefByExportedType(IMDInternalImport *pCTImport, mdExportedType mdCurrent,
2094 IMDInternalImport *pTDImport, mdTypeDef *mtd)
2107 LPCSTR szcNameSpace;
2111 IfFailRet(pCTImport->GetExportedTypeProps(
2119 if ((TypeFromToken(mdImpl) == mdtExportedType) &&
2120 (mdImpl != mdExportedTypeNil)) {
2121 // mdCurrent is a nested ExportedType
2122 IfFailRet(FindTypeDefByExportedType(pCTImport, mdImpl, pTDImport, mtd));
2124 // Get TypeDef token for this nested type
2125 return pTDImport->FindTypeDef(szcNameSpace, szcName, *mtd, mtd);
2128 // Get TypeDef token for this top-level type
2129 return pTDImport->FindTypeDef(szcNameSpace, szcName, mdTokenNil, mtd);
2132 #ifndef DACCESS_COMPILE
2134 VOID ClassLoader::CreateCanonicallyCasedKey(LPCUTF8 pszNameSpace, LPCUTF8 pszName, __out LPUTF8 *ppszOutNameSpace, __out LPUTF8 *ppszOutName)
2141 INJECT_FAULT(COMPlusThrowOM(););
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);
2155 INT32 iNameLength = InternalCasingHelper::InvariantToLowerNoThrow(NULL, 0, pszName);
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())
2167 ThrowHR(COR_E_OVERFLOW);
2170 AllocMemHolder<char> pszOutNameSpace (GetAssembly()->GetHighFrequencyHeap()->AllocMem(allocSize));
2171 *ppszOutNameSpace = pszOutNameSpace;
2175 **ppszOutNameSpace = '\0';
2179 if (!InternalCasingHelper::InvariantToLowerNoThrow(*ppszOutNameSpace, iNSLength, pszNameSpace))
2185 *ppszOutName = *ppszOutNameSpace + iNSLength;
2187 if (!InternalCasingHelper::InvariantToLowerNoThrow(*ppszOutName, iNameLength, pszName))
2192 pszOutNameSpace.SuppressRelease();
2196 #endif // #ifndef DACCESS_COMPILE
2200 // Return a class that is already loaded
2201 // Only for type refs and type defs (not type specs)
2204 TypeHandle ClassLoader::LookupTypeDefOrRefInModule(Module *pModule, mdToken cl, ClassLoadLevel *pLoadLevel)
2206 CONTRACT(TypeHandle)
2212 PRECONDITION(CheckPointer(pModule));
2213 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2218 BAD_FORMAT_NOTHROW_ASSERT((TypeFromToken(cl) == mdtTypeRef ||
2219 TypeFromToken(cl) == mdtTypeDef ||
2220 TypeFromToken(cl) == mdtTypeSpec));
2222 TypeHandle typeHandle;
2224 if (TypeFromToken(cl) == mdtTypeDef)
2225 typeHandle = pModule->LookupTypeDef(cl, pLoadLevel);
2226 else if (TypeFromToken(cl) == mdtTypeRef)
2228 typeHandle = pModule->LookupTypeRef(cl);
2230 if (pLoadLevel && !typeHandle.IsNull())
2232 *pLoadLevel = typeHandle.GetLoadLevel();
2239 DomainAssembly *ClassLoader::GetDomainAssembly()
2241 WRAPPER_NO_CONTRACT;
2242 return GetAssembly()->GetDomainAssembly();
2245 #ifndef DACCESS_COMPILE
2248 // Free all modules associated with this loader
2250 void ClassLoader::FreeModules()
2258 DISABLED(FORBID_FAULT); //Lots of crud to clean up to make this work
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();
2267 // Have the module free its various tables and some of the EEClass links
2268 if (i.GetModule() != pManifest)
2269 i.GetModule()->Destruct();
2272 // Now do the manifest module.
2273 pManifest->Destruct();
2278 ClassLoader::~ClassLoader()
2286 DISABLED(FORBID_FAULT); //Lots of crud to clean up to make this work
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;
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",
2318 // m_pAvailableClasses->m_dwDebugMemory,
2319 // m_dwFieldDescData,
2320 // m_dwMethodDescData,
2322 // m_dwInterfaceMapSize,
2323 // m_dwMethodTableSize,
2325 // m_dwStaticFieldData,
2326 // m_dwDebugMethods,
2327 // m_dwDebugFieldDescs,
2328 // m_dwDebugClasses,
2329 // m_dwDebugDuplicateInterfaceSlots,
2335 m_UnresolvedClassLock.Destroy();
2336 m_AvailableClassLock.Destroy();
2337 m_AvailableTypesLock.Destroy();
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)
2358 m_pAssembly = pAssembly;
2360 m_pUnresolvedClassHash = NULL;
2361 m_cUnhashedModules = 0;
2364 m_dwDebugMethods = 0;
2365 m_dwDebugFieldDescs = 0;
2366 m_dwDebugClasses = 0;
2367 m_dwDebugDuplicateInterfaceSlots = 0;
2369 m_dwInterfaceMapSize = 0;
2370 m_dwMethodTableSize = 0;
2372 m_dwStaticFieldData = 0;
2373 m_dwFieldDescData = 0;
2374 m_dwMethodDescData = 0;
2375 m_dwEEClassData = 0;
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)
2389 STANDARD_VM_CONTRACT;
2391 m_pUnresolvedClassHash = PendingTypeLoadTable::Create(GetAssembly()->GetLowFrequencyHeap(),
2392 UNRESOLVED_CLASS_HASH_BUCKETS,
2395 m_UnresolvedClassLock.Init(CrstUnresolvedClassLock);
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(
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));
2413 CorTypeInfo::CheckConsistency();
2418 #endif // #ifndef DACCESS_COMPILE
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)
2431 CONTRACT(TypeHandle)
2433 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2434 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
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));
2445 if (TypeFromToken(typeDefOrRefOrSpec) == mdtTypeSpec)
2448 PCCOR_SIGNATURE pSig;
2450 IMDInternalImport *pInternalImport = pModule->GetMDImport();
2451 if (FAILED(pInternalImport->GetTypeSpecFromToken(typeDefOrRefOrSpec, &pSig, &cSig)))
2453 #ifndef DACCESS_COMPILE
2454 if (fNotFoundAction == ThrowIfNotFound)
2456 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, typeDefOrRefOrSpec, IDS_CLASSLOAD_BADFORMAT);
2458 #endif //!DACCESS_COMPILE
2459 RETURN (TypeHandle());
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);
2473 RETURN (LoadTypeDefOrRefThrowing(pModule, typeDefOrRefOrSpec,
2476 ((fLoadTypes == LoadTypes) ? tdNoTypes : tdAllTypes),
2479 } // ClassLoader::LoadTypeDefOrRefOrSpecThrowing
2481 // Given a token specifying a typeDef, and a module in which to
2482 // interpret that token, find or load the corresponding type handle.
2486 TypeHandle ClassLoader::LoadTypeDefThrowing(Module *pModule,
2488 NotFoundAction fNotFoundAction /* = ThrowIfNotFound */ ,
2489 PermitUninstantiatedFlag fUninstantiated /* = FailIfUninstDefOrRef */,
2490 mdToken tokenNotToLoad,
2491 ClassLoadLevel level,
2492 Instantiation * pTargetInstantiation)
2495 CONTRACT(TypeHandle)
2497 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2498 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
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()));
2507 POSTCONDITION(CheckPointer(RETVAL, NameHandle::OKToLoad(typeDef, tokenNotToLoad) && (fNotFoundAction == ThrowIfNotFound) ? NULL_NOT_OK : NULL_OK));
2508 POSTCONDITION(RETVAL.IsNull() || RETVAL.GetCl() == typeDef);
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())
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);
2526 if (existingLoadLevel >= level)
2530 IMDInternalImport *pInternalImport = pModule->GetMDImport();
2532 #ifndef DACCESS_COMPILE
2533 if (typeHnd.IsNull() && pTargetInstantiation != NULL)
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);
2539 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, typeDef, IDS_CLASSLOAD_BADFORMAT);
2540 DWORD nGenericClassParams = pInternalImport->EnumGetCount(&hEnumGenericPars);
2541 pInternalImport->EnumClose(&hEnumGenericPars);
2543 if (pTargetInstantiation->GetNumArgs() != nGenericClassParams)
2544 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, typeDef, IDS_CLASSLOAD_TYPEWRONGNUMGENERICARGS);
2548 if (IsNilToken(typeDef) || TypeFromToken(typeDef) != mdtTypeDef || !pInternalImport->IsValidToken(typeDef) )
2550 LOG((LF_CLASSLOADER, LL_INFO10, "Bogus class token to load: 0x%08x\n", typeDef));
2551 typeHnd = TypeHandle();
2555 // *****************************************************************************
2557 // Important invariant:
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.
2566 // Not found - try to load it unless we are told not to
2568 #ifndef DACCESS_COMPILE
2569 if ( !NameHandle::OKToLoad(typeDef, tokenNotToLoad) )
2571 typeHnd = TypeHandle();
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
2579 _ASSERTE(!FORBIDGC_LOADER_USE_ENABLED());
2583 if (pModule->IsReflection())
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();
2589 // Avoid infinite recursion
2590 if (tokenNotToLoad != tdAllAssemblies)
2592 AppDomain* pDomain = SystemDomain::GetCurrentDomain();
2597 if (FAILED(pInternalImport->GetNameOfTypeDef(typeDef, &className, &nameSpace)))
2599 LOG((LF_CLASSLOADER, LL_INFO10, "Bogus TypeDef record while loading: 0x%08x\n", typeDef));
2600 typeHnd = TypeHandle();
2604 MAKE_FULL_PATH_ON_STACK_UTF8(pszFullName,
2608 ASSEMBLYREF asmRef = NULL;
2609 DomainAssembly *pDomainAssembly = NULL;
2610 GCPROTECT_BEGIN(asmRef);
2612 pDomainAssembly = pDomain->RaiseTypeResolveEventThrowing(
2613 pModule->GetAssembly()->GetDomainAssembly(),
2614 pszFullName, &asmRef);
2618 _ASSERTE(pDomainAssembly != NULL);
2619 if (pDomainAssembly->GetAssembly()->GetLoaderAllocator()->IsCollectible())
2621 if (!pModule->GetLoaderAllocator()->IsCollectible())
2623 LOG((LF_CLASSLOADER, LL_INFO10, "Bad result from TypeResolveEvent while loader TypeDef record: 0x%08x\n", typeDef));
2624 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
2627 pModule->GetLoaderAllocator()->EnsureReference(pDomainAssembly->GetAssembly()->GetLoaderAllocator());
2631 if (pDomainAssembly != NULL)
2633 Assembly *pAssembly = pDomainAssembly->GetAssembly();
2635 NameHandle name(nameSpace, className);
2636 name.SetTypeToken(pModule, typeDef);
2637 name.SetTokenNotToLoad(tdAllAssemblies);
2638 typeHnd = pAssembly->GetLoader()->LoadTypeHandleThrowing(&name, level);
2645 TypeKey typeKey(pModule, typeDef);
2646 typeHnd = pModule->GetClassLoader()->LoadTypeHandleForTypeKey(&typeKey,
2651 #endif // !DACCESS_COMPILE
2654 #ifndef DACCESS_COMPILE
2655 if ((fUninstantiated == FailIfUninstDefOrRef) && !typeHnd.IsNull() && typeHnd.IsGenericTypeDefinition())
2657 typeHnd = TypeHandle();
2660 if ((fNotFoundAction == ThrowIfNotFound) && typeHnd.IsNull() && (tokenNotToLoad != tdAllTypes))
2662 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(),
2664 IDS_CLASSLOAD_GENERAL);
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
2677 TypeHandle ClassLoader::LoadTypeDefOrRefThrowing(Module *pModule,
2678 mdToken typeDefOrRef,
2679 NotFoundAction fNotFoundAction /* = ThrowIfNotFound */ ,
2680 PermitUninstantiatedFlag fUninstantiated /* = FailIfUninstDefOrRef */,
2681 mdToken tokenNotToLoad,
2682 ClassLoadLevel level)
2685 CONTRACT(TypeHandle)
2687 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2688 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
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()));
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());
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
2709 BOOLEAN bReturnNullOkWhenNoResolutionScope = false;
2710 if (fNotFoundAction == ThrowButNullV11McppWorkaround)
2712 bReturnNullOkWhenNoResolutionScope = true;
2713 fNotFoundAction = ThrowIfNotFound;
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())
2721 if (existingLoadLevel < level)
2723 pModule = typeHnd.GetModule();
2724 typeDefOrRef = typeHnd.GetCl();
2728 if (!typeHnd.IsNull() && existingLoadLevel >= level)
2730 // perform the check that it's not an uninstantiated TypeDef/TypeRef
2731 // being used inappropriately.
2732 if (!((fUninstantiated == FailIfUninstDefOrRef) && !typeHnd.IsNull() && typeHnd.IsGenericTypeDefinition()))
2739 // otherwise try to resolve the TypeRef and/or load the corresponding TypeDef
2740 IMDInternalImport *pInternalImport = pModule->GetMDImport();
2741 mdToken tokType = TypeFromToken(typeDefOrRef);
2743 if (IsNilToken(typeDefOrRef) || ((tokType != mdtTypeDef)&&(tokType != mdtTypeRef))
2744 || !pInternalImport->IsValidToken(typeDefOrRef) )
2747 LOG((LF_CLASSLOADER, LL_INFO10, "Bogus class token to load: 0x%08x\n", typeDefOrRef));
2750 typeHnd = TypeHandle();
2753 else if (tokType == mdtTypeRef)
2755 BOOL fNoResolutionScope;
2756 Module *pFoundModule = Assembly::FindModuleByTypeRef(pModule, typeDefOrRef,
2757 tokenNotToLoad==tdAllTypes ?
2760 &fNoResolutionScope);
2762 if (pFoundModule != NULL)
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
2768 LPCUTF8 pszNameSpace;
2769 LPCUTF8 pszClassName;
2770 if (FAILED(pInternalImport->GetNameOfTypeRef(
2775 typeHnd = TypeHandle();
2779 if (fNoResolutionScope)
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(),
2788 ClassLoader::ReturnNullIfNotFound,
2789 tokenNotToLoad==tdAllTypes ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes,
2792 if(typeHnd.IsNull() && bReturnNullOkWhenNoResolutionScope)
2794 fNotFoundAction = ReturnNullIfNotFound;
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);
2809 #ifndef DACCESS_COMPILE
2810 if (!(typeHnd.IsNull()))
2811 pModule->StoreTypeRef(typeDefOrRef, typeHnd);
2817 // This is the mdtTypeDef case...
2818 typeHnd = LoadTypeDefThrowing(pModule, typeDefOrRef,
2825 TypeHandle thRes = typeHnd;
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();
2832 // perform the check to throw when the thing is not found
2833 if ((fNotFoundAction == ThrowIfNotFound) && thRes.IsNull() && (tokenNotToLoad != tdAllTypes))
2835 #ifndef DACCESS_COMPILE
2836 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(),
2838 IDS_CLASSLOAD_GENERAL);
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.
2859 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2860 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2862 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2863 PRECONDITION(CheckPointer(pTypeRefModule));
2868 // It's a TypeDef already
2869 if (TypeFromToken(typeRefToken) == mdtTypeDef)
2871 if (ppTypeDefModule != NULL)
2872 *ppTypeDefModule = pTypeRefModule;
2873 if (pTypeDefToken != NULL)
2874 *pTypeDefToken = typeRefToken;
2878 TypeHandle typeHnd = pTypeRefModule->LookupTypeRef(typeRefToken);
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))
2884 if (ppTypeDefModule != NULL)
2885 *ppTypeDefModule = typeHnd.GetModule();
2886 if (pTypeDefToken != NULL)
2887 *pTypeDefToken = typeHnd.GetCl();
2891 BOOL fNoResolutionScope; //not used
2892 Module * pFoundRefModule = Assembly::FindModuleByTypeRef(
2896 &fNoResolutionScope);
2898 if (pFoundRefModule == NULL)
2899 { // We didn't find the TypeRef anywhere
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))
2907 if (typeHnd.GetModule() != pFoundRefModule)
2909 *pfUsesTypeForwarder = TRUE;
2912 if (ppTypeDefModule != NULL)
2913 *ppTypeDefModule = typeHnd.GetModule();
2914 if (pTypeDefToken != NULL)
2915 *pTypeDefToken = typeHnd.GetCl();
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)))
2926 NameHandle nameHandle(pTypeRefModule, typeRefToken);
2927 nameHandle.SetName(pszNameSpace, pszClassName);
2928 if (loadFlag != Loader::Load)
2930 nameHandle.SetTokenNotToLoad(tdAllTypes);
2933 return ResolveNameToTypeDefThrowing(pFoundRefModule, &nameHandle, ppTypeDefModule, pTypeDefToken, loadFlag, pfUsesTypeForwarder);
2938 ClassLoader::ResolveNameToTypeDefThrowing(
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.
2948 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2949 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2951 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2952 PRECONDITION(CheckPointer(pModule));
2953 PRECONDITION(CheckPointer(pName));
2959 mdToken foundTypeDef;
2960 Module * pFoundModule;
2961 mdExportedType foundExportedType;
2962 Module * pSourceModule = pModule;
2963 Module * pFoundRefModule = pModule;
2965 for (UINT32 nTypeForwardingChainSize = 0; nTypeForwardingChainSize < const_cMaxTypeForwardingChainSize; nTypeForwardingChainSize++)
2967 foundTypeDef = mdTokenNil;
2968 pFoundModule = NULL;
2969 foundExportedType = mdTokenNil;
2970 if (!pSourceModule->GetClassLoader()->FindClassModuleThrowing(
2977 pSourceModule->IsReflection() ? NULL : pSourceModule,
2983 // Type is already loaded and cached in the loader's by-name table
2984 if (!typeHnd.IsNull())
2986 if ((typeHnd.GetModule() != pFoundRefModule) && (pfUsesTypeForwarder != NULL))
2987 { // We followed at least one type forwarder to resolve the type
2988 *pfUsesTypeForwarder = TRUE;
2990 if (ppTypeDefModule != NULL)
2991 *ppTypeDefModule = typeHnd.GetModule();
2992 if (pTypeDefToken != NULL)
2993 *pTypeDefToken = typeHnd.GetCl();
2997 if (pFoundModule == NULL)
2998 { // Module was probably not loaded
3002 if (TypeFromToken(foundExportedType) != mdtExportedType)
3003 { // It's not exported type
3004 _ASSERTE(foundExportedType == mdTokenNil);
3006 if ((pFoundModule != pFoundRefModule) && (pfUsesTypeForwarder != NULL))
3007 { // We followed at least one type forwarder to resolve the type
3008 *pfUsesTypeForwarder = TRUE;
3010 if (pTypeDefToken != NULL)
3011 *pTypeDefToken = foundTypeDef;
3012 if (ppTypeDefModule != NULL)
3013 *ppTypeDefModule = pFoundModule;
3016 // It's exported type
3018 // Repeat the search for the type in the newly found module
3019 pSourceModule = pFoundModule;
3021 // Type forwarding chain is too long
3023 } // ClassLoader::ResolveTokenToTypeDefThrowing
3025 #ifndef DACCESS_COMPILE
3027 //---------------------------------------------------------------------------------------
3031 ClassLoader::GetEnclosingClassThrowing(
3032 IMDInternalImport * pInternalImport,
3035 mdTypeDef * tdEnclosing)
3041 INJECT_FAULT(COMPlusThrowOM());
3046 _ASSERTE(tdEnclosing);
3047 *tdEnclosing = mdTypeDefNil;
3049 HRESULT hr = pInternalImport->GetNestedClassProps(cl, tdEnclosing);
3053 if (hr != CLDB_E_RECORD_NOTFOUND)
3058 if (TypeFromToken(*tdEnclosing) != mdtTypeDef)
3059 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_ENCLOSING);
3060 } // ClassLoader::GetEnclosingClassThrowing
3063 //---------------------------------------------------------------------------------------
3065 // Load a parent type or implemented interface type.
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>
3076 ClassLoader::LoadApproxTypeThrowing(
3079 SigPointer * pSigInst,
3080 const SigTypeContext * pClassTypeContext)
3082 CONTRACT(TypeHandle)
3086 INJECT_FAULT(COMPlusThrowOM());
3088 PRECONDITION(CheckPointer(pSigInst, NULL_OK));
3089 PRECONDITION(CheckPointer(pModule));
3090 POSTCONDITION(CheckPointer(RETVAL));
3094 IMDInternalImport * pInternalImport = pModule->GetMDImport();
3096 if (TypeFromToken(tok) == mdtTypeSpec)
3099 PCCOR_SIGNATURE pSig;
3100 IfFailThrowBF(pInternalImport->GetTypeSpecFromToken(tok, &pSig, &cSig), BFA_METADATA_CORRUPT, pModule);
3102 SigPointer sigptr = SigPointer(pSig, cSig);
3103 CorElementType type = ELEMENT_TYPE_END;
3104 IfFailThrowBF(sigptr.GetElemType(&type), BFA_BAD_SIGNATURE, pModule);
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);
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);
3113 if (type != ELEMENT_TYPE_CLASS)
3114 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, tok, IDS_CLASSLOAD_GENERAL);
3116 mdToken genericTok = 0;
3117 IfFailThrowBF(sigptr.GetToken(&genericTok), BFA_BAD_SIGNATURE, pModule);
3118 IfFailThrowBF(sigptr.GetData(NULL), BFA_BAD_SIGNATURE, pModule);
3120 if (pSigInst != NULL)
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,
3128 TypeHandle genericTypeTH = LoadTypeDefOrRefThrowing(
3131 ClassLoader::ThrowIfNotFound,
3132 ClassLoader::PermitUninstDefOrRef,
3134 CLASS_LOAD_APPROXPARENTS);
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())
3144 RETURN genericTypeTH;
3148 // approxTypes, i.e. approximate reference types by Object, i.e. load the canonical type
3149 RETURN SigPointer(pSig, cSig).GetTypeHandleThrowing(
3152 ClassLoader::LoadTypes,
3153 CLASS_LOAD_APPROXPARENTS,
3154 TRUE /*dropGenericArgumentLevel*/);
3159 if (pSigInst != NULL)
3160 *pSigInst = SigPointer();
3161 RETURN LoadTypeDefOrRefThrowing(
3164 ClassLoader::ThrowIfNotFound,
3165 ClassLoader::FailIfUninstDefOrRef,
3167 CLASS_LOAD_APPROXPARENTS);
3169 } // ClassLoader::LoadApproxTypeThrowing
3172 //---------------------------------------------------------------------------------------
3176 ClassLoader::LoadApproxParentThrowing(
3179 SigPointer * pParentInst,
3180 const SigTypeContext * pClassTypeContext)
3186 INJECT_FAULT(COMPlusThrowOM());
3191 mdTypeRef crExtends;
3192 MethodTable * pParentMethodTable = NULL;
3193 TypeHandle parentType;
3195 Assembly * pAssembly = pModule->GetAssembly();
3196 IMDInternalImport * pInternalImport = pModule->GetMDImport();
3198 // Initialize the return value;
3199 *pParentInst = SigPointer();
3201 // Now load all dependencies of this class
3202 if (FAILED(pInternalImport->GetTypeDefProps(
3204 &dwAttrClass, // AttrClass
3207 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
3210 if (RidFromToken(crExtends) != mdTokenNil)
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);
3217 pParentMethodTable = parentType.GetMethodTable();
3219 if (pParentMethodTable == NULL)
3220 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_PARENTNULL);
3222 // cannot inherit from an interface
3223 if (pParentMethodTable->IsInterface())
3224 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_PARENTINTERFACE);
3226 if (IsTdInterface(dwAttrClass))
3228 // Interfaces must extend from Object
3229 if (! pParentMethodTable->IsObjectClass())
3230 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_INTERFACEOBJECT);
3234 return pParentMethodTable;
3235 } // ClassLoader::LoadApproxParentThrowing
3237 // Perform a single phase of class loading
3238 // It is the caller's responsibility to lock
3240 TypeHandle ClassLoader::DoIncrementalLoad(TypeKey *pTypeKey, TypeHandle typeHnd, ClassLoadLevel currentLevel)
3245 PRECONDITION(CheckPointer(pTypeKey));
3246 PRECONDITION(currentLevel >= CLASS_LOAD_BEGIN && currentLevel < CLASS_LOADED);
3252 if (LoggingOn(LF_CLASSLOADER, LL_INFO10000))
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]));
3260 // Level is BEGIN if and only if type handle is null
3261 CONSISTENCY_CHECK((currentLevel == CLASS_LOAD_BEGIN) == typeHnd.IsNull());
3263 switch (currentLevel)
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 :
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;
3279 case CLASS_LOAD_UNRESTOREDTYPEKEY :
3280 #ifdef FEATURE_PREJIT
3281 typeHnd.DoRestoreTypeKey();
3285 // Attain level CLASS_LOAD_APPROXPARENTS, starting with unrestored class
3286 case CLASS_LOAD_UNRESTORED :
3287 #ifdef FEATURE_PREJIT
3289 CONSISTENCY_CHECK(!typeHnd.IsRestored_NoLogging());
3290 if (typeHnd.IsTypeDesc())
3291 typeHnd.AsTypeDesc()->Restore();
3293 typeHnd.AsMethodTable()->Restore();
3298 // Attain level CLASS_LOAD_EXACTPARENTS
3299 case CLASS_LOAD_APPROXPARENTS :
3300 if (!typeHnd.IsTypeDesc())
3302 LoadExactParents(typeHnd.AsMethodTable());
3306 case CLASS_LOAD_EXACTPARENTS :
3307 case CLASS_DEPENDENCIES_LOADED :
3313 if (typeHnd.GetLoadLevel() >= CLASS_LOAD_EXACTPARENTS)
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)
3328 CONTRACT(TypeHandle)
3331 PRECONDITION(CheckPointer(pKey));
3333 POSTCONDITION(RETVAL.CheckMatchesKey(pKey));
3338 TypeHandle typeHnd = TypeHandle();
3340 if (!pKey->IsConstructed())
3342 typeHnd = CreateTypeHandleForTypeDefThrowing(pKey->GetModule(),
3343 pKey->GetTypeToken(),
3344 pKey->GetInstantiation(),
3347 else if (pKey->HasInstantiation())
3349 if (IsCanonicalGenericInstantiation(pKey->GetInstantiation()))
3351 typeHnd = CreateTypeHandleForTypeDefThrowing(pKey->GetModule(),
3352 pKey->GetTypeToken(),
3353 pKey->GetInstantiation(),
3358 typeHnd = CreateTypeHandleForNonCanonicalGenericInstantiation(pKey,
3361 #if defined(_DEBUG) && !defined(CROSSGEN_COMPILE)
3362 if (Nullable::IsNullableType(typeHnd))
3363 Nullable::CheckFieldOffsets(typeHnd);
3366 else if (pKey->GetKind() == ELEMENT_TYPE_FNPTR)
3368 Module *pLoaderModule = ComputeLoaderModule(pKey);
3369 pLoaderModule->GetLoaderAllocator()->EnsureInstantiation(NULL, Instantiation(pKey->GetRetAndArgTypes(), pKey->GetNumArgs() + 1));
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)));
3375 typeHnd = TypeHandle(new(mem) FnPtrTypeDesc(pKey->GetCallConv(), numArgs, pKey->GetRetAndArgTypes()));
3379 Module *pLoaderModule = ComputeLoaderModule(pKey);
3380 PREFIX_ASSUME(pLoaderModule!=NULL);
3382 CorElementType kind = pKey->GetKind();
3383 TypeHandle paramType = pKey->GetElementType();
3384 MethodTable *templateMT;
3386 // Create a new type descriptor and insert into constructed type table
3387 if (CorTypeInfo::IsArray(kind))
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);
3393 // Arrays of BYREFS not allowed
3394 if (paramType.GetInternalCorElementType() == ELEMENT_TYPE_BYREF)
3396 ThrowTypeLoadException(pKey, IDS_CLASSLOAD_BYREFARRAY);
3399 // Arrays of ByRefLike types not allowed
3400 MethodTable* pMT = paramType.GetMethodTable();
3403 if (pMT->IsByRefLike())
3405 ThrowTypeLoadException(pKey, IDS_CLASSLOAD_BYREFLIKEARRAY);
3409 // We really don't need this check anymore.
3410 if (rank > MAX_RANK)
3412 ThrowTypeLoadException(pKey, IDS_CLASSLOAD_RANK_TOOLARGE);
3415 templateMT = pLoaderModule->CreateArrayMethodTable(paramType, kind, rank, pamTracker);
3417 BYTE* mem = (BYTE*) pamTracker->Track(pLoaderModule->GetAssembly()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(ArrayTypeDesc))));
3418 typeHnd = TypeHandle(new(mem) ArrayTypeDesc(templateMT, paramType));
3422 // no parameterized type allowed on a reference
3423 if (paramType.GetInternalCorElementType() == ELEMENT_TYPE_BYREF ||
3424 paramType.GetInternalCorElementType() == ELEMENT_TYPE_TYPEDBYREF)
3426 ThrowTypeLoadException(pKey, IDS_CLASSLOAD_GENERAL);
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.
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);
3439 BYTE* mem = (BYTE*) pamTracker->Track(pLoaderModule->GetAssembly()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(ParamTypeDesc))));
3440 typeHnd = TypeHandle(new(mem) ParamTypeDesc(kind, templateMT, paramType));
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
3452 TypeHandle ClassLoader::PublishType(TypeKey *pTypeKey, TypeHandle typeHnd)
3457 PRECONDITION(CheckPointer(typeHnd));
3458 PRECONDITION(CheckPointer(pTypeKey));
3460 // Key must match that of the handle
3461 PRECONDITION(typeHnd.CheckMatchesKey(pTypeKey));
3463 // Don't publish array template method tables; these are accessed only through type descs
3464 PRECONDITION(typeHnd.IsTypeDesc() || !typeHnd.AsMethodTable()->IsArray());
3469 if (pTypeKey->IsConstructed())
3471 Module *pLoaderModule = ComputeLoaderModule(pTypeKey);
3472 EETypeHashTable *pTable = pLoaderModule->GetAvailableParamTypes();
3474 // m_AvailableTypesLock has to be taken in cooperative mode to avoid deadlocks during GC
3477 CrstHolder ch(&pLoaderModule->GetClassLoader()->m_AvailableTypesLock);
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())
3484 pTable->InsertValue(typeHnd);
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())
3490 CorElementType kind = pTypeKey->GetKind();
3491 MethodTable *typeHandleMethodTable = typeHnd.GetMethodTable();
3492 if ((typeHandleMethodTable != NULL) && (typeHandleMethodTable->GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator()))
3494 _ASSERTE(!"MethodTable of type loaded into CoreLib during NGen is not from CoreLib!");
3496 if ((kind != ELEMENT_TYPE_FNPTR) && (kind != ELEMENT_TYPE_VAR) && (kind != ELEMENT_TYPE_MVAR))
3498 if ((kind == ELEMENT_TYPE_SZARRAY) || (kind == ELEMENT_TYPE_ARRAY) || (kind == ELEMENT_TYPE_BYREF) || (kind == ELEMENT_TYPE_PTR) || (kind == ELEMENT_TYPE_VALUETYPE))
3500 // Check to ensure param value is also part of CoreLib.
3501 if (pTypeKey->GetElementType().GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator())
3503 _ASSERTE(!"Param value of type key used to load type during NGEN not located within CoreLib yet type is placed into CoreLib");
3506 else if (kind == ELEMENT_TYPE_FNPTR)
3508 // Check to ensure the parameter types of fnptr are in CoreLib
3509 for (DWORD i = 0; i <= pTypeKey->GetNumArgs(); i++)
3511 if (pTypeKey->GetRetAndArgTypes()[i].GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator())
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");
3517 else if (kind == ELEMENT_TYPE_CLASS)
3519 // Check to ensure that the generic parameters are all within CoreLib
3520 for (DWORD i = 0; i < pTypeKey->GetNumGenericArgs(); i++)
3522 if (pTypeKey->GetInstantiation()[i].GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator())
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");
3530 // Should not be able to get here
3531 _ASSERTE(!"Unknown type key type");
3539 Module *pModule = pTypeKey->GetModule();
3540 mdTypeDef typeDef = pTypeKey->GetTypeToken();
3542 // m_AvailableTypesLock has to be taken in cooperative mode to avoid deadlocks during GC
3545 CrstHolder ch(&pModule->GetClassLoader()->m_AvailableTypesLock);
3547 // ! We cannot fail after this point.
3548 CANNOTTHROWCOMPLUSEXCEPTION();
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())
3556 MethodTable *pMT = typeHnd.AsMethodTable();
3558 MethodTable::IntroducedMethodIterator it(pMT);
3559 for (; it.IsValid(); it.Next())
3561 MethodDesc * pMD = it.GetMethodDesc();
3562 CONSISTENCY_CHECK(pMD != NULL && pMD->GetMethodTable() == pMT);
3563 if (!pMD->IsUnboxingStub())
3565 pModule->EnsuredStoreMethodDef(pMD->GetMemberDef(), pMD);
3569 ApproxFieldDescIterator fdIterator(pMT, ApproxFieldDescIterator::ALL_FIELDS);
3572 while ((pFD = fdIterator.Next()) != NULL)
3574 if (pFD->GetEnclosingMethodTable() == pMT)
3576 pModule->EnsuredStoreFieldDef(pFD->GetMemberDef(), pFD);
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);
3587 // Notify profiler and debugger that a type load has completed
3588 // Also adjust perf counters
3590 void ClassLoader::Notify(TypeHandle typeHnd)
3595 PRECONDITION(CheckPointer(typeHnd));
3599 LOG((LF_CLASSLOADER, LL_INFO1000, "Notify: %p %s\n", typeHnd.AsPtr(), typeHnd.IsTypeDesc() ? "typedesc" : typeHnd.AsMethodTable()->GetDebugClassName()));
3601 if (typeHnd.IsTypeDesc())
3604 MethodTable * pMT = typeHnd.AsMethodTable();
3606 #ifdef PROFILING_SUPPORTED
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:
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)
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));
3624 // Profiler can turn off TrackClasses during the Started() callback. Need to
3625 // retest the flag here.
3627 if (CORProfilerTrackClasses())
3629 LOG((LF_CLASSLOADER, LL_INFO1000, "Notifying profiler of Finished1 %p %s\n", pMT, pMT->GetDebugClassName()));
3630 g_profControlBlock.pProfInterface->ClassLoadFinished(TypeHandleToClassID(typeHnd),
3636 #endif //PROFILING_SUPPORTED
3638 g_IBCLogger.LogMethodTableAccess(pMT);
3640 if (pMT->IsTypicalTypeDefinition())
3642 LOG((LF_CLASSLOADER, LL_INFO100, "Successfully loaded class %s\n", pMT->GetDebugClassName()));
3644 #ifdef DEBUGGING_SUPPORTED
3646 Module * pModule = pMT->GetModule();
3647 // Update metadata for dynamic module.
3648 pModule->UpdateDynamicMetadataIfNeeded();
3651 if (CORDebuggerAttached())
3653 LOG((LF_CORDB, LL_EVERYTHING, "NotifyDebuggerLoad clsload 2239 class %s\n", pMT->GetDebugClassName()));
3654 typeHnd.NotifyDebuggerLoad(NULL, FALSE);
3656 #endif // DEBUGGING_SUPPORTED
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)
3671 LOADS_TYPE(targetLevel);
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)
3680 BOOL fBailed = FALSE;
3681 typeHnd.DoFullyLoad(NULL, CLASS_DEPENDENCIES_LOADED, NULL, &fBailed, pInstContext);
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)
3688 DFLPendingList pendingList;
3689 BOOL fBailed = FALSE;
3691 typeHnd.DoFullyLoad(NULL, CLASS_LOADED, &pendingList, &fBailed, pInstContext);
3694 // In the case of a circular dependency, one or more types will have
3695 // had their promotions deferred.
3697 // If we got to this point, all checks have successfully passed on
3698 // the transitive closure (otherwise, DoFullyLoad would have thrown.)
3700 // So we can go ahead and mark everyone as fully loaded.
3702 UINT numTH = pendingList.Count();
3703 TypeHandle *pTHPending = pendingList.Table();
3704 for (UINT i = 0; i < numTH; i++)
3706 // NOTE: It is possible for duplicates to appear in this list so
3707 // don't do any operation that isn't idempodent.
3709 pTHPending[i].SetIsFullyLoaded();
3716 TypeHandle ClassLoader::LoadTypeHandleForTypeKey(TypeKey *pTypeKey,
3718 ClassLoadLevel targetLevel/*=CLASS_LOADED*/,
3719 const InstantiationContext *pInstContext/*=NULL*/)
3728 LOADS_TYPE(targetLevel);
3735 if (LoggingOn(LF_CLASSLOADER, LL_INFO1000))
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();
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.
3749 if (!pTypeKey->IsConstructed())
3751 pTypeKey->GetModule()->GetDomainFile();
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)
3758 typeHnd = LoadTypeHandleForTypeKey_Body(pTypeKey,
3760 targetLevelUnderLock);
3761 _ASSERTE(!typeHnd.IsNull());
3763 _ASSERTE(typeHnd.GetLoadLevel() >= targetLevelUnderLock);
3765 PushFinalLevels(typeHnd, targetLevel, pInstContext);
3771 TypeHandle ClassLoader::LoadTypeHandleForTypeKeyNoLock(TypeKey *pTypeKey,
3772 ClassLoadLevel targetLevel/*=CLASS_LOADED*/,
3773 const InstantiationContext *pInstContext/*=NULL*/)
3782 LOADS_TYPE(targetLevel);
3783 PRECONDITION(CheckPointer(pTypeKey));
3784 PRECONDITION(targetLevel >= 0 && targetLevel <= CLASS_LOADED);
3790 TypeHandle typeHnd = TypeHandle();
3792 ClassLoadLevel currentLevel = CLASS_LOAD_BEGIN;
3793 ClassLoadLevel targetLevelUnderLock = targetLevel < CLASS_DEPENDENCIES_LOADED ? targetLevel : (ClassLoadLevel) (CLASS_DEPENDENCIES_LOADED-1);
3794 while (currentLevel < targetLevelUnderLock)
3796 typeHnd = DoIncrementalLoad(pTypeKey, typeHnd, currentLevel);
3797 CONSISTENCY_CHECK(typeHnd.GetLoadLevel() > currentLevel);
3798 currentLevel = typeHnd.GetLoadLevel();
3801 PushFinalLevels(typeHnd, targetLevel, pInstContext);
3806 //---------------------------------------------------------------------------------------
3808 class PendingTypeLoadHolder
3811 PendingTypeLoadEntry * m_pEntry;
3812 PendingTypeLoadHolder * m_pPrevious;
3815 PendingTypeLoadHolder(PendingTypeLoadEntry * pEntry)
3817 LIMITED_METHOD_CONTRACT;
3819 m_pThread = GetThread();
3822 m_pPrevious = m_pThread->GetPendingTypeLoad();
3823 m_pThread->SetPendingTypeLoad(this);
3826 ~PendingTypeLoadHolder()
3828 LIMITED_METHOD_CONTRACT;
3830 _ASSERTE(m_pThread->GetPendingTypeLoad() == this);
3831 m_pThread->SetPendingTypeLoad(m_pPrevious);
3834 static bool CheckForDeadLockOnCurrentThread(PendingTypeLoadEntry * pEntry)
3836 LIMITED_METHOD_CONTRACT;
3838 PendingTypeLoadHolder * pCurrent = GetThread()->GetPendingTypeLoad();
3840 while (pCurrent != NULL)
3842 if (pCurrent->m_pEntry == pEntry)
3845 pCurrent = pCurrent->m_pPrevious;
3852 //---------------------------------------------------------------------------------------
3855 ClassLoader::LoadTypeHandleForTypeKey_Body(
3858 ClassLoadLevel targetLevel)
3860 CONTRACT(TypeHandle)
3863 POSTCONDITION(!typeHnd.IsNull() && typeHnd.GetLoadLevel() >= targetLevel);
3867 if (!pTypeKey->IsConstructed())
3869 Module *pModule = pTypeKey->GetModule();
3870 mdTypeDef cl = pTypeKey->GetTypeToken();
3872 STRESS_LOG2(LF_CLASSLOADER, LL_INFO100000, "LoadTypeHandle: Loading Class from Module %p token %x\n", pModule, cl);
3875 IMDInternalImport* pInternalImport = pModule->GetMDImport();
3878 if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &className, &nameSpace)))
3880 className = nameSpace = "Invalid TypeDef record";
3882 if (g_pConfig->ShouldBreakOnClassLoad(className))
3883 CONSISTENCY_CHECK_MSGF(false, ("BreakOnClassLoad: typename '%s' ", className));
3887 ReleaseHolder<PendingTypeLoadEntry> pLoadingEntry;
3888 CrstHolderWithState unresolvedClassLockHolder(&m_UnresolvedClassLock, false);
3891 unresolvedClassLockHolder.Acquire();
3893 // Is it in the hash of classes currently being loaded?
3894 pLoadingEntry = m_pUnresolvedClassHash->GetValue(pTypeKey);
3897 pLoadingEntry->AddRef();
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();
3905 // Check one last time before waiting that the type handle is not sufficiently loaded to
3906 // prevent deadlocks
3909 if (typeHnd.IsNull())
3911 typeHnd = LookupTypeHandleForTypeKey(pTypeKey);
3914 if (!typeHnd.IsNull())
3916 if (typeHnd.GetLoadLevel() >= targetLevel)
3921 if (PendingTypeLoadHolder::CheckForDeadLockOnCurrentThread(pLoadingEntry))
3923 // Attempting recursive load
3924 ClassLoader::ThrowTypeLoadException(pTypeKey, IDS_CLASSLOAD_GENERAL);
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.
3932 if (typeHnd.IsNull() && GetThread()->HasThreadStateNC(Thread::TSNC_LoadsTypeViolation))
3934 PendingTypeLoadHolder ptlh(pLoadingEntry);
3935 typeHnd = DoIncrementalLoad(pTypeKey, TypeHandle(), CLASS_LOAD_BEGIN);
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());
3946 // Result of other thread loading the class
3947 HRESULT hr = pLoadingEntry->m_hrResult;
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.
3956 if (typeHnd.IsNull())
3958 typeHnd = LookupTypeHandleForTypeKey(pTypeKey);
3961 if (!typeHnd.IsNull())
3963 if (typeHnd.GetLoadLevel() >= targetLevel)
3968 if (hr == E_ABORT) {
3969 LOG((LF_CLASSLOADER, LL_INFO10, "need to retry LoadTypeHandle: %x\n", hr));
3973 LOG((LF_CLASSLOADER, LL_INFO10, "Failed to load in other entry: %x\n", hr));
3975 if (hr == E_OUTOFMEMORY) {
3979 pLoadingEntry->ThrowException();
3982 // Get a pointer to the EEClass being loaded
3983 typeHnd = pLoadingEntry->m_typeHandle;
3985 if (!typeHnd.IsNull())
3987 // If the type load on the other thread loaded the type to the needed level, return it here.
3988 if (typeHnd.GetLoadLevel() >= targetLevel)
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.
3997 if (typeHnd.IsNull())
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);
4004 ClassLoadLevel currentLevel = CLASS_LOAD_BEGIN;
4005 if (!typeHnd.IsNull())
4007 currentLevel = typeHnd.GetLoadLevel();
4008 if (currentLevel >= targetLevel)
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
4016 if (!(m_pUnresolvedClassHash->InsertValue(pLoadingEntry)))
4021 // Leave the global lock, so that other threads may now start waiting on our class's lock
4022 unresolvedClassLockHolder.Release();
4026 PendingTypeLoadHolder ptlh(pLoadingEntry);
4028 TRIGGERS_TYPELOAD();
4030 while (currentLevel < targetLevel)
4032 typeHnd = DoIncrementalLoad(pTypeKey, typeHnd, currentLevel);
4033 CONSISTENCY_CHECK(typeHnd.GetLoadLevel() > currentLevel);
4034 currentLevel = typeHnd.GetLoadLevel();
4036 // If other threads are waiting for this load, unblock them as soon as possible to prevent deadlocks.
4037 if (pLoadingEntry->HasWaiters())
4041 _ASSERTE(!typeHnd.IsNull());
4042 pLoadingEntry->SetResult(typeHnd);
4046 LOG((LF_CLASSLOADER, LL_INFO10, "Caught an exception loading: %x, %0x (Module)\n", pTypeKey->GetTypeToken(), pTypeKey->GetModule()));
4048 if (!GetThread()->HasThreadStateNC(Thread::TSNC_LoadsTypeViolation))
4050 // Fix up the loading entry.
4051 Exception *pException = GET_EXCEPTION();
4052 pLoadingEntry->SetException(pException);
4055 // Unlink this class from the unresolved class list.
4056 unresolvedClassLockHolder.Acquire();
4057 m_pUnresolvedClassHash->DeleteValue(pTypeKey);
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();
4063 // Unblock any thread waiting to load same type as in TypeLoadEntry
4064 pLoadingEntry->UnblockWaiters();
4068 // Unlink this class from the unresolved class list.
4069 unresolvedClassLockHolder.Acquire();
4070 m_pUnresolvedClassHash->DeleteValue(pTypeKey);
4071 unresolvedClassLockHolder.Release();
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();
4081 if (currentLevel < targetLevel)
4085 } // ClassLoader::LoadTypeHandleForTypeKey_Body
4087 #endif //!DACCESS_COMPILE
4089 //---------------------------------------------------------------------------------------
4093 ClassLoader::LoadArrayTypeThrowing(
4094 TypeHandle elemType,
4095 CorElementType arrayKind,
4097 LoadTypesFlag fLoadTypes, //=LoadTypes
4098 ClassLoadLevel level)
4100 CONTRACT(TypeHandle)
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); }
4108 POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
4112 CorElementType predefinedElementType = ELEMENT_TYPE_END;
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];
4120 RETURN(TypeHandle(typeDesc));
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];
4130 RETURN(TypeHandle(typeDesc));
4131 predefinedElementType = ELEMENT_TYPE_OBJECT;
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];
4137 RETURN(TypeHandle(typeDesc));
4138 predefinedElementType = ELEMENT_TYPE_STRING;
4141 predefinedElementType = ELEMENT_TYPE_END;
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())
4153 elemType = ClassLoader::CanonicalizeGenericArg(elemType);
4157 TypeKey key(arrayKind, elemType, FALSE, rank);
4158 TypeHandle th = LoadConstructedTypeThrowing(&key, fLoadTypes, level);
4160 if (predefinedElementType != ELEMENT_TYPE_END && !th.IsNull() && th.IsFullyLoaded())
4162 g_pPredefinedArrayTypes[predefinedElementType] = th.AsArray();
4166 } // ClassLoader::LoadArrayTypeThrowing
4168 #ifndef DACCESS_COMPILE
4170 VOID ClassLoader::AddAvailableClassDontHaveLock(Module *pModule,
4172 AllocMemTracker *pamTracker)
4180 INJECT_FAULT(COMPlusThrowOM(););
4184 #ifdef FEATURE_COMINTEROP
4185 _ASSERTE(!pModule->GetAssembly()->IsWinMD()); // WinMD files should never get into this path, otherwise provide szWinRtNamespacePrefix
4188 CrstHolder ch(&m_AvailableClassLock);
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)
4195 LazyPopulateCaseSensitiveHashTables();
4198 AddAvailableClassHaveLock(
4202 NULL, // szWinRtNamespacePrefix
4203 0); // cchWinRtNamespacePrefix
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.
4212 // This routine assumes you already have the lock. Use AddAvailableClassDontHaveLock() if you
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.
4218 VOID ClassLoader::AddAvailableClassHaveLock(
4221 AllocMemTracker * pamTracker,
4222 LPCSTR szWinRtNamespacePrefix,
4223 DWORD cchWinRtNamespacePrefix) // Optimization for faster prefix comparison implementation
4231 INJECT_FAULT(COMPlusThrowOM(););
4235 EEClassHashTable *pClassHash = pModule->GetAvailableClassHash();
4236 EEClassHashTable *pClassCaseInsHash = pModule->GetAvailableClassCaseInsHash();
4239 LPCUTF8 pszNameSpace;
4240 HashDatum ThrowawayData;
4241 IMDInternalImport *pMDImport = pModule->GetMDImport();
4242 if (FAILED(pMDImport->GetNameOfTypeDef(classdef, &pszName, &pszNameSpace)))
4244 pszName = pszNameSpace = "Invalid TypeDef token";
4245 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4248 EEClassHashEntry_t *pBucket;
4249 mdTypeDef enclosing;
4250 if (SUCCEEDED(pMDImport->GetNestedClassProps(classdef, &enclosing))) {
4253 LPCUTF8 pszEnclosingName;
4254 LPCUTF8 pszEnclosingNameSpace;
4255 mdTypeDef enclEnclosing;
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));
4261 EEClassHashTable::LookupContext sContext;
4262 if (FAILED(pMDImport->GetNameOfTypeDef(enclosing, &pszEnclosingName, &pszEnclosingNameSpace)))
4264 pszName = pszNameSpace = "Invalid TypeDef token";
4265 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4267 if ((pBucket = pClassHash->GetValue(pszEnclosingNameSpace,
4271 &sContext)) != NULL) {
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,
4279 pBucket->GetEncloser())) &&
4280 (pBucket = pClassHash->FindNextNestedClass(pszEnclosingNameSpace,
4283 &sContext)) != NULL);
4286 if (!pBucket) // Enclosing type not found in hash table
4287 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_ENCLOSING_TYPE_NOT_FOUND);
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);
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;
4303 if (pClassCaseInsHash) {
4304 CreateCanonicallyCasedKey(pszNameSpace, pszName, &pszLowerCaseNS, &pszLowerCaseName);
4305 pCaseInsEntry = pClassCaseInsHash->AllocNewEntry(pamTracker);
4308 EEClassHashEntry_t *pEntry = pClassHash->FindItem(pszNameSpace, pszName, FALSE, NULL);
4310 HashDatum Data = pEntry->GetData();
4312 if (((size_t)Data & EECLASSHASH_TYPEHANDLE_DISCR) &&
4313 ((size_t)Data & EECLASSHASH_MDEXPORT_DISCR)) {
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);
4320 Data = (HashDatum)((size_t)Data | EECLASSHASH_ALREADYSEEN);
4321 pEntry->SetData(Data);
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);
4333 pEntry = pClassHash->AllocNewEntry(pamTracker);
4335 CANNOTTHROWCOMPLUSEXCEPTION();
4338 pClassHash->InsertValueUsingPreallocatedEntry(pEntry, pszNameSpace, pszName, EEClassHashTable::CompressClassDef(classdef), NULL);
4340 if (pClassCaseInsHash)
4341 pClassCaseInsHash->InsertValueUsingPreallocatedEntry(pCaseInsEntry, pszLowerCaseNS, pszLowerCaseName, pEntry, pEntry->GetEncloser());
4344 #ifdef FEATURE_COMINTEROP
4345 // Check WinRT namespace prefix if required
4346 if (szWinRtNamespacePrefix != NULL)
4349 if (FAILED(pMDImport->GetTypeDefProps(classdef, &dwAttr, NULL)))
4351 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
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))
4357 // Guaranteed by the caller - code:ClassLoader::PopulateAvailableClassHashTable
4358 _ASSERTE(cchWinRtNamespacePrefix == strlen(szWinRtNamespacePrefix));
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)
4371 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_WINRT_INVALID_NAMESPACE_FOR_TYPE);
4375 #endif // FEATURE_COMINTEROP
4379 VOID ClassLoader::AddExportedTypeDontHaveLock(Module *pManifestModule,
4381 AllocMemTracker *pamTracker)
4389 INJECT_FAULT(COMPlusThrowOM(););
4393 CrstHolder ch(&m_AvailableClassLock);
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)
4400 LazyPopulateCaseSensitiveHashTables();
4403 AddExportedTypeHaveLock(
4409 VOID ClassLoader::AddExportedTypeHaveLock(Module *pManifestModule,
4411 AllocMemTracker *pamTracker)
4419 INJECT_FAULT(COMPlusThrowOM(););
4426 LPCSTR pszNameSpace;
4427 IMDInternalImport* pAsmImport = pManifestModule->GetMDImport();
4428 if (FAILED(pAsmImport->GetExportedTypeProps(
4436 pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4439 HashDatum ThrowawayData;
4441 if (TypeFromToken(mdImpl) == mdtExportedType)
4444 LPCUTF8 pszEnclosingNameSpace;
4445 LPCUTF8 pszEnclosingName;
4447 if (FAILED(pAsmImport->GetExportedTypeProps(
4449 &pszEnclosingNameSpace,
4455 pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
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,
4466 TypeFromToken(nextImpl) == mdtExportedType,
4467 &sContext)) != NULL) {
4469 // check to see if this is the correct class
4470 if (EEClassHashTable::UncompressModuleAndClassDef(ThrowawayData) == mdImpl) {
4471 ThrowawayData = EEClassHashTable::CompressClassDef(cl);
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);
4476 pBucket = pManifestModule->GetAvailableClassHash()->FindNextNestedClass(pszEnclosingNameSpace, pszEnclosingName, &ThrowawayData, &sContext);
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
4485 // Defined in the manifest module - add to the hash table by TypeDef instead
4486 if (mdImpl == mdFileNil)
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.
4495 pManifestModule->GetAvailableClassHash()->InsertValueIfNotFound(pszNameSpace, pszName, &ThrowawayData, NULL, FALSE, &bFound, pamTracker);
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)
4503 mdExportedType foundExportedType = EEClassHashTable::UncompressModuleAndClassDef(ThrowawayData);
4504 if (FAILED(pAsmImport->GetExportedTypeProps(
4512 pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4517 foundTypeImpl = mdFileNil;
4520 if (mdImpl != foundTypeImpl)
4522 pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_MULT_TYPE_SAME_NAME);
4528 static MethodTable* GetEnclosingMethodTable(MethodTable *pMT)
4530 CONTRACT(MethodTable*)
4534 INJECT_FAULT(COMPlusThrowOM(););
4536 PRECONDITION(CheckPointer(pMT));
4537 POSTCONDITION(RETVAL == NULL || RETVAL->IsTypicalTypeDefinition());
4541 RETURN pMT->LoadEnclosingMethodTable();
4544 StaticAccessCheckContext::StaticAccessCheckContext(MethodDesc* pCallerMethod)
4548 LIMITED_METHOD_CONTRACT;
4549 PRECONDITION(CheckPointer(pCallerMethod));
4553 m_pCallerMethod = pCallerMethod;
4554 m_pCallerMT = m_pCallerMethod->GetMethodTable();
4555 m_pCallerAssembly = m_pCallerMT->GetAssembly();
4558 StaticAccessCheckContext::StaticAccessCheckContext(MethodDesc* pCallerMethod, MethodTable* pCallerType)
4562 LIMITED_METHOD_CONTRACT;
4563 PRECONDITION(CheckPointer(pCallerMethod, NULL_OK));
4564 PRECONDITION(CheckPointer(pCallerType));
4568 m_pCallerMethod = pCallerMethod;
4569 m_pCallerMT = pCallerType;
4570 m_pCallerAssembly = pCallerType->GetAssembly();
4573 //******************************************************************************
4576 AccessCheckOptions* AccessCheckOptions::s_pNormalAccessChecks;
4578 //******************************************************************************
4580 void AccessCheckOptions::Startup()
4582 STANDARD_VM_CONTRACT;
4584 s_pNormalAccessChecks = new AccessCheckOptions(
4585 AccessCheckOptions::kNormalAccessibilityChecks,
4588 (MethodTable *)NULL);
4591 //******************************************************************************
4592 AccessCheckOptions::AccessCheckOptions(
4593 const AccessCheckOptions & templateOptions,
4594 BOOL throwIfTargetIsInaccessible) :
4595 m_pAccessContext(templateOptions.m_pAccessContext)
4597 WRAPPER_NO_CONTRACT;
4600 templateOptions.m_accessCheckType,
4601 throwIfTargetIsInaccessible,
4602 templateOptions.m_pTargetMT,
4603 templateOptions.m_pTargetMethod,
4604 templateOptions.m_pTargetField);
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.
4612 BOOL AccessCheckOptions::DemandMemberAccess(AccessCheckContext *pContext, MethodTable * pTargetMT, BOOL visibilityCheck) const
4619 PRECONDITION(m_accessCheckType != kNormalAccessibilityChecks);
4620 PRECONDITION(CheckPointer(pContext));
4624 _ASSERTE(m_accessCheckType != kNormalAccessibilityChecks);
4626 if (NingenEnabled())
4628 // NinGen should always perform normal accessibility checks
4631 if (m_fThrowIfTargetIsInaccessible)
4633 ThrowAccessException(pContext, pTargetMT, NULL);
4639 if (pTargetMT && pTargetMT->GetAssembly()->IsDisabledPrivateReflection())
4641 if (m_fThrowIfTargetIsInaccessible)
4643 ThrowAccessException(pContext, pTargetMT, NULL);
4649 BOOL canAccessTarget = FALSE;
4651 #ifndef CROSSGEN_COMPILE
4653 // In CoreCLR kRestrictedMemberAccess means that one can access private/internal
4654 // classes/members in app code.
4655 if (m_accessCheckType != kMemberAccess && pTargetMT)
4657 // We allow all transparency checks to succeed in LCG methods and reflection invocation.
4658 if (m_accessCheckType == kNormalAccessNoTransparency || m_accessCheckType == kRestrictedMemberAccessNoTransparency)
4662 // Always allow interop (NULL) callers full access.
4663 if (pContext->IsCalledFromInterop())
4667 if (m_fThrowIfTargetIsInaccessible)
4669 ThrowAccessException(pContext, pTargetMT, NULL);
4672 #endif // CROSSGEN_COMPILE
4674 return canAccessTarget;
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.
4682 void AccessCheckOptions::ThrowAccessException(
4683 AccessCheckContext* pContext,
4684 MethodTable* pFailureMT, /* = NULL */
4685 Exception* pInnerException /* = NULL */) const
4692 PRECONDITION(CheckPointer(pContext));
4693 PRECONDITION(CheckPointer(pInnerException, NULL_OK));
4694 PRECONDITION(m_fThrowIfTargetIsInaccessible);
4700 MethodDesc* pCallerMD = pContext->GetCallerMethod();
4702 if (m_pTargetMT != NULL)
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);
4709 else if (m_pTargetMethod != NULL)
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)
4720 ThrowTypeAccessException(pContext, pFailureMT, 0, pInnerException);
4724 ThrowMethodAccessException(pContext, m_pTargetMethod, 0, pInnerException);
4729 _ASSERTE(m_pTargetField != NULL);
4730 ThrowFieldAccessException(pContext, m_pTargetField, 0, pInnerException);
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
4747 if (DoNormalAccessibilityChecks())
4749 if (pContext->GetCallerAssembly()->IgnoresAccessChecksTo(pTargetMT->GetAssembly()))
4754 if (m_fThrowIfTargetIsInaccessible)
4756 ThrowAccessException(pContext, pTargetMT);
4762 return DemandMemberAccess(pContext, pTargetMT, visibilityCheck);
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
4775 PRECONDITION(CheckPointer(pContext));
4779 if (m_fThrowIfTargetIsInaccessible)
4781 ThrowAccessException(pContext);
4787 void DECLSPEC_NORETURN ThrowFieldAccessException(AccessCheckContext* pContext,
4789 UINT messageID /* = 0 */,
4790 Exception *pInnerException /* = NULL */)
4797 PRECONDITION(CheckPointer(pContext));
4798 PRECONDITION(CheckPointer(pFD));
4802 MethodDesc* pCallerMD = pContext->GetCallerMethod();
4804 ThrowFieldAccessException(pCallerMD,
4810 void DECLSPEC_NORETURN ThrowFieldAccessException(MethodDesc* pCallerMD,
4812 UINT messageID /* = 0 */,
4813 Exception *pInnerException /* = NULL */)
4820 PRECONDITION(CheckPointer(pCallerMD, NULL_OK));
4821 PRECONDITION(CheckPointer(pFD));
4825 if (pCallerMD != NULL)
4829 messageID = IDS_E_FIELDACCESS;
4832 EX_THROW_WITH_INNER(EEFieldException, (pFD, pCallerMD, SString::Empty(), messageID), pInnerException);
4836 EX_THROW_WITH_INNER(EEFieldException, (pFD), pInnerException);
4840 void DECLSPEC_NORETURN ThrowMethodAccessException(AccessCheckContext* pContext,
4841 MethodDesc *pCalleeMD,
4842 UINT messageID /* = 0 */,
4843 Exception *pInnerException /* = NULL */)
4850 PRECONDITION(CheckPointer(pContext));
4851 PRECONDITION(CheckPointer(pCalleeMD));
4855 MethodDesc* pCallerMD = pContext->GetCallerMethod();
4857 ThrowMethodAccessException(pCallerMD,
4863 void DECLSPEC_NORETURN ThrowMethodAccessException(MethodDesc* pCallerMD,
4864 MethodDesc *pCalleeMD,
4865 UINT messageID /* = 0 */,
4866 Exception *pInnerException /* = NULL */)
4873 PRECONDITION(CheckPointer(pCallerMD, NULL_OK));
4874 PRECONDITION(CheckPointer(pCalleeMD));
4878 if (pCallerMD != NULL)
4882 messageID = IDS_E_METHODACCESS;
4885 EX_THROW_WITH_INNER(EEMethodException, (pCalleeMD, pCallerMD, SString::Empty(), messageID), pInnerException);
4889 EX_THROW_WITH_INNER(EEMethodException, (pCalleeMD), pInnerException);
4893 void DECLSPEC_NORETURN ThrowTypeAccessException(AccessCheckContext* pContext,
4895 UINT messageID /* = 0 */,
4896 Exception *pInnerException /* = NULL */)
4903 PRECONDITION(CheckPointer(pContext));
4904 PRECONDITION(CheckPointer(pMT));
4908 MethodDesc* pCallerMD = pContext->GetCallerMethod();
4910 ThrowTypeAccessException(pCallerMD,
4916 void DECLSPEC_NORETURN ThrowTypeAccessException(MethodDesc* pCallerMD,
4918 UINT messageID /* = 0 */,
4919 Exception *pInnerException /* = NULL */)
4926 PRECONDITION(CheckPointer(pCallerMD, NULL_OK));
4927 PRECONDITION(CheckPointer(pMT));
4931 if (pCallerMD != NULL)
4935 messageID = IDS_E_TYPEACCESS;
4938 EX_THROW_WITH_INNER(EETypeAccessException, (pMT, pCallerMD, SString::Empty(), messageID), pInnerException);
4942 EX_THROW_WITH_INNER(EETypeAccessException, (pMT), pInnerException);
4946 //---------------------------------------------------------------------------------------
4948 // Checks to see if access to a member with assembly visiblity is allowed.
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
4958 // TRUE if pTargetAssembly is pAccessingAssembly, or if pTargetAssembly allows
4959 // pAccessingAssembly friend access to the target. FALSE otherwise.
4962 static BOOL AssemblyOrFriendAccessAllowed(Assembly *pAccessingAssembly,
4963 Assembly *pTargetAssembly,
4964 FieldDesc *pOptionalTargetField,
4965 MethodDesc *pOptionalTargetMethod,
4966 MethodTable *pOptionalTargetType)
4972 PRECONDITION(CheckPointer(pAccessingAssembly));
4973 PRECONDITION(CheckPointer(pTargetAssembly));
4974 PRECONDITION(pOptionalTargetField != NULL || pOptionalTargetMethod != NULL || pOptionalTargetType != NULL);
4975 PRECONDITION(pOptionalTargetField == NULL || pOptionalTargetMethod == NULL);
4979 if (pAccessingAssembly == pTargetAssembly)
4984 if (pAccessingAssembly->IgnoresAccessChecksTo(pTargetAssembly))
4989 else if (pOptionalTargetField != NULL)
4991 return pTargetAssembly->GrantsFriendAccessTo(pAccessingAssembly, pOptionalTargetField);
4993 else if (pOptionalTargetMethod != NULL)
4995 return pTargetAssembly->GrantsFriendAccessTo(pAccessingAssembly, pOptionalTargetMethod);
4999 return pTargetAssembly->GrantsFriendAccessTo(pAccessingAssembly, pOptionalTargetType);
5003 //******************************************************************************
5004 // This function determines whether a target class is accessible from
5005 // some given class.
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)
5016 INJECT_FAULT(COMPlusThrowOM(););
5018 PRECONDITION(CheckPointer(pContext));
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)
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++)
5034 TypeHandle th = inst[i];
5036 MethodTable* pMT = th.GetMethodTableOfElementType();
5038 // Either a TypeVarTypeDesc or a FnPtrTypeDesc. No access check needed.
5042 if (!CanAccessClass(
5046 accessCheckOptions))
5051 // If we are here, the current class has access to all of the target's instantiating args,
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.
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
5076 INJECT_FAULT(COMPlusThrowOM(););
5078 PRECONDITION(CheckPointer(pContext));
5079 PRECONDITION(CheckPointer(pTargetClass));
5083 // If there is no target class, allow access.
5084 // @todo: what does that mean?
5085 //if (!pTargetClass)
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++)
5096 TypeHandle th = inst[i];
5098 MethodTable* pMT = th.GetMethodTableOfElementType();
5100 // Either a TypeVarTypeDesc or a FnPtrTypeDesc. No access check needed.
5104 if (!CanAccessClass(
5108 accessCheckOptions))
5110 // no need to call accessCheckOptions.DemandMemberAccessOrFail here because the base case in
5111 // CanAccessClass does that already
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.
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()))
5128 // Always allow interop callers full access.
5129 if (pContext->IsCalledFromInterop())
5132 Assembly* pCurrentAssembly = pContext->GetCallerAssembly();
5133 _ASSERTE(pCurrentAssembly != NULL);
5135 if (AssemblyOrFriendAccessAllowed(pCurrentAssembly,
5145 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetClass, TRUE /*visibilityCheck*/);
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();
5156 switch(dwProtection) {
5157 case tdNestedPublic:
5158 dwProtection = mdPublic;
5160 case tdNestedFamily:
5161 dwProtection = mdFamily;
5163 case tdNestedPrivate:
5164 dwProtection = mdPrivate;
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.
5179 // Always allow interop callers full access.
5180 if (pContext->IsCalledFromInterop())
5183 if (AssemblyOrFriendAccessAllowed(pContext->GetCallerAssembly(), pTargetAssembly, NULL, NULL, pTargetClass))
5184 dwProtection = (dwProtection == tdNestedFamANDAssem) ? mdFamily : mdPublic;
5185 else if (dwProtection == tdNestedFamORAssem)
5186 dwProtection = mdFamily;
5188 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetClass, TRUE /*visibilityCheck*/);
5193 THROW_BAD_FORMAT_MAYBE(!"Unexpected class visibility flag value", BFA_BAD_VISIBILITY, pTargetClass);
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(
5203 GetEnclosingMethodTable(pTargetClass),
5208 accessCheckOptions);
5209 } // BOOL ClassLoader::CanAccessClass()
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.
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
5231 INJECT_FAULT(COMPlusThrowOM(););
5232 PRECONDITION(CheckPointer(pContext));
5237 AccessCheckOptions accessCheckOptionsNoThrow(accessCheckOptions, FALSE);
5239 if (!CheckAccessMember(pContext,
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))
5249 // If we're here, CheckAccessMember didn't allow access.
5250 BOOL canAccess = FALSE;
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();
5257 // if this is called from interop, the CheckAccessMember call above should have already succeeded.
5258 _ASSERTE(!pContext->IsCalledFromInterop());
5260 BOOL isNestedClass = (pCurrentMT && pCurrentMT->GetClass()->IsNested());
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);
5268 StaticAccessCheckContext accessContext(pContext->GetCallerMethod(),
5270 pContext->GetCallerAssembly());
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(
5279 pOptionalTargetMethod,
5280 pOptionalTargetField,
5281 accessCheckOptionsNoThrow);
5286 BOOL fail = accessCheckOptions.FailOrThrow(pContext);
5292 } // BOOL ClassLoader::CanAccess()
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)
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
5318 INJECT_FAULT(COMPlusThrowOM(););
5319 PRECONDITION(CheckPointer(pContext));
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,
5330 accessCheckOptions))
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(
5339 pOptionalTargetMethod,
5340 accessCheckOptions))
5345 // pOptionalTargetMethod and pOptionalTargetField can never be NULL at the same time.
5346 _ASSERTE(pOptionalTargetMethod == NULL || pOptionalTargetField == NULL);
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.
5352 if (IsMdPublic(dwMemberAccess))
5357 // Always allow interop callers full access.
5358 if (pContext->IsCalledFromInterop())
5361 MethodTable* pCurrentMT = pContext->GetCallerMT();
5363 if (IsMdPrivateScope(dwMemberAccess))
5365 if (pCurrentMT != NULL && pCurrentMT->GetModule() == pTargetMT->GetModule())
5371 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
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);
5385 if (pTargetMT == NULL ||
5386 IsMdAssem(dwMemberAccess) ||
5387 IsMdFamORAssem(dwMemberAccess) ||
5388 IsMdFamANDAssem(dwMemberAccess))
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
5394 // @todo: What does it mean for the target class to be NULL?
5396 Assembly* pCurrentAssembly = pContext->GetCallerAssembly();
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);
5402 const BOOL fAssemblyOrFriendAccessAllowed = AssemblyOrFriendAccessAllowed(pCurrentAssembly,
5404 pOptionalTargetField,
5405 pOptionalTargetMethod,
5408 if ((pTargetMT == NULL || IsMdAssem(dwMemberAccess) || IsMdFamORAssem(dwMemberAccess)) &&
5409 fAssemblyOrFriendAccessAllowed)
5413 else if (IsMdFamANDAssem(dwMemberAccess) &&
5414 !fAssemblyOrFriendAccessAllowed)
5416 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
5420 // Nested classes can access all members of the parent class.
5421 while(pCurrentMT != NULL)
5424 if (pTargetMT->HasSameTypeDefAs(pCurrentMT))
5427 if (IsMdPrivate(dwMemberAccess))
5429 if (!pCurrentMT->GetClass()->IsNested())
5431 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
5434 else if (IsMdFamORAssem(dwMemberAccess) || IsMdFamily(dwMemberAccess) || IsMdFamANDAssem(dwMemberAccess))
5436 if (CanAccessFamily(pCurrentMT, pTargetMT))
5442 pCurrentMT = GetEnclosingMethodTable(pCurrentMT);
5445 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
5448 // The family check is actually in two parts (Partition I, 8.5.3.2). The first part:
5450 // ...accessible to referents that support the same type
5451 // (i.e., an exact type and all of the types that inherit
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).
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.
5466 // Translation: The C++ protected rule. For those unfamiliar, it means that:
5468 // GrandChild : Child
5474 // int protectedField;
5477 // Child::function(GrandChild * o) {
5478 // o->protectedField; //This access is legal.
5481 // GrandChild:function2(Child * o) {
5482 // o->protectedField; //This access is illegal.
5485 // The reason for this rule is that if you had:
5488 // Child::function3( Sibling * o ) {
5489 // o->protectedField; //This access is illegal
5492 // This is intuitively correct. However, you need to prevent:
5493 // Child::function4( Sibling * o ) {
5494 // ((Parent*)o)->protectedField;
5497 // Which means that you must access protected fields through a type that is yourself or one of your
5500 //This checks the first part of the rule above.
5502 BOOL ClassLoader::CanAccessFamily(
5503 MethodTable *pCurrentClass,
5504 MethodTable *pTargetClass)
5510 INJECT_FAULT(COMPlusThrowOM(););
5512 PRECONDITION(CheckPointer(pTargetClass));
5516 _ASSERTE(pCurrentClass);
5517 _ASSERTE(pTargetClass);
5519 BOOL bIsInterface = pTargetClass->IsInterface();
5521 //Look to see if Current is a child of the Target.
5522 while (pCurrentClass) {
5525 // Calling a protected interface member
5526 MethodTable::InterfaceMapIterator it = pCurrentClass->IterateInterfaceMap();
5529 // We only loosely check if they are of the same generic type
5530 if (it.GetInterface()->HasSameTypeDefAs(pTargetClass))
5536 MethodTable *pCurInstance = pCurrentClass;
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
5542 if (pCurInstance->HasSameTypeDefAs(pTargetClass)) {
5546 pCurInstance = pCurInstance->GetParentMethodTable();
5550 ///Looking at 8.5.3, it looks like a protected member of a nested class in a parent type is also
5552 pCurrentClass = GetEnclosingMethodTable(pCurrentClass);
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
5563 protected int m_family;
5565 class Derived<T> : Base {
5567 public int function(Derived<T> d) {
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
5579 BOOL CanAccessFamilyVerificationEnclosingHelper(MethodTable * pMTCurrentEnclosingClass,
5580 TypeHandle thInstanceClass)
5590 _ASSERTE(pMTCurrentEnclosingClass);
5592 if (thInstanceClass.IsGenericVariable())
5594 //In this case it is a TypeVarTypeDesc (i.e. T). If this access would be legal due to a
5600 public class Inner<U> where U : My<T>
5607 protected int field;
5610 //We need to find the generic class constraint. (The above is legal because U must be a My<T> which makes this
5612 // There may only be 1 class constraint on a generic parameter
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)
5622 // If we did not find a class constraint, we cannot generate a methodtable to search for
5627 for (DWORD i = 0; i < numConstraints; i++)
5629 if (!constraints[i].IsInterface())
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
5635 // protected int field;
5637 // public class Inner<U,V> where V:U where U : Outer4<T>
5639 // public int Method(V param) { return (++param.field); }
5642 return CanAccessFamilyVerificationEnclosingHelper(pMTCurrentEnclosingClass, constraints[i]);
5645 // If we did not find a class constraint, we cannot generate a methodtable to search for
5651 MethodTable * pAccessor = pMTCurrentEnclosingClass;
5652 //If thInstanceClass is a MethodTable, we should only be doing the TypeDef comparison (see
5654 if (!thInstanceClass.IsTypeDesc())
5656 MethodTable *pInstanceMT = thInstanceClass.AsMethodTable();
5658 // This is a CanCastTo implementation for classes, assuming we should ignore generic instantiation parameters.
5661 if (pAccessor->HasSameTypeDefAs(pInstanceMT))
5663 pInstanceMT = pInstanceMT->GetParentMethodTable();
5664 }while(pInstanceMT);
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.
5671 if (thInstanceClass.CanCastTo(TypeHandle(pAccessor)))
5675 pMTCurrentEnclosingClass = GetEnclosingMethodTable(pMTCurrentEnclosingClass);
5676 }while(pMTCurrentEnclosingClass);
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.
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.
5689 BOOL ClassLoader::CanAccessFamilyVerification(TypeHandle thCurrentClass,
5690 TypeHandle thInstanceClass)
5696 INJECT_FAULT(COMPlusThrowOM(););
5698 PRECONDITION(!thCurrentClass.IsNull());
5699 PRECONDITION(!thCurrentClass.IsTypeDesc());
5703 //Check to see if Instance is equal to or derived from pCurrentClass.
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)))
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())
5716 return CanAccessFamilyVerificationEnclosingHelper(pAccessor, thInstanceClass);
5721 #endif // #ifndef DACCESS_COMPILE
5723 #ifdef DACCESS_COMPILE
5726 ClassLoader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
5728 WRAPPER_NO_CONTRACT;
5732 EMEM_OUT(("MEM: %p ClassLoader\n", dac_cast<TADDR>(this)));
5734 if (m_pAssembly.IsValid())
5736 ModuleIterator modIter = GetAssembly()->IterateModules();
5738 while (modIter.Next())
5740 modIter.GetModule()->EnumMemoryRegions(flags, true);
5745 #endif // #ifdef DACCESS_COMPILE