diff --git a/docs/design/specs/Ecma-335-Augments.md b/docs/design/specs/Ecma-335-Augments.md index 6dd9a81099ccc4..e9722759ea80e6 100644 --- a/docs/design/specs/Ecma-335-Augments.md +++ b/docs/design/specs/Ecma-335-Augments.md @@ -381,6 +381,12 @@ The text should be deleted: > Furthermore, ~~the InterfaceImpl table is sorted using the Interface column as a secondary key, and~~ the GenericParam table is sorted using the Number column as a secondary key. +In addition to the TypeDef table having a special ordering constraint, the ExportedTypes table ALSO has the same constraint. + +This line should be changed. + +> Finally, this TypeDef _and ExportedType_ ~~table has~~ _tables have_ a special ordering constraint: the definition of an enclosing class shall precede the definition of all classes it encloses. + ## Module Initializer All modules may have a module initializer. A module initializer is defined as the type initializer (§ II.10.5.3) of the `` type (§ II.10.8). diff --git a/src/coreclr/ildasm/dasm.cpp b/src/coreclr/ildasm/dasm.cpp index 860b36f2e93666..672c73180212d7 100644 --- a/src/coreclr/ildasm/dasm.cpp +++ b/src/coreclr/ildasm/dasm.cpp @@ -38,6 +38,14 @@ DECLARE_NATIVE_STRING_RESOURCE_TABLE(NATIVE_STRING_RESOURCE_NAME); #include "mdfileformat.h" + //***************************************** + // look up function for TypeDef + //***************************************** +HRESULT FindTypeDef(IMDInternalImport *pImport, + LPCSTR szNamespace, // [IN] Namespace for the TypeDef. + LPCSTR szName, // [IN] Name of the TypeDef. + mdToken tkEnclosingClass, // [IN] TypeRef/TypeDef Token for the enclosing class. + mdTypeDef *ptypedef); // [IN] return typedef struct MIDescriptor { @@ -471,7 +479,7 @@ HRESULT IsClassRefInScope(mdTypeRef classref) MAKE_NAME_IF_NONE(pszClassName,classref); IfFailRet(g_pImport->GetResolutionScopeOfTypeRef(classref, &tkRes)); - hr = g_pImport->FindTypeDef(pszNameSpace, pszClassName, + hr = FindTypeDef(g_pImport, pszNameSpace, pszClassName, (TypeFromToken(tkRes) == mdtTypeRef) ? tkRes : mdTokenNil, &classdef); return hr; @@ -1337,7 +1345,7 @@ mdToken ResolveTypeDefReflectionNotation(IMDInternalImport *pIMDI, szNamespace = ""; szName = pch+1; } - if(SUCCEEDED(pIMDI->FindTypeDef(szNamespace,szName,tkEncloser,&tk))) + if(SUCCEEDED(FindTypeDef(pIMDI, szNamespace,szName,tkEncloser,&tk))) return tk; else return 0; @@ -1599,7 +1607,7 @@ mdToken TypeRefToTypeDef(mdToken tk, IMDInternalImport *pIMDI, IMDInternalImport goto AssignAndReturn; } - if (FAILED((*ppIMDInew)->FindTypeDef(szNamespace,szName,tkEncloser,&tkTypeDef))) + if (FAILED(FindTypeDef(*ppIMDInew, szNamespace,szName,tkEncloser,&tkTypeDef))) { tkTypeDef = mdTypeDefNil; } @@ -7820,6 +7828,102 @@ BOOL DumpFile() pMetaDataDispenser->Release(); return fSuccess; } + +//***************************************************************************** +// Given a classname, return the typedef +//***************************************************************************** +HRESULT +FindTypeDef( + IMDInternalImport *pImport, + LPCSTR szTypeDefNamespace, // [IN] Namespace for the TypeDef. + LPCSTR szTypeDefName, // [IN] Name of the TypeDef. + mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef of enclosing class. + mdTypeDef * ptkTypeDef) // [OUT] return typedef +{ + HRESULT hr = S_OK; + + _ASSERTE((szTypeDefName != NULL) && (ptkTypeDef != NULL)); + _ASSERTE((TypeFromToken(tkEnclosingClass) == mdtTypeRef) || + (TypeFromToken(tkEnclosingClass) == mdtTypeDef) || + IsNilToken(tkEnclosingClass)); + + // initialize the output parameter + *ptkTypeDef = mdTypeDefNil; + + // Treat no namespace as empty string. + if (szTypeDefNamespace == NULL) + szTypeDefNamespace = ""; + + // Do a linear search + HENUMInternal typeDefEnum; + + LPCSTR szName; + LPCSTR szNamespace; + DWORD dwFlags; + + // Get TypeDef of the tkEnclosingClass passed in + if (TypeFromToken(tkEnclosingClass) == mdtTypeRef) + { + mdToken tkResolutionScope; + IfFailRet(pImport->GetResolutionScopeOfTypeRef(tkEnclosingClass, &tkResolutionScope)); + IfFailRet(pImport->GetNameOfTypeRef(tkEnclosingClass, &szNamespace, &szName)); + + // Update tkEnclosingClass to TypeDef + IfFailRet(FindTypeDef( + pImport, + szNamespace, + szName, + (TypeFromToken(tkResolutionScope) == mdtTypeRef) ? tkResolutionScope : mdTokenNil, + &tkEnclosingClass)); + _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef); + } + + // Search for the TypeDef + IfFailRet(pImport->EnumTypeDefInit(&typeDefEnum)); + mdTypeDef td; + + while (pImport->EnumNext(&typeDefEnum, &td)) + { + IfFailRet(pImport->GetTypeDefProps(td, &dwFlags, NULL)); + + if (!IsTdNested(dwFlags) && !IsNilToken(tkEnclosingClass)) + { + // If the class is not Nested and EnclosingClass passed in is not nil + continue; + } + else if (IsTdNested(dwFlags) && IsNilToken(tkEnclosingClass)) + { + // If the class is nested and EnclosingClass passed is nil + continue; + } + else if (!IsNilToken(tkEnclosingClass)) + { + _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef); + mdTypeDef tkEnclosingClassTmp; + HRESULT hr = pImport->GetNestedClassProps(td, &tkEnclosingClassTmp); + if (hr == CLDB_E_RECORD_NOTFOUND) + continue; // td is not nested + IfFailRet(hr); // All other failure HRESULTS result in this function failing + + if (tkEnclosingClass != tkEnclosingClassTmp) + continue; + } + + IfFailRet(pImport->GetNameOfTypeDef(td, &szName, &szNamespace)); + + if (strcmp(szTypeDefName, szName) == 0) + { + if (strcmp(szTypeDefNamespace, szNamespace) == 0) + { + *ptkTypeDef = td; + return S_OK; + } + } + } + // Cannot find the TypeDef by name + return CLDB_E_RECORD_NOTFOUND; +} // FindTypeDef + #ifdef _PREFAST_ #pragma warning(pop) #endif diff --git a/src/coreclr/inc/corhlprpriv.h b/src/coreclr/inc/corhlprpriv.h index ffa249543329e3..a043b08a4a4b07 100644 --- a/src/coreclr/inc/corhlprpriv.h +++ b/src/coreclr/inc/corhlprpriv.h @@ -294,9 +294,9 @@ class CQuickMemoryBase } // Copy single byte string and hold it - const char * SetStringNoThrow(const char * pStr, SIZE_T len) + const char * SetString(const char * pStr, SIZE_T len) { - LPSTR buffer = (LPSTR) AllocNoThrow(len + 1); + LPSTR buffer = (LPSTR) AllocThrows(len + 1); if (buffer != NULL) { diff --git a/src/coreclr/inc/metadata.h b/src/coreclr/inc/metadata.h index 766893bea17b8a..d65e6dff91f21a 100644 --- a/src/coreclr/inc/metadata.h +++ b/src/coreclr/inc/metadata.h @@ -676,16 +676,6 @@ DECLARE_INTERFACE_(IMDInternalImport, IUnknown) mdInterfaceImpl iiImpl, // given a interfaceimpl mdToken *ptkType) PURE; - //***************************************** - // look up function for TypeDef - //***************************************** - __checkReturn - STDMETHOD(FindTypeDef)( - LPCSTR szNamespace, // [IN] Namespace for the TypeDef. - LPCSTR szName, // [IN] Name of the TypeDef. - mdToken tkEnclosingClass, // [IN] TypeRef/TypeDef Token for the enclosing class. - mdTypeDef *ptypedef) PURE; // [IN] return typedef - //***************************************** // return name and sig of a memberref //***************************************** diff --git a/src/coreclr/md/enc/mdinternalrw.cpp b/src/coreclr/md/enc/mdinternalrw.cpp index 487d256f8de0f9..a72180056cc555 100644 --- a/src/coreclr/md/enc/mdinternalrw.cpp +++ b/src/coreclr/md/enc/mdinternalrw.cpp @@ -2633,31 +2633,6 @@ HRESULT MDInternalRW::GetMethodSpecProps( // S_OK or error. return hr; } // MDInternalRW::GetMethodSpecProps -//***************************************************************************** -// Given a classname, return the typedef -//***************************************************************************** -__checkReturn -HRESULT MDInternalRW::FindTypeDef( // return hresult - LPCSTR szNamespace, // [IN] Namespace for the TypeDef. - LPCSTR szName, // [IN] Name of the TypeDef. - mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef of enclosing class. - mdTypeDef *ptypedef) // [OUT] return typedef -{ - HRESULT hr = S_OK; - LOCKREADIFFAILRET(); - - _ASSERTE(ptypedef); - - // initialize the output parameter - *ptypedef = mdTypeDefNil; - - return ImportHelper::FindTypeDefByName(&(m_pStgdb->m_MiniMd), - szNamespace, - szName, - tkEnclosingClass, - ptypedef); -} // MDInternalRW::FindTypeDef - //***************************************************************************** // Given a memberref, return a pointer to memberref's name and signature //***************************************************************************** diff --git a/src/coreclr/md/inc/mdinternalrw.h b/src/coreclr/md/inc/mdinternalrw.h index 144d63b1189956..3591c7e02a9cba 100644 --- a/src/coreclr/md/inc/mdinternalrw.h +++ b/src/coreclr/md/inc/mdinternalrw.h @@ -417,23 +417,6 @@ class MDInternalRW : public IMDInternalImportENC, public IMDCommon PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data ULONG *pcbSigBlob); // [OUT] actual size of signature blob - //***************************************** - // look up function for TypeDef - //***************************************** - __checkReturn - STDMETHODIMP FindTypeDef( - LPCSTR szNamespace, // [IN] Namespace for the TypeDef. - LPCSTR szName, // [IN] Name of the TypeDef. - mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef of enclosing class. - mdTypeDef *ptypedef); // [OUT] return typedef - - __checkReturn - STDMETHODIMP FindTypeDefByGUID( - REFGUID guid, // guid to look up - mdTypeDef *ptypedef); // return typedef - - - //***************************************** // return name and sig of a memberref //***************************************** diff --git a/src/coreclr/md/runtime/mdinternalro.cpp b/src/coreclr/md/runtime/mdinternalro.cpp index 96d72558485527..dcb5a480cdf0bc 100644 --- a/src/coreclr/md/runtime/mdinternalro.cpp +++ b/src/coreclr/md/runtime/mdinternalro.cpp @@ -1696,111 +1696,7 @@ HRESULT MDInternalRO::GetMethodSpecProps( // S_OK or error. return hr; -} // MDInternalRO::GetMethodSpecProps - - - -//***************************************************************************** -// Given a classname, return the typedef -//***************************************************************************** -__checkReturn -HRESULT -MDInternalRO::FindTypeDef( - LPCSTR szTypeDefNamespace, // [IN] Namespace for the TypeDef. - LPCSTR szTypeDefName, // [IN] Name of the TypeDef. - mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef of enclosing class. - mdTypeDef * ptkTypeDef) // [OUT] return typedef -{ - HRESULT hr = S_OK; - - _ASSERTE((szTypeDefName != NULL) && (ptkTypeDef != NULL)); - _ASSERTE((TypeFromToken(tkEnclosingClass) == mdtTypeRef) || - (TypeFromToken(tkEnclosingClass) == mdtTypeDef) || - IsNilToken(tkEnclosingClass)); - - // initialize the output parameter - *ptkTypeDef = mdTypeDefNil; - - // Treat no namespace as empty string. - if (szTypeDefNamespace == NULL) - szTypeDefNamespace = ""; - - // Do a linear search - ULONG cTypeDefRecs = m_LiteWeightStgdb.m_MiniMd.getCountTypeDefs(); - TypeDefRec * pTypeDefRec; - LPCUTF8 szName; - LPCUTF8 szNamespace; - DWORD dwFlags; - - // Get TypeDef of the tkEnclosingClass passed in - if (TypeFromToken(tkEnclosingClass) == mdtTypeRef) - { - TypeRefRec * pTypeRefRec; - mdToken tkResolutionScope; - - IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetTypeRefRecord(RidFromToken(tkEnclosingClass), &pTypeRefRec)); - tkResolutionScope = m_LiteWeightStgdb.m_MiniMd.getResolutionScopeOfTypeRef(pTypeRefRec); - IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNamespaceOfTypeRef(pTypeRefRec, &szNamespace)); - IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfTypeRef(pTypeRefRec, &szName)); - - // Update tkEnclosingClass to TypeDef - IfFailRet(FindTypeDef( - szNamespace, - szName, - (TypeFromToken(tkResolutionScope) == mdtTypeRef) ? tkResolutionScope : mdTokenNil, - &tkEnclosingClass)); - _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef); - } - - // Search for the TypeDef - for (ULONG i = 1; i <= cTypeDefRecs; i++) - { - IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetTypeDefRecord(i, &pTypeDefRec)); - - dwFlags = m_LiteWeightStgdb.m_MiniMd.getFlagsOfTypeDef(pTypeDefRec); - - if (!IsTdNested(dwFlags) && !IsNilToken(tkEnclosingClass)) - { - // If the class is not Nested and EnclosingClass passed in is not nil - continue; - } - else if (IsTdNested(dwFlags) && IsNilToken(tkEnclosingClass)) - { - // If the class is nested and EnclosingClass passed is nil - continue; - } - else if (!IsNilToken(tkEnclosingClass)) - { - _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef); - - RID iNestedClassRec; - NestedClassRec * pNestedClassRec; - mdTypeDef tkEnclosingClassTmp; - - IfFailRet(m_LiteWeightStgdb.m_MiniMd.FindNestedClassFor(i, &iNestedClassRec)); - if (InvalidRid(iNestedClassRec)) - continue; - IfFailRet(m_LiteWeightStgdb.m_MiniMd.GetNestedClassRecord(iNestedClassRec, &pNestedClassRec)); - tkEnclosingClassTmp = m_LiteWeightStgdb.m_MiniMd.getEnclosingClassOfNestedClass(pNestedClassRec); - if (tkEnclosingClass != tkEnclosingClassTmp) - continue; - } - - IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNameOfTypeDef(pTypeDefRec, &szName)); - if (strcmp(szTypeDefName, szName) == 0) - { - IfFailRet(m_LiteWeightStgdb.m_MiniMd.getNamespaceOfTypeDef(pTypeDefRec, &szNamespace)); - if (strcmp(szTypeDefNamespace, szNamespace) == 0) - { - *ptkTypeDef = TokenFromRid(i, mdtTypeDef); - return S_OK; - } - } - } - // Cannot find the TypeDef by name - return CLDB_E_RECORD_NOTFOUND; -} // MDInternalRO::FindTypeDef - +} // MDInternalRO::GetMethodSpecPropsk //***************************************************************************** // Given a memberref, return a pointer to memberref's name and signature //***************************************************************************** diff --git a/src/coreclr/md/runtime/mdinternalro.h b/src/coreclr/md/runtime/mdinternalro.h index b76c2f40672260..91775ef5f69f19 100644 --- a/src/coreclr/md/runtime/mdinternalro.h +++ b/src/coreclr/md/runtime/mdinternalro.h @@ -404,23 +404,6 @@ class MDInternalRO : public IMDInternalImport, IMDCommon PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data ULONG *pcbSigBlob); // [OUT] actual size of signature blob - //***************************************** - // look up function for TypeDef - //***************************************** - __checkReturn - STDMETHODIMP FindTypeDef( - LPCSTR szNamespace, // [IN] Namespace for the TypeDef. - LPCSTR szName, // [IN] Name of the TypeDef. - mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef of enclosing class. - mdTypeDef *ptypedef); // [OUT] return typedef - - __checkReturn - STDMETHODIMP FindTypeDefByGUID( - REFGUID guid, // guid to look up - mdTypeDef *ptypedef); // return typedef - - - //***************************************** // return name and sig of a memberref //***************************************** diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp index 8833aa45742b30..eff18ed372bcac 100644 --- a/src/coreclr/vm/assembly.cpp +++ b/src/coreclr/vm/assembly.cpp @@ -199,9 +199,6 @@ void Assembly::Init(AllocMemTracker *pamTracker, LoaderAllocator *pLoaderAllocat PrepareModuleForAssembly(m_pModule, pamTracker); - if (!m_pModule->IsReadyToRun()) - CacheManifestExportedTypes(pamTracker); - // We'll load the friend assembly information lazily. For the ngen case we should avoid // loading it entirely. //CacheFriendAssemblyInfo(); @@ -952,24 +949,6 @@ Module * Assembly::FindModuleByTypeRef( #ifndef DACCESS_COMPILE -void Assembly::CacheManifestExportedTypes(AllocMemTracker *pamTracker) -{ - STANDARD_VM_CONTRACT; - - mdToken mdExportedType; - - HENUMInternalHolder phEnum(GetMDImport()); - phEnum.EnumInit(mdtExportedType, - mdTokenNil); - - ClassLoader::AvailableClasses_LockHolder lh(m_pClassLoader); - - for(int i = 0; GetMDImport()->EnumNext(&phEnum, &mdExportedType); i++) - m_pClassLoader->AddExportedTypeHaveLock(GetModule(), - mdExportedType, - pamTracker); -} - void Assembly::PrepareModuleForAssembly(Module* module, AllocMemTracker *pamTracker) { STANDARD_VM_CONTRACT; diff --git a/src/coreclr/vm/assembly.hpp b/src/coreclr/vm/assembly.hpp index 19c98283ffe5c5..148e73a45c5c93 100644 --- a/src/coreclr/vm/assembly.hpp +++ b/src/coreclr/vm/assembly.hpp @@ -416,8 +416,6 @@ class Assembly //**************************************************************************************** - void CacheManifestExportedTypes(AllocMemTracker *pamTracker); - void CacheFriendAssemblyInfo(); #ifndef DACCESS_COMPILE ReleaseHolder GetFriendAssemblyInfo(); diff --git a/src/coreclr/vm/assemblynative.cpp b/src/coreclr/vm/assemblynative.cpp index 340096c919e989..79caef32d4eae0 100644 --- a/src/coreclr/vm/assemblynative.cpp +++ b/src/coreclr/vm/assemblynative.cpp @@ -362,10 +362,27 @@ extern "C" void QCALLTYPE AssemblyNative_GetTypeCore(QCall::AssemblyHandle assem ClassLoader* pClassLoader = pAssembly->GetLoader(); NameHandle typeName(pManifestModule, mdtBaseType); + CQuickBytes qbszNamespace; for (int32_t i = -1; i < cNestedTypeNamesLength; i++) { - typeName.SetName((i == -1) ? szTypeName : rgszNestedTypeNames[i]); + LPCUTF8 szFullyQualifiedName = (i == -1) ? szTypeName : rgszNestedTypeNames[i]; + + LPCUTF8 szNameSpace = ""; + LPCUTF8 szName = ""; + + if ((szName = ns::FindSep(szFullyQualifiedName)) != NULL) + { + SIZE_T d = szName - szFullyQualifiedName; + szNameSpace = qbszNamespace.SetString(szFullyQualifiedName, d); + szName++; + } + else + { + szName = szFullyQualifiedName; + } + + typeName.SetName(szNameSpace, szName); // typeName.m_pBucket gets set here if the type is found // it will be used in the next iteration to look up the nested type @@ -415,6 +432,7 @@ extern "C" void QCALLTYPE AssemblyNative_GetTypeCoreIgnoreCase(QCall::AssemblyHa ClassLoader* pClassLoader = pAssembly->GetLoader(); NameHandle typeName(pManifestModule, mdtBaseType); + CQuickBytes qbszNamespace; // Set up the name handle typeName.SetCaseInsensitive(); @@ -427,7 +445,23 @@ extern "C" void QCALLTYPE AssemblyNative_GetTypeCoreIgnoreCase(QCall::AssemblyHa // The type name is expected to be lower-cased by the caller for case-insensitive lookups name.LowerCase(); - typeName.SetName(name.GetUTF8()); + LPCUTF8 szFullyQualifiedName = name.GetUTF8(); + + LPCUTF8 szNameSpace = ""; + LPCUTF8 szName = ""; + + if ((szName = ns::FindSep(szFullyQualifiedName)) != NULL) + { + SIZE_T d = szName - szFullyQualifiedName; + szNameSpace = qbszNamespace.SetString(szFullyQualifiedName, d); + szName++; + } + else + { + szName = szFullyQualifiedName; + } + + typeName.SetName(szNameSpace, szName); // typeName.m_pBucket gets set here if the type is found // it will be used in the next iteration to look up the nested type diff --git a/src/coreclr/vm/binder.cpp b/src/coreclr/vm/binder.cpp index 23b14a34ee43b6..193cc3217c2271 100644 --- a/src/coreclr/vm/binder.cpp +++ b/src/coreclr/vm/binder.cpp @@ -83,10 +83,13 @@ PTR_MethodTable CoreLibBinder::LookupClassLocal(BinderClassID id) (void)ClassLoader::LoadTypeByNameThrowing(GetModule()->GetAssembly(), &nameHandle); // Now load the nested type. - nameHandle.SetName(NULL, nestedTypeMaybe + 1); + nameHandle.SetName("", nestedTypeMaybe + 1); // We don't support nested types in nested types. _ASSERTE(strchr(nameHandle.GetName(), '+') == NULL); + + // We don't support nested types with explicit namespaces + _ASSERTE(strchr(nameHandle.GetName(), '.') == NULL); pMT = ClassLoader::LoadTypeByNameThrowing(GetModule()->GetAssembly(), &nameHandle).AsMethodTable(); } diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index cbabf92302b798..9a7dbc2f41de33 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -460,7 +460,7 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName) { m_pAvailableClasses = EEClassHashTable::Create(this, GetAssembly()->IsCollectible() ? AVAILABLE_CLASSES_HASH_BUCKETS_COLLECTIBLE : AVAILABLE_CLASSES_HASH_BUCKETS, - FALSE /* bCaseInsensitive */, pamTracker); + NULL, pamTracker); } if (m_pAvailableParamTypes == NULL) diff --git a/src/coreclr/vm/classcompat.cpp b/src/coreclr/vm/classcompat.cpp index b089dad7fdafb6..80b30a140b59de 100644 --- a/src/coreclr/vm/classcompat.cpp +++ b/src/coreclr/vm/classcompat.cpp @@ -3270,23 +3270,8 @@ HRESULT MethodTableBuilder::FindMethodDeclarationForMethodImpl( // in a different scope. if(TypeFromToken(typeref) == mdtTypeRef) { - LPCUTF8 pszNameSpace; - LPCUTF8 pszClassName; - - if (FAILED(pMDInternalImport->GetNameOfTypeRef(typeref, &pszNameSpace, &pszClassName))) - { - IfFailRet(COR_E_TYPELOAD); - } - mdToken tkRes; - if (FAILED(pMDInternalImport->GetResolutionScopeOfTypeRef(typeref, &tkRes))) - { - IfFailRet(COR_E_TYPELOAD); - } - hr = pMDInternalImport->FindTypeDef(pszNameSpace, - pszClassName, - (TypeFromToken(tkRes) == mdtTypeRef) ? tkRes : mdTokenNil, - &tkDef); - if(FAILED(hr)) + tkDef = GetModule()->GetClassLoader()->LookupTypeDefTokenThatMatchesTypeRef(typeref); + if (tkDef == mdTypeDefNil) { IfFailRet(COR_E_TYPELOAD); } diff --git a/src/coreclr/vm/classhash.cpp b/src/coreclr/vm/classhash.cpp index 8ea03a315154ce..e49c13bf46e3c9 100644 --- a/src/coreclr/vm/classhash.cpp +++ b/src/coreclr/vm/classhash.cpp @@ -37,7 +37,7 @@ PTR_VOID EEClassHashEntry::GetData() } CONTRACTL_END; - return m_Data; + return VolatileLoadWithoutBarrier(&m_Data); } #ifndef DACCESS_COMPILE @@ -68,7 +68,7 @@ void EEClassHashEntry::SetEncloser(EEClassHashEntry *pEncloser) } /*static*/ -EEClassHashTable *EEClassHashTable::Create(Module *pModule, DWORD dwNumBuckets, BOOL bCaseInsensitive, AllocMemTracker *pamTracker) +EEClassHashTable *EEClassHashTable::Create(Module *pModule, DWORD dwNumBuckets, PTR_EEClassHashTable pCaseSensitiveTable, AllocMemTracker *pamTracker) { CONTRACTL { @@ -88,7 +88,7 @@ EEClassHashTable *EEClassHashTable::Create(Module *pModule, DWORD dwNumBuckets, // loader heap instead of new so use an in-place new to call the constructors now. new (pThis) EEClassHashTable(pModule, pHeap, dwNumBuckets); - pThis->m_bCaseInsensitive = bCaseInsensitive; + pThis->m_pCaseSensitiveTable = pCaseSensitiveTable != NULL ? pCaseSensitiveTable : pThis; return pThis; } @@ -223,17 +223,17 @@ VOID EEClassHashTable::ConstructKeyFromData(PTR_EEClassHashEntry pEntry, // IN THROWS; WRAPPER(MODE_ANY); WRAPPER(GC_TRIGGERS); - if (m_bCaseInsensitive) INJECT_FAULT(COMPlusThrowOM();); else WRAPPER(FORBID_FAULT); + if (IsCaseInsensitiveTable()) INJECT_FAULT(COMPlusThrowOM();); else WRAPPER(FORBID_FAULT); SUPPORTS_DAC; } CONTRACTL_END; { #ifdef _DEBUG_IMPL - _ASSERTE(!(m_bCaseInsensitive && FORBIDGC_LOADER_USE_ENABLED())); + _ASSERTE(!(IsCaseInsensitiveTable() && FORBIDGC_LOADER_USE_ENABLED())); #endif - // cqb - If m_bCaseInsensitive is true for the hash table, the bytes in Key will be allocated + // cqb - If IsCaseInsensitiveTable() is true for the hash table, the bytes in Key will be allocated // from cqb. This is to prevent wasting bytes in the Loader Heap. Thusly, it is important to note that // in this case, the lifetime of Key is bounded by the lifetime of cqb, which will free the memory // it allocated on destruction. @@ -244,7 +244,7 @@ VOID EEClassHashTable::ConstructKeyFromData(PTR_EEClassHashEntry pEntry, // IN IMDInternalImport *pInternalImport = NULL; PTR_VOID Data = NULL; - if (!m_bCaseInsensitive) + if (!IsCaseInsensitiveTable()) Data = pEntry->GetData(); else Data = (PTR_EEClassHashEntry(pEntry->GetData()))->GetData(); @@ -287,7 +287,7 @@ VOID EEClassHashTable::ConstructKeyFromData(PTR_EEClassHashEntry pEntry, // IN } } - if (!m_bCaseInsensitive) + if (!IsCaseInsensitiveTable()) { LPUTF8 Key[2]; @@ -311,54 +311,6 @@ VOID EEClassHashTable::ConstructKeyFromData(PTR_EEClassHashEntry pEntry, // IN #ifndef DACCESS_COMPILE -EEClassHashEntry_t *EEClassHashTable::InsertValue(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID Data, EEClassHashEntry_t *pEncloser, AllocMemTracker *pamTracker) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - - INJECT_FAULT(COMPlusThrowOM();); - PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED()); - } - CONTRACTL_END; - - _ASSERTE(pszNamespace != NULL); - _ASSERTE(pszClassName != NULL); - _ASSERTE(m_pModule != NULL); - - EEClassHashEntry *pEntry = BaseAllocateEntry(pamTracker); - - pEntry->SetData(Data); - pEntry->SetEncloser(pEncloser); -#ifdef _DEBUG - pEntry->DebugKey[0] = pszNamespace; - pEntry->DebugKey[1] = pszClassName; -#endif - - BaseInsertEntry(Hash(pszNamespace, pszClassName), pEntry); - - return pEntry; -} - -#ifdef _DEBUG -class ConstructKeyCallbackValidate : public EEClassHashTable::ConstructKeyCallback -{ -public: - virtual void UseKeys(_In_reads_(2) LPUTF8 *Key) - { - LIMITED_METHOD_CONTRACT; - STATIC_CONTRACT_DEBUG_ONLY; - _ASSERTE (strcmp(pNewEntry->DebugKey[1], Key[1]) == 0); - _ASSERTE (strcmp(pNewEntry->DebugKey[0], Key[0]) == 0); - SUPPORTS_DAC; - } - - EEClassHashEntry_t *pNewEntry; - -}; -#endif // _DEBUG // This entrypoint lets the caller separate the allocation of the entrypoint from the actual insertion into the hashtable. (This lets us // do multiple insertions without having to worry about an OOM occurring inbetween.) @@ -386,303 +338,13 @@ EEClassHashEntry_t *EEClassHashTable::InsertValueUsingPreallocatedEntry(EEClassH pNewEntry->DebugKey[1] = pszClassName; #endif - BaseInsertEntry(Hash(pszNamespace, pszClassName), pNewEntry); - - return pNewEntry; -} - -EEClassHashEntry_t *EEClassHashTable::InsertValueIfNotFound(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, EEClassHashEntry_t *pEncloser, BOOL IsNested, BOOL *pbFound, AllocMemTracker *pamTracker) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM();); - - PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED()); - } - CONTRACTL_END; - - _ASSERTE(m_pModule != NULL); - _ASSERTE(pszNamespace != NULL); - _ASSERTE(pszClassName != NULL); - - EEClassHashEntry_t * pNewEntry = FindItem(pszNamespace, pszClassName, IsNested, NULL); - - if (pNewEntry) - { - *pData = pNewEntry->GetData(); - *pbFound = TRUE; - return pNewEntry; - } - - // Reached here implies that we didn't find the entry and need to insert it - *pbFound = FALSE; - - pNewEntry = BaseAllocateEntry(pamTracker); - - pNewEntry->SetData(*pData); - pNewEntry->SetEncloser(pEncloser); - -#ifdef _DEBUG - pNewEntry->DebugKey[0] = pszNamespace; - pNewEntry->DebugKey[1] = pszClassName; -#endif - - BaseInsertEntry(Hash(pszNamespace, pszClassName), pNewEntry); + BaseInsertEntry(Hash(pszNamespace, pszClassName, pEncloser != NULL ? GetHash(pEncloser) : 0), pNewEntry); return pNewEntry; } #endif // !DACCESS_COMPILE -EEClassHashEntry_t *EEClassHashTable::FindItem(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, BOOL IsNested, LookupContext *pContext) -{ - CONTRACTL - { - if (m_bCaseInsensitive) THROWS; else NOTHROW; - if (m_bCaseInsensitive) GC_TRIGGERS; else GC_NOTRIGGER; - if (m_bCaseInsensitive) INJECT_FAULT(COMPlusThrowOM();); else FORBID_FAULT; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; - - _ASSERTE(m_pModule != NULL); - _ASSERTE(pszNamespace != NULL); - _ASSERTE(pszClassName != NULL); - - // It's legal for the caller not to pass us a LookupContext (when the type being queried is not nested - // there will never be any need to iterate over the search results). But we might need to iterate - // internally (since we lookup via hash and hashes may collide). So substitute our own private context if - // one was not provided. - LookupContext sAltContext; - if (pContext == NULL) - pContext = &sAltContext; - - // The base class provides the ability to enumerate all entries with the same hash code. We call this and - // further check which of these entries actually match the full key (there can be multiple hits with - // nested types in the picture). - PTR_EEClassHashEntry pSearch = BaseFindFirstEntryByHash(Hash(pszNamespace, pszClassName), pContext); - - while (pSearch) - { - LPCUTF8 rgKey[] = { pszNamespace, pszClassName }; - - if (CompareKeys(pSearch, rgKey)) - { - // If (IsNested), then we're looking for a nested class - // If (pSearch->pEncloser), we've found a nested class - if ((IsNested != FALSE) == (pSearch->GetEncloser() != NULL)) - { - return pSearch; - } - } - - pSearch = BaseFindNextEntryByHash(pContext); - } - - return NULL; -} - -EEClassHashEntry_t *EEClassHashTable::FindNextNestedClass(const NameHandle* pName, PTR_VOID *pData, LookupContext *pContext) -{ - CONTRACTL - { - if (m_bCaseInsensitive) THROWS; else NOTHROW; - if (m_bCaseInsensitive) GC_TRIGGERS; else GC_NOTRIGGER; - if (m_bCaseInsensitive) INJECT_FAULT(COMPlusThrowOM();); else FORBID_FAULT; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; - - _ASSERTE(m_pModule != NULL); - _ASSERTE(pName); - - if (pName->GetNameSpace()) - { - return FindNextNestedClass(pName->GetNameSpace(), pName->GetName(), pData, pContext); - } - else { -#ifndef DACCESS_COMPILE - return FindNextNestedClass(pName->GetName(), pData, pContext); // this won't support dac-- - // it allocates a new namespace string -#else - DacNotImpl(); - return NULL; -#endif - } -} - - -EEClassHashEntry_t *EEClassHashTable::FindNextNestedClass(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, LookupContext *pContext) -{ - CONTRACTL - { - if (m_bCaseInsensitive) THROWS; else NOTHROW; - if (m_bCaseInsensitive) GC_TRIGGERS; else GC_NOTRIGGER; - if (m_bCaseInsensitive) INJECT_FAULT(COMPlusThrowOM();); else FORBID_FAULT; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; - - _ASSERTE(m_pModule != NULL); - - PTR_EEClassHashEntry pSearch = BaseFindNextEntryByHash(pContext); - - while (pSearch) - { - LPCUTF8 rgKey[] = { pszNamespace, pszClassName }; - - if (pSearch->GetEncloser() && CompareKeys(pSearch, rgKey)) - { - *pData = pSearch->GetData(); - return pSearch; - } - - pSearch = BaseFindNextEntryByHash(pContext); - } - - return NULL; -} - -const UTF8 Utf8Empty[] = { 0 }; - -EEClassHashEntry_t *EEClassHashTable::FindNextNestedClass(LPCUTF8 pszFullyQualifiedName, PTR_VOID *pData, LookupContext *pContext) -{ - CONTRACTL - { - if (m_bCaseInsensitive) THROWS; else NOTHROW; - if (m_bCaseInsensitive) GC_TRIGGERS; else GC_NOTRIGGER; - if (m_bCaseInsensitive) INJECT_FAULT(COMPlusThrowOM();); else FORBID_FAULT; - MODE_ANY; - } - CONTRACTL_END; - - _ASSERTE(m_pModule != NULL); - - CQuickBytes szNamespace; - - LPCUTF8 pNamespace = Utf8Empty; - LPCUTF8 p; - - if ((p = ns::FindSep(pszFullyQualifiedName)) != NULL) - { - SIZE_T d = p - pszFullyQualifiedName; - - FAULT_NOT_FATAL(); - pNamespace = szNamespace.SetStringNoThrow(pszFullyQualifiedName, d); - - if (NULL == pNamespace) - { - return NULL; - } - - p++; - } - else - { - p = pszFullyQualifiedName; - } - - return FindNextNestedClass(pNamespace, p, pData, pContext); -} - - -EEClassHashEntry_t * EEClassHashTable::GetValue(LPCUTF8 pszFullyQualifiedName, PTR_VOID *pData, BOOL IsNested, LookupContext *pContext) -{ - CONTRACTL - { - if (m_bCaseInsensitive) THROWS; else NOTHROW; - if (m_bCaseInsensitive) GC_TRIGGERS; else GC_NOTRIGGER; - if (m_bCaseInsensitive) INJECT_FAULT(COMPlusThrowOM();); else FORBID_FAULT; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; - - _ASSERTE(m_pModule != NULL); - - CQuickBytes szNamespace; - - LPCUTF8 pNamespace = Utf8Empty; - - LPCUTF8 p = ns::FindSep(pszFullyQualifiedName); - - if (p != NULL) - { - SIZE_T d = p - pszFullyQualifiedName; - - FAULT_NOT_FATAL(); - pNamespace = szNamespace.SetStringNoThrow(pszFullyQualifiedName, d); - - if (NULL == pNamespace) - { - return NULL; - } - - p++; - } - else - { - p = pszFullyQualifiedName; - } - - EEClassHashEntry_t * ret = GetValue(pNamespace, p, pData, IsNested, pContext); - - return ret; -} - - -EEClassHashEntry_t * EEClassHashTable::GetValue(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, BOOL IsNested, LookupContext *pContext) -{ - CONTRACTL - { - if (m_bCaseInsensitive) THROWS; else NOTHROW; - if (m_bCaseInsensitive) GC_TRIGGERS; else GC_NOTRIGGER; - if (m_bCaseInsensitive) INJECT_FAULT(COMPlusThrowOM();); else FORBID_FAULT; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; - - - _ASSERTE(m_pModule != NULL); - EEClassHashEntry_t *pItem = FindItem(pszNamespace, pszClassName, IsNested, pContext); - if (pItem) - *pData = pItem->GetData(); - - return pItem; -} - - -EEClassHashEntry_t * EEClassHashTable::GetValue(const NameHandle* pName, PTR_VOID *pData, BOOL IsNested, LookupContext *pContext) -{ - CONTRACTL - { - // for DAC builds m_bCaseInsensitive should be false - if (m_bCaseInsensitive) THROWS; else NOTHROW; - if (m_bCaseInsensitive) GC_TRIGGERS; else GC_NOTRIGGER; - if (m_bCaseInsensitive) INJECT_FAULT(COMPlusThrowOM();); else FORBID_FAULT; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; - - - _ASSERTE(pName); - _ASSERTE(m_pModule != NULL); - if(pName->GetNameSpace() == NULL) { - return GetValue(pName->GetName(), pData, IsNested, pContext); - } - else { - return GetValue(pName->GetNameSpace(), pName->GetName(), pData, IsNested, pContext); - } -} - class ConstructKeyCallbackCompare : public EEClassHashTable::ConstructKeyCallback { public: @@ -708,9 +370,9 @@ BOOL EEClassHashTable::CompareKeys(PTR_EEClassHashEntry pEntry, LPCUTF8 * pKey2) { CONTRACTL { - if (m_bCaseInsensitive) THROWS; else NOTHROW; - if (m_bCaseInsensitive) GC_TRIGGERS; else GC_NOTRIGGER; - if (m_bCaseInsensitive) INJECT_FAULT(COMPlusThrowOM();); else FORBID_FAULT; + if (IsCaseInsensitiveTable()) THROWS; else NOTHROW; + if (IsCaseInsensitiveTable()) GC_TRIGGERS; else GC_NOTRIGGER; + if (IsCaseInsensitiveTable()) INJECT_FAULT(COMPlusThrowOM();); else FORBID_FAULT; MODE_ANY; SUPPORTS_DAC; } @@ -791,7 +453,7 @@ EEClassHashTable *EEClassHashTable::MakeCaseInsensitiveTable(Module *pModule, Al // Allocate the table and verify that we actually got one. EEClassHashTable * pCaseInsTable = EEClassHashTable::Create(pModule, max(BaseGetElementCount() / 2, 11), - TRUE /* bCaseInsensitive */, + this, pamTracker); // Walk all of the buckets and insert them into our new case insensitive table @@ -808,9 +470,409 @@ EEClassHashTable *EEClassHashTable::MakeCaseInsensitiveTable(Module *pModule, Al //Add the newly created name to our hash table. The hash datum is a pointer //to the entry associated with that name in this hashtable. - pCaseInsTable->InsertValue(pszLowerNameSpace, pszLowerClsName, (PTR_VOID)pTempEntry, pTempEntry->GetEncloser(), pamTracker); + pCaseInsTable->InsertValueUsingPreallocatedEntry(pCaseInsTable->BaseAllocateEntry(pamTracker), pszLowerNameSpace, pszLowerClsName, pTempEntry, pTempEntry->GetEncloser()); } return pCaseInsTable; } #endif // !DACCESS_COMPILE + +BOOL CompareNestedEntryWithExportedType(IMDInternalImport * pImport, + mdExportedType mdCurrent, + EEClassHashTable * pClassHash, + PTR_EEClassHashEntry pEntry) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + FORBID_FAULT; + SUPPORTS_DAC; + } + CONTRACTL_END; + + LPCUTF8 Key[2]; + + do + { + if (FAILED(pImport->GetExportedTypeProps( + mdCurrent, + &Key[0], + &Key[1], + &mdCurrent, + NULL, //binding (type def) + NULL))) //flags + { + return FALSE; + } + + if (pClassHash->CompareKeys(pEntry, Key)) + { + // Reached top level class for mdCurrent - return whether + // or not pEntry is a top level class + // (pEntry is a top level class if its pEncloser is NULL) + if ((TypeFromToken(mdCurrent) != mdtExportedType) || + (mdCurrent == mdExportedTypeNil)) + { + return pEntry->GetEncloser() == NULL; + } + } + else // Keys don't match - wrong entry + { + return FALSE; + } + } + while ((pEntry = pEntry->GetEncloser()) != NULL); + + // Reached the top level class for pEntry, but mdCurrent is nested + return FALSE; +} + +DWORD ComputeHashFunctionWithExportedType(EEClassHashTable * pClassHash, EEClassHashTable * pCaseSensitiveClassHash, IMDInternalImport *pImport, mdExportedType etCurrent, BOOL *pFailed) +{ + LPCSTR _namespace, name; + if (FAILED(pImport->GetExportedTypeProps( + etCurrent, + &_namespace, + &name, + &etCurrent, + NULL, //binding (type def) + NULL))) //flags + { + return FALSE; + } + DWORD hashEncloser = 0; + if (TypeFromToken(etCurrent) == mdtExportedType && etCurrent != mdExportedTypeNil) + { + // The enclosing hash is always based on the entry from the case sensitive table + hashEncloser = ComputeHashFunctionWithExportedType(pCaseSensitiveClassHash, pCaseSensitiveClassHash, pImport, etCurrent, pFailed); + } + return pClassHash->Hash(_namespace, name, hashEncloser); +} + +BOOL CompareNestedEntryWithTypeDef(IMDInternalImport * pImport, + mdTypeDef mdCurrent, + EEClassHashTable * pClassHash, + PTR_EEClassHashEntry pEntry) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + FORBID_FAULT; + SUPPORTS_DAC; + } + CONTRACTL_END; + + LPCUTF8 Key[2]; + + do { + if (FAILED(pImport->GetNameOfTypeDef(mdCurrent, &Key[1], &Key[0]))) + { + return FALSE; + } + + if (pClassHash->CompareKeys(pEntry, Key)) { + // Reached top level class for mdCurrent - return whether + // or not pEntry is a top level class + // (pEntry is a top level class if its pEncloser is NULL) + if (FAILED(pImport->GetNestedClassProps(mdCurrent, &mdCurrent))) + return pEntry->GetEncloser() == NULL; + } + else // Keys don't match - wrong entry + return FALSE; + } + while ((pEntry = pEntry->GetEncloser()) != NULL); + + // Reached the top level class for pEntry, but mdCurrent is nested + return FALSE; +} + +DWORD ComputeHashFunctionWithTypeDef(EEClassHashTable *pClassHash, EEClassHashTable *pCaseSensitiveClassHash, IMDInternalImport *pImport, mdTypeDef tdCurrent, BOOL *pFailed) +{ + LPCSTR _namespace, name; + if (FAILED(pImport->GetNameOfTypeDef(tdCurrent, &name, &_namespace))) + { + *pFailed = TRUE; + return 0; + } + DWORD hashEncloser = 0; + if (SUCCEEDED(pImport->GetNestedClassProps(tdCurrent, &tdCurrent))) + { + // The enclosing hash is always based on the entry from the case sensitive table + hashEncloser = ComputeHashFunctionWithTypeDef(pCaseSensitiveClassHash, pCaseSensitiveClassHash, pImport, tdCurrent, pFailed); + } + return pClassHash->Hash(_namespace, name, hashEncloser); +} + +BOOL CompareNestedEntryWithTypeRef(IMDInternalImport * pImport, + mdTypeRef mdCurrent, + EEClassHashTable * pClassHash, + PTR_EEClassHashEntry pEntry) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + FORBID_FAULT; + SUPPORTS_DAC; + } + CONTRACTL_END; + + LPCUTF8 Key[2]; + + do { + if (FAILED(pImport->GetNameOfTypeRef(mdCurrent, &Key[0], &Key[1]))) + { + return FALSE; + } + + if (pClassHash->CompareKeys(pEntry, Key)) + { + if (FAILED(pImport->GetResolutionScopeOfTypeRef(mdCurrent, &mdCurrent))) + { + return FALSE; + } + // Reached top level class for mdCurrent - return whether + // or not pEntry is a top level class + // (pEntry is a top level class if its pEncloser is NULL) + if ((TypeFromToken(mdCurrent) != mdtTypeRef) || + (mdCurrent == mdTypeRefNil)) + return pEntry->GetEncloser() == NULL; + } + else // Keys don't match - wrong entry + return FALSE; + } + while ((pEntry = pEntry->GetEncloser())!=NULL); + + // Reached the top level class for pEntry, but mdCurrent is nested + return FALSE; +} + + +DWORD ComputeHashFunctionWithTypeRef(EEClassHashTable *pClassHash, EEClassHashTable *pCaseSensitiveClassHash, IMDInternalImport *pImport, mdTypeRef trCurrent, BOOL *pFailed) +{ + LPCSTR _namespace, name; + if (FAILED(pImport->GetNameOfTypeRef(trCurrent, &_namespace, &name))) + { + *pFailed = TRUE; + return 0; + } + DWORD hashEncloser = 0; + if (SUCCEEDED(pImport->GetResolutionScopeOfTypeRef(trCurrent, &trCurrent)) && TypeFromToken(trCurrent) == mdtTypeRef) + { + // The enclosing hash is always based on the entry from the case sensitive table + hashEncloser = ComputeHashFunctionWithTypeRef(pCaseSensitiveClassHash, pCaseSensitiveClassHash, pImport, trCurrent, pFailed); + } + return pClassHash->Hash(_namespace, name, hashEncloser); +} + +/*static*/ +BOOL EEClassHashTable::IsNested(ModuleBase *pModule, mdToken token, mdToken *mdEncloser) +{ + CONTRACTL + { + if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS; + if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS; + if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); } + MODE_ANY; + SUPPORTS_DAC; + } + CONTRACTL_END; + + switch(TypeFromToken(token)) { + case mdtTypeDef: + return (SUCCEEDED(pModule->GetMDImport()->GetNestedClassProps(token, mdEncloser))); + + case mdtTypeRef: + IfFailThrow(pModule->GetMDImport()->GetResolutionScopeOfTypeRef(token, mdEncloser)); + return ((TypeFromToken(*mdEncloser) == mdtTypeRef) && + (*mdEncloser != mdTypeRefNil)); + + case mdtExportedType: + _ASSERTE(pModule->IsFullModule()); + IfFailThrow(((Module*)pModule)->GetAssembly()->GetMDImport()->GetExportedTypeProps( + token, + NULL, // namespace + NULL, // name + mdEncloser, + NULL, //binding (type def) + NULL)); //flags + return ((TypeFromToken(*mdEncloser) == mdtExportedType) && + (*mdEncloser != mdExportedTypeNil)); + + default: + ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE); + } +} + +BOOL EEClassHashTable::IsNested(const NameHandle* pName, mdToken *mdEncloser) +{ + CONTRACTL + { + if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS; + if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS; + if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); } + MODE_ANY; + SUPPORTS_DAC; + } + CONTRACTL_END; + + if (pName->GetTypeModule()) { + if (TypeFromToken(pName->GetTypeToken()) == mdtBaseType) + { + if (!pName->GetBucket().IsNull()) + return TRUE; + return FALSE; + } + else + return IsNested(pName->GetTypeModule(), pName->GetTypeToken(), mdEncloser); + } + else + return FALSE; +} + +PTR_EEClassHashEntry EEClassHashTable::FindByNameHandle(const NameHandle* pName) +{ + // TODO remove this pointless local + EEClassHashTable *pTable = this; + + PTR_EEClassHashEntry pBucket; + mdToken mdEncloser; + bool isNested = IsNested(pName, &mdEncloser); + LPCUTF8 pszName = NULL, pszNamespace = NULL; + DWORD hash; + BOOL failed; + + _ASSERTE(pName->GetNameSpace() != NULL); + _ASSERTE(pName->GetName() != NULL); + + pszName = pName->GetName(); + pszNamespace = pName->GetNameSpace(); + + mdToken typeToken = pName->GetTypeToken(); + ModuleBase *pNameModule = pName->GetTypeModule(); + + switch (TypeFromToken(typeToken)) + { + case mdtTypeDef: + PREFIX_ASSUME(pNameModule != NULL); + hash = ComputeHashFunctionWithTypeDef(pTable, m_pCaseSensitiveTable, pNameModule->GetMDImport(), typeToken, &failed); + break; + case mdtTypeRef: + PREFIX_ASSUME(pNameModule != NULL); + hash = ComputeHashFunctionWithTypeRef(pTable, m_pCaseSensitiveTable, pNameModule->GetMDImport(), typeToken, &failed); + break; + case mdtExportedType: + PREFIX_ASSUME(pNameModule != NULL); + hash = ComputeHashFunctionWithExportedType(pTable, m_pCaseSensitiveTable, pNameModule->GetMDImport(), typeToken, &failed); + break; + default: + DWORD enclosingHash; + if (pName->GetBucket().IsNull()) + { + enclosingHash = 0; + } + else + { + // The enclosing hash is always based on the entry from the case sensitive table + // A NameHandle bucket is always the entry in the CaseSensitive table + enclosingHash = GetHash(pName->GetBucket().GetClassHashBasedEntryValue()); + } + hash = Hash(pszNamespace, pszName, enclosingHash); + break; + } + + EEClassHashTable::LookupContext lookupContext; + pBucket = pTable->BaseFindFirstEntryByHash(hash, &lookupContext); + LPCUTF8 key[] = {pszNamespace, pszName}; + while (pBucket != NULL) + { + if (pTable->CompareKeys(pBucket, key)) + { + if ((pBucket->GetEncloser() != NULL) == isNested) + { + if (isNested) + { + bool hasNameBucket = !pName->GetBucket().IsNull(); +#ifdef _DEBUG + bool expectedMatchCheck = !hasNameBucket || (pBucket->GetEncloser() == pName->GetBucket().GetClassHashBasedEntryValue()); + bool expectedNotMatchCheck = !hasNameBucket || (pBucket->GetEncloser() != pName->GetBucket().GetClassHashBasedEntryValue()); +#endif +#ifndef _DEBUG + // In non-debug builds, we can simply check the encloser in the name first. If it matches then we've found the right + // result, and if it doesn't match it also indicates that it shouldn't match. We only do this in non-debug builds + // as we want to validate via asserts that this code is correct. + if (!pName->GetBucket().IsNull()) + { + if (pBucket->GetEncloser() == pName->GetBucket().GetClassHashBasedEntryValue()) + { + // We found our result + break; + } + } else +#endif // !_DEBUG + if (TypeFromToken(typeToken) == mdtTypeDef) + { + if (CompareNestedEntryWithTypeDef(pNameModule->GetMDImport(), + mdEncloser, + this, + pBucket->GetEncloser())) + { + _ASSERTE(expectedMatchCheck); + // We found our result + break; + } + _ASSERTE(expectedNotMatchCheck); + } + else if (TypeFromToken(typeToken) == mdtTypeRef) + { + if (CompareNestedEntryWithTypeRef(pNameModule->GetMDImport(), + mdEncloser, + this, + pBucket->GetEncloser())) + { + _ASSERTE(expectedMatchCheck); + // We found our result + break; + } + _ASSERTE(expectedNotMatchCheck); + } + else if (TypeFromToken(typeToken) == mdtExportedType) + { + if (CompareNestedEntryWithExportedType(pNameModule->GetMDImport(), + mdEncloser, + this, + pBucket->GetEncloser())) + { + _ASSERTE(expectedMatchCheck); + // We found our result + break; + } + _ASSERTE(expectedNotMatchCheck); + } + else + { + // String based lookup always set the encloser bucket on the name. We will only + // hit this particular block in debug builds + if (pBucket->GetEncloser() == pName->GetBucket().GetClassHashBasedEntryValue()) + { + // We found our result + break; + } + } + } + else + { + // We found our result + break; + } + } + } + pBucket = pTable->BaseFindNextEntryByHash(&lookupContext); + } + return pBucket; +} diff --git a/src/coreclr/vm/classhash.h b/src/coreclr/vm/classhash.h index 4fd943165b4787..60c2650fff9ceb 100644 --- a/src/coreclr/vm/classhash.h +++ b/src/coreclr/vm/classhash.h @@ -39,6 +39,7 @@ typedef struct EEClassHashEntry PTR_VOID GetData(); void SetData(PTR_VOID data) DAC_EMPTY(); + private: PTR_VOID m_Data; // Either the token (if EECLASSHASH_TYPEHANDLE_DISCR), or the type handle encoded // as a relative pointer @@ -61,27 +62,20 @@ class EEClassHashTable : public DacEnumerableHashTable::LookupContext LookupContext; - static EEClassHashTable *Create(Module *pModule, DWORD dwNumBuckets, BOOL bCaseInsensitive, AllocMemTracker *pamTracker); + static EEClassHashTable *Create(Module *pModule, DWORD dwNumBuckets, PTR_EEClassHashTable caseSensitiveTable, AllocMemTracker *pamTracker); //NOTICE: look at InsertValue() in ClassLoader, that may be the function you want to use. Use this only // when you are sure you want to insert the value in 'this' table. This function does not deal // with case (as often the class loader has to) - EEClassHashEntry_t *InsertValue(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID Data, EEClassHashEntry_t *pEncloser, AllocMemTracker *pamTracker); - EEClassHashEntry_t *InsertValueIfNotFound(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, EEClassHashEntry_t *pEncloser, BOOL IsNested, BOOL *pbFound, AllocMemTracker *pamTracker); EEClassHashEntry_t *InsertValueUsingPreallocatedEntry(EEClassHashEntry_t *pStorageForNewEntry, LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID Data, EEClassHashEntry_t *pEncloser); - EEClassHashEntry_t *GetValue(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, BOOL IsNested, LookupContext *pContext); - EEClassHashEntry_t *GetValue(LPCUTF8 pszFullyQualifiedName, PTR_VOID *pData, BOOL IsNested, LookupContext *pContext); - EEClassHashEntry_t *GetValue(const NameHandle* pName, PTR_VOID *pData, BOOL IsNested, LookupContext *pContext); EEClassHashEntry_t *AllocNewEntry(AllocMemTracker *pamTracker); EEClassHashTable *MakeCaseInsensitiveTable(Module *pModule, AllocMemTracker *pamTracker); - EEClassHashEntry_t *FindItem(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, BOOL IsNested, LookupContext *pContext); - EEClassHashEntry_t *FindNextNestedClass(const NameHandle* pName, PTR_VOID *pData, LookupContext *pContext); - EEClassHashEntry_t *FindNextNestedClass(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, LookupContext *pContext); - EEClassHashEntry_t *FindNextNestedClass(LPCUTF8 pszFullyQualifiedName, PTR_VOID *pData, LookupContext *pContext); + + PTR_EEClassHashEntry FindByNameHandle(const NameHandle* pName); BOOL CompareKeys(PTR_EEClassHashEntry pEntry, LPCUTF8 * pKey2); - static DWORD Hash(LPCUTF8 pszNamespace, LPCUTF8 pszClassName); + static DWORD Hash(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, DWORD enclosingHash); class ConstructKeyCallback { @@ -97,15 +91,32 @@ class EEClassHashTable : public DacEnumerableHashTable(pModule, pHeap, cInitialBuckets) {} + DacEnumerableHashTable(pModule, pHeap, cInitialBuckets), + m_pCaseSensitiveTable(NULL) {} #endif VOID ConstructKeyFromData(PTR_EEClassHashEntry pEntry, ConstructKeyCallback * pCallback); - BOOL m_bCaseInsensitive; // Default is true FALSE unless we call MakeCaseInsensitiveTable + bool IsCaseInsensitiveTable() { return m_pCaseSensitiveTable != this; } + + static BOOL IsNested(ModuleBase *pModule, mdToken token, mdToken *mdEncloser); + static BOOL IsNested(const NameHandle* pName, mdToken *mdEncloser); + + PTR_EEClassHashTable m_pCaseSensitiveTable; // This will be a recursive pointer for the case sensitive table }; +inline DWORD GetHash(PTR_EEClassHashEntry eeclassHashEntry) +{ + // This is only safe, as the only allocator for the EEClassHashEntry type is the hash table + return EEClassHashTable::HashEntryToHash(eeclassHashEntry); +} + #endif // !__CLASS_HASH_INCLUDED diff --git a/src/coreclr/vm/classhash.inl b/src/coreclr/vm/classhash.inl index 25caf51d579fbe..554c0c2005c463 100644 --- a/src/coreclr/vm/classhash.inl +++ b/src/coreclr/vm/classhash.inl @@ -38,7 +38,7 @@ inline PTR_VOID EEClassHashTable::CompressClassDef(mdToken cl) } } -inline DWORD EEClassHashTable::Hash(LPCUTF8 pszNamespace, LPCUTF8 pszClassName) +inline DWORD EEClassHashTable::Hash(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, DWORD hashEncloser) { CONTRACTL { @@ -60,6 +60,11 @@ inline DWORD EEClassHashTable::Hash(LPCUTF8 pszNamespace, LPCUTF8 pszClassName) while ((dwChar = *pszClassName++) != 0) dwHash = ((dwHash << 5) + dwHash) ^ dwChar; + if (hashEncloser != 0) + { + dwHash = ((dwHash << 5) + dwHash) ^ hashEncloser; + } + return dwHash; } diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp index ae4aa4f71c9f30..5d24690499aa45 100644 --- a/src/coreclr/vm/clsload.cpp +++ b/src/coreclr/vm/clsload.cpp @@ -284,6 +284,26 @@ TypeHandle ClassLoader::LoadTypeByNameThrowing(Assembly *pAssembly, ClassLoadLevel level) { WRAPPER_NO_CONTRACT; + + CQuickBytes qbszNamespace; + + if (nameSpace == NULL) + { + LPCUTF8 szFullyQualifiedName = name; + nameSpace = ""; + + if ((name = ns::FindSep(szFullyQualifiedName)) != NULL) + { + SIZE_T d = name - szFullyQualifiedName; + nameSpace = qbszNamespace.SetString(szFullyQualifiedName, d); + name++; + } + else + { + name = szFullyQualifiedName; + } + } + NameHandle nameHandle(nameSpace, name); return LoadTypeByNameThrowing(pAssembly, &nameHandle, fNotFound, fLoadTypes, level); } @@ -431,217 +451,121 @@ EEClassHashEntry_t* ClassLoader::InsertValue(EEClassHashTable *pClassHash, EECla return pEntry; } - } #endif // #ifndef DACCESS_COMPILE -BOOL ClassLoader::CompareNestedEntryWithExportedType(IMDInternalImport * pImport, - mdExportedType mdCurrent, - EEClassHashTable * pClassHash, - PTR_EEClassHashEntry pEntry) +mdTypeDef ClassLoader::LookupTypeDefTokenThatMatchesTypeRef(mdTypeRef typeRef) { - CONTRACTL - { - INSTANCE_CHECK; - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - FORBID_FAULT; - SUPPORTS_DAC; - } - CONTRACTL_END; - - LPCUTF8 Key[2]; + WRAPPER_NO_CONTRACT; - do - { - if (FAILED(pImport->GetExportedTypeProps( - mdCurrent, - &Key[0], - &Key[1], - &mdCurrent, - NULL, //binding (type def) - NULL))) //flags - { - return FALSE; - } + Module *pModule = GetAssembly()->GetModule(); + NameHandle typeName(pModule, mdtBaseType); + typeName.SetTokenNotToLoad(tdAllTypes); + return LookupTypeDefTokenThatMatchesTokenHelper(pModule->GetMDImport(), typeRef, &typeName); +} - if (pClassHash->CompareKeys(pEntry, Key)) - { - // Reached top level class for mdCurrent - return whether - // or not pEntry is a top level class - // (pEntry is a top level class if its pEncloser is NULL) - if ((TypeFromToken(mdCurrent) != mdtExportedType) || - (mdCurrent == mdExportedTypeNil)) - { - return pEntry->GetEncloser() == NULL; - } - } - else // Keys don't match - wrong entry - { - return FALSE; - } - } - while ((pEntry = pEntry->GetEncloser()) != NULL); +mdTypeDef ClassLoader::LookupTypeDefTokenThatMatchesToken(IMDInternalImport* pMDImportTokenLookup, mdToken token) +{ + WRAPPER_NO_CONTRACT; - // Reached the top level class for pEntry, but mdCurrent is nested - return FALSE; + NameHandle typeName(GetAssembly()->GetModule(), mdtBaseType); + typeName.SetTokenNotToLoad(tdAllTypes); + return LookupTypeDefTokenThatMatchesTokenHelper(pMDImportTokenLookup, token, &typeName); } - -BOOL ClassLoader::CompareNestedEntryWithTypeDef(IMDInternalImport * pImport, - mdTypeDef mdCurrent, - EEClassHashTable * pClassHash, - PTR_EEClassHashEntry pEntry) +mdTypeDef ClassLoader::LookupTypeDefTokenThatMatchesTokenHelper(IMDInternalImport* pMDImportTokenLookup, mdToken token, NameHandle *pName) { CONTRACTL { INSTANCE_CHECK; - NOTHROW; - GC_NOTRIGGER; MODE_ANY; - FORBID_FAULT; + THROWS; + GC_TRIGGERS; SUPPORTS_DAC; } - CONTRACTL_END; - - LPCUTF8 Key[2]; - - do { - if (FAILED(pImport->GetNameOfTypeDef(mdCurrent, &Key[1], &Key[0]))) - { - return FALSE; - } + CONTRACTL_END - if (pClassHash->CompareKeys(pEntry, Key)) { - // Reached top level class for mdCurrent - return whether - // or not pEntry is a top level class - // (pEntry is a top level class if its pEncloser is NULL) - if (FAILED(pImport->GetNestedClassProps(mdCurrent, &mdCurrent))) - return pEntry->GetEncloser() == NULL; - } - else // Keys don't match - wrong entry - return FALSE; - } - while ((pEntry = pEntry->GetEncloser()) != NULL); - // Reached the top level class for pEntry, but mdCurrent is nested - return FALSE; -} + Module* pModule = GetAssembly()->GetModule(); + LPCUTF8 pszNameSpace; + LPCUTF8 pszClassName; + mdToken resolutionScope; -BOOL ClassLoader::CompareNestedEntryWithTypeRef(IMDInternalImport * pImport, - mdTypeRef mdCurrent, - EEClassHashTable * pClassHash, - PTR_EEClassHashEntry pEntry) -{ - CONTRACTL + if (TypeFromToken(token) == mdtTypeRef) { - INSTANCE_CHECK; - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - FORBID_FAULT; - SUPPORTS_DAC; - } - CONTRACTL_END; - - LPCUTF8 Key[2]; - - do { - if (FAILED(pImport->GetNameOfTypeRef(mdCurrent, &Key[0], &Key[1]))) + if (FAILED(pMDImportTokenLookup->GetNameOfTypeRef(token, &pszNameSpace, &pszClassName))) { - return FALSE; + ThrowHR(COR_E_BADIMAGEFORMAT); } - - if (pClassHash->CompareKeys(pEntry, Key)) + if (FAILED(pMDImportTokenLookup->GetResolutionScopeOfTypeRef(token, &resolutionScope))) { - if (FAILED(pImport->GetResolutionScopeOfTypeRef(mdCurrent, &mdCurrent))) - { - return FALSE; - } - // Reached top level class for mdCurrent - return whether - // or not pEntry is a top level class - // (pEntry is a top level class if its pEncloser is NULL) - if ((TypeFromToken(mdCurrent) != mdtTypeRef) || - (mdCurrent == mdTypeRefNil)) - return pEntry->GetEncloser() == NULL; + ThrowHR(COR_E_BADIMAGEFORMAT); } - else // Keys don't match - wrong entry - return FALSE; } - while ((pEntry = pEntry->GetEncloser())!=NULL); - - // Reached the top level class for pEntry, but mdCurrent is nested - return FALSE; -} - - -/*static*/ -BOOL ClassLoader::IsNested(ModuleBase *pModule, mdToken token, mdToken *mdEncloser) -{ - CONTRACTL + else { - if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS; - if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS; - if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); } - MODE_ANY; - SUPPORTS_DAC; + _ASSERTE(TypeFromToken(token) == mdtExportedType); + if (FAILED(pMDImportTokenLookup->GetExportedTypeProps( + token, + &pszNameSpace, + &pszClassName, + &resolutionScope, + NULL, //binding (type def) + NULL))) //flags + { + ThrowHR(COR_E_BADIMAGEFORMAT); + } } - CONTRACTL_END; - switch(TypeFromToken(token)) { - case mdtTypeDef: - return (SUCCEEDED(pModule->GetMDImport()->GetNestedClassProps(token, mdEncloser))); + if ((TypeFromToken(resolutionScope) == mdtTypeRef) || ((TypeFromToken(resolutionScope) == mdtExportedType) && resolutionScope != mdExportedTypeNil)) + { + mdTypeDef tkTypeDef = LookupTypeDefTokenThatMatchesTokenHelper(pMDImportTokenLookup, resolutionScope, pName); + if (tkTypeDef == mdTypeDefNil) + { + return mdTypeDefNil; + } - case mdtTypeRef: - IfFailThrow(pModule->GetMDImport()->GetResolutionScopeOfTypeRef(token, mdEncloser)); - return ((TypeFromToken(*mdEncloser) == mdtTypeRef) && - (*mdEncloser != mdTypeRefNil)); + // This bucket will be used for the followon type lookup + _ASSERTE(!pName->GetBucket().IsNull()); + } - case mdtExportedType: - _ASSERTE(pModule->IsFullModule()); - IfFailThrow(((Module*)pModule)->GetAssembly()->GetMDImport()->GetExportedTypeProps( - token, - NULL, // namespace - NULL, // name - mdEncloser, - NULL, //binding (type def) - NULL)); //flags - return ((TypeFromToken(*mdEncloser) == mdtExportedType) && - (*mdEncloser != mdExportedTypeNil)); + pName->SetName(pszNameSpace, pszClassName); + TypeHandle thUnused; + Module *pFoundModule; + mdToken foundExportedTypeUnused = mdTokenNil; + mdToken mdFoundTypeToken = mdTokenNil; + HashedTypeEntry foundEntry; - default: - ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE); + if (!FindClassModuleThrowing( + pName, + &thUnused, + &mdFoundTypeToken, + &pFoundModule, + &foundExportedTypeUnused, + &foundEntry, + pModule, + pName->OKToLoad() ? Loader::Load + : Loader::DontLoad)) + { + // Didn't find anything, no point in further processing + return mdTypeDefNil; } -} -BOOL ClassLoader::IsNested(const NameHandle* pName, mdToken *mdEncloser) -{ - CONTRACTL + if (TypeFromToken(mdFoundTypeToken) != mdtTypeDef || RidFromToken(mdFoundTypeToken) == 0) { - INSTANCE_CHECK; - if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS; - if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS; - if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); } - MODE_ANY; - SUPPORTS_DAC; + return mdTypeDefNil; } - CONTRACTL_END; - if (pName->GetTypeModule()) { - if (TypeFromToken(pName->GetTypeToken()) == mdtBaseType) - { - if (!pName->GetBucket().IsNull()) - return TRUE; - return FALSE; - } - else - return IsNested(pName->GetTypeModule(), pName->GetTypeToken(), mdEncloser); + _ASSERTE(!foundEntry.IsNull()); + + if (pName->GetTypeToken() == mdtBaseType) + { // We should return the found bucket in the pName + pName->SetBucket(foundEntry); } - else - return FALSE; + + return mdFoundTypeToken; } void ClassLoader::GetClassValue(NameHandleTable nhTable, @@ -666,7 +590,7 @@ void ClassLoader::GetClassValue(NameHandleTable nhTable, CONTRACTL_END - EEClassHashEntry_t *pBucket = NULL; + PTR_EEClassHashEntry pBucket = NULL; needsToBuildHashtable = FALSE; @@ -749,54 +673,11 @@ void ClassLoader::GetClassValue(NameHandleTable nhTable, } _ASSERTE(pTable); - mdToken mdEncloser; - BOOL isNested = IsNested(pName, &mdEncloser); - - if (isNested) - { - ModuleBase *pNameModule = pName->GetTypeModule(); - PREFIX_ASSUME(pNameModule != NULL); - - EEClassHashTable::LookupContext sContext; - if ((pBucket = pTable->GetValue(pName, pData, TRUE, &sContext)) != NULL) - { - switch (TypeFromToken(pName->GetTypeToken())) - { - case mdtTypeDef: - while ((!CompareNestedEntryWithTypeDef(pNameModule->GetMDImport(), - mdEncloser, - pCurrentClsModule->GetAvailableClassHash(), - pBucket->GetEncloser())) && - (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL); - break; - case mdtTypeRef: - while ((!CompareNestedEntryWithTypeRef(pNameModule->GetMDImport(), - mdEncloser, - pCurrentClsModule->GetAvailableClassHash(), - pBucket->GetEncloser())) && - (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL); - break; - case mdtExportedType: - _ASSERTE(pNameModule->IsFullModule()); - while ((!CompareNestedEntryWithExportedType(((Module*)pNameModule)->GetAssembly()->GetMDImport(), - mdEncloser, - pCurrentClsModule->GetAvailableClassHash(), - pBucket->GetEncloser())) && - (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL); - break; - default: - while ((pBucket->GetEncloser() != pName->GetBucket().GetClassHashBasedEntryValue()) && - (pBucket = pTable->FindNextNestedClass(pName, pData, &sContext)) != NULL); - } - } - } - else - { - pBucket = pTable->GetValue(pName, pData, FALSE, NULL); - } + pBucket = pTable->FindByNameHandle(pName); if (pBucket) // Return on the first success { + *pData = pBucket->GetData(); pFoundEntry->SetClassHashBasedEntryValue(pBucket); return; } @@ -822,20 +703,45 @@ VOID ClassLoader::PopulateAvailableClassHashTable(Module* pModule, } CONTRACTL_END; - mdTypeDef td; - HENUMInternal hTypeDefEnum; + SArray entries; IMDInternalImport * pImport = pModule->GetMDImport(); + { + mdTypeDef td; + HENUMInternalHolder hTypeDefEnum(pImport); - IfFailThrow(pImport->EnumTypeDefInit(&hTypeDefEnum)); + hTypeDefEnum.EnumTypeDefInit(); - // Now loop through all the classdefs adding the CVID and scope to the hash - while(pImport->EnumNext(&hTypeDefEnum, &td)) { + DWORD cEntries = hTypeDefEnum.EnumGetCount() + 1; // Add 1 since this enum doesn't report the class + EEClassHashEntry_t** pBuffer = entries.OpenRawBuffer(cEntries); + memset(pBuffer, 0, sizeof(EEClassHashEntry_t*) * cEntries); + entries.CloseRawBuffer(); - AddAvailableClassHaveLock(pModule, - td, - pamTracker); + // Now loop through all the classdefs adding the CVID and scope to the hash + while(pImport->EnumNext(&hTypeDefEnum, &td)) + { + AddAvailableClassHaveLock(pModule, + td, + &entries, + pamTracker); + } + } + + { + // Add exported types to the hashtable + HENUMInternalHolder phEnum(pImport); + phEnum.EnumInit(mdtExportedType, mdTokenNil); + + DWORD cEntries = phEnum.EnumGetCount(); + EEClassHashEntry_t** pBuffer = entries.OpenRawBuffer(cEntries); + memset(pBuffer, 0, sizeof(EEClassHashEntry_t*) * cEntries); + entries.CloseRawBuffer(); + + mdToken mdExportedType; + while (pImport->EnumNext(&phEnum, &mdExportedType)) + { + AddExportedTypeHaveLock(pModule, mdExportedType, &entries, pamTracker); + } } - pImport->EnumClose(&hTypeDefEnum); } @@ -881,21 +787,12 @@ void ClassLoader::LazyPopulateCaseSensitiveHashTables() // (either images compiled with an old version of crossgen, or for case-insensitive type lookups in R2R modules) _ASSERT(pModule->IsReadyToRun()); - EEClassHashTable * pNewClassHash = EEClassHashTable::Create(pModule, AVAILABLE_CLASSES_HASH_BUCKETS, FALSE /* bCaseInsensitive */, &amTracker); + EEClassHashTable * pNewClassHash = EEClassHashTable::Create(pModule, AVAILABLE_CLASSES_HASH_BUCKETS, NULL, &amTracker); pModule->SetAvailableClassHash(pNewClassHash); PopulateAvailableClassHashTable(pModule, &amTracker); } - // Add exported types to the hashtable - IMDInternalImport * pManifestImport = GetAssembly()->GetMDImport(); - HENUMInternalHolder phEnum(pManifestImport); - phEnum.EnumInit(mdtExportedType, mdTokenNil); - - mdToken mdExportedType; - while (pManifestImport->EnumNext(&phEnum, &mdExportedType)) - AddExportedTypeHaveLock(GetAssembly()->GetModule(), mdExportedType, &amTracker); - amTracker.SuppressRelease(); } @@ -1260,7 +1157,7 @@ BOOL ClassLoader::FindClassModuleThrowing( return TRUE; } - EEClassHashEntry_t * pBucket = foundEntry.GetClassHashBasedEntryValue(); + PTR_EEClassHashEntry pBucket = foundEntry.GetClassHashBasedEntryValue(); if (pBucket == NULL) { @@ -1310,7 +1207,7 @@ BOOL ClassLoader::FindClassModuleThrowing( if (pName->GetTable() == nhCaseInsensitive) { _ASSERTE(Data); - pBucket = PTR_EEClassHashEntry(Data); + pBucket = dac_cast(dac_cast((Data))); Data = pBucket->GetData(); } @@ -1521,7 +1418,7 @@ ClassLoader::LoadTypeHandleThrowing( if (SUCCEEDED(pClsLdr->FindTypeDefByExportedType( pClsLdr->GetAssembly()->GetMDImport(), FoundExportedType, - pFoundModule->GetMDImport(), + pFoundModule, &FoundCl))) { typeHnd = pClsLdr->LoadTypeDefThrowing( @@ -1547,16 +1444,7 @@ ClassLoader::LoadTypeHandleThrowing( const HashedTypeEntry& bucket = pName->GetBucket(); // Reset pName's bucket entry - if (bucket.GetEntryType() == HashedTypeEntry::IsHashedClassEntry && bucket.GetClassHashBasedEntryValue()->GetEncloser()) - { - // We will be searching for the type name again, so set the nesting/context type to the - // encloser of just found type - pName->SetBucket(HashedTypeEntry().SetClassHashBasedEntryValue(bucket.GetClassHashBasedEntryValue()->GetEncloser())); - } - else - { - pName->SetBucket(HashedTypeEntry()); - } + pName->SetBucket(HashedTypeEntry()); // Update the class loader for the new module/token pair. pClsLdr = pFoundModule->GetClassLoader(); @@ -1734,7 +1622,7 @@ TypeHandle ClassLoader::LoadGenericInstantiationThrowing(Module *pModule, // token for the type we care about. /*static*/ HRESULT ClassLoader::FindTypeDefByExportedType(IMDInternalImport *pCTImport, mdExportedType mdCurrent, - IMDInternalImport *pTDImport, mdTypeDef *mtd) + Module *pTDModule, mdTypeDef *mtd) { CONTRACTL { @@ -1746,30 +1634,12 @@ HRESULT ClassLoader::FindTypeDefByExportedType(IMDInternalImport *pCTImport, mdE } CONTRACTL_END - mdToken mdImpl; - LPCSTR szcNameSpace; - LPCSTR szcName; - HRESULT hr; - - IfFailRet(pCTImport->GetExportedTypeProps( - mdCurrent, - &szcNameSpace, - &szcName, - &mdImpl, - NULL, //binding - NULL)); //flags - - if ((TypeFromToken(mdImpl) == mdtExportedType) && - (mdImpl != mdExportedTypeNil)) { - // mdCurrent is a nested ExportedType - IfFailRet(FindTypeDefByExportedType(pCTImport, mdImpl, pTDImport, mtd)); - - // Get TypeDef token for this nested type - return pTDImport->FindTypeDef(szcNameSpace, szcName, *mtd, mtd); + *mtd = pTDModule->GetClassLoader()->LookupTypeDefTokenThatMatchesToken(pCTImport, mdCurrent); + if (*mtd == mdTypeDefNil) + { + return E_FAIL; } - - // Get TypeDef token for this top-level type - return pTDImport->FindTypeDef(szcNameSpace, szcName, mdTokenNil, mtd); + return S_OK; } #ifndef DACCESS_COMPILE @@ -3708,6 +3578,7 @@ VOID ClassLoader::AddAvailableClassDontHaveLock(Module *pModule, AddAvailableClassHaveLock( pModule, classdef, + NULL, pamTracker); } @@ -3723,6 +3594,7 @@ VOID ClassLoader::AddAvailableClassDontHaveLock(Module *pModule, VOID ClassLoader::AddAvailableClassHaveLock( Module * pModule, mdTypeDef classdef, + SArray* classEntries, AllocMemTracker * pamTracker) // Optimization for faster prefix comparison implementation { CONTRACTL @@ -3737,10 +3609,10 @@ VOID ClassLoader::AddAvailableClassHaveLock( EEClassHashTable *pClassHash = pModule->GetAvailableClassHash(); EEClassHashTable *pClassCaseInsHash = pModule->GetAvailableClassCaseInsHash(); + EEClassHashEntry_t * insertedEntry = NULL; LPCUTF8 pszName; LPCUTF8 pszNameSpace; - HashDatum ThrowawayData; IMDInternalImport *pMDImport = pModule->GetMDImport(); if (FAILED(pMDImport->GetNameOfTypeDef(classdef, &pszName, &pszNameSpace))) { @@ -3748,101 +3620,45 @@ VOID ClassLoader::AddAvailableClassHaveLock( pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN); } - EEClassHashEntry_t *pBucket; mdTypeDef enclosing; + EEClassHashEntry_t *pEncloser = NULL; if (SUCCEEDED(pMDImport->GetNestedClassProps(classdef, &enclosing))) { // nested type - LPCUTF8 pszEnclosingName; - LPCUTF8 pszEnclosingNameSpace; - mdTypeDef enclEnclosing; - - // Find this type's encloser's entry in the available table. - // We'll save a pointer to it in the new hash entry for this type. - BOOL fNestedEncl = SUCCEEDED(pMDImport->GetNestedClassProps(enclosing, &enclEnclosing)); - - EEClassHashTable::LookupContext sContext; - if (FAILED(pMDImport->GetNameOfTypeDef(enclosing, &pszEnclosingName, &pszEnclosingNameSpace))) + COUNT_T classEntryIndex = RidFromToken(enclosing) - 1; + _ASSERTE(RidFromToken(enclosing) < RidFromToken(classdef)); + if (classEntries != NULL && classEntries->GetCount() > classEntryIndex) { - pszName = pszNameSpace = "Invalid TypeDef token"; - pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN); + pEncloser = (*classEntries)[classEntryIndex]; } - if ((pBucket = pClassHash->GetValue(pszEnclosingNameSpace, - pszEnclosingName, - &ThrowawayData, - fNestedEncl, - &sContext)) != NULL) { - if (fNestedEncl) { - // Find entry for enclosing class - NOTE, this assumes that the - // enclosing class's TypeDef or ExportedType was inserted previously, - // which assumes that, when enuming TD's, we get the enclosing class first - while ((!CompareNestedEntryWithTypeDef(pMDImport, - enclEnclosing, - pClassHash, - pBucket->GetEncloser())) && - (pBucket = pClassHash->FindNextNestedClass(pszEnclosingNameSpace, - pszEnclosingName, - &ThrowawayData, - &sContext)) != NULL); + else + { + LPCUTF8 pszEnclosingName; + LPCUTF8 pszEnclosingNameSpace; + if (FAILED(pMDImport->GetNameOfTypeDef(enclosing, &pszEnclosingName, &pszEnclosingNameSpace))) + { + pszName = pszNameSpace = "Invalid TypeDef token"; + pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN); } + NameHandle nameHandleEncloser(pModule, enclosing); + nameHandleEncloser.SetName(pszEnclosingNameSpace, pszEnclosingName); - if (!pBucket) // Enclosing type not found in hash table - pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_ENCLOSING_TYPE_NOT_FOUND); - - // In this hash table, if the lower bit is set, it means a Module, otherwise it means EEClass* - ThrowawayData = EEClassHashTable::CompressClassDef(classdef); - InsertValue(pClassHash, pClassCaseInsHash, pszNameSpace, pszName, ThrowawayData, pBucket, pamTracker); + pEncloser = pClassHash->FindByNameHandle(&nameHandleEncloser); } - } - else { - // Don't add duplicate top-level classes. Top-level classes are - // added to the beginning of the bucket, while nested classes are - // added to the end. So, a duplicate top-level class could hide - // the previous type's EEClass* entry in the hash table. - EEClassHashEntry_t *pCaseInsEntry = NULL; - LPUTF8 pszLowerCaseNS = NULL; - LPUTF8 pszLowerCaseName = NULL; - - if (pClassCaseInsHash) { - CreateCanonicallyCasedKey(pszNameSpace, pszName, &pszLowerCaseNS, &pszLowerCaseName); - pCaseInsEntry = pClassCaseInsHash->AllocNewEntry(pamTracker); - } - - EEClassHashEntry_t *pEntry = pClassHash->FindItem(pszNameSpace, pszName, FALSE, NULL); - if (pEntry) { - HashDatum Data = pEntry->GetData(); - if (((size_t)Data & EECLASSHASH_TYPEHANDLE_DISCR) && - ((size_t)Data & EECLASSHASH_MDEXPORT_DISCR)) { - - // it's an ExportedType - check the 'already seen' bit and if on, report a class loading exception - // otherwise, set it - if ((size_t)Data & EECLASSHASH_ALREADYSEEN) - pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_MULT_TYPE_SAME_NAME); - else { - Data = (HashDatum)((size_t)Data | EECLASSHASH_ALREADYSEEN); - pEntry->SetData(Data); - } - } - else { - // We want to throw an exception for a duplicate typedef. - // However, this used to be allowed in 1.0/1.1, and some third-party DLLs have - // been obfuscated so that they have duplicate private typedefs. - // We must allow this for old assemblies for app compat reasons - pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_MULT_TYPE_SAME_NAME); - } + if (pEncloser == NULL) + { + pModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_ENCLOSING_TYPE_NOT_FOUND); } - else { - pEntry = pClassHash->AllocNewEntry(pamTracker); - - CANNOTTHROWCOMPLUSEXCEPTION(); - FAULT_FORBID(); - - pClassHash->InsertValueUsingPreallocatedEntry(pEntry, pszNameSpace, pszName, EEClassHashTable::CompressClassDef(classdef), NULL); + } + insertedEntry = InsertValue(pClassHash, pClassCaseInsHash, pszNameSpace, pszName, EEClassHashTable::CompressClassDef(classdef), pEncloser, pamTracker); - if (pClassCaseInsHash) - pClassCaseInsHash->InsertValueUsingPreallocatedEntry(pCaseInsEntry, pszLowerCaseNS, pszLowerCaseName, pEntry, pEntry->GetEncloser()); - } + _ASSERTE(insertedEntry != NULL); + if (classEntries != NULL) + { + COUNT_T classEntryIndex = RidFromToken(classdef) - 1; + _ASSERTE(classEntryIndex < classEntries->GetCount()); + (*classEntries)[classEntryIndex] = insertedEntry; } } @@ -3865,11 +3681,13 @@ VOID ClassLoader::AddExportedTypeDontHaveLock(Module *pManifestModule, AddExportedTypeHaveLock( pManifestModule, cl, + NULL, pamTracker); } VOID ClassLoader::AddExportedTypeHaveLock(Module *pManifestModule, mdExportedType cl, + SArray* exportedEntries, AllocMemTracker *pamTracker) { CONTRACTL @@ -3882,6 +3700,10 @@ VOID ClassLoader::AddExportedTypeHaveLock(Module *pManifestModule, } CONTRACTL_END + EEClassHashTable *pClassHash = pManifestModule->GetAvailableClassHash(); + EEClassHashTable *pClassCaseInsHash = pManifestModule->GetAvailableClassCaseInsHash(); + EEClassHashEntry_t * insertedEntry = NULL; + EEClassHashEntry_t *pEncloser = NULL; mdToken mdImpl; LPCSTR pszName; @@ -3898,92 +3720,55 @@ VOID ClassLoader::AddExportedTypeHaveLock(Module *pManifestModule, pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN); } - HashDatum ThrowawayData; - if (TypeFromToken(mdImpl) == mdtExportedType) { - // nested class - LPCUTF8 pszEnclosingNameSpace; - LPCUTF8 pszEnclosingName; - mdToken nextImpl; - if (FAILED(pAsmImport->GetExportedTypeProps( - mdImpl, - &pszEnclosingNameSpace, - &pszEnclosingName, - &nextImpl, - NULL, // type def - NULL))) // flags + COUNT_T exportedEntryIndex = RidFromToken(mdImpl) - 1; + _ASSERTE(RidFromToken(mdImpl) < RidFromToken(cl)); + if (exportedEntries != NULL && exportedEntries->GetCount() > exportedEntryIndex) { - pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN); + pEncloser = (*exportedEntries)[exportedEntryIndex]; } + else + { + // nested class + LPCUTF8 pszEnclosingNameSpace; + LPCUTF8 pszEnclosingName; + mdToken nextImpl; + if (FAILED(pAsmImport->GetExportedTypeProps( + mdImpl, + &pszEnclosingNameSpace, + &pszEnclosingName, + &nextImpl, + NULL, // type def + NULL))) // flags + { + pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN); + } - // Find entry for enclosing class - NOTE, this assumes that the - // enclosing class's ExportedType was inserted previously, which assumes that, - // when enuming ExportedTypes, we get the enclosing class first - EEClassHashEntry_t *pBucket; - EEClassHashTable::LookupContext sContext; - if ((pBucket = pManifestModule->GetAvailableClassHash()->GetValue(pszEnclosingNameSpace, - pszEnclosingName, - &ThrowawayData, - TypeFromToken(nextImpl) == mdtExportedType, - &sContext)) != NULL) { - do { - // check to see if this is the correct class - if (EEClassHashTable::UncompressModuleAndClassDef(ThrowawayData) == mdImpl) { - ThrowawayData = EEClassHashTable::CompressClassDef(cl); - - // we explicitly don't check for the case insensitive hash table because we know it can't have been created yet - pManifestModule->GetAvailableClassHash()->InsertValue(pszNameSpace, pszName, ThrowawayData, pBucket, pamTracker); - } - pBucket = pManifestModule->GetAvailableClassHash()->FindNextNestedClass(pszEnclosingNameSpace, pszEnclosingName, &ThrowawayData, &sContext); - } while (pBucket); + NameHandle nameHandleEncloser(pManifestModule, mdImpl); + nameHandleEncloser.SetName(pszEnclosingNameSpace, pszEnclosingName); + pEncloser = pClassHash->FindByNameHandle(&nameHandleEncloser); } - // If the encloser is not in the hash table, this nested class - // was defined in the manifest module, so it doesn't need to be added - return; + if (pEncloser == NULL) + { + // This can happen if the enclosing type was defined in the manifest module, and was instead added by TypeDef instead. + return; + } } else { // Defined in the manifest module - add to the hash table by TypeDef instead if (mdImpl == mdFileNil) return; + } - // Don't add duplicate top-level classes - // In this hash table, if the lower bit is set, it means a Module, otherwise it means EEClass* - ThrowawayData = EEClassHashTable::CompressClassDef(cl); - // ThrowawayData is an IN OUT param. Going in its the pointer to the new value if the entry needs - // to be inserted. The OUT param points to the value stored in the hash table. - BOOL bFound; - pManifestModule->GetAvailableClassHash()->InsertValueIfNotFound(pszNameSpace, pszName, &ThrowawayData, NULL, FALSE, &bFound, pamTracker); - if (bFound) { - - // Check for duplicate ExportedTypes - // Let it slide if it's pointing to the same type - mdToken foundTypeImpl; - if ((size_t)ThrowawayData & EECLASSHASH_MDEXPORT_DISCR) - { - mdExportedType foundExportedType = EEClassHashTable::UncompressModuleAndClassDef(ThrowawayData); - if (FAILED(pAsmImport->GetExportedTypeProps( - foundExportedType, - NULL, // namespace - NULL, // name - &foundTypeImpl, - NULL, // TypeDef - NULL))) // flags - { - pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_INVALID_TOKEN); - } - } - else - { - foundTypeImpl = mdFileNil; - } - - if (mdImpl != foundTypeImpl) - { - pManifestModule->GetAssembly()->ThrowBadImageException(pszNameSpace, pszName, BFA_MULT_TYPE_SAME_NAME); - } - } + insertedEntry = InsertValue(pClassHash, pClassCaseInsHash, pszNameSpace, pszName, EEClassHashTable::CompressClassDef(cl), pEncloser, pamTracker); + _ASSERTE(insertedEntry != NULL); + if (exportedEntries != NULL) + { + COUNT_T exportedEntryIndex = RidFromToken(cl) - 1; + _ASSERTE(exportedEntryIndex < exportedEntries->GetCount()); + (*exportedEntries)[exportedEntryIndex] = insertedEntry; } } diff --git a/src/coreclr/vm/clsload.hpp b/src/coreclr/vm/clsload.hpp index fd2aabe3801ed1..a2387f0348922e 100644 --- a/src/coreclr/vm/clsload.hpp +++ b/src/coreclr/vm/clsload.hpp @@ -59,7 +59,7 @@ class HashedTypeEntry IsNullEntry, // Uninitialized HashedTypeEntry IsHashedTokenEntry, // Entry is a token value in a R2R hashtable in from the R2R module IsHashedClassEntry // Entry is a EEClassHashEntry_t from the hashtable constructed at - // module load time (or from the hashtable loaded from the native image) + // module load time } EntryType; typedef struct @@ -83,15 +83,15 @@ class HashedTypeEntry EntryType GetEntryType() const { return m_EntryType; } bool IsNull() const { return m_EntryType == EntryType::IsNullEntry; } - const HashedTypeEntry& SetClassHashBasedEntryValue(EEClassHashEntry_t * pClassHashEntry) + const HashedTypeEntry& SetClassHashBasedEntryValue(PTR_EEClassHashEntry pClassHashEntry) { LIMITED_METHOD_CONTRACT; m_EntryType = EntryType::IsHashedClassEntry; - m_pClassHashEntry = dac_cast(pClassHashEntry); + m_pClassHashEntry = pClassHashEntry; return *this; } - EEClassHashEntry_t * GetClassHashBasedEntryValue() const + PTR_EEClassHashEntry GetClassHashBasedEntryValue() const { LIMITED_METHOD_CONTRACT; @@ -138,18 +138,6 @@ class NameHandle memset((void*) this, NULL, sizeof(*this)); } - NameHandle(LPCUTF8 name) : - m_nameSpace(NULL), - m_name(name), - m_pTypeScope(PTR_NULL), - m_mdType(mdTokenNil), - m_mdTokenNotToLoad(tdNoTypes), - m_WhichTable(nhCaseSensitive), - m_Bucket() - { - LIMITED_METHOD_CONTRACT; - } - NameHandle(LPCUTF8 nameSpace, LPCUTF8 name) : m_nameSpace(nameSpace), m_name(name), @@ -161,6 +149,8 @@ class NameHandle { LIMITED_METHOD_CONTRACT; SUPPORTS_DAC; + _ASSERTE(nameSpace != NULL); + _ASSERTE(name != NULL); } NameHandle(ModuleBase* pModule, mdToken token); @@ -180,17 +170,13 @@ class NameHandle m_Bucket = p.m_Bucket; } - void SetName(LPCUTF8 pName) - { - LIMITED_METHOD_CONTRACT; - m_name = pName; - } - void SetName(LPCUTF8 pNameSpace, LPCUTF8 pName) { LIMITED_METHOD_CONTRACT; SUPPORTS_DAC_HOST_ONLY; + _ASSERTE(pNameSpace != NULL); + _ASSERTE(pName != NULL); m_nameSpace = pNameSpace; m_name = pName; } @@ -748,6 +734,11 @@ class ClassLoader TypeHandle LoadTypeHandleThrowIfFailed(NameHandle* pName, ClassLoadLevel level = CLASS_LOADED, Module* pLookInThisModuleOnly=NULL); + mdTypeDef LookupTypeDefTokenThatMatchesTypeRef(mdTypeRef typeRef); + mdTypeDef LookupTypeDefTokenThatMatchesToken(IMDInternalImport* pMDImportTokenLookup, mdToken token); +private: + mdTypeDef LookupTypeDefTokenThatMatchesTokenHelper(IMDInternalImport* pMDImportTokenLookup, mdToken token, NameHandle *pName); + public: // Looks up class in the local module table, if it is there it succeeds, // Otherwise it fails, This is meant only for optimizations etc @@ -761,6 +752,7 @@ class ClassLoader VOID AddAvailableClassHaveLock(Module * pModule, mdTypeDef classdef, + SArray* classEntries, AllocMemTracker * pamTracker); VOID AddExportedTypeDontHaveLock(Module *pManifestModule, @@ -769,6 +761,7 @@ class ClassLoader VOID AddExportedTypeHaveLock(Module *pManifestModule, mdExportedType cl, + SArray* exportedEntries, AllocMemTracker *pamTracker); public: @@ -876,7 +869,7 @@ class ClassLoader static HRESULT FindTypeDefByExportedType(IMDInternalImport *pCTImport, mdExportedType mdCurrent, - IMDInternalImport *pTDImport, + Module *pTDModule, mdTypeDef *mtd); class AvailableClasses_LockHolder : public CrstHolder diff --git a/src/coreclr/vm/dacenumerablehash.h b/src/coreclr/vm/dacenumerablehash.h index 1da48cfdeba533..8f5108b8528321 100644 --- a/src/coreclr/vm/dacenumerablehash.h +++ b/src/coreclr/vm/dacenumerablehash.h @@ -273,6 +273,8 @@ class DacEnumerableHashTable DPTR(VALUE) BaseFindFirstEntryByHash(DacEnumerableHashValue iHash, LookupContext *pContext); DPTR(VALUE) BaseFindNextEntryByHash(LookupContext *pContext); + static DacEnumerableHashValue BaseValuePtrToHash(DPTR(VALUE) pValue); + PTR_Module GetModule() { return m_pModule; diff --git a/src/coreclr/vm/dacenumerablehash.inl b/src/coreclr/vm/dacenumerablehash.inl index 6f78c53955c839..a6083e26fda4ea 100644 --- a/src/coreclr/vm/dacenumerablehash.inl +++ b/src/coreclr/vm/dacenumerablehash.inl @@ -14,6 +14,7 @@ // doing this in a DAC-friendly fashion involves some DAC gymnastics. The following couple of macros factor // those complexities out. #define VALUE_FROM_VOLATILE_ENTRY(_ptr) dac_cast(PTR_TO_MEMBER_TADDR(VolatileEntry, (_ptr), m_sValue)) +#define VALUE_TO_VOLATILE_ENTRY(_ptr) dac_cast(dac_cast(_ptr)) #ifndef DACCESS_COMPILE @@ -591,3 +592,12 @@ DPTR(VALUE) DacEnumerableHashTable::BaseIterator::Next() return NULL; } + +template +/*static*/ DacEnumerableHashValue DacEnumerableHashTable::BaseValuePtrToHash(DPTR(VALUE) pValue) +{ +#ifndef DACCESS_COMPILE + _ASSERTE(offsetof(VolatileEntry, m_sValue) == 0); +#endif + return VALUE_TO_VOLATILE_ENTRY(pValue)->m_iHashValue; +} diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 44ddcf546064bb..b382887513c2bc 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -2564,23 +2564,8 @@ HRESULT MethodTableBuilder::FindMethodDeclarationForMethodImpl( if (TypeFromToken(typeref) == mdtTypeRef) { // We only get here when we know the token does not reference a type in a different scope. - LPCUTF8 pszNameSpace; - LPCUTF8 pszClassName; - - if (FAILED(pMDInternalImport->GetNameOfTypeRef(typeref, &pszNameSpace, &pszClassName))) - { - IfFailRet(COR_E_TYPELOAD); - } - mdToken tkRes; - if (FAILED(pMDInternalImport->GetResolutionScopeOfTypeRef(typeref, &tkRes))) - { - IfFailRet(COR_E_TYPELOAD); - } - hr = pMDInternalImport->FindTypeDef(pszNameSpace, - pszClassName, - (TypeFromToken(tkRes) == mdtTypeRef) ? tkRes : mdTokenNil, - &tkDef); - if (FAILED(hr)) + tkDef = GetModule()->GetClassLoader()->LookupTypeDefTokenThatMatchesTypeRef(typeref); + if (tkDef == mdTypeDefNil) { IfFailRet(COR_E_TYPELOAD); } @@ -4047,45 +4032,7 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, if (TypeFromToken(dwByValueClassToken) == mdtTypeRef) { // It's a typeref - check if it's a class that has a static field of itself - LPCUTF8 pszNameSpace; - LPCUTF8 pszClassName; - if (FAILED(pInternalImport->GetNameOfTypeRef(dwByValueClassToken, &pszNameSpace, &pszClassName))) - { - BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT); - } - - if (IsStrLongerThan((char *)pszClassName, MAX_CLASS_NAME) - || IsStrLongerThan((char *)pszNameSpace, MAX_CLASS_NAME) - || (strlen(pszClassName) + strlen(pszNameSpace) + 1 >= MAX_CLASS_NAME)) - { - BuildMethodTableThrowException(BFA_TYPEREG_NAME_TOO_LONG, mdMethodDefNil); - } - - mdToken tkRes; - if (FAILED(pInternalImport->GetResolutionScopeOfTypeRef(dwByValueClassToken, &tkRes))) - { - BuildMethodTableThrowException(BFA_BAD_TYPEREF_TOKEN, dwByValueClassToken); - } - - if (TypeFromToken(tkRes) == mdtTypeRef) - { - if (!pInternalImport->IsValidToken(tkRes)) - { - BuildMethodTableThrowException(BFA_BAD_TYPEREF_TOKEN, mdMethodDefNil); - } - } - else - { - tkRes = mdTokenNil; - } - - if (FAILED(pInternalImport->FindTypeDef(pszNameSpace, - pszClassName, - tkRes, - &dwByValueClassToken))) - { - dwByValueClassToken = mdTokenNil; - } + dwByValueClassToken = GetModule()->GetClassLoader()->LookupTypeDefTokenThatMatchesTypeRef(dwByValueClassToken); } // If field is static typeref BOOL selfref = IsSelfReferencingStaticValueTypeField(dwByValueClassToken, diff --git a/src/coreclr/vm/readytoruninfo.cpp b/src/coreclr/vm/readytoruninfo.cpp index e75373db8855aa..40ffa8e7d0eaca 100644 --- a/src/coreclr/vm/readytoruninfo.cpp +++ b/src/coreclr/vm/readytoruninfo.cpp @@ -94,42 +94,21 @@ BOOL ReadyToRunInfo::TryLookupTypeTokenFromName(const NameHandle *pName, mdToken LPCUTF8 pszName = NULL; LPCUTF8 pszNameSpace = NULL; - // Reserve stack space for parsing out the namespace in a name-based lookup - // at this scope so the stack space is in scope for all usages in this method. - CQuickBytes namespaceBuffer; // // Compute the hashcode of the type (hashcode based on type name and namespace name) // int dwHashCode = 0; + _ASSERTE(pName->GetName() != NULL); + _ASSERTE(pName->GetNameSpace() != NULL); + if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL) { // Name-based lookups (ex: Type.GetType()). pszName = pName->GetName(); - pszNameSpace = ""; - if (pName->GetNameSpace() != NULL) - { - pszNameSpace = pName->GetNameSpace(); - } - else - { - LPCUTF8 p; - - if ((p = ns::FindSep(pszName)) != NULL) - { - SIZE_T d = p - pszName; - - FAULT_NOT_FATAL(); - pszNameSpace = namespaceBuffer.SetStringNoThrow(pszName, d); - - if (pszNameSpace == NULL) - return FALSE; - - pszName = (p + 1); - } - } + pszNameSpace = pName->GetNameSpace(); _ASSERT(pszNameSpace != NULL); dwHashCode ^= ComputeNameHashCode(pszNameSpace, pszName);