Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,7 @@ internal ref struct ThreadStaticsInfo
internal unsafe struct MethodTableAuxiliaryData
{
private uint Flags;
private int CachedVersionResilientHashCode;
private void* LoaderModule;
private nint ExposedClassObjectRaw;

Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/vm/methodtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,11 @@ struct MethodTableAuxiliaryData
};
};

// Lazily initialized cache for the version-resilient hash code of this MethodTable.
// A stored value of 0 indicates the field hasn't been set yet.
// Placed here to fill the 4-byte alignment padding between m_dwFlags and m_pLoaderModule,
// so this field adds no extra size to the struct on 64-bit platforms.
int m_cachedVersionResilientHashCode;

PTR_Module m_pLoaderModule;
Comment thread
jkotas marked this conversation as resolved.

Expand Down
52 changes: 33 additions & 19 deletions src/coreclr/vm/versionresilienthashcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,38 +110,52 @@ int GetVersionResilientTypeHashCode(TypeHandle type)
{
STANDARD_VM_CONTRACT;

if (type.IsArray())
{
return ComputeArrayTypeHashCode(GetVersionResilientTypeHashCode(type.GetArrayElementTypeHandle()), type.GetRank());
}
else
if (!type.IsTypeDesc())
{
MethodTable *pMT = type.AsMethodTable();

_ASSERTE(!pMT->IsArray());
_ASSERTE(!IsNilToken(pMT->GetCl()));

LPCUTF8 szNamespace;
LPCUTF8 szName;
IfFailThrow(pMT->GetMDImport()->GetNameOfTypeDef(pMT->GetCl(), &szName, &szNamespace));
int hashcode = ComputeNameHashCode(szNamespace, szName);
_ASSERTE(pMT->IsArray() || !IsNilToken(pMT->GetCl()));

MethodTable *pMTEnclosing = pMT->LoadEnclosingMethodTable(CLASS_LOAD_APPROXPARENTS);
if (pMTEnclosing != NULL)
int cachedHashCode = VolatileLoadWithoutBarrier(&pMT->GetAuxiliaryData()->m_cachedVersionResilientHashCode);
if (cachedHashCode != 0)
{
hashcode = ComputeNestedTypeHashCode(GetVersionResilientTypeHashCode(TypeHandle(pMTEnclosing)), hashcode);
return cachedHashCode;
}

if (!pMT->IsGenericTypeDefinition() && pMT->HasInstantiation())
int hashcode;
if (pMT->IsArray())
{
return ComputeGenericInstanceHashCode(hashcode,
pMT->GetInstantiation().GetNumArgs(), pMT->GetInstantiation(), GetVersionResilientTypeHashCode);
hashcode = ComputeArrayTypeHashCode(GetVersionResilientTypeHashCode(type.GetArrayElementTypeHandle()), type.GetRank());
}
else
{
return hashcode;
LPCUTF8 szNamespace;
LPCUTF8 szName;
IfFailThrow(pMT->GetMDImport()->GetNameOfTypeDef(pMT->GetCl(), &szName, &szNamespace));
hashcode = ComputeNameHashCode(szNamespace, szName);

MethodTable *pMTEnclosing = pMT->LoadEnclosingMethodTable(CLASS_LOAD_APPROXPARENTS);
if (pMTEnclosing != NULL)
{
hashcode = ComputeNestedTypeHashCode(GetVersionResilientTypeHashCode(TypeHandle(pMTEnclosing)), hashcode);
}

if (!pMT->IsGenericTypeDefinition() && pMT->HasInstantiation())
{
hashcode = ComputeGenericInstanceHashCode(hashcode,
pMT->GetInstantiation().GetNumArgs(), pMT->GetInstantiation(), GetVersionResilientTypeHashCode);
}
}

// 0 is used as the sentinel "not yet cached" value, so only cache if non-zero.
// Types with a hash code of exactly 0 are extremely rare in practice; they will simply
// have their hash code recomputed on every call, which is still correct behavior.
if (hashcode != 0)
Comment thread
jkotas marked this conversation as resolved.
{
VolatileStore(&pMT->GetAuxiliaryDataForWrite()->m_cachedVersionResilientHashCode, hashcode);
}
Comment thread
jkotas marked this conversation as resolved.

return hashcode;
}
else
if (type.IsPointer())
Expand Down
Loading