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 "virtualcallstub.h"
49 #include "stringarraylist.h"
52 // This method determines the "loader module" for an instantiated type
53 // or method. The rule must ensure that any types involved in the
54 // instantiated type or method do not outlive the loader module itself
55 // with respect to app-domain unloading (e.g. MyList<MyType> can't be
56 // put in the module of MyList if MyList's assembly is
57 // app-domain-neutral but MyType's assembly is app-domain-specific).
58 // The rule we use is:
60 // * Pick the first type in the class instantiation, followed by
61 // method instantiation, whose loader module is non-shared (app-domain-bound)
62 // * If no type is app-domain-bound, return the module containing the generic type itself
64 // Some useful effects of this rule (for ngen purposes) are:
66 // * G<object,...,object> lives in the module defining G
67 // * non-mscorlib instantiations of mscorlib-defined generic types live in the module
68 // of the instantiation (when only one module is invloved in the instantiation)
72 PTR_Module ClassLoader::ComputeLoaderModuleWorker(
73 Module * pDefinitionModule, // the module that declares the generic type or method
74 mdToken token, // method or class token for this item
75 Instantiation classInst, // the type arguments to the type (if any)
76 Instantiation methodInst) // the type arguments to the method (if any)
84 PRECONDITION(CheckPointer(pDefinitionModule, NULL_OK));
85 POSTCONDITION(CheckPointer(RETVAL));
90 if (classInst.IsEmpty() && methodInst.IsEmpty())
91 RETURN PTR_Module(pDefinitionModule);
93 #ifndef DACCESS_COMPILE
94 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
96 // Use special loader module placement during compilation of fragile native images.
98 // ComputeLoaderModuleForCompilation algorithm assumes that we are using fragile native image
99 // for CoreLib (or compiling CoreLib itself). It is not the case for ReadyToRun compilation because
100 // CoreLib as always treated as IL there (see code:PEFile::ShouldTreatNIAsMSIL for details).
102 if (IsCompilationProcess() && !IsReadyToRunCompilation())
104 RETURN(ComputeLoaderModuleForCompilation(pDefinitionModule, token, classInst, methodInst));
106 #endif // FEATURE_PREJIT
107 #endif // #ifndef DACCESS_COMPILE
109 Module *pLoaderModule = NULL;
111 if (pDefinitionModule)
113 if (pDefinitionModule->IsCollectible())
114 goto ComputeCollectibleLoaderModule;
115 pLoaderModule = pDefinitionModule;
118 for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
120 TypeHandle classArg = classInst[i];
121 _ASSERTE(!classArg.IsEncodedFixup());
122 Module* pModule = classArg.GetLoaderModule();
123 if (pModule->IsCollectible())
124 goto ComputeCollectibleLoaderModule;
125 if (pLoaderModule == NULL)
126 pLoaderModule = pModule;
129 for (DWORD i = 0; i < methodInst.GetNumArgs(); i++)
131 TypeHandle methodArg = methodInst[i];
132 _ASSERTE(!methodArg.IsEncodedFixup());
133 Module *pModule = methodArg.GetLoaderModule();
134 if (pModule->IsCollectible())
135 goto ComputeCollectibleLoaderModule;
136 if (pLoaderModule == NULL)
137 pLoaderModule = pModule;
140 if (pLoaderModule == NULL)
142 CONSISTENCY_CHECK(MscorlibBinder::GetModule() && MscorlibBinder::GetModule()->IsSystem());
144 pLoaderModule = MscorlibBinder::GetModule();
149 ComputeCollectibleLoaderModule:
150 LoaderAllocator *pLoaderAllocatorOfDefiningType = NULL;
151 LoaderAllocator *pOldestLoaderAllocator = NULL;
152 Module *pOldestLoaderModule = NULL;
153 UINT64 oldestFoundAge = 0;
154 DWORD classArgsCount = classInst.GetNumArgs();
155 DWORD totalArgsCount = classArgsCount + methodInst.GetNumArgs();
157 if (pDefinitionModule != NULL) pLoaderAllocatorOfDefiningType = pDefinitionModule->GetLoaderAllocator();
159 for (DWORD i = 0; i < totalArgsCount; i++) {
163 if (i < classArgsCount)
166 arg = methodInst[i - classArgsCount];
168 Module *pModuleCheck = arg.GetLoaderModule();
169 LoaderAllocator *pLoaderAllocatorCheck = pModuleCheck->GetLoaderAllocator();
171 if (pLoaderAllocatorCheck != pLoaderAllocatorOfDefiningType &&
172 pLoaderAllocatorCheck->IsCollectible() &&
173 pLoaderAllocatorCheck->GetCreationNumber() > oldestFoundAge)
175 pOldestLoaderModule = pModuleCheck;
176 pOldestLoaderAllocator = pLoaderAllocatorCheck;
177 oldestFoundAge = pLoaderAllocatorCheck->GetCreationNumber();
181 // Only if we didn't find a different loader allocator than the defining loader allocator do we
182 // use the defining loader allocator
183 if (pOldestLoaderModule != NULL)
184 pLoaderModule = pOldestLoaderModule;
186 pLoaderModule = pDefinitionModule;
188 RETURN PTR_Module(pLoaderModule);
191 #ifndef DACCESS_COMPILE
192 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
194 PTR_Module ClassLoader::ComputeLoaderModuleForCompilation(
195 Module * pDefinitionModule, // the module that declares the generic type or method
196 mdToken token, // method or class token for this item
197 Instantiation classInst, // the type arguments to the type (if any)
198 Instantiation methodInst) // the type arguments to the method (if any)
206 PRECONDITION(CheckPointer(pDefinitionModule, NULL_OK));
207 POSTCONDITION(CheckPointer(RETVAL));
211 // The NGEN rule for compiling constructed types and instantiated methods
212 // into modules other than their "natural" LoaderModule. This is at the heart of
213 // "full generics NGEN".
215 // If this instantiation doesn't have a unique home then use the ngen module
217 // OK, we're certainly NGEN'ing. And if we're NGEN'ing then we're not on the debugger thread.
218 CONSISTENCY_CHECK(((GetThread() && GetAppDomain()) || IsGCThread()) &&
219 "unexpected: running a load on debug thread but IsCompilationProcess() returned TRUE");
221 // Save it into its PreferredZapModule if it's always going to be saved there.
222 // This is a stable choice - no need to record it in the table (as we do for others below)
223 if (Module::IsAlwaysSavedInPreferredZapModule(classInst, methodInst))
225 RETURN (Module::ComputePreferredZapModule(pDefinitionModule, classInst, methodInst));
228 // Check if this compilation process has already decided on an adjustment. Once we decide
229 // on the LoaderModule for an item it must be stable for the duration of a
230 // compilation process, no matter how many modules get NGEN'd.
232 ZapperLoaderModuleTableKey key(pDefinitionModule,
237 Module * pZapperLoaderModule = g_pCEECompileInfo->LookupZapperLoaderModule(&key);
238 if (pZapperLoaderModule != NULL)
240 RETURN (pZapperLoaderModule);
243 // OK, we need to compute a non-standard zapping module.
245 Module * pPreferredZapModule = Module::ComputePreferredZapModule(pDefinitionModule, classInst, methodInst);
247 // Check if we're NGEN'ing but where perhaps the compilation domain
248 // isn't set up yet. This can happen in following situations:
249 // - Managed code running during startup before compilation domain is setup.
250 // - Exceptions (e.g. invalid program exceptions) thrown from compilation domain and caught in default domain
252 // We're a little stuck - we can't force the item into an NGEN image at this point. So just bail out
253 // and use the loader module we've computed without recording the choice. The loader module should always
254 // be mscorlib in this case.
255 AppDomain * pAppDomain = GetAppDomain();
256 if (!pAppDomain->IsCompilationDomain() ||
257 !pAppDomain->ToCompilationDomain()->GetTargetModule())
259 _ASSERTE(pPreferredZapModule->IsSystem() || IsNgenPDBCompilationProcess());
260 RETURN (pPreferredZapModule);
263 Module * pTargetModule = pAppDomain->ToCompilationDomain()->GetTargetModule();
265 // If it is multi-module assembly and we have not saved PZM yet, do not create
266 // speculative instantiation - just save it in PZM.
267 if (pTargetModule->GetAssembly() == pPreferredZapModule->GetAssembly() &&
268 !pPreferredZapModule->IsModuleSaved())
270 pZapperLoaderModule = pPreferredZapModule;
274 // Everything else can be saved into the current module.
275 pZapperLoaderModule = pTargetModule;
278 // If generating WinMD resilient code and we so far choose to use the target module,
279 // we need to check if the definition module or any of the instantiation type can
280 // cause version resilient problems.
281 if (g_fNGenWinMDResilient && pZapperLoaderModule == pTargetModule)
283 if (pDefinitionModule != NULL && !pDefinitionModule->IsInCurrentVersionBubble())
285 pZapperLoaderModule = pDefinitionModule;
286 goto ModuleAdjustedForVersionResiliency;
289 for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
291 Module * pModule = classInst[i].GetLoaderModule();
292 if (!pModule->IsInCurrentVersionBubble())
294 pZapperLoaderModule = pModule;
295 goto ModuleAdjustedForVersionResiliency;
299 for (DWORD i = 0; i < methodInst.GetNumArgs(); i++)
301 Module * pModule = methodInst[i].GetLoaderModule();
302 if (!pModule->IsInCurrentVersionBubble())
304 pZapperLoaderModule = pModule;
305 goto ModuleAdjustedForVersionResiliency;
308 ModuleAdjustedForVersionResiliency: ;
311 // Record this choice just in case we're NGEN'ing multiple modules
312 // to make sure we always do the same thing if we're asked to compute
313 // the loader module again.
315 // Note this whole code path only happens while NGEN'ing, so this violation
316 // is not so bad. It is needed since we allocate stuff on the heap.
317 CONTRACT_VIOLATION(ThrowsViolation|FaultViolation);
319 // Copy the instantiation arrays so they can escape the scope of this method.
320 // Since this is a permanent entry in a table for this compilation process
321 // we do not need to collect these. If we did have to we would do it when we deleteed the
322 // ZapperLoaderModuleTable.
323 NewArrayHolder<TypeHandle> pClassArgs = NULL;
324 if (!classInst.IsEmpty())
326 pClassArgs = new TypeHandle[classInst.GetNumArgs()];
327 for (unsigned int i = 0; i < classInst.GetNumArgs(); i++)
328 pClassArgs[i] = classInst[i];
331 NewArrayHolder<TypeHandle> pMethodArgs = NULL;
332 if (!methodInst.IsEmpty())
334 pMethodArgs = new TypeHandle[methodInst.GetNumArgs()];
335 for (unsigned int i = 0; i < methodInst.GetNumArgs(); i++)
336 pMethodArgs[i] = methodInst[i];
339 ZapperLoaderModuleTableKey key2(pDefinitionModule,
341 Instantiation(pClassArgs, classInst.GetNumArgs()),
342 Instantiation(pMethodArgs, methodInst.GetNumArgs()));
343 g_pCEECompileInfo->RecordZapperLoaderModule(&key2, pZapperLoaderModule);
345 pClassArgs.SuppressRelease();
346 pMethodArgs.SuppressRelease();
348 RETURN (pZapperLoaderModule);
350 #endif // FEATURE_NATIVE_IMAGE_GENERATION
351 #endif // #ifndef DACCESS_COMPILE
354 Module * ClassLoader::ComputeLoaderModule(MethodTable * pMT,
356 Instantiation methodInst)
367 return ComputeLoaderModuleWorker(pMT->GetModule(),
369 pMT->GetInstantiation(),
373 Module *ClassLoader::ComputeLoaderModule(TypeKey *typeKey)
385 if (typeKey->GetKind() == ELEMENT_TYPE_CLASS)
386 return ComputeLoaderModuleWorker(typeKey->GetModule(),
387 typeKey->GetTypeToken(),
388 typeKey->GetInstantiation(),
390 else if (typeKey->GetKind() == ELEMENT_TYPE_FNPTR)
391 return ComputeLoaderModuleForFunctionPointer(typeKey->GetRetAndArgTypes(), typeKey->GetNumArgs() + 1);
393 return ComputeLoaderModuleForParamType(typeKey->GetElementType());
397 BOOL ClassLoader::IsTypicalInstantiation(Module *pModule, mdToken token, Instantiation inst)
404 PRECONDITION(CheckPointer(pModule));
405 PRECONDITION(TypeFromToken(token) == mdtTypeDef || TypeFromToken(token) == mdtMethodDef);
410 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
412 TypeHandle thArg = inst[i];
414 if (thArg.IsGenericVariable())
416 TypeVarTypeDesc* tyvar = thArg.AsGenericVariable();
418 PREFIX_ASSUME(tyvar!=NULL);
419 if ((tyvar->GetTypeOrMethodDef() != token) ||
420 (tyvar->GetModule() != dac_cast<PTR_Module>(pModule)) ||
421 (tyvar->GetIndex() != i))
432 // External class loader entry point: load a type by name
434 TypeHandle ClassLoader::LoadTypeByNameThrowing(Assembly *pAssembly,
437 NotFoundAction fNotFound,
438 ClassLoader::LoadTypesFlag fLoadTypes,
439 ClassLoadLevel level)
443 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
444 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
445 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
448 if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
450 PRECONDITION(CheckPointer(pAssembly));
451 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
452 POSTCONDITION(CheckPointer(RETVAL,
453 (fNotFound == ThrowIfNotFound && fLoadTypes == LoadTypes )? NULL_NOT_OK : NULL_OK));
454 POSTCONDITION(RETVAL.IsNull() || RETVAL.CheckLoadLevel(level));
456 #ifdef DACCESS_COMPILE
457 PRECONDITION((fNotFound == ClassLoader::ReturnNullIfNotFound) && (fLoadTypes == DontLoadTypes));
462 NameHandle nameHandle(nameSpace, name);
463 if (fLoadTypes == DontLoadTypes)
464 nameHandle.SetTokenNotToLoad(tdAllTypes);
465 if (fNotFound == ThrowIfNotFound)
466 RETURN pAssembly->GetLoader()->LoadTypeHandleThrowIfFailed(&nameHandle, level);
468 RETURN pAssembly->GetLoader()->LoadTypeHandleThrowing(&nameHandle, level);
471 #ifndef DACCESS_COMPILE
473 #define DAC_LOADS_TYPE(level, expression) \
474 if (FORBIDGC_LOADER_USE_ENABLED() || (expression)) \
475 { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
478 #define DAC_LOADS_TYPE(level, expression) { LOADS_TYPE(CLASS_LOAD_BEGIN); }
479 #endif // #ifndef DACCESS_COMPILE
482 // Find a class given name, using the classloader's global list of known classes.
483 // If the type is found, it will be restored unless pName->GetTokenNotToLoad() prohibits that
484 // Returns NULL if class not found AND pName->OKToLoad returns false
485 TypeHandle ClassLoader::LoadTypeHandleThrowIfFailed(NameHandle* pName, ClassLoadLevel level,
486 Module* pLookInThisModuleOnly/*=NULL*/)
491 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
492 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
493 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
494 DAC_LOADS_TYPE(level, !pName->OKToLoad());
496 PRECONDITION(CheckPointer(pName));
497 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
498 POSTCONDITION(CheckPointer(RETVAL, pName->OKToLoad() ? NULL_NOT_OK : NULL_OK));
499 POSTCONDITION(RETVAL.IsNull() || RETVAL.CheckLoadLevel(level));
504 // Lookup in the classes that this class loader knows about
505 TypeHandle typeHnd = LoadTypeHandleThrowing(pName, level, pLookInThisModuleOnly);
507 if(typeHnd.IsNull()) {
509 if ( pName->OKToLoad() ) {
512 LPCUTF8 szName = pName->GetName();
514 szName = "<UNKNOWN>";
516 StackSString codeBase;
517 GetAssembly()->GetCodeBase(codeBase);
519 LOG((LF_CLASSLOADER, LL_INFO10, "Failed to find class \"%s\" in the manifest for assembly \"%ws\"\n", szName, (LPCWSTR)codeBase));
523 #ifndef DACCESS_COMPILE
524 m_pAssembly->ThrowTypeLoadException(pName, IDS_CLASSLOAD_GENERAL);
534 #ifndef DACCESS_COMPILE
536 //<TODO>@TODO: Need to allow exceptions to be thrown when classloader is cleaned up</TODO>
537 EEClassHashEntry_t* ClassLoader::InsertValue(EEClassHashTable *pClassHash, EEClassHashTable *pClassCaseInsHash, LPCUTF8 pszNamespace, LPCUTF8 pszClassName, HashDatum Data, EEClassHashEntry_t *pEncloser, AllocMemTracker *pamTracker)
545 INJECT_FAULT(COMPlusThrowOM(););
549 LPUTF8 pszLowerCaseNS = NULL;
550 LPUTF8 pszLowerCaseName = NULL;
551 EEClassHashEntry_t *pCaseInsEntry = NULL;
553 EEClassHashEntry_t *pEntry = pClassHash->AllocNewEntry(pamTracker);
555 if (pClassCaseInsHash) {
556 CreateCanonicallyCasedKey(pszNamespace, pszClassName, &pszLowerCaseNS, &pszLowerCaseName);
557 pCaseInsEntry = pClassCaseInsHash->AllocNewEntry(pamTracker);
562 // ! We cannot fail after this point.
563 CANNOTTHROWCOMPLUSEXCEPTION();
567 pClassHash->InsertValueUsingPreallocatedEntry(pEntry, pszNamespace, pszClassName, Data, pEncloser);
569 //If we're keeping a table for case-insensitive lookup, keep that up to date
570 if (pClassCaseInsHash)
571 pClassCaseInsHash->InsertValueUsingPreallocatedEntry(pCaseInsEntry, pszLowerCaseNS, pszLowerCaseName, pEntry, pEncloser);
578 #endif // #ifndef DACCESS_COMPILE
580 BOOL ClassLoader::CompareNestedEntryWithExportedType(IMDInternalImport * pImport,
581 mdExportedType mdCurrent,
582 EEClassHashTable * pClassHash,
583 PTR_EEClassHashEntry pEntry)
600 if (FAILED(pImport->GetExportedTypeProps(
605 NULL, //binding (type def)
611 if (pClassHash->CompareKeys(pEntry, Key))
613 // Reached top level class for mdCurrent - return whether
614 // or not pEntry is a top level class
615 // (pEntry is a top level class if its pEncloser is NULL)
616 if ((TypeFromToken(mdCurrent) != mdtExportedType) ||
617 (mdCurrent == mdExportedTypeNil))
619 return pEntry->GetEncloser() == NULL;
622 else // Keys don't match - wrong entry
627 while ((pEntry = pEntry->GetEncloser()) != NULL);
629 // Reached the top level class for pEntry, but mdCurrent is nested
634 BOOL ClassLoader::CompareNestedEntryWithTypeDef(IMDInternalImport * pImport,
636 EEClassHashTable * pClassHash,
637 PTR_EEClassHashEntry pEntry)
653 if (FAILED(pImport->GetNameOfTypeDef(mdCurrent, &Key[1], &Key[0])))
658 if (pClassHash->CompareKeys(pEntry, Key)) {
659 // Reached top level class for mdCurrent - return whether
660 // or not pEntry is a top level class
661 // (pEntry is a top level class if its pEncloser is NULL)
662 if (FAILED(pImport->GetNestedClassProps(mdCurrent, &mdCurrent)))
663 return pEntry->GetEncloser() == NULL;
665 else // Keys don't match - wrong entry
668 while ((pEntry = pEntry->GetEncloser()) != NULL);
670 // Reached the top level class for pEntry, but mdCurrent is nested
675 BOOL ClassLoader::CompareNestedEntryWithTypeRef(IMDInternalImport * pImport,
677 EEClassHashTable * pClassHash,
678 PTR_EEClassHashEntry pEntry)
694 if (FAILED(pImport->GetNameOfTypeRef(mdCurrent, &Key[0], &Key[1])))
699 if (pClassHash->CompareKeys(pEntry, Key))
701 if (FAILED(pImport->GetResolutionScopeOfTypeRef(mdCurrent, &mdCurrent)))
705 // Reached top level class for mdCurrent - return whether
706 // or not pEntry is a top level class
707 // (pEntry is a top level class if its pEncloser is NULL)
708 if ((TypeFromToken(mdCurrent) != mdtTypeRef) ||
709 (mdCurrent == mdTypeRefNil))
710 return pEntry->GetEncloser() == NULL;
712 else // Keys don't match - wrong entry
715 while ((pEntry = pEntry->GetEncloser())!=NULL);
717 // Reached the top level class for pEntry, but mdCurrent is nested
723 BOOL ClassLoader::IsNested(Module *pModule, mdToken token, mdToken *mdEncloser)
727 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
728 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
729 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
735 switch(TypeFromToken(token)) {
737 return (SUCCEEDED(pModule->GetMDImport()->GetNestedClassProps(token, mdEncloser)));
740 IfFailThrow(pModule->GetMDImport()->GetResolutionScopeOfTypeRef(token, mdEncloser));
741 return ((TypeFromToken(*mdEncloser) == mdtTypeRef) &&
742 (*mdEncloser != mdTypeRefNil));
744 case mdtExportedType:
745 IfFailThrow(pModule->GetAssembly()->GetManifestImport()->GetExportedTypeProps(
750 NULL, //binding (type def)
752 return ((TypeFromToken(*mdEncloser) == mdtExportedType) &&
753 (*mdEncloser != mdExportedTypeNil));
756 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE);
760 BOOL ClassLoader::IsNested(const NameHandle* pName, mdToken *mdEncloser)
765 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
766 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
767 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
773 if (pName->GetTypeModule()) {
774 if (TypeFromToken(pName->GetTypeToken()) == mdtBaseType)
776 if (!pName->GetBucket().IsNull())
781 return IsNested(pName->GetTypeModule(), pName->GetTypeToken(), mdEncloser);
787 void ClassLoader::GetClassValue(NameHandleTable nhTable,
788 const NameHandle *pName,
790 EEClassHashTable **ppTable,
791 Module* pLookInThisModuleOnly,
792 HashedTypeEntry* pFoundEntry,
793 Loader::LoadFlag loadFlag,
794 BOOL& needsToBuildHashtable)
800 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
801 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
802 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
803 PRECONDITION(CheckPointer(pName));
810 EEClassHashEntry_t *pBucket = NULL;
812 needsToBuildHashtable = FALSE;
815 if (pName->GetName()) {
816 if (pName->GetNameSpace() == NULL)
817 LOG((LF_CLASSLOADER, LL_INFO1000, "Looking up %s by name.\n",
820 LOG((LF_CLASSLOADER, LL_INFO1000, "Looking up %s.%s by name.\n",
821 pName->GetNameSpace(), pName->GetName()));
825 BOOL isNested = IsNested(pName, &mdEncloser);
827 PTR_Assembly assembly = GetAssembly();
828 PREFIX_ASSUME(assembly != NULL);
829 ModuleIterator i = assembly->IterateModules();
833 Module * pCurrentClsModule = i.GetModule();
834 PREFIX_ASSUME(pCurrentClsModule != NULL);
836 if (pCurrentClsModule->IsResource())
838 if (pLookInThisModuleOnly && (pCurrentClsModule != pLookInThisModuleOnly))
841 #ifdef FEATURE_READYTORUN
842 if (nhTable == nhCaseSensitive && pCurrentClsModule->IsReadyToRun() && pCurrentClsModule->GetReadyToRunInfo()->HasHashtableOfTypes() &&
843 pCurrentClsModule->GetAvailableClassHash() == NULL)
845 // For R2R modules, we only search the hashtable of token types stored in the module's image, and don't fallback
846 // to searching m_pAvailableClasses or m_pAvailableClassesCaseIns (in fact, we don't even allocate them for R2R modules).
847 // Also note that type lookups in R2R modules only support case sensitive lookups.
849 mdToken mdFoundTypeToken;
850 if (pCurrentClsModule->GetReadyToRunInfo()->TryLookupTypeTokenFromName(pName, &mdFoundTypeToken))
852 if (TypeFromToken(mdFoundTypeToken) == mdtExportedType)
855 Module * pTargetModule = GetAssembly()->FindModuleByExportedType(mdFoundTypeToken, loadFlag, mdTypeDefNil, &mdUnused);
857 pFoundEntry->SetTokenBasedEntryValue(mdFoundTypeToken, pTargetModule);
861 pFoundEntry->SetTokenBasedEntryValue(mdFoundTypeToken, pCurrentClsModule);
864 return; // Return on the first success
870 EEClassHashTable* pTable = NULL;
871 if (nhTable == nhCaseSensitive)
873 *ppTable = pTable = pCurrentClsModule->GetAvailableClassHash();
875 #ifdef FEATURE_READYTORUN
876 if (pTable == NULL && pCurrentClsModule->IsReadyToRun() && !pCurrentClsModule->GetReadyToRunInfo()->HasHashtableOfTypes())
878 // Old R2R image generated without the hashtable of types.
879 // We fallback to the slow path of creating the hashtable dynamically
880 // at execution time in that scenario. The caller will handle
881 pFoundEntry->SetClassHashBasedEntryValue(NULL);
882 needsToBuildHashtable = TRUE;
889 // currently we expect only these two kinds--for DAC builds, nhTable will be nhCaseSensitive
890 _ASSERTE(nhTable == nhCaseInsensitive);
891 *ppTable = pTable = pCurrentClsModule->GetAvailableClassCaseInsHash();
895 // We have not built the table yet - the caller will handle
896 pFoundEntry->SetClassHashBasedEntryValue(NULL);
897 needsToBuildHashtable = TRUE;
905 Module *pNameModule = pName->GetTypeModule();
906 PREFIX_ASSUME(pNameModule != NULL);
908 EEClassHashTable::LookupContext sContext;
909 if ((pBucket = pTable->GetValue(pName, pData, TRUE, &sContext)) != NULL)
911 switch (TypeFromToken(pName->GetTypeToken()))
914 while ((!CompareNestedEntryWithTypeDef(pNameModule->GetMDImport(),
916 pCurrentClsModule->GetAvailableClassHash(),
917 pBucket->GetEncloser())) &&
918 (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
921 while ((!CompareNestedEntryWithTypeRef(pNameModule->GetMDImport(),
923 pCurrentClsModule->GetAvailableClassHash(),
924 pBucket->GetEncloser())) &&
925 (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
927 case mdtExportedType:
928 while ((!CompareNestedEntryWithExportedType(pNameModule->GetAssembly()->GetManifestImport(),
930 pCurrentClsModule->GetAvailableClassHash(),
931 pBucket->GetEncloser())) &&
932 (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
935 while ((pBucket->GetEncloser() != pName->GetBucket().GetClassHashBasedEntryValue()) &&
936 (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL);
942 pBucket = pTable->GetValue(pName, pData, FALSE, NULL);
945 if (pBucket) // Return on the first success
947 pFoundEntry->SetClassHashBasedEntryValue(pBucket);
953 // No results found: default to a NULL EEClassHashEntry_t result
954 pFoundEntry->SetClassHashBasedEntryValue(NULL);
957 #ifndef DACCESS_COMPILE
959 VOID ClassLoader::PopulateAvailableClassHashTable(Module* pModule,
960 AllocMemTracker *pamTracker)
968 INJECT_FAULT(COMPlusThrowOM(););
973 HENUMInternal hTypeDefEnum;
974 IMDInternalImport * pImport = pModule->GetMDImport();
976 LPCSTR szWinRtNamespacePrefix = NULL;
977 DWORD cchWinRtNamespacePrefix = 0;
979 #ifdef FEATURE_COMINTEROP
981 StackScratchBuffer ssFileNameBuffer;
983 if (pModule->GetAssembly()->IsWinMD())
984 { // WinMD file in execution context (not ReflectionOnly context) - use its file name as WinRT namespace prefix
985 // (Windows requirement)
986 // Note: Reflection can work on 'unfinished' WinMD files where the types are in 'wrong' WinMD file (i.e.
987 // type namespace does not start with the file name)
989 _ASSERTE(pModule->GetFile()->IsAssembly()); // No multi-module WinMD file support
990 _ASSERTE(!pModule->GetFile()->GetPath().IsEmpty());
993 pModule->GetFile()->GetPath(),
999 szWinRtNamespacePrefix = ssFileName.GetUTF8(ssFileNameBuffer);
1000 cchWinRtNamespacePrefix = (DWORD)strlen(szWinRtNamespacePrefix);
1002 #endif //FEATURE_COMINTEROP
1004 IfFailThrow(pImport->EnumTypeDefInit(&hTypeDefEnum));
1006 // Now loop through all the classdefs adding the CVID and scope to the hash
1007 while(pImport->EnumTypeDefNext(&hTypeDefEnum, &td)) {
1009 AddAvailableClassHaveLock(pModule,
1012 szWinRtNamespacePrefix,
1013 cchWinRtNamespacePrefix);
1015 pImport->EnumTypeDefClose(&hTypeDefEnum);
1019 void ClassLoader::LazyPopulateCaseSensitiveHashTablesDontHaveLock()
1027 INJECT_FAULT(COMPlusThrowOM());
1032 CrstHolder ch(&m_AvailableClassLock);
1033 LazyPopulateCaseSensitiveHashTables();
1036 void ClassLoader::LazyPopulateCaseSensitiveHashTables()
1044 INJECT_FAULT(COMPlusThrowOM());
1048 AllocMemTracker amTracker;
1049 ModuleIterator i = GetAssembly()->IterateModules();
1051 // Create a case-sensitive hashtable for each module, and fill it with the module's typedef entries
1054 Module *pModule = i.GetModule();
1055 PREFIX_ASSUME(pModule != NULL);
1056 if (pModule->IsResource() || pModule->GetAvailableClassHash() != NULL)
1059 // Lazy construction of the case-sensitive hashtable of types is *only* a scenario for ReadyToRun images
1060 // (either images compiled with an old version of crossgen, or for case-insensitive type lookups in R2R modules)
1061 _ASSERT(pModule->IsReadyToRun());
1063 EEClassHashTable * pNewClassHash = EEClassHashTable::Create(pModule, AVAILABLE_CLASSES_HASH_BUCKETS, FALSE /* bCaseInsensitive */, &amTracker);
1064 pModule->SetAvailableClassHash(pNewClassHash);
1066 PopulateAvailableClassHashTable(pModule, &amTracker);
1069 // Add exported types of the manifest module to the hashtable
1070 if (!GetAssembly()->GetManifestModule()->IsResource())
1072 IMDInternalImport * pManifestImport = GetAssembly()->GetManifestImport();
1073 HENUMInternalHolder phEnum(pManifestImport);
1074 phEnum.EnumInit(mdtExportedType, mdTokenNil);
1076 mdToken mdExportedType;
1077 while (pManifestImport->EnumNext(&phEnum, &mdExportedType))
1078 AddExportedTypeHaveLock(GetAssembly()->GetManifestModule(), mdExportedType, &amTracker);
1081 amTracker.SuppressRelease();
1084 void ClassLoader::LazyPopulateCaseInsensitiveHashTables()
1092 INJECT_FAULT(COMPlusThrowOM());
1096 if (!GetAssembly()->GetManifestModule()->IsResource() && GetAssembly()->GetManifestModule()->GetAvailableClassHash() == NULL)
1098 // This is a R2R assembly, and a case insensitive type lookup was triggered.
1099 // Construct the case-sensitive table first, since the case-insensitive table
1100 // create piggy-backs on the first.
1101 LazyPopulateCaseSensitiveHashTables();
1104 // Add any unhashed modules into our hash tables, and try again.
1106 AllocMemTracker amTracker;
1107 ModuleIterator i = GetAssembly()->IterateModules();
1111 Module *pModule = i.GetModule();
1112 if (pModule->IsResource())
1115 if (pModule->GetAvailableClassCaseInsHash() == NULL)
1117 EEClassHashTable *pNewClassCaseInsHash = pModule->GetAvailableClassHash()->MakeCaseInsensitiveTable(pModule, &amTracker);
1119 LOG((LF_CLASSLOADER, LL_INFO10, "%s's classes being added to case insensitive hash table\n",
1120 pModule->GetSimpleName()));
1123 CANNOTTHROWCOMPLUSEXCEPTION();
1126 amTracker.SuppressRelease();
1127 pModule->SetAvailableClassCaseInsHash(pNewClassCaseInsHash);
1128 FastInterlockDecrement((LONG*)&m_cUnhashedModules);
1135 void DECLSPEC_NORETURN ClassLoader::ThrowTypeLoadException(TypeKey *pKey,
1138 STATIC_CONTRACT_THROWS;
1140 StackSString fullName;
1141 StackSString assemblyName;
1142 TypeString::AppendTypeKey(fullName, pKey);
1143 pKey->GetModule()->GetAssembly()->GetDisplayName(assemblyName);
1144 ::ThrowTypeLoadException(fullName, assemblyName, NULL, resIDWhy);
1150 TypeHandle ClassLoader::LoadConstructedTypeThrowing(TypeKey *pKey,
1151 LoadTypesFlag fLoadTypes /*= LoadTypes*/,
1152 ClassLoadLevel level /*=CLASS_LOADED*/,
1153 const InstantiationContext *pInstContext /*=NULL*/)
1155 CONTRACT(TypeHandle)
1157 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1158 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1159 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1160 if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
1161 PRECONDITION(CheckPointer(pKey));
1162 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1163 PRECONDITION(CheckPointer(pInstContext, NULL_OK));
1164 POSTCONDITION(CheckPointer(RETVAL, fLoadTypes==DontLoadTypes ? NULL_OK : NULL_NOT_OK));
1165 POSTCONDITION(RETVAL.IsNull() || RETVAL.GetLoadLevel() >= level);
1172 ClassLoadLevel existingLoadLevel = CLASS_LOAD_BEGIN;
1174 // Lookup in the classes that this class loader knows about
1176 if (pKey->HasInstantiation() && ClassLoader::IsTypicalSharedInstantiation(pKey->GetInstantiation()))
1178 _ASSERTE(pKey->GetModule() == ComputeLoaderModule(pKey));
1179 typeHnd = pKey->GetModule()->LookupFullyCanonicalInstantiation(pKey->GetTypeToken(), &existingLoadLevel);
1182 if (typeHnd.IsNull())
1184 typeHnd = LookupTypeHandleForTypeKey(pKey);
1185 if (!typeHnd.IsNull())
1187 existingLoadLevel = typeHnd.GetLoadLevel();
1188 if (existingLoadLevel >= level)
1189 g_IBCLogger.LogTypeHashTableAccess(&typeHnd);
1193 // If something has been published in the tables, and it's at the right level, just return it
1194 if (!typeHnd.IsNull() && existingLoadLevel >= level)
1199 #ifndef DACCESS_COMPILE
1200 if (typeHnd.IsNull() && pKey->HasInstantiation())
1202 if (!Generics::CheckInstantiation(pKey->GetInstantiation()))
1203 pKey->GetModule()->GetAssembly()->ThrowTypeLoadException(pKey->GetModule()->GetMDImport(), pKey->GetTypeToken(), IDS_CLASSLOAD_INVALIDINSTANTIATION);
1207 // If we're not loading any types at all, then we're not creating
1208 // instantiations either because we're in FORBIDGC_LOADER_USE mode, so
1209 // we should bail out here.
1210 if (fLoadTypes == DontLoadTypes)
1211 RETURN TypeHandle();
1213 #ifndef DACCESS_COMPILE
1214 // If we got here, we now have to allocate a new parameterized type.
1215 // By definition, forbidgc-users aren't allowed to reach this point.
1216 CONSISTENCY_CHECK(!FORBIDGC_LOADER_USE_ENABLED());
1218 Module *pLoaderModule = ComputeLoaderModule(pKey);
1219 RETURN(pLoaderModule->GetClassLoader()->LoadTypeHandleForTypeKey(pKey, typeHnd, level, pInstContext));
1228 void ClassLoader::EnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level)
1232 PRECONDITION(CheckPointer(typeHnd));
1233 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1234 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1235 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1236 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1237 if (FORBIDGC_LOADER_USE_ENABLED()) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
1244 #ifndef DACCESS_COMPILE // Nothing to do for the DAC case
1246 if (typeHnd.GetLoadLevel() < level)
1248 #ifdef FEATURE_PREJIT
1249 if (typeHnd.GetLoadLevel() == CLASS_LOAD_UNRESTOREDTYPEKEY)
1251 typeHnd.DoRestoreTypeKey();
1254 if (level > CLASS_LOAD_UNRESTORED)
1256 TypeKey typeKey = typeHnd.GetTypeKey();
1258 Module *pLoaderModule = ComputeLoaderModule(&typeKey);
1259 pLoaderModule->GetClassLoader()->LoadTypeHandleForTypeKey(&typeKey, typeHnd, level);
1263 #endif // DACCESS_COMPILE
1267 void ClassLoader::TryEnsureLoaded(TypeHandle typeHnd, ClassLoadLevel level)
1269 WRAPPER_NO_CONTRACT;
1271 #ifndef DACCESS_COMPILE // Nothing to do for the DAC case
1275 ClassLoader::EnsureLoaded(typeHnd, level);
1279 // Some type may not load successfully. For eg. generic instantiations
1280 // that do not satisfy the constraints of the type arguments.
1282 EX_END_CATCH(RethrowTerminalExceptions);
1284 #endif // DACCESS_COMPILE
1287 // This is separated out to avoid the overhead of C++ exception handling in the non-locking case.
1289 TypeHandle ClassLoader::LookupTypeKeyUnderLock(TypeKey *pKey,
1290 EETypeHashTable *pTable,
1293 WRAPPER_NO_CONTRACT;
1296 // m_AvailableTypesLock has to be taken in cooperative mode to avoid deadlocks during GC
1297 GCX_MAYBE_COOP_NO_THREAD_BROKEN(!IsGCThread());
1299 CrstHolder ch(pLock);
1300 return pTable->GetValue(pKey);
1304 TypeHandle ClassLoader::LookupTypeKey(TypeKey *pKey,
1305 EETypeHashTable *pTable,
1307 BOOL fCheckUnderLock)
1313 PRECONDITION(CheckPointer(pKey));
1314 PRECONDITION(pKey->IsConstructed());
1315 PRECONDITION(CheckPointer(pTable));
1316 PRECONDITION(!fCheckUnderLock || CheckPointer(pLock));
1323 if (fCheckUnderLock)
1325 th = LookupTypeKeyUnderLock(pKey, pTable, pLock);
1329 th = pTable->GetValue(pKey);
1335 #ifdef FEATURE_PREJIT
1337 TypeHandle ClassLoader::LookupInPreferredZapModule(TypeKey *pKey, BOOL fCheckUnderLock)
1343 PRECONDITION(CheckPointer(pKey));
1344 PRECONDITION(pKey->IsConstructed());
1349 // First look for an NGEN'd type in the preferred ngen module
1351 PTR_Module pPreferredZapModule = Module::ComputePreferredZapModule(pKey);
1353 if (pPreferredZapModule != NULL && pPreferredZapModule->HasNativeImage())
1355 th = LookupTypeKey(pKey,
1356 pPreferredZapModule->GetAvailableParamTypes(),
1357 &pPreferredZapModule->GetClassLoader()->m_AvailableTypesLock,
1363 #endif // FEATURE_PREJIT
1367 TypeHandle ClassLoader::LookupInLoaderModule(TypeKey *pKey, BOOL fCheckUnderLock)
1373 PRECONDITION(CheckPointer(pKey));
1374 PRECONDITION(pKey->IsConstructed());
1379 Module *pLoaderModule = ComputeLoaderModule(pKey);
1380 PREFIX_ASSUME(pLoaderModule!=NULL);
1382 return LookupTypeKey(pKey,
1383 pLoaderModule->GetAvailableParamTypes(),
1384 &pLoaderModule->GetClassLoader()->m_AvailableTypesLock,
1390 TypeHandle ClassLoader::LookupTypeHandleForTypeKey(TypeKey *pKey)
1392 WRAPPER_NO_CONTRACT;
1395 // Make an initial lookup without taking any locks.
1396 TypeHandle th = LookupTypeHandleForTypeKeyInner(pKey, FALSE);
1398 // A non-null TypeHandle for the above lookup indicates success
1399 // A null TypeHandle only indicates "well, it might have been there,
1400 // try again with a lock". This kind of negative result will
1401 // only happen while accessing the underlying EETypeHashTable
1402 // during a resize, i.e. very rarely. In such a case, we just
1403 // perform the lookup again, but indicate that appropriate locks
1408 th = LookupTypeHandleForTypeKeyInner(pKey, TRUE);
1414 TypeHandle ClassLoader::LookupTypeHandleForTypeKeyInner(TypeKey *pKey, BOOL fCheckUnderLock)
1421 PRECONDITION(CheckPointer(pKey));
1427 // Check if it's the typical instantiation. In this case it's not stored in the same
1428 // way as other constructed types.
1429 if (!pKey->IsConstructed() ||
1430 (pKey->GetKind() == ELEMENT_TYPE_CLASS && ClassLoader::IsTypicalInstantiation(pKey->GetModule(),
1431 pKey->GetTypeToken(),
1432 pKey->GetInstantiation())))
1434 return TypeHandle(pKey->GetModule()->LookupTypeDef(pKey->GetTypeToken()));
1437 #ifdef FEATURE_PREJIT
1438 // The following ways of finding a constructed type should be mutually exclusive!
1439 // 1. Look for a zapped item in the PreferredZapModule
1440 // 2. Look for a unzapped (JIT-loaded) item in the LoaderModule
1442 TypeHandle thPZM = LookupInPreferredZapModule(pKey, fCheckUnderLock);
1443 if (!thPZM.IsNull())
1447 #endif // FEATURE_PREJIT
1449 // Next look in the loader module. This is where the item is guaranteed to live if
1450 // it is not latched from an NGEN image, i.e. if it is JIT loaded.
1451 // If the thing is not NGEN'd then this may
1452 // be different to pPreferredZapModule. If they are the same then
1453 // we can reuse the results of the lookup above.
1454 TypeHandle thLM = LookupInLoaderModule(pKey, fCheckUnderLock);
1460 return TypeHandle();
1463 // FindClassModuleThrowing discovers which module the type you're looking for is in and loads the Module if necessary.
1464 // Basically, it iterates through all of the assembly's modules until a name match is found in a module's
1465 // AvailableClassHashTable.
1467 // The possible outcomes are:
1469 // - Function returns TRUE - class exists and we successfully found/created the containing Module. See below
1470 // for how to deconstruct the results.
1471 // - Function returns FALSE - class affirmatively NOT found (that means it doesn't exist as a regular type although
1472 // it could also be a parameterized type)
1473 // - Function throws - OOM or some other reason we couldn't do the job (if it's a case-sensitive search
1474 // and you're looking for already loaded type or you've set the TokenNotToLoad.
1475 // we are guaranteed not to find a reason to throw.)
1478 // If it succeeds (returns TRUE), one of the following will occur. Check (*pType)->IsNull() to discriminate.
1480 // 1. *pType: set to the null TypeHandle()
1481 // *ppModule: set to the owning Module
1482 // *pmdClassToken: set to the typedef
1483 // *pmdFoundExportedType: if this name bound to an ExportedType, this contains the mdtExportedType token (otherwise,
1484 // it's set to mdTokenNil.) You need this because in this case, *pmdClassToken is just
1485 // a best guess and you need to verify it. (The division of labor between this
1486 // and LoadTypeHandle could definitely be better!)
1488 // 2. *pType: set to non-null TypeHandle()
1489 // This means someone else had already done this same lookup before you and caused the actual
1490 // TypeHandle to be cached. Since we know that's what you *really* wanted, we'll just forget the
1491 // Module/typedef stuff and give you the actual TypeHandle.
1494 BOOL ClassLoader::FindClassModuleThrowing(
1495 const NameHandle * pName,
1497 mdToken * pmdClassToken,
1499 mdToken * pmdFoundExportedType,
1500 HashedTypeEntry * pFoundEntry,
1501 Module * pLookInThisModuleOnly,
1502 Loader::LoadFlag loadFlag)
1507 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1508 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1509 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1510 PRECONDITION(CheckPointer(pName));
1511 PRECONDITION(CheckPointer(ppModule));
1517 // Note that the type name is expected to be lower-cased by the caller for case-insensitive lookups
1519 NameHandleTable nhTable = pName->GetTable();
1521 // Remember if there are any unhashed modules. We must do this before
1522 // the actual look to avoid a race condition with other threads doing lookups.
1524 BOOL incomplete = (m_cUnhashedModules > 0);
1528 EEClassHashTable * pTable = NULL;
1529 HashedTypeEntry foundEntry;
1530 BOOL needsToBuildHashtable;
1531 GetClassValue(nhTable, pName, &Data, &pTable, pLookInThisModuleOnly, &foundEntry, loadFlag, needsToBuildHashtable);
1533 // In the case of R2R modules, the search is only performed in the hashtable saved in the
1534 // R2R image, and this is why we return (whether we found a valid typedef token or not).
1535 // Note: case insensitive searches are not used/supported in R2R images.
1536 if (foundEntry.GetEntryType() == HashedTypeEntry::EntryType::IsHashedTokenEntry)
1538 *pType = TypeHandle();
1539 HashedTypeEntry::TokenTypeEntry tokenAndModulePair = foundEntry.GetTokenBasedEntryValue();
1540 switch (TypeFromToken(tokenAndModulePair.m_TypeToken))
1543 *pmdClassToken = tokenAndModulePair.m_TypeToken;
1544 *pmdFoundExportedType = mdTokenNil;
1546 case mdtExportedType:
1547 *pmdClassToken = mdTokenNil;
1548 *pmdFoundExportedType = tokenAndModulePair.m_TypeToken;
1554 *ppModule = tokenAndModulePair.m_pModule;
1555 if (pFoundEntry != NULL)
1556 *pFoundEntry = foundEntry;
1561 EEClassHashEntry_t * pBucket = foundEntry.GetClassHashBasedEntryValue();
1563 if (pBucket == NULL)
1565 AvailableClasses_LockHolder lh(this);
1567 // Try again with the lock. This will protect against another thread reallocating
1568 // the hash table underneath us
1569 GetClassValue(nhTable, pName, &Data, &pTable, pLookInThisModuleOnly, &foundEntry, loadFlag, needsToBuildHashtable);
1570 pBucket = foundEntry.GetClassHashBasedEntryValue();
1572 #ifndef DACCESS_COMPILE
1573 if (needsToBuildHashtable && (pBucket == NULL) && (m_cUnhashedModules > 0))
1575 _ASSERT(needsToBuildHashtable);
1577 if (nhTable == nhCaseInsensitive)
1579 LazyPopulateCaseInsensitiveHashTables();
1583 // Note: This codepath is only valid for R2R scenarios
1584 LazyPopulateCaseSensitiveHashTables();
1587 // Try yet again with the new classes added
1588 GetClassValue(nhTable, pName, &Data, &pTable, pLookInThisModuleOnly, &foundEntry, loadFlag, needsToBuildHashtable);
1589 pBucket = foundEntry.GetClassHashBasedEntryValue();
1590 _ASSERT(!needsToBuildHashtable);
1595 // Same check as above, but this time we've checked with the lock so the table will be populated
1596 if (pBucket == NULL)
1598 #if defined(_DEBUG_IMPL) && !defined(DACCESS_COMPILE)
1599 LPCUTF8 szName = pName->GetName();
1601 szName = "<UNKNOWN>";
1602 LOG((LF_CLASSLOADER, LL_INFO10, "Failed to find type \"%s\", assembly \"%ws\" in hash table. Incomplete = %d\n",
1603 szName, GetAssembly()->GetDebugName(), incomplete));
1608 if (pName->GetTable() == nhCaseInsensitive)
1611 pBucket = PTR_EEClassHashEntry(Data);
1612 Data = pBucket->GetData();
1615 // Lower bit is a discriminator. If the lower bit is NOT SET, it means we have
1616 // a TypeHandle. Otherwise, we have a Module/CL.
1617 if ((dac_cast<TADDR>(Data) & EECLASSHASH_TYPEHANDLE_DISCR) == 0)
1619 TypeHandle t = TypeHandle::FromPtr(Data);
1620 _ASSERTE(!t.IsNull());
1623 if (pFoundEntry != NULL)
1625 pFoundEntry->SetClassHashBasedEntryValue(pBucket);
1630 // We have a Module/CL
1631 if (!pTable->UncompressModuleAndClassDef(Data,
1635 pmdFoundExportedType))
1637 _ASSERTE(loadFlag != Loader::Load);
1641 *pType = TypeHandle();
1642 if (pFoundEntry != NULL)
1644 pFoundEntry->SetClassHashBasedEntryValue(pBucket);
1647 } // ClassLoader::FindClassModuleThrowing
1649 #ifndef DACCESS_COMPILE
1650 // Returns true if the full name (namespace+name) of pName matches that
1651 // of typeHnd; otherwise false. Because this is nothrow, it will default
1652 // to false for all exceptions (such as OOM).
1653 bool CompareNameHandleWithTypeHandleNoThrow(
1654 const NameHandle * pName,
1661 // This block is specifically designed to handle transient faults such
1662 // as OOM exceptions.
1663 CONTRACT_VIOLATION(FaultViolation | ThrowsViolation);
1664 StackSString ssBuiltName;
1665 ns::MakePath(ssBuiltName,
1666 StackSString(SString::Utf8, pName->GetNameSpace()),
1667 StackSString(SString::Utf8, pName->GetName()));
1668 StackSString ssName;
1669 typeHnd.GetName(ssName);
1670 fRet = ssName.Equals(ssBuiltName) == TRUE;
1674 // Technically, the above operations should never result in a non-OOM
1675 // exception, but we'll put the rethrow line in there just in case.
1676 CONSISTENCY_CHECK(!GET_EXCEPTION()->IsTerminal());
1677 RethrowTerminalExceptions;
1679 EX_END_CATCH(SwallowAllExceptions);
1683 #endif // #ifndef DACCESS_COMPILE
1685 // 1024 seems like a good bet at detecting a loop in the type forwarding.
1686 static const UINT32 const_cMaxTypeForwardingChainSize = 1024;
1688 // Does not throw an exception if the type was not found. Use LoadTypeHandleThrowIfFailed()
1689 // instead if you need that.
1693 // Will be set to the 'final' TypeDef bucket if pName->GetTokenType() is mdtBaseType.
1696 ClassLoader::LoadTypeHandleThrowing(
1698 ClassLoadLevel level,
1699 Module * pLookInThisModuleOnly /*=NULL*/)
1701 CONTRACT(TypeHandle) {
1703 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1704 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1705 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1706 DAC_LOADS_TYPE(level, !pName->OKToLoad());
1707 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1708 PRECONDITION(CheckPointer(pName));
1709 POSTCONDITION(RETVAL.IsNull() || RETVAL.GetLoadLevel() >= level);
1715 Module * pFoundModule = NULL;
1717 HashedTypeEntry foundEntry;
1718 mdExportedType FoundExportedType = mdTokenNil;
1720 UINT32 cLoopIterations = 0;
1722 ClassLoader * pClsLdr = this;
1726 if (cLoopIterations++ >= const_cMaxTypeForwardingChainSize)
1727 { // If we've looped too many times due to type forwarding, return null TypeHandle
1728 // Would prefer to return a format exception, but the original behaviour
1729 // was to detect a stack overflow possibility and return a null, and
1730 // so we need to maintain this.
1731 typeHnd = TypeHandle();
1735 // Look outside the lock (though we're actually still a long way from the
1736 // lock at this point...). This may discover that the type is actually
1737 // defined in another module...
1739 if (!pClsLdr->FindClassModuleThrowing(
1746 pLookInThisModuleOnly,
1747 pName->OKToLoad() ? Loader::Load
1748 : Loader::DontLoad))
1749 { // Didn't find anything, no point looping indefinitely
1752 _ASSERTE(!foundEntry.IsNull());
1754 if (pName->GetTypeToken() == mdtBaseType)
1755 { // We should return the found bucket in the pName
1756 pName->SetBucket(foundEntry);
1759 if (!typeHnd.IsNull())
1760 { // Found the cached value, or a constructedtype
1761 if (typeHnd.GetLoadLevel() < level)
1763 typeHnd = pClsLdr->LoadTypeDefThrowing(
1764 typeHnd.GetModule(),
1766 ClassLoader::ReturnNullIfNotFound,
1767 ClassLoader::PermitUninstDefOrRef, // When loading by name we always permit naked type defs/refs
1768 pName->GetTokenNotToLoad(),
1774 // Found a cl, pModule pair
1776 // If the found module's class loader is not the same as the current class loader,
1777 // then this is a forwarded type and we want to do something else (see
1778 // code:#LoadTypeHandle_TypeForwarded).
1779 if (pFoundModule->GetClassLoader() == pClsLdr)
1781 BOOL fTrustTD = TRUE;
1782 #ifndef DACCESS_COMPILE
1783 CONTRACT_VIOLATION(ThrowsViolation);
1784 BOOL fVerifyTD = FALSE;
1786 // If this is an exported type with a mdTokenNil class token, then then
1787 // exported type did not give a typedefID hint. We won't be able to trust the typedef
1789 if ((FoundExportedType != mdTokenNil) && (FoundCl == mdTokenNil))
1794 // verify that FoundCl is a valid token for pFoundModule, because
1795 // it may be just the hint saved in an ExportedType in another scope
1798 fTrustTD = pFoundModule->GetMDImport()->IsValidToken(FoundCl);
1800 #endif // #ifndef DACCESS_COMPILE
1804 typeHnd = pClsLdr->LoadTypeDefThrowing(
1807 ClassLoader::ReturnNullIfNotFound,
1808 ClassLoader::PermitUninstDefOrRef, // when loading by name we always permit naked type defs/refs
1809 pName->GetTokenNotToLoad(),
1812 #ifndef DACCESS_COMPILE
1813 // If we used a TypeDef saved in a ExportedType, if we didn't verify
1814 // the hash for this internal module, don't trust the TD value.
1817 if (typeHnd.IsNull() || !CompareNameHandleWithTypeHandleNoThrow(pName, typeHnd))
1819 if (SUCCEEDED(pClsLdr->FindTypeDefByExportedType(
1820 pClsLdr->GetAssembly()->GetManifestImport(),
1822 pFoundModule->GetMDImport(),
1825 typeHnd = pClsLdr->LoadTypeDefThrowing(
1828 ClassLoader::ReturnNullIfNotFound,
1829 ClassLoader::PermitUninstDefOrRef,
1830 pName->GetTokenNotToLoad(),
1835 typeHnd = TypeHandle();
1839 #endif // #ifndef DACCESS_COMPILE
1843 { //#LoadTypeHandle_TypeForwarded
1844 // pName is a host instance so it's okay to set fields in it in a DAC build
1845 const HashedTypeEntry& bucket = pName->GetBucket();
1847 // Reset pName's bucket entry
1848 if (bucket.GetEntryType() == HashedTypeEntry::IsHashedClassEntry && bucket.GetClassHashBasedEntryValue()->GetEncloser())
1850 // We will be searching for the type name again, so set the nesting/context type to the
1851 // encloser of just found type
1852 pName->SetBucket(HashedTypeEntry().SetClassHashBasedEntryValue(bucket.GetClassHashBasedEntryValue()->GetEncloser()));
1856 pName->SetBucket(HashedTypeEntry());
1859 // Update the class loader for the new module/token pair.
1860 pClsLdr = pFoundModule->GetClassLoader();
1861 pLookInThisModuleOnly = NULL;
1864 #ifndef DACCESS_COMPILE
1865 // Replace AvailableClasses Module entry with found TypeHandle
1866 if (!typeHnd.IsNull() &&
1867 typeHnd.IsRestored() &&
1868 foundEntry.GetEntryType() == HashedTypeEntry::EntryType::IsHashedClassEntry &&
1869 (foundEntry.GetClassHashBasedEntryValue() != NULL) &&
1870 (foundEntry.GetClassHashBasedEntryValue()->GetData() != typeHnd.AsPtr()))
1872 foundEntry.GetClassHashBasedEntryValue()->SetData(typeHnd.AsPtr());
1874 #endif // !DACCESS_COMPILE
1878 } // ClassLoader::LoadTypeHandleThrowing
1881 TypeHandle ClassLoader::LoadPointerOrByrefTypeThrowing(CorElementType typ,
1882 TypeHandle baseType,
1883 LoadTypesFlag fLoadTypes/*=LoadTypes*/,
1884 ClassLoadLevel level/*=CLASS_LOADED*/)
1886 CONTRACT(TypeHandle)
1888 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1889 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1890 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1891 if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
1893 PRECONDITION(CheckPointer(baseType));
1894 PRECONDITION(typ == ELEMENT_TYPE_BYREF || typ == ELEMENT_TYPE_PTR);
1895 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1896 POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
1901 TypeKey key(typ, baseType);
1902 RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level));
1906 TypeHandle ClassLoader::LoadNativeValueTypeThrowing(TypeHandle baseType,
1907 LoadTypesFlag fLoadTypes/*=LoadTypes*/,
1908 ClassLoadLevel level/*=CLASS_LOADED*/)
1910 CONTRACT(TypeHandle)
1912 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1913 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1914 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1916 PRECONDITION(CheckPointer(baseType));
1917 PRECONDITION(baseType.AsMethodTable()->IsValueType());
1918 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1919 POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
1923 TypeKey key(ELEMENT_TYPE_VALUETYPE, baseType);
1924 RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level));
1928 TypeHandle ClassLoader::LoadFnptrTypeThrowing(BYTE callConv,
1931 LoadTypesFlag fLoadTypes/*=LoadTypes*/,
1932 ClassLoadLevel level/*=CLASS_LOADED*/)
1934 CONTRACT(TypeHandle)
1936 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1937 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1938 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
1939 if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
1940 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1941 POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
1947 TypeKey key(callConv, ntypars, inst);
1948 RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level));
1951 // Find an instantiation of a generic type if it has already been created.
1952 // If typeDef is not a generic type or is already instantiated then throw an exception.
1953 // If its arity does not match ntypars then throw an exception.
1954 // Value will be non-null if we're loading types.
1956 TypeHandle ClassLoader::LoadGenericInstantiationThrowing(Module *pModule,
1959 LoadTypesFlag fLoadTypes/*=LoadTypes*/,
1960 ClassLoadLevel level/*=CLASS_LOADED*/,
1961 const InstantiationContext *pInstContext/*=NULL*/,
1962 BOOL fFromNativeImage /*=FALSE*/)
1964 // This can be called in FORBIDGC_LOADER_USE mode by the debugger to find
1965 // a particular generic type instance that is already loaded.
1966 CONTRACT(TypeHandle)
1968 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1969 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1970 if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
1971 PRECONDITION(CheckPointer(pModule));
1973 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
1974 PRECONDITION(CheckPointer(pInstContext, NULL_OK));
1975 POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
1980 // Essentially all checks to determine if a generic instantiation of a type
1981 // is well-formed go in this method, i.e. this is the
1982 // "choke" point through which all attempts
1983 // to create an instantiation flow. There is a similar choke point for generic
1984 // methods in genmeth.cpp.
1986 if (inst.IsEmpty() || ClassLoader::IsTypicalInstantiation(pModule, typeDef, inst))
1988 TypeHandle th = LoadTypeDefThrowing(pModule, typeDef,
1990 PermitUninstDefOrRef,
1991 fLoadTypes == DontLoadTypes ? tdAllTypes : tdNoTypes,
1993 fFromNativeImage ? NULL : &inst);
1994 _ASSERTE(th.GetNumGenericArgs() == inst.GetNumArgs());
1998 if (!fFromNativeImage)
2000 TypeHandle th = ClassLoader::LoadTypeDefThrowing(pModule, typeDef,
2002 PermitUninstDefOrRef,
2003 fLoadTypes == DontLoadTypes ? tdAllTypes : tdNoTypes,
2005 fFromNativeImage ? NULL : &inst);
2006 _ASSERTE(th.GetNumGenericArgs() == inst.GetNumArgs());
2009 TypeKey key(pModule, typeDef, inst);
2011 #ifndef DACCESS_COMPILE
2012 // To avoid loading useless shared instantiations, normalize shared instantiations to the canonical form
2013 // (e.g. Dictionary<String,_Canon> -> Dictionary<_Canon,_Canon>)
2014 // The denormalized shared instantiations should be needed only during JITing, so it is fine to skip this
2015 // for DACCESS_COMPILE.
2016 if (TypeHandle::IsCanonicalSubtypeInstantiation(inst) && !IsCanonicalGenericInstantiation(inst))
2018 RETURN(ClassLoader::LoadCanonicalGenericInstantiation(&key, fLoadTypes, level));
2022 RETURN(LoadConstructedTypeThrowing(&key, fLoadTypes, level, pInstContext));
2025 // For non-nested classes, gets the ExportedType name and finds the corresponding
2027 // For nested classes, gets the name of the ExportedType and its encloser.
2028 // Recursively gets and keeps the name for each encloser until we have the top
2029 // level one. Gets the TypeDef token for that. Then, returns from the
2030 // recursion, using the last found TypeDef token in order to find the
2031 // next nested level down TypeDef token. Finally, returns the TypeDef
2032 // token for the type we care about.
2034 HRESULT ClassLoader::FindTypeDefByExportedType(IMDInternalImport *pCTImport, mdExportedType mdCurrent,
2035 IMDInternalImport *pTDImport, mdTypeDef *mtd)
2048 LPCSTR szcNameSpace;
2052 IfFailRet(pCTImport->GetExportedTypeProps(
2060 if ((TypeFromToken(mdImpl) == mdtExportedType) &&
2061 (mdImpl != mdExportedTypeNil)) {
2062 // mdCurrent is a nested ExportedType
2063 IfFailRet(FindTypeDefByExportedType(pCTImport, mdImpl, pTDImport, mtd));
2065 // Get TypeDef token for this nested type
2066 return pTDImport->FindTypeDef(szcNameSpace, szcName, *mtd, mtd);
2069 // Get TypeDef token for this top-level type
2070 return pTDImport->FindTypeDef(szcNameSpace, szcName, mdTokenNil, mtd);
2073 #ifndef DACCESS_COMPILE
2075 VOID ClassLoader::CreateCanonicallyCasedKey(LPCUTF8 pszNameSpace, LPCUTF8 pszName, __out LPUTF8 *ppszOutNameSpace, __out LPUTF8 *ppszOutName)
2082 INJECT_FAULT(COMPlusThrowOM(););
2087 StackSString nameSpace(SString::Utf8, pszNameSpace);
2088 nameSpace.LowerCase();
2090 StackScratchBuffer nameSpaceBuffer;
2091 pszNameSpace = nameSpace.GetUTF8(nameSpaceBuffer);
2094 StackSString name(SString::Utf8, pszName);
2097 StackScratchBuffer nameBuffer;
2098 pszName = name.GetUTF8(nameBuffer);
2101 size_t iNSLength = strlen(pszNameSpace);
2102 size_t iNameLength = strlen(pszName);
2104 //Calc & allocate path length
2105 //Includes terminating null
2106 S_SIZE_T allocSize = S_SIZE_T(iNSLength) + S_SIZE_T(iNameLength) + S_SIZE_T(2);
2107 AllocMemHolder<char> alloc(GetAssembly()->GetHighFrequencyHeap()->AllocMem(allocSize));
2109 memcpy(*ppszOutNameSpace = (char*)alloc, pszNameSpace, iNSLength + 1);
2110 memcpy(*ppszOutName = (char*)alloc + iNSLength + 1, pszName, iNameLength + 1);
2112 alloc.SuppressRelease();
2115 #endif // #ifndef DACCESS_COMPILE
2119 // Return a class that is already loaded
2120 // Only for type refs and type defs (not type specs)
2123 TypeHandle ClassLoader::LookupTypeDefOrRefInModule(Module *pModule, mdToken cl, ClassLoadLevel *pLoadLevel)
2125 CONTRACT(TypeHandle)
2131 PRECONDITION(CheckPointer(pModule));
2132 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2137 BAD_FORMAT_NOTHROW_ASSERT((TypeFromToken(cl) == mdtTypeRef ||
2138 TypeFromToken(cl) == mdtTypeDef ||
2139 TypeFromToken(cl) == mdtTypeSpec));
2141 TypeHandle typeHandle;
2143 if (TypeFromToken(cl) == mdtTypeDef)
2144 typeHandle = pModule->LookupTypeDef(cl, pLoadLevel);
2145 else if (TypeFromToken(cl) == mdtTypeRef)
2147 typeHandle = pModule->LookupTypeRef(cl);
2149 if (pLoadLevel && !typeHandle.IsNull())
2151 *pLoadLevel = typeHandle.GetLoadLevel();
2158 DomainAssembly *ClassLoader::GetDomainAssembly()
2160 WRAPPER_NO_CONTRACT;
2161 return GetAssembly()->GetDomainAssembly();
2164 #ifndef DACCESS_COMPILE
2167 // Free all modules associated with this loader
2169 void ClassLoader::FreeModules()
2177 DISABLED(FORBID_FAULT); //Lots of crud to clean up to make this work
2181 Module *pManifest = NULL;
2182 if (GetAssembly() && (NULL != (pManifest = GetAssembly()->GetManifestModule()))) {
2183 // Unload the manifest last, since it contains the module list in its rid map
2184 ModuleIterator i = GetAssembly()->IterateModules();
2186 // Have the module free its various tables and some of the EEClass links
2187 if (i.GetModule() != pManifest)
2188 i.GetModule()->Destruct();
2191 // Now do the manifest module.
2192 pManifest->Destruct();
2197 ClassLoader::~ClassLoader()
2205 DISABLED(FORBID_FAULT); //Lots of crud to clean up to make this work
2210 // Do not walk m_pUnresolvedClassHash at destruct time as it is loaderheap allocated memory
2211 // and may already have been deallocated via an AllocMemTracker.
2212 m_pUnresolvedClassHash = (PendingTypeLoadTable*)(UINT_PTR)0xcccccccc;
2219 // "Deleting classloader %x\n"
2220 // " >EEClass data: %10d bytes\n"
2221 // " >Classname hash: %10d bytes\n"
2222 // " >FieldDesc data: %10d bytes\n"
2223 // " >MethodDesc data: %10d bytes\n"
2224 // " >GCInfo: %10d bytes\n"
2225 // " >Interface maps: %10d bytes\n"
2226 // " >MethodTables: %10d bytes\n"
2227 // " >Vtables: %10d bytes\n"
2228 // " >Static fields: %10d bytes\n"
2229 // "# methods: %10d\n"
2230 // "# field descs: %10d\n"
2231 // "# classes: %10d\n"
2232 // "# dup intf slots: %10d\n"
2233 // "# array classrefs: %10d\n"
2234 // "Array class overhead:%10d bytes\n",
2237 // m_pAvailableClasses->m_dwDebugMemory,
2238 // m_dwFieldDescData,
2239 // m_dwMethodDescData,
2241 // m_dwInterfaceMapSize,
2242 // m_dwMethodTableSize,
2244 // m_dwStaticFieldData,
2245 // m_dwDebugMethods,
2246 // m_dwDebugFieldDescs,
2247 // m_dwDebugClasses,
2248 // m_dwDebugDuplicateInterfaceSlots,
2254 m_UnresolvedClassLock.Destroy();
2255 m_AvailableClassLock.Destroy();
2256 m_AvailableTypesLock.Destroy();
2260 //----------------------------------------------------------------------------
2261 // The constructor should only initialize enough to ensure that the destructor doesn't
2262 // crash. It cannot allocate or do anything that might fail as that would leave
2263 // the ClassLoader undestructable. Any such tasks should be done in ClassLoader::Init().
2264 //----------------------------------------------------------------------------
2265 ClassLoader::ClassLoader(Assembly *pAssembly)
2277 m_pAssembly = pAssembly;
2279 m_pUnresolvedClassHash = NULL;
2280 m_cUnhashedModules = 0;
2283 m_dwDebugMethods = 0;
2284 m_dwDebugFieldDescs = 0;
2285 m_dwDebugClasses = 0;
2286 m_dwDebugDuplicateInterfaceSlots = 0;
2288 m_dwInterfaceMapSize = 0;
2289 m_dwMethodTableSize = 0;
2291 m_dwStaticFieldData = 0;
2292 m_dwFieldDescData = 0;
2293 m_dwMethodDescData = 0;
2294 m_dwEEClassData = 0;
2299 //----------------------------------------------------------------------------
2300 // This function completes the initialization of the ClassLoader. It can
2301 // assume the constructor is run and that the function is entered with
2302 // ClassLoader in a safely destructable state. This function can throw
2303 // but whether it throws or succeeds, it must leave the ClassLoader in a safely
2304 // destructable state.
2305 //----------------------------------------------------------------------------
2306 VOID ClassLoader::Init(AllocMemTracker *pamTracker)
2308 STANDARD_VM_CONTRACT;
2310 m_pUnresolvedClassHash = PendingTypeLoadTable::Create(GetAssembly()->GetLowFrequencyHeap(),
2311 UNRESOLVED_CLASS_HASH_BUCKETS,
2314 m_UnresolvedClassLock.Init(CrstUnresolvedClassLock);
2316 // This lock is taken within the classloader whenever we have to enter a
2317 // type in one of the modules governed by the loader.
2318 // The process of creating these types may be reentrant. The ordering has
2319 // not yet been sorted out, and when we sort it out we should also modify the
2320 // ordering for m_AvailableTypesLock in BaseDomain.
2321 m_AvailableClassLock.Init(
2325 // This lock is taken within the classloader whenever we have to insert a new param. type into the table
2326 // This lock also needs to be taken for a read operation in a GC_NOTRIGGER scope, thus the ANYMODE flag.
2327 m_AvailableTypesLock.Init(
2328 CrstAvailableParamTypes,
2329 (CrstFlags)(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD));
2332 CorTypeInfo::CheckConsistency();
2337 #endif // #ifndef DACCESS_COMPILE
2340 TypeHandle ClassLoader::LoadTypeDefOrRefOrSpecThrowing(Module *pModule,
2341 mdToken typeDefOrRefOrSpec,
2342 const SigTypeContext *pTypeContext,
2343 NotFoundAction fNotFoundAction /* = ThrowIfNotFound */ ,
2344 PermitUninstantiatedFlag fUninstantiated /* = FailIfUninstDefOrRef */,
2345 LoadTypesFlag fLoadTypes/*=LoadTypes*/ ,
2346 ClassLoadLevel level /* = CLASS_LOADED */,
2347 BOOL dropGenericArgumentLevel /* = FALSE */,
2348 const Substitution *pSubst)
2350 CONTRACT(TypeHandle)
2352 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2353 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2355 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2356 if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
2357 PRECONDITION(CheckPointer(pModule));
2358 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
2359 PRECONDITION(FORBIDGC_LOADER_USE_ENABLED() || GetAppDomain()->CheckCanLoadTypes(pModule->GetAssembly()));
2360 POSTCONDITION(CheckPointer(RETVAL, (fNotFoundAction == ThrowIfNotFound)? NULL_NOT_OK : NULL_OK));
2364 if (TypeFromToken(typeDefOrRefOrSpec) == mdtTypeSpec)
2367 PCCOR_SIGNATURE pSig;
2369 IMDInternalImport *pInternalImport = pModule->GetMDImport();
2370 if (FAILED(pInternalImport->GetTypeSpecFromToken(typeDefOrRefOrSpec, &pSig, &cSig)))
2372 #ifndef DACCESS_COMPILE
2373 if (fNotFoundAction == ThrowIfNotFound)
2375 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, typeDefOrRefOrSpec, IDS_CLASSLOAD_BADFORMAT);
2377 #endif //!DACCESS_COMPILE
2378 RETURN (TypeHandle());
2380 SigPointer sigptr(pSig, cSig);
2381 TypeHandle typeHnd = sigptr.GetTypeHandleThrowing(pModule, pTypeContext, fLoadTypes,
2382 level, dropGenericArgumentLevel, pSubst);
2383 #ifndef DACCESS_COMPILE
2384 if ((fNotFoundAction == ThrowIfNotFound) && typeHnd.IsNull())
2385 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, typeDefOrRefOrSpec,
2386 IDS_CLASSLOAD_GENERAL);
2392 RETURN (LoadTypeDefOrRefThrowing(pModule, typeDefOrRefOrSpec,
2395 ((fLoadTypes == LoadTypes) ? tdNoTypes : tdAllTypes),
2398 } // ClassLoader::LoadTypeDefOrRefOrSpecThrowing
2400 // Given a token specifying a typeDef, and a module in which to
2401 // interpret that token, find or load the corresponding type handle.
2405 TypeHandle ClassLoader::LoadTypeDefThrowing(Module *pModule,
2407 NotFoundAction fNotFoundAction /* = ThrowIfNotFound */ ,
2408 PermitUninstantiatedFlag fUninstantiated /* = FailIfUninstDefOrRef */,
2409 mdToken tokenNotToLoad,
2410 ClassLoadLevel level,
2411 Instantiation * pTargetInstantiation)
2414 CONTRACT(TypeHandle)
2416 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2417 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2419 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2420 DAC_LOADS_TYPE(level, !NameHandle::OKToLoad(typeDef, tokenNotToLoad));
2421 PRECONDITION(CheckPointer(pModule));
2422 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
2423 PRECONDITION(FORBIDGC_LOADER_USE_ENABLED()
2424 || GetAppDomain()->CheckCanLoadTypes(pModule->GetAssembly()));
2426 POSTCONDITION(CheckPointer(RETVAL, NameHandle::OKToLoad(typeDef, tokenNotToLoad) && (fNotFoundAction == ThrowIfNotFound) ? NULL_NOT_OK : NULL_OK));
2427 POSTCONDITION(RETVAL.IsNull() || RETVAL.GetCl() == typeDef);
2434 // First, attempt to find the class if it is already loaded
2435 ClassLoadLevel existingLoadLevel = CLASS_LOAD_BEGIN;
2436 typeHnd = pModule->LookupTypeDef(typeDef, &existingLoadLevel);
2437 if (!typeHnd.IsNull())
2439 #ifndef DACCESS_COMPILE
2440 // If the type is loaded, we can do cheap arity verification
2441 if (pTargetInstantiation != NULL && pTargetInstantiation->GetNumArgs() != typeHnd.AsMethodTable()->GetNumGenericArgs())
2442 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(), typeDef, IDS_CLASSLOAD_TYPEWRONGNUMGENERICARGS);
2445 if (existingLoadLevel >= level)
2449 IMDInternalImport *pInternalImport = pModule->GetMDImport();
2451 #ifndef DACCESS_COMPILE
2452 if (typeHnd.IsNull() && pTargetInstantiation != NULL)
2454 // If the type is not loaded yet, we have to do heavy weight arity verification based on metadata
2455 HENUMInternal hEnumGenericPars;
2456 HRESULT hr = pInternalImport->EnumInit(mdtGenericParam, typeDef, &hEnumGenericPars);
2458 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, typeDef, IDS_CLASSLOAD_BADFORMAT);
2459 DWORD nGenericClassParams = pInternalImport->EnumGetCount(&hEnumGenericPars);
2460 pInternalImport->EnumClose(&hEnumGenericPars);
2462 if (pTargetInstantiation->GetNumArgs() != nGenericClassParams)
2463 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, typeDef, IDS_CLASSLOAD_TYPEWRONGNUMGENERICARGS);
2467 if (IsNilToken(typeDef) || TypeFromToken(typeDef) != mdtTypeDef || !pInternalImport->IsValidToken(typeDef) )
2469 LOG((LF_CLASSLOADER, LL_INFO10, "Bogus class token to load: 0x%08x\n", typeDef));
2470 typeHnd = TypeHandle();
2474 // *****************************************************************************
2476 // Important invariant:
2478 // The rule here is that we never go to LoadTypeHandleForTypeKey if a Find should succeed.
2479 // This is vital, because otherwise a stack crawl will open up opportunities for
2480 // GC. Since operations like setting up a GCFrame will trigger a crawl in stress
2481 // mode, a GC at that point would be disastrous. We can't assert this, because
2482 // of race conditions. (In other words, the type could suddently be find-able
2483 // because another thread loaded it while we were in this method.
2485 // Not found - try to load it unless we are told not to
2487 #ifndef DACCESS_COMPILE
2488 if ( !NameHandle::OKToLoad(typeDef, tokenNotToLoad) )
2490 typeHnd = TypeHandle();
2494 // Anybody who puts himself in a FORBIDGC_LOADER state has promised
2495 // to use us only for resolving, not loading. We are now transitioning into
2498 _ASSERTE(!FORBIDGC_LOADER_USE_ENABLED());
2502 if (pModule->IsReflection())
2504 // Don't try to load types that are not in available table, when this
2505 // is an in-memory module. Raise the type-resolve event instead.
2506 typeHnd = TypeHandle();
2508 // Avoid infinite recursion
2509 if (tokenNotToLoad != tdAllAssemblies)
2511 AppDomain* pDomain = SystemDomain::GetCurrentDomain();
2516 if (FAILED(pInternalImport->GetNameOfTypeDef(typeDef, &className, &nameSpace)))
2518 LOG((LF_CLASSLOADER, LL_INFO10, "Bogus TypeDef record while loading: 0x%08x\n", typeDef));
2519 typeHnd = TypeHandle();
2523 MAKE_FULL_PATH_ON_STACK_UTF8(pszFullName,
2527 ASSEMBLYREF asmRef = NULL;
2528 DomainAssembly *pDomainAssembly = NULL;
2529 GCPROTECT_BEGIN(asmRef);
2531 pDomainAssembly = pDomain->RaiseTypeResolveEventThrowing(
2532 pModule->GetAssembly()->GetDomainAssembly(),
2533 pszFullName, &asmRef);
2537 _ASSERTE(pDomainAssembly != NULL);
2538 if (pDomainAssembly->GetAssembly()->GetLoaderAllocator()->IsCollectible())
2540 if (!pModule->GetLoaderAllocator()->IsCollectible())
2542 LOG((LF_CLASSLOADER, LL_INFO10, "Bad result from TypeResolveEvent while loader TypeDef record: 0x%08x\n", typeDef));
2543 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
2546 pModule->GetLoaderAllocator()->EnsureReference(pDomainAssembly->GetAssembly()->GetLoaderAllocator());
2550 if (pDomainAssembly != NULL)
2552 Assembly *pAssembly = pDomainAssembly->GetAssembly();
2554 NameHandle name(nameSpace, className);
2555 name.SetTypeToken(pModule, typeDef);
2556 name.SetTokenNotToLoad(tdAllAssemblies);
2557 typeHnd = pAssembly->GetLoader()->LoadTypeHandleThrowing(&name, level);
2564 TypeKey typeKey(pModule, typeDef);
2565 typeHnd = pModule->GetClassLoader()->LoadTypeHandleForTypeKey(&typeKey,
2570 #endif // !DACCESS_COMPILE
2573 #ifndef DACCESS_COMPILE
2574 if ((fUninstantiated == FailIfUninstDefOrRef) && !typeHnd.IsNull() && typeHnd.IsGenericTypeDefinition())
2576 typeHnd = TypeHandle();
2579 if ((fNotFoundAction == ThrowIfNotFound) && typeHnd.IsNull() && (tokenNotToLoad != tdAllTypes))
2581 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(),
2583 IDS_CLASSLOAD_GENERAL);
2591 // Given a token specifying a typeDef or typeRef, and a module in
2592 // which to interpret that token, find or load the corresponding type
2596 TypeHandle ClassLoader::LoadTypeDefOrRefThrowing(Module *pModule,
2597 mdToken typeDefOrRef,
2598 NotFoundAction fNotFoundAction /* = ThrowIfNotFound */ ,
2599 PermitUninstantiatedFlag fUninstantiated /* = FailIfUninstDefOrRef */,
2600 mdToken tokenNotToLoad,
2601 ClassLoadLevel level)
2604 CONTRACT(TypeHandle)
2606 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2607 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2609 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2610 PRECONDITION(CheckPointer(pModule));
2611 PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
2612 PRECONDITION(FORBIDGC_LOADER_USE_ENABLED()
2613 || GetAppDomain()->CheckCanLoadTypes(pModule->GetAssembly()));
2615 POSTCONDITION(CheckPointer(RETVAL, NameHandle::OKToLoad(typeDefOrRef, tokenNotToLoad) && (fNotFoundAction == ThrowIfNotFound) ? NULL_NOT_OK : NULL_OK));
2616 POSTCONDITION(level <= CLASS_LOAD_UNRESTORED || RETVAL.IsNull() || RETVAL.IsRestored());
2621 // NotFoundAction could be the bizarre 'ThrowButNullV11McppWorkaround',
2622 // which means ThrowIfNotFound EXCEPT if this might be the Everett MCPP
2623 // Nil-token ResolutionScope for value type. In that case, it means
2624 // ReturnNullIfNotFound.
2625 // If we have ThrowButNullV11McppWorkaround, remember that NULL *might*
2626 // be OK if there is no resolution scope, but change the value to
2628 BOOLEAN bReturnNullOkWhenNoResolutionScope = false;
2629 if (fNotFoundAction == ThrowButNullV11McppWorkaround)
2631 bReturnNullOkWhenNoResolutionScope = true;
2632 fNotFoundAction = ThrowIfNotFound;
2635 // First, attempt to find the class if it is already loaded
2636 ClassLoadLevel existingLoadLevel = CLASS_LOAD_BEGIN;
2637 TypeHandle typeHnd = LookupTypeDefOrRefInModule(pModule, typeDefOrRef, &existingLoadLevel);
2638 if (!typeHnd.IsNull())
2640 if (existingLoadLevel < level)
2642 pModule = typeHnd.GetModule();
2643 typeDefOrRef = typeHnd.GetCl();
2647 if (!typeHnd.IsNull() && existingLoadLevel >= level)
2649 // perform the check that it's not an uninstantiated TypeDef/TypeRef
2650 // being used inappropriately.
2651 if (!((fUninstantiated == FailIfUninstDefOrRef) && !typeHnd.IsNull() && typeHnd.IsGenericTypeDefinition()))
2658 // otherwise try to resolve the TypeRef and/or load the corresponding TypeDef
2659 IMDInternalImport *pInternalImport = pModule->GetMDImport();
2660 mdToken tokType = TypeFromToken(typeDefOrRef);
2662 if (IsNilToken(typeDefOrRef) || ((tokType != mdtTypeDef)&&(tokType != mdtTypeRef))
2663 || !pInternalImport->IsValidToken(typeDefOrRef) )
2666 LOG((LF_CLASSLOADER, LL_INFO10, "Bogus class token to load: 0x%08x\n", typeDefOrRef));
2669 typeHnd = TypeHandle();
2672 else if (tokType == mdtTypeRef)
2674 BOOL fNoResolutionScope;
2675 Module *pFoundModule = Assembly::FindModuleByTypeRef(pModule, typeDefOrRef,
2676 tokenNotToLoad==tdAllTypes ?
2679 &fNoResolutionScope);
2681 if (pFoundModule != NULL)
2684 // Not in my module, have to look it up by name. This is the primary path
2685 // taken by the TypeRef case, i.e. we've resolve a TypeRef to a TypeDef/Module
2687 LPCUTF8 pszNameSpace;
2688 LPCUTF8 pszClassName;
2689 if (FAILED(pInternalImport->GetNameOfTypeRef(
2694 typeHnd = TypeHandle();
2698 if (fNoResolutionScope)
2700 // Everett C++ compiler can generate a TypeRef with RS=0
2701 // without respective TypeDef for unmanaged valuetypes,
2702 // referenced only by pointers to them,
2703 // so we can fail to load legally w/ no exception
2704 typeHnd = ClassLoader::LoadTypeByNameThrowing(pFoundModule->GetAssembly(),
2707 ClassLoader::ReturnNullIfNotFound,
2708 tokenNotToLoad==tdAllTypes ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes,
2711 if(typeHnd.IsNull() && bReturnNullOkWhenNoResolutionScope)
2713 fNotFoundAction = ReturnNullIfNotFound;
2719 NameHandle nameHandle(pModule, typeDefOrRef);
2720 nameHandle.SetName(pszNameSpace, pszClassName);
2721 nameHandle.SetTokenNotToLoad(tokenNotToLoad);
2722 typeHnd = pFoundModule->GetClassLoader()->
2723 LoadTypeHandleThrowIfFailed(&nameHandle, level,
2724 pFoundModule->IsReflection() ? NULL : pFoundModule);
2728 #ifndef DACCESS_COMPILE
2729 if (!(typeHnd.IsNull()))
2730 pModule->StoreTypeRef(typeDefOrRef, typeHnd);
2736 // This is the mdtTypeDef case...
2737 typeHnd = LoadTypeDefThrowing(pModule, typeDefOrRef,
2744 TypeHandle thRes = typeHnd;
2746 // reject the load if it's an uninstantiated TypeDef/TypeRef
2747 // being used inappropriately.
2748 if ((fUninstantiated == FailIfUninstDefOrRef) && !typeHnd.IsNull() && typeHnd.IsGenericTypeDefinition())
2749 thRes = TypeHandle();
2751 // perform the check to throw when the thing is not found
2752 if ((fNotFoundAction == ThrowIfNotFound) && thRes.IsNull() && (tokenNotToLoad != tdAllTypes))
2754 #ifndef DACCESS_COMPILE
2755 pModule->GetAssembly()->ThrowTypeLoadException(pModule->GetMDImport(),
2757 IDS_CLASSLOAD_GENERAL);
2768 ClassLoader::ResolveTokenToTypeDefThrowing(
2769 Module * pTypeRefModule,
2770 mdTypeRef typeRefToken,
2771 Module ** ppTypeDefModule,
2772 mdTypeDef * pTypeDefToken,
2773 Loader::LoadFlag loadFlag,
2774 BOOL * pfUsesTypeForwarder) // The semantic of this parameter: TRUE if a type forwarder is found. It is never set to FALSE.
2778 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2779 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2781 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2782 PRECONDITION(CheckPointer(pTypeRefModule));
2787 // It's a TypeDef already
2788 if (TypeFromToken(typeRefToken) == mdtTypeDef)
2790 if (ppTypeDefModule != NULL)
2791 *ppTypeDefModule = pTypeRefModule;
2792 if (pTypeDefToken != NULL)
2793 *pTypeDefToken = typeRefToken;
2797 TypeHandle typeHnd = pTypeRefModule->LookupTypeRef(typeRefToken);
2799 // Type is already (partially) loaded and cached in the module's TypeRef table
2800 // Do not return here if we are checking for type forwarders
2801 if (!typeHnd.IsNull() && (pfUsesTypeForwarder == NULL))
2803 if (ppTypeDefModule != NULL)
2804 *ppTypeDefModule = typeHnd.GetModule();
2805 if (pTypeDefToken != NULL)
2806 *pTypeDefToken = typeHnd.GetCl();
2810 BOOL fNoResolutionScope; //not used
2811 Module * pFoundRefModule = Assembly::FindModuleByTypeRef(
2815 &fNoResolutionScope);
2817 if (pFoundRefModule == NULL)
2818 { // We didn't find the TypeRef anywhere
2822 // If checking for type forwarders, then we can see if a type forwarder was used based on the output of
2823 // pFoundRefModule and typeHnd (if typeHnd is set)
2824 if (!typeHnd.IsNull() && (pfUsesTypeForwarder != NULL))
2826 if (typeHnd.GetModule() != pFoundRefModule)
2828 *pfUsesTypeForwarder = TRUE;
2831 if (ppTypeDefModule != NULL)
2832 *ppTypeDefModule = typeHnd.GetModule();
2833 if (pTypeDefToken != NULL)
2834 *pTypeDefToken = typeHnd.GetCl();
2838 // Not in my module, have to look it up by name
2839 LPCUTF8 pszNameSpace;
2840 LPCUTF8 pszClassName;
2841 if (FAILED(pTypeRefModule->GetMDImport()->GetNameOfTypeRef(typeRefToken, &pszNameSpace, &pszClassName)))
2845 NameHandle nameHandle(pTypeRefModule, typeRefToken);
2846 nameHandle.SetName(pszNameSpace, pszClassName);
2847 if (loadFlag != Loader::Load)
2849 nameHandle.SetTokenNotToLoad(tdAllTypes);
2852 return ResolveNameToTypeDefThrowing(pFoundRefModule, &nameHandle, ppTypeDefModule, pTypeDefToken, loadFlag, pfUsesTypeForwarder);
2857 ClassLoader::ResolveNameToTypeDefThrowing(
2859 const NameHandle * pName,
2860 Module ** ppTypeDefModule,
2861 mdTypeDef * pTypeDefToken,
2862 Loader::LoadFlag loadFlag,
2863 BOOL * pfUsesTypeForwarder) // The semantic of this parameter: TRUE if a type forwarder is found. It is never set to FALSE.
2867 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
2868 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
2870 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
2871 PRECONDITION(CheckPointer(pModule));
2872 PRECONDITION(CheckPointer(pName));
2878 mdToken foundTypeDef;
2879 Module * pFoundModule;
2880 mdExportedType foundExportedType;
2881 Module * pSourceModule = pModule;
2882 Module * pFoundRefModule = pModule;
2884 for (UINT32 nTypeForwardingChainSize = 0; nTypeForwardingChainSize < const_cMaxTypeForwardingChainSize; nTypeForwardingChainSize++)
2886 foundTypeDef = mdTokenNil;
2887 pFoundModule = NULL;
2888 foundExportedType = mdTokenNil;
2889 if (!pSourceModule->GetClassLoader()->FindClassModuleThrowing(
2896 pSourceModule->IsReflection() ? NULL : pSourceModule,
2902 // Type is already loaded and cached in the loader's by-name table
2903 if (!typeHnd.IsNull())
2905 if ((typeHnd.GetModule() != pFoundRefModule) && (pfUsesTypeForwarder != NULL))
2906 { // We followed at least one type forwarder to resolve the type
2907 *pfUsesTypeForwarder = TRUE;
2909 if (ppTypeDefModule != NULL)
2910 *ppTypeDefModule = typeHnd.GetModule();
2911 if (pTypeDefToken != NULL)
2912 *pTypeDefToken = typeHnd.GetCl();
2916 if (pFoundModule == NULL)
2917 { // Module was probably not loaded
2921 if (TypeFromToken(foundExportedType) != mdtExportedType)
2922 { // It's not exported type
2923 _ASSERTE(foundExportedType == mdTokenNil);
2925 if ((pFoundModule != pFoundRefModule) && (pfUsesTypeForwarder != NULL))
2926 { // We followed at least one type forwarder to resolve the type
2927 *pfUsesTypeForwarder = TRUE;
2929 if (pTypeDefToken != NULL)
2930 *pTypeDefToken = foundTypeDef;
2931 if (ppTypeDefModule != NULL)
2932 *ppTypeDefModule = pFoundModule;
2935 // It's exported type
2937 // Repeat the search for the type in the newly found module
2938 pSourceModule = pFoundModule;
2940 // Type forwarding chain is too long
2942 } // ClassLoader::ResolveTokenToTypeDefThrowing
2944 #ifndef DACCESS_COMPILE
2946 //---------------------------------------------------------------------------------------
2950 ClassLoader::GetEnclosingClassThrowing(
2951 IMDInternalImport * pInternalImport,
2954 mdTypeDef * tdEnclosing)
2960 INJECT_FAULT(COMPlusThrowOM());
2965 _ASSERTE(tdEnclosing);
2966 *tdEnclosing = mdTypeDefNil;
2968 HRESULT hr = pInternalImport->GetNestedClassProps(cl, tdEnclosing);
2972 if (hr != CLDB_E_RECORD_NOTFOUND)
2977 if (TypeFromToken(*tdEnclosing) != mdtTypeDef)
2978 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_ENCLOSING);
2979 } // ClassLoader::GetEnclosingClassThrowing
2982 //---------------------------------------------------------------------------------------
2984 // Load a parent type or implemented interface type.
2986 // If this is an instantiated type represented by a type spec, then instead of attempting to load the
2987 // exact type, load an approximate instantiation in which all reference types are replaced by Object.
2988 // The exact instantiated types will be loaded later by LoadInstantiatedInfo.
2989 // We do this to avoid cycles early in class loading caused by definitions such as
2990 // struct M : ICloneable<M> // load ICloneable<object>
2991 // class C<T> : D<C<T>,int> for any T // load D<object,int>
2995 ClassLoader::LoadApproxTypeThrowing(
2998 SigPointer * pSigInst,
2999 const SigTypeContext * pClassTypeContext)
3001 CONTRACT(TypeHandle)
3005 INJECT_FAULT(COMPlusThrowOM());
3007 PRECONDITION(CheckPointer(pSigInst, NULL_OK));
3008 PRECONDITION(CheckPointer(pModule));
3009 POSTCONDITION(CheckPointer(RETVAL));
3013 IMDInternalImport * pInternalImport = pModule->GetMDImport();
3015 if (TypeFromToken(tok) == mdtTypeSpec)
3018 PCCOR_SIGNATURE pSig;
3019 IfFailThrowBF(pInternalImport->GetTypeSpecFromToken(tok, &pSig, &cSig), BFA_METADATA_CORRUPT, pModule);
3021 SigPointer sigptr = SigPointer(pSig, cSig);
3022 CorElementType type = ELEMENT_TYPE_END;
3023 IfFailThrowBF(sigptr.GetElemType(&type), BFA_BAD_SIGNATURE, pModule);
3025 // The only kind of type specs that we recognise are instantiated types
3026 if (type != ELEMENT_TYPE_GENERICINST)
3027 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, tok, IDS_CLASSLOAD_GENERAL);
3029 // Of these, we outlaw instantiated value classes (they can't be interfaces and can't be subclassed)
3030 IfFailThrowBF(sigptr.GetElemType(&type), BFA_BAD_SIGNATURE, pModule);
3032 if (type != ELEMENT_TYPE_CLASS)
3033 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, tok, IDS_CLASSLOAD_GENERAL);
3035 mdToken genericTok = 0;
3036 IfFailThrowBF(sigptr.GetToken(&genericTok), BFA_BAD_SIGNATURE, pModule);
3037 IfFailThrowBF(sigptr.GetData(NULL), BFA_BAD_SIGNATURE, pModule);
3039 if (pSigInst != NULL)
3042 // Try to load the generic type itself
3043 THROW_BAD_FORMAT_MAYBE(
3044 ((TypeFromToken(genericTok) == mdtTypeRef) || (TypeFromToken(genericTok) == mdtTypeDef)),
3045 BFA_UNEXPECTED_GENERIC_TOKENTYPE,
3047 TypeHandle genericTypeTH = LoadTypeDefOrRefThrowing(
3050 ClassLoader::ThrowIfNotFound,
3051 ClassLoader::PermitUninstDefOrRef,
3053 CLASS_LOAD_APPROXPARENTS);
3055 // We load interfaces at very approximate types - the generic
3056 // interface itself. We fix this up in LoadInstantiatedInfo.
3057 // This allows us to load recursive interfaces on structs such
3058 // as "struct VC : I<VC>". The details of the interface
3059 // are not currently needed during the first phase
3060 // of setting up the method table.
3061 if (genericTypeTH.IsInterface())
3063 RETURN genericTypeTH;
3067 // approxTypes, i.e. approximate reference types by Object, i.e. load the canonical type
3068 RETURN SigPointer(pSig, cSig).GetTypeHandleThrowing(
3071 ClassLoader::LoadTypes,
3072 CLASS_LOAD_APPROXPARENTS,
3073 TRUE /*dropGenericArgumentLevel*/);
3078 if (pSigInst != NULL)
3079 *pSigInst = SigPointer();
3080 RETURN LoadTypeDefOrRefThrowing(
3083 ClassLoader::ThrowIfNotFound,
3084 ClassLoader::FailIfUninstDefOrRef,
3086 CLASS_LOAD_APPROXPARENTS);
3088 } // ClassLoader::LoadApproxTypeThrowing
3091 //---------------------------------------------------------------------------------------
3095 ClassLoader::LoadApproxParentThrowing(
3098 SigPointer * pParentInst,
3099 const SigTypeContext * pClassTypeContext)
3105 INJECT_FAULT(COMPlusThrowOM());
3110 mdTypeRef crExtends;
3111 MethodTable * pParentMethodTable = NULL;
3112 TypeHandle parentType;
3114 Assembly * pAssembly = pModule->GetAssembly();
3115 IMDInternalImport * pInternalImport = pModule->GetMDImport();
3117 // Initialize the return value;
3118 *pParentInst = SigPointer();
3120 // Now load all dependencies of this class
3121 if (FAILED(pInternalImport->GetTypeDefProps(
3123 &dwAttrClass, // AttrClass
3126 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
3129 if (RidFromToken(crExtends) != mdTokenNil)
3131 // Do an "approximate" load of the parent, replacing reference types in the instantiation by Object
3132 // This is to avoid cycles in the loader e.g. on class C : D<C> or class C<T> : D<C<T>>
3133 // We fix up the exact parent later in LoadInstantiatedInfo
3134 parentType = LoadApproxTypeThrowing(pModule, crExtends, pParentInst, pClassTypeContext);
3136 pParentMethodTable = parentType.GetMethodTable();
3138 if (pParentMethodTable == NULL)
3139 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_PARENTNULL);
3141 // cannot inherit from an interface
3142 if (pParentMethodTable->IsInterface())
3143 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_PARENTINTERFACE);
3145 if (IsTdInterface(dwAttrClass))
3147 // Interfaces must extend from Object
3148 if (! pParentMethodTable->IsObjectClass())
3149 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_INTERFACEOBJECT);
3153 return pParentMethodTable;
3154 } // ClassLoader::LoadApproxParentThrowing
3156 // Perform a single phase of class loading
3157 // It is the caller's responsibility to lock
3159 TypeHandle ClassLoader::DoIncrementalLoad(TypeKey *pTypeKey, TypeHandle typeHnd, ClassLoadLevel currentLevel)
3164 PRECONDITION(CheckPointer(pTypeKey));
3165 PRECONDITION(currentLevel >= CLASS_LOAD_BEGIN && currentLevel < CLASS_LOADED);
3171 if (LoggingOn(LF_CLASSLOADER, LL_INFO10000))
3174 TypeString::AppendTypeKeyDebug(name, pTypeKey);
3175 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]));
3179 // Level is BEGIN if and only if type handle is null
3180 CONSISTENCY_CHECK((currentLevel == CLASS_LOAD_BEGIN) == typeHnd.IsNull());
3182 switch (currentLevel)
3184 // Attain at least level CLASS_LOAD_UNRESTORED (if just locating type in ngen image)
3185 // or at least level CLASS_LOAD_APPROXPARENTS (if creating type for the first time)
3186 case CLASS_LOAD_BEGIN :
3188 IBCLoggerAwareAllocMemTracker amTracker;
3189 typeHnd = CreateTypeHandleForTypeKey(pTypeKey, &amTracker);
3190 CONSISTENCY_CHECK(!typeHnd.IsNull());
3191 TypeHandle published = PublishType(pTypeKey, typeHnd);
3192 if (published == typeHnd)
3193 amTracker.SuppressRelease();
3194 typeHnd = published;
3198 case CLASS_LOAD_UNRESTOREDTYPEKEY :
3199 #ifdef FEATURE_PREJIT
3200 typeHnd.DoRestoreTypeKey();
3204 // Attain level CLASS_LOAD_APPROXPARENTS, starting with unrestored class
3205 case CLASS_LOAD_UNRESTORED :
3206 #ifdef FEATURE_PREJIT
3208 CONSISTENCY_CHECK(!typeHnd.IsRestored_NoLogging());
3209 if (typeHnd.IsTypeDesc())
3210 typeHnd.AsTypeDesc()->Restore();
3212 typeHnd.AsMethodTable()->Restore();
3217 // Attain level CLASS_LOAD_EXACTPARENTS
3218 case CLASS_LOAD_APPROXPARENTS :
3219 if (!typeHnd.IsTypeDesc())
3221 LoadExactParents(typeHnd.AsMethodTable());
3225 case CLASS_LOAD_EXACTPARENTS :
3226 case CLASS_DEPENDENCIES_LOADED :
3232 if (typeHnd.GetLoadLevel() >= CLASS_LOAD_EXACTPARENTS)
3241 // For non-canonical instantiations of generic types, create a fresh type by replicating the canonical instantiation
3242 // For canonical instantiations of generic types, create a brand new method table
3243 // For other constructed types, create a type desc and template method table if necessary
3244 // For all other types, create a method table
3245 TypeHandle ClassLoader::CreateTypeHandleForTypeKey(TypeKey* pKey, AllocMemTracker* pamTracker)
3247 CONTRACT(TypeHandle)
3250 PRECONDITION(CheckPointer(pKey));
3252 POSTCONDITION(RETVAL.CheckMatchesKey(pKey));
3257 TypeHandle typeHnd = TypeHandle();
3259 if (!pKey->IsConstructed())
3261 typeHnd = CreateTypeHandleForTypeDefThrowing(pKey->GetModule(),
3262 pKey->GetTypeToken(),
3263 pKey->GetInstantiation(),
3266 else if (pKey->HasInstantiation())
3268 if (IsCanonicalGenericInstantiation(pKey->GetInstantiation()))
3270 typeHnd = CreateTypeHandleForTypeDefThrowing(pKey->GetModule(),
3271 pKey->GetTypeToken(),
3272 pKey->GetInstantiation(),
3277 typeHnd = CreateTypeHandleForNonCanonicalGenericInstantiation(pKey,
3280 #if defined(_DEBUG) && !defined(CROSSGEN_COMPILE)
3281 if (Nullable::IsNullableType(typeHnd))
3282 Nullable::CheckFieldOffsets(typeHnd);
3285 else if (pKey->GetKind() == ELEMENT_TYPE_FNPTR)
3287 Module *pLoaderModule = ComputeLoaderModule(pKey);
3288 pLoaderModule->GetLoaderAllocator()->EnsureInstantiation(NULL, Instantiation(pKey->GetRetAndArgTypes(), pKey->GetNumArgs() + 1));
3290 PREFIX_ASSUME(pLoaderModule!=NULL);
3291 DWORD numArgs = pKey->GetNumArgs();
3292 BYTE* mem = (BYTE*) pamTracker->Track(pLoaderModule->GetAssembly()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(FnPtrTypeDesc)) + S_SIZE_T(sizeof(TypeHandle)) * S_SIZE_T(numArgs)));
3294 typeHnd = TypeHandle(new(mem) FnPtrTypeDesc(pKey->GetCallConv(), numArgs, pKey->GetRetAndArgTypes()));
3298 Module *pLoaderModule = ComputeLoaderModule(pKey);
3299 PREFIX_ASSUME(pLoaderModule!=NULL);
3301 CorElementType kind = pKey->GetKind();
3302 TypeHandle paramType = pKey->GetElementType();
3303 MethodTable *templateMT;
3305 // Create a new type descriptor and insert into constructed type table
3306 if (CorTypeInfo::IsArray(kind))
3308 DWORD rank = pKey->GetRank();
3309 THROW_BAD_FORMAT_MAYBE((kind != ELEMENT_TYPE_ARRAY) || rank > 0, BFA_MDARRAY_BADRANK, pLoaderModule);
3310 THROW_BAD_FORMAT_MAYBE((kind != ELEMENT_TYPE_SZARRAY) || rank == 1, BFA_SDARRAY_BADRANK, pLoaderModule);
3312 // Arrays of BYREFS not allowed
3313 if (paramType.GetInternalCorElementType() == ELEMENT_TYPE_BYREF)
3315 ThrowTypeLoadException(pKey, IDS_CLASSLOAD_BYREFARRAY);
3318 // Arrays of ByRefLike types not allowed
3319 MethodTable* pMT = paramType.GetMethodTable();
3322 if (pMT->IsByRefLike())
3324 ThrowTypeLoadException(pKey, IDS_CLASSLOAD_BYREFLIKEARRAY);
3328 // We really don't need this check anymore.
3329 if (rank > MAX_RANK)
3331 ThrowTypeLoadException(pKey, IDS_CLASSLOAD_RANK_TOOLARGE);
3334 templateMT = pLoaderModule->CreateArrayMethodTable(paramType, kind, rank, pamTracker);
3336 BYTE* mem = (BYTE*) pamTracker->Track(pLoaderModule->GetAssembly()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(ArrayTypeDesc))));
3337 typeHnd = TypeHandle(new(mem) ArrayTypeDesc(templateMT, paramType));
3341 // no parameterized type allowed on a reference
3342 if (paramType.GetInternalCorElementType() == ELEMENT_TYPE_BYREF ||
3343 paramType.GetInternalCorElementType() == ELEMENT_TYPE_TYPEDBYREF)
3345 ThrowTypeLoadException(pKey, IDS_CLASSLOAD_GENERAL);
3348 // We do allow parametrized types of ByRefLike types. Languages may restrict them to produce safe or verifiable code,
3349 // but there is not a good reason for restricting them in the runtime.
3351 // let <Type>* type have a method table
3352 // System.UIntPtr's method table is used for types like int*, void *, string * etc.
3353 if (kind == ELEMENT_TYPE_PTR)
3354 templateMT = MscorlibBinder::GetElementType(ELEMENT_TYPE_U);
3358 BYTE* mem = (BYTE*) pamTracker->Track(pLoaderModule->GetAssembly()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(ParamTypeDesc))));
3359 typeHnd = TypeHandle(new(mem) ParamTypeDesc(kind, templateMT, paramType));
3366 // Publish a type (and possibly member information) in the loader's
3367 // tables Types are published before they are fully loaded. In
3368 // particular, exact parent info (base class and interfaces) is loaded
3371 TypeHandle ClassLoader::PublishType(TypeKey *pTypeKey, TypeHandle typeHnd)
3376 PRECONDITION(CheckPointer(typeHnd));
3377 PRECONDITION(CheckPointer(pTypeKey));
3379 // Key must match that of the handle
3380 PRECONDITION(typeHnd.CheckMatchesKey(pTypeKey));
3382 // Don't publish array template method tables; these are accessed only through type descs
3383 PRECONDITION(typeHnd.IsTypeDesc() || !typeHnd.AsMethodTable()->IsArray());
3388 if (pTypeKey->IsConstructed())
3390 Module *pLoaderModule = ComputeLoaderModule(pTypeKey);
3391 EETypeHashTable *pTable = pLoaderModule->GetAvailableParamTypes();
3393 // m_AvailableTypesLock has to be taken in cooperative mode to avoid deadlocks during GC
3396 CrstHolder ch(&pLoaderModule->GetClassLoader()->m_AvailableTypesLock);
3398 // The type could have been loaded by a different thread as side-effect of avoiding deadlocks caused by LoadsTypeViolation
3399 TypeHandle existing = pTable->GetValue(pTypeKey);
3400 if (!existing.IsNull())
3403 pTable->InsertValue(typeHnd);
3406 // Checks to help ensure that the CoreLib in the ngen process does not get contaminated with pointers to the compilation domains.
3407 if (pLoaderModule->IsSystem() && IsCompilationProcess() && pLoaderModule->HasNativeImage())
3409 CorElementType kind = pTypeKey->GetKind();
3410 MethodTable *typeHandleMethodTable = typeHnd.GetMethodTable();
3411 if ((typeHandleMethodTable != NULL) && (typeHandleMethodTable->GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator()))
3413 _ASSERTE(!"MethodTable of type loaded into CoreLib during NGen is not from CoreLib!");
3415 if ((kind != ELEMENT_TYPE_FNPTR) && (kind != ELEMENT_TYPE_VAR) && (kind != ELEMENT_TYPE_MVAR))
3417 if ((kind == ELEMENT_TYPE_SZARRAY) || (kind == ELEMENT_TYPE_ARRAY) || (kind == ELEMENT_TYPE_BYREF) || (kind == ELEMENT_TYPE_PTR) || (kind == ELEMENT_TYPE_VALUETYPE))
3419 // Check to ensure param value is also part of CoreLib.
3420 if (pTypeKey->GetElementType().GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator())
3422 _ASSERTE(!"Param value of type key used to load type during NGEN not located within CoreLib yet type is placed into CoreLib");
3425 else if (kind == ELEMENT_TYPE_FNPTR)
3427 // Check to ensure the parameter types of fnptr are in CoreLib
3428 for (DWORD i = 0; i <= pTypeKey->GetNumArgs(); i++)
3430 if (pTypeKey->GetRetAndArgTypes()[i].GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator())
3432 _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");
3436 else if (kind == ELEMENT_TYPE_CLASS)
3438 // Check to ensure that the generic parameters are all within CoreLib
3439 for (DWORD i = 0; i < pTypeKey->GetNumGenericArgs(); i++)
3441 if (pTypeKey->GetInstantiation()[i].GetLoaderAllocator() != pLoaderModule->GetLoaderAllocator())
3443 _ASSERTE(!"Instantiation parameter of generic class type key used to load type during NGEN not located within CoreLib yet type is placed into CoreLib");
3449 // Should not be able to get here
3450 _ASSERTE(!"Unknown type key type");
3458 Module *pModule = pTypeKey->GetModule();
3459 mdTypeDef typeDef = pTypeKey->GetTypeToken();
3461 // m_AvailableTypesLock has to be taken in cooperative mode to avoid deadlocks during GC
3464 CrstHolder ch(&pModule->GetClassLoader()->m_AvailableTypesLock);
3466 // ! We cannot fail after this point.
3467 CANNOTTHROWCOMPLUSEXCEPTION();
3470 // The type could have been loaded by a different thread as side-effect of avoiding deadlocks caused by LoadsTypeViolation
3471 TypeHandle existing = pModule->LookupTypeDef(typeDef);
3472 if (!existing.IsNull())
3475 MethodTable *pMT = typeHnd.AsMethodTable();
3477 MethodTable::IntroducedMethodIterator it(pMT);
3478 for (; it.IsValid(); it.Next())
3480 MethodDesc * pMD = it.GetMethodDesc();
3481 CONSISTENCY_CHECK(pMD != NULL && pMD->GetMethodTable() == pMT);
3482 if (!pMD->IsUnboxingStub())
3484 pModule->EnsuredStoreMethodDef(pMD->GetMemberDef(), pMD);
3488 ApproxFieldDescIterator fdIterator(pMT, ApproxFieldDescIterator::ALL_FIELDS);
3491 while ((pFD = fdIterator.Next()) != NULL)
3493 if (pFD->GetEnclosingMethodTable() == pMT)
3495 pModule->EnsuredStoreFieldDef(pFD->GetMemberDef(), pFD);
3499 // Publish the type last - to ensure that nobody can see it until all the method and field RID maps are filled in
3500 pModule->EnsuredStoreTypeDef(typeDef, typeHnd);
3506 // Notify profiler and debugger that a type load has completed
3507 // Also adjust perf counters
3509 void ClassLoader::Notify(TypeHandle typeHnd)
3514 PRECONDITION(CheckPointer(typeHnd));
3518 LOG((LF_CLASSLOADER, LL_INFO1000, "Notify: %p %s\n", typeHnd.AsPtr(), typeHnd.IsTypeDesc() ? "typedesc" : typeHnd.AsMethodTable()->GetDebugClassName()));
3520 if (typeHnd.IsTypeDesc())
3523 MethodTable * pMT = typeHnd.AsMethodTable();
3525 #ifdef PROFILING_SUPPORTED
3527 BEGIN_PIN_PROFILER(CORProfilerTrackClasses());
3528 // We don't tell profilers about typedescs, as per IF above. Also, we don't
3529 // tell profilers about:
3531 // ...generics with unbound variables
3532 (!pMT->ContainsGenericVariables()) &&
3533 // ...or array method tables
3534 // (This check is mainly for NGEN restore, as JITted code won't hit
3535 // this code path for array method tables anyway)
3538 LOG((LF_CLASSLOADER, LL_INFO1000, "Notifying profiler of Started1 %p %s\n", pMT, pMT->GetDebugClassName()));
3539 // Record successful load of the class for the profiler
3540 g_profControlBlock.pProfInterface->ClassLoadStarted(TypeHandleToClassID(typeHnd));
3543 // Profiler can turn off TrackClasses during the Started() callback. Need to
3544 // retest the flag here.
3546 if (CORProfilerTrackClasses())
3548 LOG((LF_CLASSLOADER, LL_INFO1000, "Notifying profiler of Finished1 %p %s\n", pMT, pMT->GetDebugClassName()));
3549 g_profControlBlock.pProfInterface->ClassLoadFinished(TypeHandleToClassID(typeHnd),
3555 #endif //PROFILING_SUPPORTED
3557 g_IBCLogger.LogMethodTableAccess(pMT);
3559 if (pMT->IsTypicalTypeDefinition())
3561 LOG((LF_CLASSLOADER, LL_INFO100, "Successfully loaded class %s\n", pMT->GetDebugClassName()));
3563 #ifdef DEBUGGING_SUPPORTED
3565 Module * pModule = pMT->GetModule();
3566 // Update metadata for dynamic module.
3567 pModule->UpdateDynamicMetadataIfNeeded();
3570 if (CORDebuggerAttached())
3572 LOG((LF_CORDB, LL_EVERYTHING, "NotifyDebuggerLoad clsload 2239 class %s\n", pMT->GetDebugClassName()));
3573 typeHnd.NotifyDebuggerLoad(NULL, FALSE);
3575 #endif // DEBUGGING_SUPPORTED
3580 //-----------------------------------------------------------------------------
3581 // Common helper for LoadTypeHandleForTypeKey and LoadTypeHandleForTypeKeyNoLock.
3582 // Makes the root level call to kick off the transitive closure walk for
3583 // the final level pushes.
3584 //-----------------------------------------------------------------------------
3585 static void PushFinalLevels(TypeHandle typeHnd, ClassLoadLevel targetLevel, const InstantiationContext *pInstContext)
3590 LOADS_TYPE(targetLevel);
3595 // This phase brings the type and all its transitive dependencies to their
3596 // final state, sans the IsFullyLoaded bit.
3597 if (targetLevel >= CLASS_DEPENDENCIES_LOADED)
3599 BOOL fBailed = FALSE;
3600 typeHnd.DoFullyLoad(NULL, CLASS_DEPENDENCIES_LOADED, NULL, &fBailed, pInstContext);
3603 // This phase does access/constraint and other type-safety checks on the type
3604 // and on its transitive dependencies.
3605 if (targetLevel == CLASS_LOADED)
3607 DFLPendingList pendingList;
3608 BOOL fBailed = FALSE;
3610 typeHnd.DoFullyLoad(NULL, CLASS_LOADED, &pendingList, &fBailed, pInstContext);
3613 // In the case of a circular dependency, one or more types will have
3614 // had their promotions deferred.
3616 // If we got to this point, all checks have successfully passed on
3617 // the transitive closure (otherwise, DoFullyLoad would have thrown.)
3619 // So we can go ahead and mark everyone as fully loaded.
3621 UINT numTH = pendingList.Count();
3622 TypeHandle *pTHPending = pendingList.Table();
3623 for (UINT i = 0; i < numTH; i++)
3625 // NOTE: It is possible for duplicates to appear in this list so
3626 // don't do any operation that isn't idempodent.
3628 pTHPending[i].SetIsFullyLoaded();
3635 TypeHandle ClassLoader::LoadTypeHandleForTypeKey(TypeKey *pTypeKey,
3637 ClassLoadLevel targetLevel/*=CLASS_LOADED*/,
3638 const InstantiationContext *pInstContext/*=NULL*/)
3647 LOADS_TYPE(targetLevel);
3654 if (LoggingOn(LF_CLASSLOADER, LL_INFO1000))
3657 TypeString::AppendTypeKeyDebug(name, pTypeKey);
3658 LOG((LF_CLASSLOADER, LL_INFO10000, "PHASEDLOAD: LoadTypeHandleForTypeKey for type %S to level %s\n", name.GetUnicode(), classLoadLevelName[targetLevel]));
3659 CrstHolder unresolvedClassLockHolder(&m_UnresolvedClassLock);
3660 m_pUnresolvedClassHash->Dump();
3664 // When using domain neutral assemblies (and not eagerly propagating dependency loads),
3665 // it's possible to get here without having injected the module into the current app domain.
3666 // GetDomainFile will accomplish that.
3668 if (!pTypeKey->IsConstructed())
3670 pTypeKey->GetModule()->GetDomainFile();
3673 ClassLoadLevel currentLevel = typeHnd.IsNull() ? CLASS_LOAD_BEGIN : typeHnd.GetLoadLevel();
3674 ClassLoadLevel targetLevelUnderLock = targetLevel < CLASS_DEPENDENCIES_LOADED ? targetLevel : (ClassLoadLevel) (CLASS_DEPENDENCIES_LOADED-1);
3675 if (currentLevel < targetLevelUnderLock)
3677 typeHnd = LoadTypeHandleForTypeKey_Body(pTypeKey,
3679 targetLevelUnderLock);
3680 _ASSERTE(!typeHnd.IsNull());
3682 _ASSERTE(typeHnd.GetLoadLevel() >= targetLevelUnderLock);
3684 PushFinalLevels(typeHnd, targetLevel, pInstContext);
3690 TypeHandle ClassLoader::LoadTypeHandleForTypeKeyNoLock(TypeKey *pTypeKey,
3691 ClassLoadLevel targetLevel/*=CLASS_LOADED*/,
3692 const InstantiationContext *pInstContext/*=NULL*/)
3701 LOADS_TYPE(targetLevel);
3702 PRECONDITION(CheckPointer(pTypeKey));
3703 PRECONDITION(targetLevel >= 0 && targetLevel <= CLASS_LOADED);
3709 TypeHandle typeHnd = TypeHandle();
3711 ClassLoadLevel currentLevel = CLASS_LOAD_BEGIN;
3712 ClassLoadLevel targetLevelUnderLock = targetLevel < CLASS_DEPENDENCIES_LOADED ? targetLevel : (ClassLoadLevel) (CLASS_DEPENDENCIES_LOADED-1);
3713 while (currentLevel < targetLevelUnderLock)
3715 typeHnd = DoIncrementalLoad(pTypeKey, typeHnd, currentLevel);
3716 CONSISTENCY_CHECK(typeHnd.GetLoadLevel() > currentLevel);
3717 currentLevel = typeHnd.GetLoadLevel();
3720 PushFinalLevels(typeHnd, targetLevel, pInstContext);
3725 //---------------------------------------------------------------------------------------
3727 class PendingTypeLoadHolder
3730 PendingTypeLoadEntry * m_pEntry;
3731 PendingTypeLoadHolder * m_pPrevious;
3734 PendingTypeLoadHolder(PendingTypeLoadEntry * pEntry)
3736 LIMITED_METHOD_CONTRACT;
3738 m_pThread = GetThread();
3741 m_pPrevious = m_pThread->GetPendingTypeLoad();
3742 m_pThread->SetPendingTypeLoad(this);
3745 ~PendingTypeLoadHolder()
3747 LIMITED_METHOD_CONTRACT;
3749 _ASSERTE(m_pThread->GetPendingTypeLoad() == this);
3750 m_pThread->SetPendingTypeLoad(m_pPrevious);
3753 static bool CheckForDeadLockOnCurrentThread(PendingTypeLoadEntry * pEntry)
3755 LIMITED_METHOD_CONTRACT;
3757 PendingTypeLoadHolder * pCurrent = GetThread()->GetPendingTypeLoad();
3759 while (pCurrent != NULL)
3761 if (pCurrent->m_pEntry == pEntry)
3764 pCurrent = pCurrent->m_pPrevious;
3771 //---------------------------------------------------------------------------------------
3774 ClassLoader::LoadTypeHandleForTypeKey_Body(
3777 ClassLoadLevel targetLevel)
3779 CONTRACT(TypeHandle)
3782 POSTCONDITION(!typeHnd.IsNull() && typeHnd.GetLoadLevel() >= targetLevel);
3786 if (!pTypeKey->IsConstructed())
3788 Module *pModule = pTypeKey->GetModule();
3789 mdTypeDef cl = pTypeKey->GetTypeToken();
3791 STRESS_LOG2(LF_CLASSLOADER, LL_INFO100000, "LoadTypeHandle: Loading Class from Module %p token %x\n", pModule, cl);
3794 IMDInternalImport* pInternalImport = pModule->GetMDImport();
3797 if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &className, &nameSpace)))
3799 className = nameSpace = "Invalid TypeDef record";
3801 if (g_pConfig->ShouldBreakOnClassLoad(className))
3802 CONSISTENCY_CHECK_MSGF(false, ("BreakOnClassLoad: typename '%s' ", className));
3806 ReleaseHolder<PendingTypeLoadEntry> pLoadingEntry;
3807 CrstHolderWithState unresolvedClassLockHolder(&m_UnresolvedClassLock, false);
3810 unresolvedClassLockHolder.Acquire();
3812 // Is it in the hash of classes currently being loaded?
3813 pLoadingEntry = m_pUnresolvedClassHash->GetValue(pTypeKey);
3816 pLoadingEntry->AddRef();
3818 // It is in the hash, which means that another thread is waiting for it (or that we are
3819 // already loading this class on this thread, which should never happen, since that implies
3820 // a recursive dependency).
3821 unresolvedClassLockHolder.Release();
3824 // Check one last time before waiting that the type handle is not sufficiently loaded to
3825 // prevent deadlocks
3828 if (typeHnd.IsNull())
3830 typeHnd = LookupTypeHandleForTypeKey(pTypeKey);
3833 if (!typeHnd.IsNull())
3835 if (typeHnd.GetLoadLevel() >= targetLevel)
3840 if (PendingTypeLoadHolder::CheckForDeadLockOnCurrentThread(pLoadingEntry))
3842 // Attempting recursive load
3843 ClassLoader::ThrowTypeLoadException(pTypeKey, IDS_CLASSLOAD_GENERAL);
3847 // Violation of type loadlevel ordering rules depends on type load failing in case of cyclic dependency that would
3848 // otherwise lead to deadlock. We will speculatively proceed with the type load to make it fail in the right spot,
3849 // in backward compatible way. In case the type load succeeds, we will only let one type win in PublishType.
3851 if (typeHnd.IsNull() && GetThread()->HasThreadStateNC(Thread::TSNC_LoadsTypeViolation))
3853 PendingTypeLoadHolder ptlh(pLoadingEntry);
3854 typeHnd = DoIncrementalLoad(pTypeKey, TypeHandle(), CLASS_LOAD_BEGIN);
3859 // Wait for class to be loaded by another thread. This is where we start tracking the
3860 // entry, so there is an implicit Acquire in our use of Assign here.
3861 CrstHolder loadingEntryLockHolder(&pLoadingEntry->m_Crst);
3862 _ASSERTE(pLoadingEntry->HasLock());
3865 // Result of other thread loading the class
3866 HRESULT hr = pLoadingEntry->m_hrResult;
3871 // Redo the lookup one more time and return a valid type if possible. The other thread could
3872 // have hit error while loading the type to higher level than we need.
3875 if (typeHnd.IsNull())
3877 typeHnd = LookupTypeHandleForTypeKey(pTypeKey);
3880 if (!typeHnd.IsNull())
3882 if (typeHnd.GetLoadLevel() >= targetLevel)
3887 if (hr == E_ABORT) {
3888 LOG((LF_CLASSLOADER, LL_INFO10, "need to retry LoadTypeHandle: %x\n", hr));
3892 LOG((LF_CLASSLOADER, LL_INFO10, "Failed to load in other entry: %x\n", hr));
3894 if (hr == E_OUTOFMEMORY) {
3898 pLoadingEntry->ThrowException();
3901 // Get a pointer to the EEClass being loaded
3902 typeHnd = pLoadingEntry->m_typeHandle;
3904 if (!typeHnd.IsNull())
3906 // If the type load on the other thread loaded the type to the needed level, return it here.
3907 if (typeHnd.GetLoadLevel() >= targetLevel)
3911 // The type load on the other thread did not load the type "enough". Begin the type load
3912 // process again to cause us to load to the needed level.
3916 if (typeHnd.IsNull())
3918 // The class was not being loaded. However, it may have already been loaded after our
3919 // first LoadTypeHandleThrowIfFailed() and before taking the lock.
3920 typeHnd = LookupTypeHandleForTypeKey(pTypeKey);
3923 ClassLoadLevel currentLevel = CLASS_LOAD_BEGIN;
3924 if (!typeHnd.IsNull())
3926 currentLevel = typeHnd.GetLoadLevel();
3927 if (currentLevel >= targetLevel)
3931 // It was not loaded, and it is not being loaded, so we must load it. Create a new LoadingEntry
3932 // and acquire it immediately so that other threads will block.
3933 pLoadingEntry = new PendingTypeLoadEntry(*pTypeKey, typeHnd); // this atomically creates a crst and acquires it
3935 if (!(m_pUnresolvedClassHash->InsertValue(pLoadingEntry)))
3940 // Leave the global lock, so that other threads may now start waiting on our class's lock
3941 unresolvedClassLockHolder.Release();
3945 PendingTypeLoadHolder ptlh(pLoadingEntry);
3947 TRIGGERS_TYPELOAD();
3949 while (currentLevel < targetLevel)
3951 typeHnd = DoIncrementalLoad(pTypeKey, typeHnd, currentLevel);
3952 CONSISTENCY_CHECK(typeHnd.GetLoadLevel() > currentLevel);
3953 currentLevel = typeHnd.GetLoadLevel();
3955 // If other threads are waiting for this load, unblock them as soon as possible to prevent deadlocks.
3956 if (pLoadingEntry->HasWaiters())
3960 _ASSERTE(!typeHnd.IsNull());
3961 pLoadingEntry->SetResult(typeHnd);
3965 LOG((LF_CLASSLOADER, LL_INFO10, "Caught an exception loading: %x, %0x (Module)\n", pTypeKey->GetTypeToken(), pTypeKey->GetModule()));
3967 if (!GetThread()->HasThreadStateNC(Thread::TSNC_LoadsTypeViolation))
3969 // Fix up the loading entry.
3970 Exception *pException = GET_EXCEPTION();
3971 pLoadingEntry->SetException(pException);
3974 // Unlink this class from the unresolved class list.
3975 unresolvedClassLockHolder.Acquire();
3976 m_pUnresolvedClassHash->DeleteValue(pTypeKey);
3978 // Release the lock before proceeding. The unhandled exception filters take number of locks that
3979 // have ordering violations with this lock.
3980 unresolvedClassLockHolder.Release();
3982 // Unblock any thread waiting to load same type as in TypeLoadEntry
3983 pLoadingEntry->UnblockWaiters();
3987 // Unlink this class from the unresolved class list.
3988 unresolvedClassLockHolder.Acquire();
3989 m_pUnresolvedClassHash->DeleteValue(pTypeKey);
3990 unresolvedClassLockHolder.Release();
3992 // Unblock any thread waiting to load same type as in TypeLoadEntry. This should be done
3993 // after pLoadingEntry is removed from m_pUnresolvedClassHash. Otherwise the other thread
3994 // (which was waiting) will keep spinning for a while after waking up, till the current thread removes
3995 // pLoadingEntry from m_pUnresolvedClassHash. This can cause hang in situation when the current
3996 // thread is a background thread and so will get very less processor cycle to perform subsequent
3997 // operations to remove the entry from hash later.
3998 pLoadingEntry->UnblockWaiters();
4000 if (currentLevel < targetLevel)
4004 } // ClassLoader::LoadTypeHandleForTypeKey_Body
4006 #endif //!DACCESS_COMPILE
4008 //---------------------------------------------------------------------------------------
4012 ClassLoader::LoadArrayTypeThrowing(
4013 TypeHandle elemType,
4014 CorElementType arrayKind,
4016 LoadTypesFlag fLoadTypes, //=LoadTypes
4017 ClassLoadLevel level)
4019 CONTRACT(TypeHandle)
4021 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
4022 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
4023 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
4024 if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
4027 POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
4031 CorElementType predefinedElementType = ELEMENT_TYPE_END;
4033 // Try finding it in our cache of primitive SD arrays
4034 if (arrayKind == ELEMENT_TYPE_SZARRAY) {
4035 predefinedElementType = elemType.GetSignatureCorElementType();
4036 if (predefinedElementType <= ELEMENT_TYPE_R8) {
4037 ArrayTypeDesc* typeDesc = g_pPredefinedArrayTypes[predefinedElementType];
4039 RETURN(TypeHandle(typeDesc));
4041 // This call to AsPtr is somewhat bogus and only used
4042 // as an optimization. If the TypeHandle is really a TypeDesc
4043 // then the equality checks for the optimizations below will
4044 // fail. Thus ArrayMT should not be used elsewhere in this function
4045 else if (elemType.AsPtr() == PTR_VOID(g_pObjectClass)) {
4046 // Code duplicated because Object[]'s SigCorElementType is E_T_CLASS, not OBJECT
4047 ArrayTypeDesc* typeDesc = g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT];
4049 RETURN(TypeHandle(typeDesc));
4050 predefinedElementType = ELEMENT_TYPE_OBJECT;
4052 else if (elemType.AsPtr() == PTR_VOID(g_pStringClass)) {
4053 // Code duplicated because String[]'s SigCorElementType is E_T_CLASS, not STRING
4054 ArrayTypeDesc* typeDesc = g_pPredefinedArrayTypes[ELEMENT_TYPE_STRING];
4056 RETURN(TypeHandle(typeDesc));
4057 predefinedElementType = ELEMENT_TYPE_STRING;
4060 predefinedElementType = ELEMENT_TYPE_END;
4065 #ifndef DACCESS_COMPILE
4066 // To avoid loading useless shared instantiations, normalize shared instantiations to the canonical form
4067 // (e.g. List<_Canon>[] -> _Canon[])
4068 // The denormalized shared instantiations should be needed only during JITing, so it is fine to skip this
4069 // for DACCESS_COMPILE.
4070 if (elemType.IsCanonicalSubtype())
4072 elemType = ClassLoader::CanonicalizeGenericArg(elemType);
4076 TypeKey key(arrayKind, elemType, FALSE, rank);
4077 TypeHandle th = LoadConstructedTypeThrowing(&key, fLoadTypes, level);
4079 if (predefinedElementType != ELEMENT_TYPE_END && !th.IsNull() && th.IsFullyLoaded())
4081 g_pPredefinedArrayTypes[predefinedElementType] = th.AsArray();
4085 } // ClassLoader::LoadArrayTypeThrowing
4087 #ifndef DACCESS_COMPILE
4089 VOID ClassLoader::AddAvailableClassDontHaveLock(Module *pModule,
4091 AllocMemTracker *pamTracker)
4099 INJECT_FAULT(COMPlusThrowOM(););
4103 #ifdef FEATURE_COMINTEROP
4104 _ASSERTE(!pModule->GetAssembly()->IsWinMD()); // WinMD files should never get into this path, otherwise provide szWinRtNamespacePrefix
4107 CrstHolder ch(&m_AvailableClassLock);
4109 AddAvailableClassHaveLock(
4113 NULL, // szWinRtNamespacePrefix
4114 0); // cchWinRtNamespacePrefix
4117 // This routine must be single threaded! The reason is that there are situations which allow
4118 // the same class name to have two different mdTypeDef tokens (for example, we load two different DLLs
4119 // simultaneously, and they have some common class files, or we convert the same class file
4120 // simultaneously on two threads). The problem is that we do not want to overwrite the old
4121 // <classname> -> pModule mapping with the new one, because this may cause identity problems.
4123 // This routine assumes you already have the lock. Use AddAvailableClassDontHaveLock() if you
4126 // Also validates that TypeDef namespace begins with szWinRTNamespacePrefix (if it is not NULL).
4127 // The prefix should be NULL for normal non-WinRT .NET assemblies.
4129 VOID ClassLoader::AddAvailableClassHaveLock(
4132 AllocMemTracker * pamTracker,
4133 LPCSTR szWinRtNamespacePrefix,
4134 DWORD cchWinRtNamespacePrefix) // Optimization for faster prefix comparison implementation
4142 INJECT_FAULT(COMPlusThrowOM(););
4146 EEClassHashTable *pClassHash = pModule->GetAvailableClassHash();
4147 EEClassHashTable *pClassCaseInsHash = pModule->GetAvailableClassCaseInsHash();
4150 LPCUTF8 pszNameSpace;
4151 HashDatum ThrowawayData;
4152 IMDInternalImport *pMDImport = pModule->GetMDImport();
4153 if (FAILED(pMDImport->GetNameOfTypeDef(classdef, &pszName, &pszNameSpace)))
4155 pszName = pszNameSpace = "Invalid TypeDef token";
4156 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4159 EEClassHashEntry_t *pBucket;
4160 mdTypeDef enclosing;
4161 if (SUCCEEDED(pMDImport->GetNestedClassProps(classdef, &enclosing))) {
4164 LPCUTF8 pszEnclosingName;
4165 LPCUTF8 pszEnclosingNameSpace;
4166 mdTypeDef enclEnclosing;
4168 // Find this type's encloser's entry in the available table.
4169 // We'll save a pointer to it in the new hash entry for this type.
4170 BOOL fNestedEncl = SUCCEEDED(pMDImport->GetNestedClassProps(enclosing, &enclEnclosing));
4172 EEClassHashTable::LookupContext sContext;
4173 if (FAILED(pMDImport->GetNameOfTypeDef(enclosing, &pszEnclosingName, &pszEnclosingNameSpace)))
4175 pszName = pszNameSpace = "Invalid TypeDef token";
4176 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4178 if ((pBucket = pClassHash->GetValue(pszEnclosingNameSpace,
4182 &sContext)) != NULL) {
4184 // Find entry for enclosing class - NOTE, this assumes that the
4185 // enclosing class's TypeDef or ExportedType was inserted previously,
4186 // which assumes that, when enuming TD's, we get the enclosing class first
4187 while ((!CompareNestedEntryWithTypeDef(pMDImport,
4190 pBucket->GetEncloser())) &&
4191 (pBucket = pClassHash->FindNextNestedClass(pszEnclosingNameSpace,
4194 &sContext)) != NULL);
4197 if (!pBucket) // Enclosing type not found in hash table
4198 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_ENCLOSING_TYPE_NOT_FOUND);
4200 // In this hash table, if the lower bit is set, it means a Module, otherwise it means EEClass*
4201 ThrowawayData = EEClassHashTable::CompressClassDef(classdef);
4202 InsertValue(pClassHash, pClassCaseInsHash, pszNameSpace, pszName, ThrowawayData, pBucket, pamTracker);
4206 // Don't add duplicate top-level classes. Top-level classes are
4207 // added to the beginning of the bucket, while nested classes are
4208 // added to the end. So, a duplicate top-level class could hide
4209 // the previous type's EEClass* entry in the hash table.
4210 EEClassHashEntry_t *pCaseInsEntry = NULL;
4211 LPUTF8 pszLowerCaseNS = NULL;
4212 LPUTF8 pszLowerCaseName = NULL;
4214 if (pClassCaseInsHash) {
4215 CreateCanonicallyCasedKey(pszNameSpace, pszName, &pszLowerCaseNS, &pszLowerCaseName);
4216 pCaseInsEntry = pClassCaseInsHash->AllocNewEntry(pamTracker);
4219 EEClassHashEntry_t *pEntry = pClassHash->FindItem(pszNameSpace, pszName, FALSE, NULL);
4221 HashDatum Data = pEntry->GetData();
4223 if (((size_t)Data & EECLASSHASH_TYPEHANDLE_DISCR) &&
4224 ((size_t)Data & EECLASSHASH_MDEXPORT_DISCR)) {
4226 // it's an ExportedType - check the 'already seen' bit and if on, report a class loading exception
4227 // otherwise, set it
4228 if ((size_t)Data & EECLASSHASH_ALREADYSEEN)
4229 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_MULT_TYPE_SAME_NAME);
4231 Data = (HashDatum)((size_t)Data | EECLASSHASH_ALREADYSEEN);
4232 pEntry->SetData(Data);
4236 // We want to throw an exception for a duplicate typedef.
4237 // However, this used to be allowed in 1.0/1.1, and some third-party DLLs have
4238 // been obfuscated so that they have duplicate private typedefs.
4239 // We must allow this for old assemblies for app compat reasons
4240 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_MULT_TYPE_SAME_NAME);
4244 pEntry = pClassHash->AllocNewEntry(pamTracker);
4246 CANNOTTHROWCOMPLUSEXCEPTION();
4249 pClassHash->InsertValueUsingPreallocatedEntry(pEntry, pszNameSpace, pszName, EEClassHashTable::CompressClassDef(classdef), NULL);
4251 if (pClassCaseInsHash)
4252 pClassCaseInsHash->InsertValueUsingPreallocatedEntry(pCaseInsEntry, pszLowerCaseNS, pszLowerCaseName, pEntry, pEntry->GetEncloser());
4255 #ifdef FEATURE_COMINTEROP
4256 // Check WinRT namespace prefix if required
4257 if (szWinRtNamespacePrefix != NULL)
4260 if (FAILED(pMDImport->GetTypeDefProps(classdef, &dwAttr, NULL)))
4262 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4265 // Check only public WinRT types that are not nested (i.e. only types available for binding, excluding NoPIA)
4266 if (IsTdPublic(dwAttr) && IsTdWindowsRuntime(dwAttr))
4268 // Guaranteed by the caller - code:ClassLoader::PopulateAvailableClassHashTable
4269 _ASSERTE(cchWinRtNamespacePrefix == strlen(szWinRtNamespacePrefix));
4271 // Now make sure namespace is, or begins with the namespace-prefix (note: 'MyN' should not match namespace 'MyName')
4272 // Note: Case insensitive comparison function has to be in sync with Win8 implementation
4273 // (ExtractExactCaseNamespaceSegmentFromMetadataFile in com\WinRT\WinTypes\TypeResolution\NamespaceResolution.cpp)
4274 BOOL fIsNamespaceSubstring = (pszNameSpace != NULL) &&
4275 ((strncmp(pszNameSpace, szWinRtNamespacePrefix, cchWinRtNamespacePrefix) == 0) ||
4276 (_strnicmp(pszNameSpace, szWinRtNamespacePrefix, cchWinRtNamespacePrefix) == 0));
4277 BOOL fIsSubNamespace = fIsNamespaceSubstring &&
4278 ((pszNameSpace[cchWinRtNamespacePrefix] == '\0') ||
4279 (pszNameSpace[cchWinRtNamespacePrefix] == '.'));
4280 if (!fIsSubNamespace)
4282 pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_WINRT_INVALID_NAMESPACE_FOR_TYPE);
4286 #endif // FEATURE_COMINTEROP
4290 VOID ClassLoader::AddExportedTypeDontHaveLock(Module *pManifestModule,
4292 AllocMemTracker *pamTracker)
4300 INJECT_FAULT(COMPlusThrowOM(););
4304 CrstHolder ch(&m_AvailableClassLock);
4306 AddExportedTypeHaveLock(
4312 VOID ClassLoader::AddExportedTypeHaveLock(Module *pManifestModule,
4314 AllocMemTracker *pamTracker)
4322 INJECT_FAULT(COMPlusThrowOM(););
4329 LPCSTR pszNameSpace;
4330 IMDInternalImport* pAsmImport = pManifestModule->GetMDImport();
4331 if (FAILED(pAsmImport->GetExportedTypeProps(
4339 pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4342 HashDatum ThrowawayData;
4344 if (TypeFromToken(mdImpl) == mdtExportedType)
4347 LPCUTF8 pszEnclosingNameSpace;
4348 LPCUTF8 pszEnclosingName;
4350 if (FAILED(pAsmImport->GetExportedTypeProps(
4352 &pszEnclosingNameSpace,
4358 pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4361 // Find entry for enclosing class - NOTE, this assumes that the
4362 // enclosing class's ExportedType was inserted previously, which assumes that,
4363 // when enuming ExportedTypes, we get the enclosing class first
4364 EEClassHashEntry_t *pBucket;
4365 EEClassHashTable::LookupContext sContext;
4366 if ((pBucket = pManifestModule->GetAvailableClassHash()->GetValue(pszEnclosingNameSpace,
4369 TypeFromToken(nextImpl) == mdtExportedType,
4370 &sContext)) != NULL) {
4372 // check to see if this is the correct class
4373 if (EEClassHashTable::UncompressModuleAndClassDef(ThrowawayData) == mdImpl) {
4374 ThrowawayData = EEClassHashTable::CompressClassDef(cl);
4376 // we explicitly don't check for the case insensitive hash table because we know it can't have been created yet
4377 pManifestModule->GetAvailableClassHash()->InsertValue(pszNameSpace, pszName, ThrowawayData, pBucket, pamTracker);
4379 pBucket = pManifestModule->GetAvailableClassHash()->FindNextNestedClass(pszEnclosingNameSpace, pszEnclosingName, &ThrowawayData, &sContext);
4383 // If the encloser is not in the hash table, this nested class
4384 // was defined in the manifest module, so it doesn't need to be added
4388 // Defined in the manifest module - add to the hash table by TypeDef instead
4389 if (mdImpl == mdFileNil)
4392 // Don't add duplicate top-level classes
4393 // In this hash table, if the lower bit is set, it means a Module, otherwise it means EEClass*
4394 ThrowawayData = EEClassHashTable::CompressClassDef(cl);
4395 // ThrowawayData is an IN OUT param. Going in its the pointer to the new value if the entry needs
4396 // to be inserted. The OUT param points to the value stored in the hash table.
4398 pManifestModule->GetAvailableClassHash()->InsertValueIfNotFound(pszNameSpace, pszName, &ThrowawayData, NULL, FALSE, &bFound, pamTracker);
4401 // Check for duplicate ExportedTypes
4402 // Let it slide if it's pointing to the same type
4403 mdToken foundTypeImpl;
4404 if ((size_t)ThrowawayData & EECLASSHASH_MDEXPORT_DISCR)
4406 mdExportedType foundExportedType = EEClassHashTable::UncompressModuleAndClassDef(ThrowawayData);
4407 if (FAILED(pAsmImport->GetExportedTypeProps(
4415 pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN);
4420 foundTypeImpl = mdFileNil;
4423 if (mdImpl != foundTypeImpl)
4425 pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_MULT_TYPE_SAME_NAME);
4431 static MethodTable* GetEnclosingMethodTable(MethodTable *pMT)
4433 CONTRACT(MethodTable*)
4437 INJECT_FAULT(COMPlusThrowOM(););
4439 PRECONDITION(CheckPointer(pMT));
4440 POSTCONDITION(RETVAL == NULL || RETVAL->IsTypicalTypeDefinition());
4444 RETURN pMT->LoadEnclosingMethodTable();
4447 StaticAccessCheckContext::StaticAccessCheckContext(MethodDesc* pCallerMethod)
4451 LIMITED_METHOD_CONTRACT;
4452 PRECONDITION(CheckPointer(pCallerMethod));
4456 m_pCallerMethod = pCallerMethod;
4457 m_pCallerMT = m_pCallerMethod->GetMethodTable();
4458 m_pCallerAssembly = m_pCallerMT->GetAssembly();
4461 StaticAccessCheckContext::StaticAccessCheckContext(MethodDesc* pCallerMethod, MethodTable* pCallerType)
4465 LIMITED_METHOD_CONTRACT;
4466 PRECONDITION(CheckPointer(pCallerMethod, NULL_OK));
4467 PRECONDITION(CheckPointer(pCallerType));
4471 m_pCallerMethod = pCallerMethod;
4472 m_pCallerMT = pCallerType;
4473 m_pCallerAssembly = pCallerType->GetAssembly();
4476 //******************************************************************************
4479 AccessCheckOptions* AccessCheckOptions::s_pNormalAccessChecks;
4481 //******************************************************************************
4483 void AccessCheckOptions::Startup()
4485 STANDARD_VM_CONTRACT;
4487 s_pNormalAccessChecks = new AccessCheckOptions(
4488 AccessCheckOptions::kNormalAccessibilityChecks,
4491 (MethodTable *)NULL);
4494 //******************************************************************************
4495 AccessCheckOptions::AccessCheckOptions(
4496 const AccessCheckOptions & templateOptions,
4497 BOOL throwIfTargetIsInaccessible) :
4498 m_pAccessContext(templateOptions.m_pAccessContext)
4500 WRAPPER_NO_CONTRACT;
4503 templateOptions.m_accessCheckType,
4504 throwIfTargetIsInaccessible,
4505 templateOptions.m_pTargetMT,
4506 templateOptions.m_pTargetMethod,
4507 templateOptions.m_pTargetField);
4510 //******************************************************************************
4511 // This function should only be called when normal accessibility is not possible.
4512 // It returns TRUE if the target can be accessed.
4513 // Otherwise, it either returns FALSE or throws an exception, depending on the value of throwIfTargetIsInaccessible.
4515 BOOL AccessCheckOptions::DemandMemberAccess(AccessCheckContext *pContext, MethodTable * pTargetMT, BOOL visibilityCheck) const
4522 PRECONDITION(m_accessCheckType != kNormalAccessibilityChecks);
4523 PRECONDITION(CheckPointer(pContext));
4527 _ASSERTE(m_accessCheckType != kNormalAccessibilityChecks);
4529 if (NingenEnabled())
4531 // NinGen should always perform normal accessibility checks
4534 if (m_fThrowIfTargetIsInaccessible)
4536 ThrowAccessException(pContext, pTargetMT, NULL);
4542 if (pTargetMT && pTargetMT->GetAssembly()->IsDisabledPrivateReflection())
4544 if (m_fThrowIfTargetIsInaccessible)
4546 ThrowAccessException(pContext, pTargetMT, NULL);
4552 BOOL canAccessTarget = FALSE;
4554 #ifndef CROSSGEN_COMPILE
4556 // In CoreCLR kRestrictedMemberAccess means that one can access private/internal
4557 // classes/members in app code.
4558 if (m_accessCheckType != kMemberAccess && pTargetMT)
4560 // We allow all transparency checks to succeed in LCG methods and reflection invocation.
4561 if (m_accessCheckType == kNormalAccessNoTransparency || m_accessCheckType == kRestrictedMemberAccessNoTransparency)
4565 // Always allow interop (NULL) callers full access.
4566 if (pContext->IsCalledFromInterop())
4570 if (m_fThrowIfTargetIsInaccessible)
4572 ThrowAccessException(pContext, pTargetMT, NULL);
4575 #endif // CROSSGEN_COMPILE
4577 return canAccessTarget;
4580 //******************************************************************************
4581 // pFailureMT - the MethodTable that we were trying to access. It can be null
4582 // if the failure is not because of a specific type. This will be a
4583 // a component of the instantiation of m_pTargetMT/m_pTargetMethod/m_pTargetField.
4585 void AccessCheckOptions::ThrowAccessException(
4586 AccessCheckContext* pContext,
4587 MethodTable* pFailureMT, /* = NULL */
4588 Exception* pInnerException /* = NULL */) const
4595 PRECONDITION(CheckPointer(pContext));
4596 PRECONDITION(CheckPointer(pInnerException, NULL_OK));
4597 PRECONDITION(m_fThrowIfTargetIsInaccessible);
4603 MethodDesc* pCallerMD = pContext->GetCallerMethod();
4605 if (m_pTargetMT != NULL)
4607 // If we know the specific type that caused the failure, display it.
4608 // Else display the whole type that we are trying to access.
4609 MethodTable * pMT = (pFailureMT != NULL) ? pFailureMT : m_pTargetMT;
4610 ThrowTypeAccessException(pContext, pMT, 0, pInnerException);
4612 else if (m_pTargetMethod != NULL)
4614 // If the caller and target method are non-null and the same, then this means that we're checking to see
4615 // if the method has access to itself in order to validate that it has access to its parameter types,
4616 // containing type, and return type. In this case, throw a more informative TypeAccessException to
4617 // describe the error that occurred (for instance, "this method doesn't have access to one of its
4618 // parameter types", rather than "this method doesn't have access to itself").
4619 // We only want to do this if we know the exact type that caused the problem, otherwise fall back to
4620 // throwing the standard MethodAccessException.
4621 if (pCallerMD != NULL && m_pTargetMethod == pCallerMD && pFailureMT != NULL)
4623 ThrowTypeAccessException(pContext, pFailureMT, 0, pInnerException);
4627 ThrowMethodAccessException(pContext, m_pTargetMethod, 0, pInnerException);
4632 _ASSERTE(m_pTargetField != NULL);
4633 ThrowFieldAccessException(pContext, m_pTargetField, 0, pInnerException);
4637 //******************************************************************************
4638 // This will do a security demand if appropriate.
4639 // If access is not possible, this will either throw an exception or return FALSE
4640 BOOL AccessCheckOptions::DemandMemberAccessOrFail(AccessCheckContext *pContext, MethodTable * pTargetMT, BOOL visibilityCheck) const
4650 if (DoNormalAccessibilityChecks())
4652 if (pContext->GetCallerAssembly()->IgnoresAccessChecksTo(pTargetMT->GetAssembly()))
4657 if (m_fThrowIfTargetIsInaccessible)
4659 ThrowAccessException(pContext, pTargetMT);
4665 return DemandMemberAccess(pContext, pTargetMT, visibilityCheck);
4668 //******************************************************************************
4669 // This should be called if access to the target is not possible.
4670 // This will either throw an exception or return FALSE.
4671 BOOL AccessCheckOptions::FailOrThrow(AccessCheckContext *pContext) const
4678 PRECONDITION(CheckPointer(pContext));
4682 if (m_fThrowIfTargetIsInaccessible)
4684 ThrowAccessException(pContext);
4690 void DECLSPEC_NORETURN ThrowFieldAccessException(AccessCheckContext* pContext,
4692 UINT messageID /* = 0 */,
4693 Exception *pInnerException /* = NULL */)
4700 PRECONDITION(CheckPointer(pContext));
4701 PRECONDITION(CheckPointer(pFD));
4705 MethodDesc* pCallerMD = pContext->GetCallerMethod();
4707 ThrowFieldAccessException(pCallerMD,
4713 void DECLSPEC_NORETURN ThrowFieldAccessException(MethodDesc* pCallerMD,
4715 UINT messageID /* = 0 */,
4716 Exception *pInnerException /* = NULL */)
4723 PRECONDITION(CheckPointer(pCallerMD, NULL_OK));
4724 PRECONDITION(CheckPointer(pFD));
4728 if (pCallerMD != NULL)
4732 messageID = IDS_E_FIELDACCESS;
4735 EX_THROW_WITH_INNER(EEFieldException, (pFD, pCallerMD, SString::Empty(), messageID), pInnerException);
4739 EX_THROW_WITH_INNER(EEFieldException, (pFD), pInnerException);
4743 void DECLSPEC_NORETURN ThrowMethodAccessException(AccessCheckContext* pContext,
4744 MethodDesc *pCalleeMD,
4745 UINT messageID /* = 0 */,
4746 Exception *pInnerException /* = NULL */)
4753 PRECONDITION(CheckPointer(pContext));
4754 PRECONDITION(CheckPointer(pCalleeMD));
4758 MethodDesc* pCallerMD = pContext->GetCallerMethod();
4760 ThrowMethodAccessException(pCallerMD,
4766 void DECLSPEC_NORETURN ThrowMethodAccessException(MethodDesc* pCallerMD,
4767 MethodDesc *pCalleeMD,
4768 UINT messageID /* = 0 */,
4769 Exception *pInnerException /* = NULL */)
4776 PRECONDITION(CheckPointer(pCallerMD, NULL_OK));
4777 PRECONDITION(CheckPointer(pCalleeMD));
4781 if (pCallerMD != NULL)
4785 messageID = IDS_E_METHODACCESS;
4788 EX_THROW_WITH_INNER(EEMethodException, (pCalleeMD, pCallerMD, SString::Empty(), messageID), pInnerException);
4792 EX_THROW_WITH_INNER(EEMethodException, (pCalleeMD), pInnerException);
4796 void DECLSPEC_NORETURN ThrowTypeAccessException(AccessCheckContext* pContext,
4798 UINT messageID /* = 0 */,
4799 Exception *pInnerException /* = NULL */)
4806 PRECONDITION(CheckPointer(pContext));
4807 PRECONDITION(CheckPointer(pMT));
4811 MethodDesc* pCallerMD = pContext->GetCallerMethod();
4813 ThrowTypeAccessException(pCallerMD,
4819 void DECLSPEC_NORETURN ThrowTypeAccessException(MethodDesc* pCallerMD,
4821 UINT messageID /* = 0 */,
4822 Exception *pInnerException /* = NULL */)
4829 PRECONDITION(CheckPointer(pCallerMD, NULL_OK));
4830 PRECONDITION(CheckPointer(pMT));
4834 if (pCallerMD != NULL)
4838 messageID = IDS_E_TYPEACCESS;
4841 EX_THROW_WITH_INNER(EETypeAccessException, (pMT, pCallerMD, SString::Empty(), messageID), pInnerException);
4845 EX_THROW_WITH_INNER(EETypeAccessException, (pMT), pInnerException);
4849 //---------------------------------------------------------------------------------------
4851 // Checks to see if access to a member with assembly visiblity is allowed.
4854 // pAccessingAssembly - The assembly requesting access to the internal member
4855 // pTargetAssembly - The assembly which contains the target member
4856 // pOptionalTargetField - Internal field being accessed OR
4857 // pOptionalTargetMethod - Internal type being accessed OR
4858 // pOptionalTargetType - Internal type being accessed
4861 // TRUE if pTargetAssembly is pAccessingAssembly, or if pTargetAssembly allows
4862 // pAccessingAssembly friend access to the target. FALSE otherwise.
4865 static BOOL AssemblyOrFriendAccessAllowed(Assembly *pAccessingAssembly,
4866 Assembly *pTargetAssembly,
4867 FieldDesc *pOptionalTargetField,
4868 MethodDesc *pOptionalTargetMethod,
4869 MethodTable *pOptionalTargetType)
4875 PRECONDITION(CheckPointer(pAccessingAssembly));
4876 PRECONDITION(CheckPointer(pTargetAssembly));
4877 PRECONDITION(pOptionalTargetField != NULL || pOptionalTargetMethod != NULL || pOptionalTargetType != NULL);
4878 PRECONDITION(pOptionalTargetField == NULL || pOptionalTargetMethod == NULL);
4882 if (pAccessingAssembly == pTargetAssembly)
4887 if (pAccessingAssembly->IgnoresAccessChecksTo(pTargetAssembly))
4892 else if (pOptionalTargetField != NULL)
4894 return pTargetAssembly->GrantsFriendAccessTo(pAccessingAssembly, pOptionalTargetField);
4896 else if (pOptionalTargetMethod != NULL)
4898 return pTargetAssembly->GrantsFriendAccessTo(pAccessingAssembly, pOptionalTargetMethod);
4902 return pTargetAssembly->GrantsFriendAccessTo(pAccessingAssembly, pOptionalTargetType);
4906 //******************************************************************************
4907 // This function determines whether a target class is accessible from
4908 // some given class.
4910 BOOL ClassLoader::CanAccessMethodInstantiation( // True if access is legal, false otherwise.
4911 AccessCheckContext* pContext,
4912 MethodDesc* pOptionalTargetMethod, // The desired method; if NULL, return TRUE (or)
4913 const AccessCheckOptions & accessCheckOptions)
4919 INJECT_FAULT(COMPlusThrowOM(););
4921 PRECONDITION(CheckPointer(pContext));
4925 // If there is no target method just allow access.
4926 // NB: the caller may just be checking access to a field or class, so we allow for NULL.
4927 if (!pOptionalTargetMethod)
4930 // Is the desired target an instantiated generic method?
4931 if (pOptionalTargetMethod->HasMethodInstantiation())
4932 { // check that the current class has access
4933 // to all of the instantiating classes.
4934 Instantiation inst = pOptionalTargetMethod->GetMethodInstantiation();
4935 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
4937 TypeHandle th = inst[i];
4939 MethodTable* pMT = th.GetMethodTableOfElementType();
4941 // Either a TypeVarTypeDesc or a FnPtrTypeDesc. No access check needed.
4945 if (!CanAccessClass(
4949 accessCheckOptions))
4954 // If we are here, the current class has access to all of the target's instantiating args,
4959 //******************************************************************************
4960 // This function determines whether a target class is accessible from
4961 // some given class.
4962 // CanAccessClass does the following checks:
4963 // 1. Transparency check on the target class
4964 // 2. Recursively calls CanAccessClass on the generic arguments of the target class if it is generic.
4965 // 3. Visibility check on the target class, if the target class is nested, this will be translated
4966 // to a member access check on the enclosing type (calling CanAccess with appropriate dwProtection.
4969 BOOL ClassLoader::CanAccessClass( // True if access is legal, false otherwise.
4970 AccessCheckContext* pContext, // The caller context
4971 MethodTable* pTargetClass, // The desired target class.
4972 Assembly* pTargetAssembly, // Assembly containing the target class.
4973 const AccessCheckOptions & accessCheckOptions)// = TRUE
4979 INJECT_FAULT(COMPlusThrowOM(););
4981 PRECONDITION(CheckPointer(pContext));
4982 PRECONDITION(CheckPointer(pTargetClass));
4986 // If there is no target class, allow access.
4987 // @todo: what does that mean?
4988 //if (!pTargetClass)
4991 // Step 2: Recursively call CanAccessClass on the generic type arguments
4992 // Is the desired target a generic instantiation?
4993 if (pTargetClass->HasInstantiation())
4994 { // Yes, so before going any further, check that the current class has access
4995 // to all of the instantiating classes.
4996 Instantiation inst = pTargetClass->GetInstantiation();
4997 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
4999 TypeHandle th = inst[i];
5001 MethodTable* pMT = th.GetMethodTableOfElementType();
5003 // Either a TypeVarTypeDesc or a FnPtrTypeDesc. No access check needed.
5007 if (!CanAccessClass(
5011 accessCheckOptions))
5013 // no need to call accessCheckOptions.DemandMemberAccessOrFail here because the base case in
5014 // CanAccessClass does that already
5018 // If we are here, the current class has access to all of the desired target's instantiating args.
5019 // Now, check whether the current class has access to the desired target itself.
5022 // Step 3: Visibility Check
5023 if (!pTargetClass->GetClass()->IsNested())
5024 { // a non-nested class can be either all public or accessible only from its own assembly (and friends).
5025 if (IsTdPublic(pTargetClass->GetClass()->GetProtection()))
5031 // Always allow interop callers full access.
5032 if (pContext->IsCalledFromInterop())
5035 Assembly* pCurrentAssembly = pContext->GetCallerAssembly();
5036 _ASSERTE(pCurrentAssembly != NULL);
5038 if (AssemblyOrFriendAccessAllowed(pCurrentAssembly,
5048 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetClass, TRUE /*visibilityCheck*/);
5053 // If we are here, the desired target class is nested. Translate the type flags
5054 // to corresponding method access flags. We need to make a note if friend access was allowed to the
5055 // type being checked since we're not passing it directly to the recurisve call to CanAccess, and
5056 // instead are just passing in the dwProtectionFlags.
5057 DWORD dwProtection = pTargetClass->GetClass()->GetProtection();
5059 switch(dwProtection) {
5060 case tdNestedPublic:
5061 dwProtection = mdPublic;
5063 case tdNestedFamily:
5064 dwProtection = mdFamily;
5066 case tdNestedPrivate:
5067 dwProtection = mdPrivate;
5069 case tdNestedFamORAssem:
5070 // If we can access the class because we have assembly or friend access, we have satisfied the
5071 // FamORAssem accessibility, so we we can simplify it down to public. Otherwise we require that
5072 // family access be allowed to grant access.
5073 case tdNestedFamANDAssem:
5074 // If we don't grant assembly or friend access to the target class, then there is no way we
5075 // could satisfy the FamANDAssem requirement. Otherwise, since we have satsified the Assm
5076 // portion, we only need to check for the Fam portion.
5077 case tdNestedAssembly:
5078 // If we don't grant assembly or friend access to the target class, and that class has assembly
5079 // protection, we can fail the request now. Otherwise we can check to make sure a public member
5080 // of the outer class is allowed, since we have satisfied the target's accessibility rules.
5082 // Always allow interop callers full access.
5083 if (pContext->IsCalledFromInterop())
5086 if (AssemblyOrFriendAccessAllowed(pContext->GetCallerAssembly(), pTargetAssembly, NULL, NULL, pTargetClass))
5087 dwProtection = (dwProtection == tdNestedFamANDAssem) ? mdFamily : mdPublic;
5088 else if (dwProtection == tdNestedFamORAssem)
5089 dwProtection = mdFamily;
5091 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetClass, TRUE /*visibilityCheck*/);
5096 THROW_BAD_FORMAT_MAYBE(!"Unexpected class visibility flag value", BFA_BAD_VISIBILITY, pTargetClass);
5099 // The desired target class is nested, so translate the class access request into
5100 // a member access request. That is, if the current class is trying to access A::B,
5101 // check if it can access things in A with the visibility of B.
5102 // So, pass A as the desired target class and visibility of B within A as the member access
5103 // We've already done transparency check above. No need to do it again.
5104 return ClassLoader::CanAccess(
5106 GetEnclosingMethodTable(pTargetClass),
5111 accessCheckOptions);
5112 } // BOOL ClassLoader::CanAccessClass()
5114 //******************************************************************************
5115 // This is a front-end to CheckAccessMember that handles the nested class scope. If can't access
5116 // from the current point and are a nested class, then try from the enclosing class.
5117 // In addition to CanAccessMember, if the caller class doesn't have access to the caller, see if the enclosing class does.
5120 BOOL ClassLoader::CanAccess( // TRUE if access is allowed, FALSE otherwise.
5121 AccessCheckContext* pContext, // The caller context
5122 MethodTable* pTargetMT, // The class containing the desired target member.
5123 Assembly* pTargetAssembly, // Assembly containing that class.
5124 DWORD dwMemberAccess, // Member access flags of the desired target member (as method bits).
5125 MethodDesc* pOptionalTargetMethod, // The target method; NULL if the target is a not a method or
5126 // there is no need to check the method's instantiation.
5127 FieldDesc* pOptionalTargetField, // or The desired field; if NULL, return TRUE
5128 const AccessCheckOptions & accessCheckOptions) // = s_NormalAccessChecks
5134 INJECT_FAULT(COMPlusThrowOM(););
5135 PRECONDITION(CheckPointer(pContext));
5140 AccessCheckOptions accessCheckOptionsNoThrow(accessCheckOptions, FALSE);
5142 if (!CheckAccessMember(pContext,
5146 pOptionalTargetMethod,
5147 pOptionalTargetField,
5148 // Suppress exceptions for nested classes since this is not a hard-failure,
5149 // and we can do additional checks
5150 accessCheckOptionsNoThrow))
5152 // If we're here, CheckAccessMember didn't allow access.
5153 BOOL canAccess = FALSE;
5155 // If the current class is nested, there may be an enclosing class that might have access
5156 // to the target. And if the pCurrentMT == NULL, the current class is global, and so there
5157 // is no enclosing class.
5158 MethodTable* pCurrentMT = pContext->GetCallerMT();
5160 // if this is called from interop, the CheckAccessMember call above should have already succeeded.
5161 _ASSERTE(!pContext->IsCalledFromInterop());
5163 BOOL isNestedClass = (pCurrentMT && pCurrentMT->GetClass()->IsNested());
5167 // A nested class also has access to anything that the enclosing class does, so
5168 // recursively check whether the enclosing class can access the desired target member.
5169 MethodTable * pEnclosingMT = GetEnclosingMethodTable(pCurrentMT);
5171 StaticAccessCheckContext accessContext(pContext->GetCallerMethod(),
5173 pContext->GetCallerAssembly());
5175 // On failure, do not throw from inside this call since that will cause the exception message
5176 // to refer to the enclosing type.
5177 canAccess = ClassLoader::CanAccess(
5182 pOptionalTargetMethod,
5183 pOptionalTargetField,
5184 accessCheckOptionsNoThrow);
5189 BOOL fail = accessCheckOptions.FailOrThrow(pContext);
5195 } // BOOL ClassLoader::CanAccess()
5197 //******************************************************************************
5198 // This is the helper function for the corresponding CanAccess()
5199 // It does the following checks:
5200 // 1. CanAccessClass on pTargetMT
5201 // 2. CanAccessMethodInstantiation if the pOptionalTargetMethod is provided and is generic.
5202 // 3. Transparency check on pTargetMT, pOptionalTargetMethod and pOptionalTargetField.
5203 // 4. Visibility check on dwMemberAccess (on pTargetMT)
5206 BOOL ClassLoader::CheckAccessMember( // TRUE if access is allowed, false otherwise.
5207 AccessCheckContext* pContext,
5208 MethodTable* pTargetMT, // The class containing the desired target member.
5209 Assembly* pTargetAssembly, // Assembly containing that class.
5210 DWORD dwMemberAccess, // Member access flags of the desired target member (as method bits).
5211 MethodDesc* pOptionalTargetMethod, // The target method; NULL if the target is a not a method or
5212 // there is no need to check the method's instantiation.
5213 FieldDesc* pOptionalTargetField, // target field, NULL if there is no Target field
5214 const AccessCheckOptions & accessCheckOptions
5221 INJECT_FAULT(COMPlusThrowOM(););
5222 PRECONDITION(CheckPointer(pContext));
5227 // we're trying to access a member that is contained in the class pTargetClass, so need to
5228 // check if have access to pTargetClass itself from the current point before worry about
5229 // having access to the member within the class
5230 if (!CanAccessClass(pContext,
5233 accessCheckOptions))
5238 // If we are trying to access a generic method, we have to ensure its instantiation is accessible.
5239 // Note that we need to perform transparency checks on the instantiation even if we have
5240 if (!CanAccessMethodInstantiation(
5242 pOptionalTargetMethod,
5243 accessCheckOptions))
5248 // pOptionalTargetMethod and pOptionalTargetField can never be NULL at the same time.
5249 _ASSERTE(pOptionalTargetMethod == NULL || pOptionalTargetField == NULL);
5251 // Perform transparency checks
5252 // We don't need to do transparency check against pTargetMT here because
5253 // it was already done in CanAccessClass above.
5255 if (IsMdPublic(dwMemberAccess))
5260 // Always allow interop callers full access.
5261 if (pContext->IsCalledFromInterop())
5264 MethodTable* pCurrentMT = pContext->GetCallerMT();
5266 if (IsMdPrivateScope(dwMemberAccess))
5268 if (pCurrentMT != NULL && pCurrentMT->GetModule() == pTargetMT->GetModule())
5274 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
5280 if (pTargetMT == NULL &&
5281 (IsMdFamORAssem(dwMemberAccess) ||
5282 IsMdFamANDAssem(dwMemberAccess) ||
5283 IsMdFamily(dwMemberAccess))) {
5284 THROW_BAD_FORMAT_MAYBE(!"Family flag is not allowed on global functions", BFA_FAMILY_ON_GLOBAL, pTargetMT);
5288 if (pTargetMT == NULL ||
5289 IsMdAssem(dwMemberAccess) ||
5290 IsMdFamORAssem(dwMemberAccess) ||
5291 IsMdFamANDAssem(dwMemberAccess))
5293 // If the member has Assembly accessibility, grant access if the current
5294 // class is in the same assembly as the desired target member, or if the
5295 // desired target member's assembly grants friend access to the current
5297 // @todo: What does it mean for the target class to be NULL?
5299 Assembly* pCurrentAssembly = pContext->GetCallerAssembly();
5301 // pCurrentAssembly should never be NULL, unless we are called from interop,
5302 // in which case we should have already returned TRUE.
5303 _ASSERTE(pCurrentAssembly != NULL);
5305 const BOOL fAssemblyOrFriendAccessAllowed = AssemblyOrFriendAccessAllowed(pCurrentAssembly,
5307 pOptionalTargetField,
5308 pOptionalTargetMethod,
5311 if ((pTargetMT == NULL || IsMdAssem(dwMemberAccess) || IsMdFamORAssem(dwMemberAccess)) &&
5312 fAssemblyOrFriendAccessAllowed)
5316 else if (IsMdFamANDAssem(dwMemberAccess) &&
5317 !fAssemblyOrFriendAccessAllowed)
5319 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
5323 // Nested classes can access all members of the parent class.
5324 while(pCurrentMT != NULL)
5327 if (pTargetMT->HasSameTypeDefAs(pCurrentMT))
5330 if (IsMdPrivate(dwMemberAccess))
5332 if (!pCurrentMT->GetClass()->IsNested())
5334 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
5337 else if (IsMdFamORAssem(dwMemberAccess) || IsMdFamily(dwMemberAccess) || IsMdFamANDAssem(dwMemberAccess))
5339 if (CanAccessFamily(pCurrentMT, pTargetMT))
5345 pCurrentMT = GetEnclosingMethodTable(pCurrentMT);
5348 return accessCheckOptions.DemandMemberAccessOrFail(pContext, pTargetMT, TRUE /*visibilityCheck*/);
5351 // The family check is actually in two parts (Partition I, 8.5.3.2). The first part:
5353 // ...accessible to referents that support the same type
5354 // (i.e., an exact type and all of the types that inherit
5357 // Translation: pCurrentClass must be the same type as pTargetClass or a derived class. (i.e. Derived
5358 // can access Base.protected but Unrelated cannot access Base.protected).
5362 // For verifiable code (see Section 8.8), there is an additional
5363 // requirement that can require a runtime check: the reference
5364 // shall be made through an item whose exact type supports
5365 // the exact type of the referent. That is, the item whose
5366 // member is being accessed shall inherit from the type
5367 // performing the access.
5369 // Translation: The C++ protected rule. For those unfamiliar, it means that:
5371 // GrandChild : Child
5377 // int protectedField;
5380 // Child::function(GrandChild * o) {
5381 // o->protectedField; //This access is legal.
5384 // GrandChild:function2(Child * o) {
5385 // o->protectedField; //This access is illegal.
5388 // The reason for this rule is that if you had:
5391 // Child::function3( Sibling * o ) {
5392 // o->protectedField; //This access is illegal
5395 // This is intuitively correct. However, you need to prevent:
5396 // Child::function4( Sibling * o ) {
5397 // ((Parent*)o)->protectedField;
5400 // Which means that you must access protected fields through a type that is yourself or one of your
5403 //This checks the first part of the rule above.
5405 BOOL ClassLoader::CanAccessFamily(
5406 MethodTable *pCurrentClass,
5407 MethodTable *pTargetClass)
5413 INJECT_FAULT(COMPlusThrowOM(););
5415 PRECONDITION(CheckPointer(pTargetClass));
5419 _ASSERTE(pCurrentClass);
5420 _ASSERTE(pTargetClass);
5422 BOOL bIsInterface = pTargetClass->IsInterface();
5424 //Look to see if Current is a child of the Target.
5425 while (pCurrentClass) {
5428 // Calling a protected interface member
5429 MethodTable::InterfaceMapIterator it = pCurrentClass->IterateInterfaceMap();
5432 // We only loosely check if they are of the same generic type
5433 if (it.GetInterface()->HasSameTypeDefAs(pTargetClass))
5439 MethodTable *pCurInstance = pCurrentClass;
5441 while (pCurInstance) {
5442 //This is correct. csc is incredibly lax about generics. Essentially if you are a subclass of
5443 //any type of generic it lets you access it. Since the standard is totally unclear, mirror that
5445 if (pCurInstance->HasSameTypeDefAs(pTargetClass)) {
5449 pCurInstance = pCurInstance->GetParentMethodTable();
5453 ///Looking at 8.5.3, it looks like a protected member of a nested class in a parent type is also
5455 pCurrentClass = GetEnclosingMethodTable(pCurrentClass);
5461 //If instance is an inner class, this also succeeds if the outer class conforms to 8.5.3.2. A nested class
5462 //is enclosed inside of the enclosing class' open type. So we need to ignore generic variables. That also
5466 protected int m_family;
5468 class Derived<T> : Base {
5470 public int function(Derived<T> d) {
5477 //Since the inner T is not the same T as the enclosing T (since accessing generic variables is a CLS rule,
5478 //not a CLI rule), we see that as a comparison between Derived<T> and Derived<T'>. CanCastTo rejects that.
5479 //Instead we just check against the typedef of the two types. This ignores all generic parameters (formal
5482 BOOL CanAccessFamilyVerificationEnclosingHelper(MethodTable * pMTCurrentEnclosingClass,
5483 TypeHandle thInstanceClass)
5493 _ASSERTE(pMTCurrentEnclosingClass);
5495 if (thInstanceClass.IsGenericVariable())
5497 //In this case it is a TypeVarTypeDesc (i.e. T). If this access would be legal due to a
5503 public class Inner<U> where U : My<T>
5510 protected int field;
5513 //We need to find the generic class constraint. (The above is legal because U must be a My<T> which makes this
5515 // There may only be 1 class constraint on a generic parameter
5517 // Get the constraints on this generic variable
5518 // At most 1 of them is a class constraint.
5519 // That class constraint methodtable can go through the normal search for matching typedef logic below
5520 TypeVarTypeDesc *tyvar = thInstanceClass.AsGenericVariable();
5521 DWORD numConstraints;
5522 TypeHandle *constraints = tyvar->GetConstraints(&numConstraints, CLASS_DEPENDENCIES_LOADED);
5523 if (constraints == NULL)
5525 // If we did not find a class constraint, we cannot generate a methodtable to search for
5530 for (DWORD i = 0; i < numConstraints; i++)
5532 if (!constraints[i].IsInterface())
5534 // We have found the class constraint on this TypeVarTypeDesc
5535 // Recurse on the found class constraint. It is possible that this constraint may also be a TypeVarTypeDesc
5538 // protected int field;
5540 // public class Inner<U,V> where V:U where U : Outer4<T>
5542 // public int Method(V param) { return (++param.field); }
5545 return CanAccessFamilyVerificationEnclosingHelper(pMTCurrentEnclosingClass, constraints[i]);
5548 // If we did not find a class constraint, we cannot generate a methodtable to search for
5554 MethodTable * pAccessor = pMTCurrentEnclosingClass;
5555 //If thInstanceClass is a MethodTable, we should only be doing the TypeDef comparison (see
5557 if (!thInstanceClass.IsTypeDesc())
5559 MethodTable *pInstanceMT = thInstanceClass.AsMethodTable();
5561 // This is a CanCastTo implementation for classes, assuming we should ignore generic instantiation parameters.
5564 if (pAccessor->HasSameTypeDefAs(pInstanceMT))
5566 pInstanceMT = pInstanceMT->GetParentMethodTable();
5567 }while(pInstanceMT);
5571 // Leave this logic in place for now, as I'm not fully confident it can't happen, and we are very close to RTM
5572 // This logic was originally written to handle TypeVarTypeDescs, but those are now handled above.
5574 if (thInstanceClass.CanCastTo(TypeHandle(pAccessor)))
5578 pMTCurrentEnclosingClass = GetEnclosingMethodTable(pMTCurrentEnclosingClass);
5579 }while(pMTCurrentEnclosingClass);
5584 //This checks the verification only part of the rule above.
5585 //From the example above:
5586 // GrandChild::function2(Child * o) {
5587 // o->protectedField; //This access is illegal.
5589 // pCurrentClass is GrandChild and pTargetClass is Child. This check is completely unnecessary for statics,
5590 // but by legacy convention you can use GrandChild for pTargetClass in that case.
5592 BOOL ClassLoader::CanAccessFamilyVerification(TypeHandle thCurrentClass,
5593 TypeHandle thInstanceClass)
5599 INJECT_FAULT(COMPlusThrowOM(););
5601 PRECONDITION(!thCurrentClass.IsNull());
5602 PRECONDITION(!thCurrentClass.IsTypeDesc());
5606 //Check to see if Instance is equal to or derived from pCurrentClass.
5608 //In some cases the type we have for the instance type is actually a TypeVarTypeDesc. In those cases we
5609 //need to check against the constraints (You're accessing a member through a 'T' with a type constraint
5610 //that makes this legal). For those cases, CanCastTo does what I want.
5611 MethodTable * pAccessor = thCurrentClass.GetMethodTable();
5612 if (thInstanceClass.CanCastTo(TypeHandle(pAccessor)))
5615 //ArrayTypeDescs are the only typedescs that have methods, and their methods don't have IL. All other
5616 //TypeDescs don't need to be here. So only run this on MethodTables.
5617 if (!thInstanceClass.IsNull())
5619 return CanAccessFamilyVerificationEnclosingHelper(pAccessor, thInstanceClass);
5624 #endif // #ifndef DACCESS_COMPILE
5626 #ifdef DACCESS_COMPILE
5629 ClassLoader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
5631 WRAPPER_NO_CONTRACT;
5635 EMEM_OUT(("MEM: %p ClassLoader\n", dac_cast<TADDR>(this)));
5637 if (m_pAssembly.IsValid())
5639 ModuleIterator modIter = GetAssembly()->IterateModules();
5641 while (modIter.Next())
5643 modIter.GetModule()->EnumMemoryRegions(flags, true);
5648 #endif // #ifdef DACCESS_COMPILE