Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 73 additions & 19 deletions src/coreclr/vm/classhash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ PTR_VOID EEClassHashEntry::GetData()
return m_Data;
}

DWORD EEClassHashEntry::GetHash()
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
SUPPORTS_DAC;
}
CONTRACTL_END;

return m_hash;
}

#ifndef DACCESS_COMPILE
void EEClassHashEntry::SetData(void *data)
{
Expand Down Expand Up @@ -67,6 +81,20 @@ void EEClassHashEntry::SetEncloser(EEClassHashEntry *pEncloser)
m_pEncloser = pEncloser;
}

void EEClassHashEntry::SetHash(DWORD hash)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;

m_hash = hash;
}


/*static*/
EEClassHashTable *EEClassHashTable::Create(Module *pModule, DWORD dwNumBuckets, BOOL bCaseInsensitive, AllocMemTracker *pamTracker)
{
Expand Down Expand Up @@ -311,6 +339,11 @@ VOID EEClassHashTable::ConstructKeyFromData(PTR_EEClassHashEntry pEntry, // IN

}

// the case-insensitive table refers to the same enclosers as the case-sensitive table.
// thus it cannot use enclosers` hashes, since encloser's case is not canonical.
// for simplicity we will just use the same encloser hash for all nested types in case-insensitive case.
#define CASE_INSENSITIVE_ENCLOSER_HASH (12345)

#ifndef DACCESS_COMPILE

EEClassHashEntry_t *EEClassHashTable::InsertValue(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID Data, EEClassHashEntry_t *pEncloser, AllocMemTracker *pamTracker)
Expand Down Expand Up @@ -339,7 +372,14 @@ EEClassHashEntry_t *EEClassHashTable::InsertValue(LPCUTF8 pszNamespace, LPCUTF8
pEntry->DebugKey[1] = pszClassName;
#endif

BaseInsertEntry(Hash(pszNamespace, pszClassName), pEntry);
DWORD encloserHash = 0;
if (pEncloser != NULL)
{
encloserHash = m_bCaseInsensitive ? CASE_INSENSITIVE_ENCLOSER_HASH : pEncloser->GetHash();
}

pEntry->SetHash(Hash(pszNamespace, pszClassName, encloserHash));
BaseInsertEntry(pEntry->GetHash(), pEntry);

return pEntry;
}
Expand Down Expand Up @@ -388,12 +428,19 @@ EEClassHashEntry_t *EEClassHashTable::InsertValueUsingPreallocatedEntry(EEClassH
pNewEntry->DebugKey[1] = pszClassName;
#endif

BaseInsertEntry(Hash(pszNamespace, pszClassName), pNewEntry);
DWORD encloserHash = 0;
if (pEncloser != NULL)
{
encloserHash = m_bCaseInsensitive ? CASE_INSENSITIVE_ENCLOSER_HASH : pEncloser->m_hash;
}

pNewEntry->SetHash(Hash(pszNamespace, pszClassName, encloserHash));
BaseInsertEntry(pNewEntry->GetHash(), pNewEntry);

return pNewEntry;
}

EEClassHashEntry_t *EEClassHashTable::InsertValueIfNotFound(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, EEClassHashEntry_t *pEncloser, BOOL IsNested, BOOL *pbFound, AllocMemTracker *pamTracker)
EEClassHashEntry_t *EEClassHashTable::InsertTopLevelValueIfNotFound(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, BOOL *pbFound, AllocMemTracker *pamTracker)
{
CONTRACTL
{
Expand All @@ -410,7 +457,7 @@ EEClassHashEntry_t *EEClassHashTable::InsertValueIfNotFound(LPCUTF8 pszNamespace
_ASSERTE(pszNamespace != NULL);
_ASSERTE(pszClassName != NULL);

EEClassHashEntry_t * pNewEntry = FindItem(pszNamespace, pszClassName, IsNested, NULL);
EEClassHashEntry_t * pNewEntry = FindItem(pszNamespace, pszClassName, /*encloserHash*/ 0, /*pContext*/ NULL);

if (pNewEntry)
{
Expand All @@ -423,23 +470,22 @@ EEClassHashEntry_t *EEClassHashTable::InsertValueIfNotFound(LPCUTF8 pszNamespace
*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);
pNewEntry->SetHash(Hash(pszNamespace, pszClassName, /*encloserHash*/ 0));
BaseInsertEntry(pNewEntry->GetHash(), pNewEntry);

return pNewEntry;
}

#endif // !DACCESS_COMPILE

EEClassHashEntry_t *EEClassHashTable::FindItem(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, BOOL IsNested, LookupContext *pContext)
EEClassHashEntry_t *EEClassHashTable::FindItem(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, DWORD encloserHash, LookupContext *pContext)
{
CONTRACTL
{
Expand All @@ -464,9 +510,17 @@ EEClassHashEntry_t *EEClassHashTable::FindItem(LPCUTF8 pszNamespace, LPCUTF8 psz
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);
// further check which of these entries actually match the full key

if (encloserHash && m_bCaseInsensitive)
{
encloserHash = CASE_INSENSITIVE_ENCLOSER_HASH;
}

DWORD hash = Hash(pszNamespace, pszClassName, encloserHash);
PTR_EEClassHashEntry pSearch = BaseFindFirstEntryByHash(hash, pContext);

_ASSERTE(pSearch == NULL || pSearch->GetHash() == hash);

while (pSearch)
{
Expand All @@ -476,7 +530,7 @@ EEClassHashEntry_t *EEClassHashTable::FindItem(LPCUTF8 pszNamespace, LPCUTF8 psz
{
// 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))
if ((encloserHash != 0) == (pSearch->GetEncloser() != NULL))
{
if (m_bCaseInsensitive)
g_IBCLogger.LogClassHashTableAccess(dac_cast<PTR_EEClassHashEntry>(pSearch->GetData()));
Expand Down Expand Up @@ -599,7 +653,7 @@ EEClassHashEntry_t *EEClassHashTable::FindNextNestedClass(LPCUTF8 pszFullyQualif
}


EEClassHashEntry_t * EEClassHashTable::GetValue(LPCUTF8 pszFullyQualifiedName, PTR_VOID *pData, BOOL IsNested, LookupContext *pContext)
EEClassHashEntry_t * EEClassHashTable::GetValue(LPCUTF8 pszFullyQualifiedName, PTR_VOID *pData, DWORD encloserHash, LookupContext *pContext)
{
CONTRACTL
{
Expand Down Expand Up @@ -638,13 +692,13 @@ EEClassHashEntry_t * EEClassHashTable::GetValue(LPCUTF8 pszFullyQualifiedName, P
p = pszFullyQualifiedName;
}

EEClassHashEntry_t * ret = GetValue(pNamespace, p, pData, IsNested, pContext);
EEClassHashEntry_t * ret = GetValue(pNamespace, p, pData, encloserHash, pContext);

return ret;
}


EEClassHashEntry_t * EEClassHashTable::GetValue(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, BOOL IsNested, LookupContext *pContext)
EEClassHashEntry_t * EEClassHashTable::GetValue(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, DWORD encloserHash, LookupContext *pContext)
{
CONTRACTL
{
Expand All @@ -658,15 +712,15 @@ EEClassHashEntry_t * EEClassHashTable::GetValue(LPCUTF8 pszNamespace, LPCUTF8 ps


_ASSERTE(m_pModule != NULL);
EEClassHashEntry_t *pItem = FindItem(pszNamespace, pszClassName, IsNested, pContext);
EEClassHashEntry_t *pItem = FindItem(pszNamespace, pszClassName, encloserHash, pContext);
if (pItem)
*pData = pItem->GetData();

return pItem;
}


EEClassHashEntry_t * EEClassHashTable::GetValue(const NameHandle* pName, PTR_VOID *pData, BOOL IsNested, LookupContext *pContext)
EEClassHashEntry_t * EEClassHashTable::GetValue(const NameHandle* pName, PTR_VOID *pData, DWORD encloserHash, LookupContext *pContext)
{
CONTRACTL
{
Expand All @@ -683,10 +737,10 @@ EEClassHashEntry_t * EEClassHashTable::GetValue(const NameHandle* pName, PTR_VOI
_ASSERTE(pName);
_ASSERTE(m_pModule != NULL);
if(pName->GetNameSpace() == NULL) {
return GetValue(pName->GetName(), pData, IsNested, pContext);
return GetValue(pName->GetName(), pData, encloserHash, pContext);
}
else {
return GetValue(pName->GetNameSpace(), pName->GetName(), pData, IsNested, pContext);
return GetValue(pName->GetNameSpace(), pName->GetName(), pData, encloserHash, pContext);
}
}

Expand Down
23 changes: 15 additions & 8 deletions src/coreclr/vm/classhash.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,18 @@ typedef struct EEClassHashEntry
PTR_VOID GetData();
void SetData(PTR_VOID data) DAC_EMPTY();

DWORD GetHash();
void SetHash(DWORD hash) DAC_EMPTY();

private:
PTR_VOID m_Data; // Either the token (if EECLASSHASH_TYPEHANDLE_DISCR), or the type handle encoded
// as a relative pointer

PTR_EEClassHashEntry m_pEncloser; // If this entry is a for a nested
// class, this field stores a
// reference to the enclosing type
// (which must be in this same
// hash).
// (which must be in this same table).
DWORD m_hash;
} EEClassHashEntry_t;

// The hash type itself. All common logic is provided by the DacEnumerableHashTable templated base class. See
Expand All @@ -67,21 +70,25 @@ class EEClassHashTable : public DacEnumerableHashTable<EEClassHashTable, EEClass
// 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 *InsertTopLevelValueIfNotFound(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, 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 *GetValue(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, PTR_VOID *pData, DWORD encloserHash, LookupContext *pContext);
EEClassHashEntry_t *GetValue(LPCUTF8 pszFullyQualifiedName, PTR_VOID *pData, DWORD encloserHash, LookupContext *pContext);
EEClassHashEntry_t *GetValue(const NameHandle* pName, PTR_VOID *pData, DWORD encloserHash, LookupContext *pContext);
EEClassHashEntry_t *FindItem(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, DWORD encloserHash, 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);

BOOL CompareKeys(PTR_EEClassHashEntry pEntry, LPCUTF8 * pKey2);

static DWORD Hash(LPCUTF8 pszNamespace, LPCUTF8 pszClassName);
static DWORD Hash(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, DWORD encloserHash);
static DWORD Hash(IMDInternalImport* pMDImport, mdToken token);

class ConstructKeyCallback
{
Expand Down
84 changes: 82 additions & 2 deletions src/coreclr/vm/classhash.inl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ inline PTR_VOID EEClassHashTable::CompressClassDef(mdToken cl)
}
}

inline DWORD EEClassHashTable::Hash(LPCUTF8 pszNamespace, LPCUTF8 pszClassName)
static DWORD HashName(LPCUTF8 pszNamespace, LPCUTF8 pszClassName)
{
CONTRACTL
{
Expand All @@ -60,7 +60,87 @@ inline DWORD EEClassHashTable::Hash(LPCUTF8 pszNamespace, LPCUTF8 pszClassName)
while ((dwChar = *pszClassName++) != 0)
dwHash = ((dwHash << 5) + dwHash) ^ dwChar;

return dwHash;
// reseve 0 hash so that we could pass 0 in no-encloser case, 31 bit is still good for our needs
return dwHash | 1;
}

static DWORD Combine(DWORD hash, DWORD encloserHash)
{
LIMITED_METHOD_CONTRACT;

// NB: there are better ways to combine hashes, but here we need a commutative operator,
// since we are not always combining hashes starting from the innermost name
hash = hash ^ encloserHash;

// reseve 0 hash so that we could pass 0 in no-encloser case, 31 bit is still good for our needs
return hash | 1;
}

inline DWORD EEClassHashTable::Hash(LPCUTF8 pszNamespace, LPCUTF8 pszClassName, DWORD encloserHash)
{
LIMITED_METHOD_CONTRACT;

return Combine(HashName(pszNamespace, pszClassName), encloserHash);
}

// hashes the name specified by the token and names of all its containers
inline DWORD EEClassHashTable::Hash(IMDInternalImport* pMDImport, mdToken token)
{
CONTRACTL
{
THROWS;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END

_ASSERTE(TypeFromToken(token) == mdtTypeDef ||
TypeFromToken(token) == mdtTypeRef ||
TypeFromToken(token) == mdtExportedType);
_ASSERTE(!IsNilToken(token));

HRESULT hr;
LPCUTF8 szNamespace;
LPCUTF8 szName;
bool hasTypeToken = true;
DWORD hashcode = 0;

while (hasTypeToken)
{
if (IsNilToken(token))
return 0;

switch (TypeFromToken(token))
{
case mdtTypeDef:
IfFailThrow(pMDImport->GetNameOfTypeDef(token, &szName, &szNamespace));
hr = pMDImport->GetNestedClassProps(token, &token);
if (hr == CLDB_E_RECORD_NOTFOUND)
hasTypeToken = false;
else
IfFailThrow(hr);
break;

case mdtTypeRef:
IfFailThrow(pMDImport->GetNameOfTypeRef(token, &szNamespace, &szName));
IfFailThrow(pMDImport->GetResolutionScopeOfTypeRef(token, &token));
hasTypeToken = (TypeFromToken(token) == mdtTypeRef);
break;

case mdtExportedType:
IfFailThrow(pMDImport->GetExportedTypeProps(token, &szNamespace, &szName, &token, NULL, NULL));
hasTypeToken = (TypeFromToken(token) == mdtExportedType);
break;

default:
ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE);
}

DWORD nameHash = HashName(szNamespace, szName);
hashcode = Combine(nameHash, hashcode);
}

return hashcode;
}

#endif // CLASSHASH_INL
Loading