summaryrefslogtreecommitdiff
path: root/src/vm/typehash.cpp
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
committerdotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
commitef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch)
treedee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/vm/typehash.cpp
downloadcoreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/vm/typehash.cpp')
-rw-r--r--src/vm/typehash.cpp874
1 files changed, 874 insertions, 0 deletions
diff --git a/src/vm/typehash.cpp b/src/vm/typehash.cpp
new file mode 100644
index 0000000000..4c3b953dbe
--- /dev/null
+++ b/src/vm/typehash.cpp
@@ -0,0 +1,874 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+//
+// File: typehash.cpp
+//
+
+//
+
+#include "common.h"
+#include "excep.h"
+#include "typehash.h"
+#include "eeconfig.h"
+#include "generics.h"
+#include "typestring.h"
+#include "typedesc.h"
+#include "typekey.h"
+#ifdef FEATURE_PREJIT
+#include "zapsig.h"
+#include "compile.h"
+#endif
+#include "ngenhash.inl"
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4244)
+#endif // _MSC_VER
+
+#ifndef DACCESS_COMPILE
+
+// ============================================================================
+// Class hash table methods
+// ============================================================================
+/* static */
+EETypeHashTable *EETypeHashTable::Create(LoaderAllocator* pAllocator, Module *pModule, DWORD dwNumBuckets, AllocMemTracker *pamTracker)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END
+
+ LoaderHeap *pHeap = pAllocator->GetLowFrequencyHeap();
+ EETypeHashTable *pThis = (EETypeHashTable*)pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(EETypeHashTable)));
+
+ new (pThis) EETypeHashTable(pModule, pHeap, dwNumBuckets);
+
+#ifdef _DEBUG
+ pThis->InitUnseal();
+#endif
+
+ pThis->m_pAllocator = pAllocator;
+
+ return pThis;
+}
+
+LoaderAllocator *EETypeHashTable::GetLoaderAllocator()
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (m_pAllocator)
+ {
+ return m_pAllocator;
+ }
+ else
+ {
+ _ASSERTE(m_pModule != NULL);
+ return m_pModule->GetLoaderAllocator();
+ }
+}
+
+#endif // #ifdef DACCESS_COMPILE
+
+void EETypeHashTable::Iterator::Reset()
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (m_pTable)
+ {
+#ifdef _DEBUG
+ m_pTable->Unseal();
+#endif
+ m_pTable = NULL;
+ }
+
+ Init();
+}
+
+void EETypeHashTable::Iterator::Init()
+{
+ WRAPPER_NO_CONTRACT;
+
+#ifdef _DEBUG
+ if (m_pTable)
+ m_pTable->Seal(); // The table cannot be changing while it is being iterated
+#endif
+
+ m_fIterating = false;
+}
+
+EETypeHashTable::Iterator::Iterator()
+{
+ WRAPPER_NO_CONTRACT;
+ m_pTable = NULL;
+ Init();
+}
+
+EETypeHashTable::Iterator::Iterator(EETypeHashTable * pTable)
+{
+ WRAPPER_NO_CONTRACT;
+ m_pTable = pTable;
+ Init();
+}
+
+EETypeHashTable::Iterator::~Iterator()
+{
+ WRAPPER_NO_CONTRACT;
+
+#ifdef _DEBUG
+ if (m_pTable)
+ m_pTable->Unseal(); // Done with the iterator so we unseal
+#endif
+}
+
+BOOL EETypeHashTable::FindNext(Iterator *it, EETypeHashEntry **ppEntry)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ if (!it->m_fIterating)
+ {
+ BaseInitIterator(&it->m_sIterator);
+ it->m_fIterating = true;
+ }
+
+ *ppEntry = it->m_sIterator.Next();
+ return *ppEntry ? TRUE : FALSE;
+}
+
+DWORD EETypeHashTable::GetCount()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return BaseGetElementCount();
+}
+
+static DWORD HashTypeHandle(DWORD level, TypeHandle t);
+
+// Calculate hash value for a type def or instantiated type def
+static DWORD HashPossiblyInstantiatedType(DWORD level, mdTypeDef token, Instantiation inst)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(TypeFromToken(token) == mdtTypeDef);
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END
+
+ INT_PTR dwHash = 5381;
+
+ dwHash = ((dwHash << 5) + dwHash) ^ token;
+ if (!inst.IsEmpty())
+ {
+ dwHash = ((dwHash << 5) + dwHash) ^ inst.GetNumArgs();
+
+ // Hash two levels of the hiearchy. A simple nesting of generics instantiations is
+ // pretty common in generic collections, e.g.: ICollection<KeyValuePair<TKey, TValue>>
+ if (level < 2)
+ {
+ // Hash n type parameters
+ for (DWORD i = 0; i < inst.GetNumArgs(); i++)
+ {
+ dwHash = ((dwHash << 5) + dwHash) ^ HashTypeHandle(level+1, inst[i]);
+ }
+ }
+ }
+
+ return dwHash;
+}
+
+// Calculate hash value for a function pointer type
+static DWORD HashFnPtrType(DWORD level, BYTE callConv, DWORD numArgs, TypeHandle *retAndArgTypes)
+{
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+ INT_PTR dwHash = 5381;
+
+ dwHash = ((dwHash << 5) + dwHash) ^ ELEMENT_TYPE_FNPTR;
+ dwHash = ((dwHash << 5) + dwHash) ^ callConv;
+ dwHash = ((dwHash << 5) + dwHash) ^ numArgs;
+ if (level < 1)
+ {
+ for (DWORD i = 0; i <= numArgs; i++)
+ {
+ dwHash = ((dwHash << 5) + dwHash) ^ HashTypeHandle(level+1, retAndArgTypes[i]);
+ }
+ }
+
+ return dwHash;
+}
+
+// Calculate hash value for an array/pointer/byref type
+static DWORD HashParamType(DWORD level, CorElementType kind, TypeHandle typeParam)
+{
+ WRAPPER_NO_CONTRACT;
+ INT_PTR dwHash = 5381;
+
+ dwHash = ((dwHash << 5) + dwHash) ^ kind;
+ dwHash = ((dwHash << 5) + dwHash) ^ HashTypeHandle(level, typeParam);
+
+ return dwHash;
+}
+
+// Calculate hash value from type handle
+static DWORD HashTypeHandle(DWORD level, TypeHandle t)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SO_TOLERANT;
+ PRECONDITION(CheckPointer(t));
+ PRECONDITION(!t.IsEncodedFixup());
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+ DWORD retVal = 0;
+
+ INTERIOR_STACK_PROBE_NOTHROW_CHECK_THREAD(goto Exit;);
+
+ if (t.HasTypeParam())
+ {
+ retVal = HashParamType(level, t.GetInternalCorElementType(), t.GetTypeParam());
+ }
+ else if (t.IsGenericVariable())
+ {
+ retVal = (dac_cast<PTR_TypeVarTypeDesc>(t.AsTypeDesc())->GetToken());
+ }
+ else if (t.HasInstantiation())
+ {
+ retVal = HashPossiblyInstantiatedType(level, t.GetCl(), t.GetInstantiation());
+ }
+ else if (t.IsFnPtrType())
+ {
+ FnPtrTypeDesc* pTD = t.AsFnPtrType();
+ retVal = HashFnPtrType(level, pTD->GetCallConv(), pTD->GetNumArgs(), pTD->GetRetAndArgTypesPointer());
+ }
+ else
+ retVal = HashPossiblyInstantiatedType(level, t.GetCl(), Instantiation());
+
+#if defined(FEATURE_STACK_PROBE) && !defined(DACCESS_COMPILE)
+Exit:
+ ;
+#endif
+ END_INTERIOR_STACK_PROBE;
+
+ return retVal;
+}
+
+// Calculate hash value from key
+static DWORD HashTypeKey(TypeKey* pKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pKey));
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+ if (pKey->GetKind() == ELEMENT_TYPE_CLASS)
+ {
+ return HashPossiblyInstantiatedType(0, pKey->GetTypeToken(), pKey->GetInstantiation());
+ }
+ else if (pKey->GetKind() == ELEMENT_TYPE_FNPTR)
+ {
+ return HashFnPtrType(0, pKey->GetCallConv(), pKey->GetNumArgs(), pKey->GetRetAndArgTypes());
+ }
+ else
+ {
+ return HashParamType(0, pKey->GetKind(), pKey->GetElementType());
+ }
+}
+
+// Look up a value in the hash table
+//
+// The logic is subtle: type handles in the hash table may not be
+// restored, but we need to compare components of the types (rank and
+// element type for arrays, generic type and instantiation for
+// instantiated types) against pKey
+//
+// We avoid restoring types during search by cracking the signature
+// encoding used by the zapper for out-of-module types e.g. in the
+// instantiation of an instantiated type.
+EETypeHashEntry_t *EETypeHashTable::FindItem(TypeKey* pKey)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pKey));
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+ EETypeHashEntry_t * result = NULL;
+
+ DWORD dwHash = HashTypeKey(pKey);
+ EETypeHashEntry_t * pSearch;
+ CorElementType kind = pKey->GetKind();
+ LookupContext sContext;
+
+ if (kind == ELEMENT_TYPE_CLASS)
+ {
+ pSearch = BaseFindFirstEntryByHash(dwHash, &sContext);
+ while (pSearch)
+ {
+ if (CompareInstantiatedType(pSearch->GetTypeHandle(), pKey->GetModule(), pKey->GetTypeToken(), pKey->GetInstantiation()))
+ {
+ result = pSearch;
+ break;
+ }
+
+ pSearch = BaseFindNextEntryByHash(&sContext);
+ }
+ }
+ else if (kind == ELEMENT_TYPE_FNPTR)
+ {
+ BYTE callConv = pKey->GetCallConv();
+ DWORD numArgs = pKey->GetNumArgs();
+ TypeHandle *retAndArgTypes = pKey->GetRetAndArgTypes();
+
+ pSearch = BaseFindFirstEntryByHash(dwHash, &sContext);
+ while (pSearch)
+ {
+ if (CompareFnPtrType(pSearch->GetTypeHandle(), callConv, numArgs, retAndArgTypes))
+ {
+ result = pSearch;
+ break;
+ }
+
+ pSearch = BaseFindNextEntryByHash(&sContext);
+ }
+ }
+ else
+ {
+ // Type parameters for array and pointer types are necessarily in the same loader module
+ // as the constructed type itself, so we can just do handle comparisons
+ // Unfortunately the rank of the array might live elsewhere
+
+ for (pSearch = BaseFindFirstEntryByHash(dwHash, &sContext);
+ pSearch != NULL;
+ pSearch = BaseFindNextEntryByHash(&sContext))
+ {
+ if (!pSearch->GetTypeHandle().IsRestored())
+ {
+ // workaround: If we encounter an unrestored MethodTable, then it
+ // isn't the type for which we are looking (plus, it will crash
+ // in GetSignatureCorElementType). However TypeDescs can be
+ // accessed when unrestored. Also they are accessed in that
+ // manner at startup when we're loading the global types
+ // (i.e. System.Object).
+
+ if (!pSearch->GetTypeHandle().IsTypeDesc())
+ {
+ // Not a match
+ continue;
+ }
+ else
+ {
+ // We have an unrestored TypeDesc
+ }
+ }
+
+ if (pSearch->GetTypeHandle().GetSignatureCorElementType() != kind)
+ continue;
+
+ if (pSearch->GetTypeHandle().GetTypeParam() != pKey->GetElementType())
+ continue;
+
+ if (pSearch->GetTypeHandle().IsTypeDesc() == pKey->IsTemplateMethodTable())
+ continue;
+
+ if (kind == ELEMENT_TYPE_ARRAY)
+ {
+ if (pKey->IsTemplateMethodTable())
+ {
+ if (pSearch->GetTypeHandle().AsMethodTable()->GetRank() != pKey->GetRank())
+ continue;
+ }
+ else
+ {
+ ArrayTypeDesc *pATD = pSearch->GetTypeHandle().AsArray();
+#ifdef FEATURE_PREJIT
+ // This ensures that GetAssemblyIfLoaded operations that may be triggered by signature walks will succeed if at all possible.
+ ClrFlsThreadTypeSwitch genericInstantionCompareHolder(ThreadType_GenericInstantiationCompare);
+
+ TADDR fixup = pATD->GetTemplateMethodTableMaybeTagged();
+ if (!CORCOMPILE_IS_POINTER_TAGGED(fixup))
+ {
+ TADDR canonFixup = pATD->GetTemplateMethodTable()->GetCanonicalMethodTableFixup();
+ if (CORCOMPILE_IS_POINTER_TAGGED(canonFixup))
+ fixup = canonFixup;
+ }
+
+ if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
+ {
+ Module *pDefiningModule;
+ PCCOR_SIGNATURE pSig = m_pModule->GetEncodedSigIfLoaded(CORCOMPILE_UNTAG_TOKEN(fixup), &pDefiningModule);
+ if (pDefiningModule == NULL)
+ break;
+
+ _ASSERTE(*pSig == ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
+ pSig++;
+ _ASSERTE(*pSig == ELEMENT_TYPE_ARRAY);
+ pSig++;
+ SigPointer sp(pSig);
+ if (FAILED(sp.SkipExactlyOne()))
+ break; // return NULL;
+
+ ULONG data;
+ if (FAILED(sp.GetData(&data)))
+ break; // return NULL;
+
+ if (data != pKey->GetRank())
+ continue;
+ }
+ else
+#endif //FEATURE_PREJIT
+ {
+ if (pATD->GetRank() != pKey->GetRank())
+ continue;
+ }
+ }
+ }
+
+ result = pSearch;
+ break;
+ }
+ }
+
+ return result;
+}
+
+BOOL EETypeHashTable::CompareInstantiatedType(TypeHandle t, Module *pModule, mdTypeDef token, Instantiation inst)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(t));
+ PRECONDITION(CheckPointer(pModule));
+ PRECONDITION(!inst.IsEmpty());
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END
+
+ if (t.IsTypeDesc())
+ return FALSE;
+
+ // Even the EEClass pointer might be encoded
+ MethodTable * pMT = t.AsMethodTable();
+
+ if (pMT->GetNumGenericArgs() != inst.GetNumArgs())
+ return FALSE;
+
+#ifdef FEATURE_PREJIT
+ // This ensures that GetAssemblyIfLoaded operations that may be triggered by signature walks will succeed if at all possible.
+ ClrFlsThreadTypeSwitch genericInstantionCompareHolder(ThreadType_GenericInstantiationCompare);
+
+ TADDR fixup = pMT->GetCanonicalMethodTableFixup();
+
+ // The EEClass pointer is actually an encoding.
+ if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
+ {
+ Module *pDefiningModule;
+ PCCOR_SIGNATURE pSig = m_pModule->GetEncodedSigIfLoaded(CORCOMPILE_UNTAG_TOKEN(fixup), &pDefiningModule);
+
+ // First check that the modules for the generic type defs match
+ if (dac_cast<TADDR>(pDefiningModule) !=
+ dac_cast<TADDR>(pModule))
+ return FALSE;
+
+ // Now crack the signature encoding, expected to be an instantiated type
+ _ASSERTE(*pSig == ELEMENT_TYPE_GENERICINST);
+ pSig++;
+ _ASSERTE(*pSig == ELEMENT_TYPE_CLASS || *pSig == ELEMENT_TYPE_VALUETYPE);
+ pSig++;
+
+ // Check that the tokens of the generic type def match
+ if (CorSigUncompressToken(pSig) != token)
+ return FALSE;
+ }
+
+ // The EEClass pointer is a real pointer
+ else
+#endif //FEATURE_PREJIT
+ {
+ // First check that the typedef tokens match
+ if (pMT->GetCl() != token)
+ return FALSE;
+
+ // The class might not be restored, and its metadata module pointer might be encoded.
+ // This will return NULL if the module for the corresponding generic class
+ // is not loaded.
+ Module *pGenericModuleIfLoaded = pMT->GetModuleIfLoaded();
+
+ // Now check that the modules match
+ if (!pGenericModuleIfLoaded ||
+ dac_cast<TADDR>(pGenericModuleIfLoaded) !=
+ dac_cast<TADDR>(pModule))
+ return FALSE;
+
+ }
+
+ Instantiation candidateInst = t.GetInstantiation();
+
+ // Now check the instantiations. Some type arguments might be encoded.
+ for (DWORD i = 0; i < inst.GetNumArgs(); i++)
+ {
+ // Fetch the type handle as TADDR. It may be may be encoded fixup - TypeHandle debug-only validation
+ // asserts on encoded fixups.
+ DACCOP_IGNORE(CastOfMarshalledType, "Dual mode DAC problem, but since the size is the same, the cast is safe");
+ TADDR candidateArg = ((FixupPointer<TADDR> *)candidateInst.GetRawArgs())[i].GetValue();
+
+ if (!ZapSig::CompareTaggedPointerToTypeHandle(m_pModule, candidateArg, inst[i]))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL EETypeHashTable::CompareFnPtrType(TypeHandle t, BYTE callConv, DWORD numArgs, TypeHandle *retAndArgTypes)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(t));
+ PRECONDITION(CheckPointer(retAndArgTypes));
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END
+
+ if (!t.IsFnPtrType())
+ return FALSE;
+
+#ifndef DACCESS_COMPILE
+#ifdef FEATURE_PREJIT
+ // This ensures that GetAssemblyIfLoaded operations that may be triggered by signature walks will succeed if at all possible.
+ ClrFlsThreadTypeSwitch genericInstantionCompareHolder(ThreadType_GenericInstantiationCompare);
+#endif
+
+ FnPtrTypeDesc* pTD = t.AsFnPtrType();
+
+ if (pTD->GetNumArgs() != numArgs || pTD->GetCallConv() != callConv)
+ return FALSE;
+
+ // Now check the return and argument types. Some type arguments might be encoded.
+ TypeHandle *retAndArgTypes2 = pTD->GetRetAndArgTypesPointer();
+ for (DWORD i = 0; i <= numArgs; i++)
+ {
+ TADDR candidateArg = retAndArgTypes2[i].AsTAddr();
+ if (!ZapSig::CompareTaggedPointerToTypeHandle(m_pModule, candidateArg, retAndArgTypes[i]))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+#else
+ DacNotImpl();
+ return FALSE;
+#endif // #ifndef DACCESS_COMPILE
+}
+
+TypeHandle EETypeHashTable::GetValue(TypeKey *pKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+ EETypeHashEntry_t *pItem = FindItem(pKey);
+
+ if (pItem)
+ {
+ TypeHandle th = pItem->GetTypeHandle();
+ g_IBCLogger.LogTypeHashTableAccess(&th);
+ return pItem->GetTypeHandle();
+ }
+ else
+ return TypeHandle();
+}
+
+#ifndef DACCESS_COMPILE
+
+BOOL EETypeHashTable::ContainsValue(TypeHandle th)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_INTOLERANT;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ TypeKey typeKey = th.GetTypeKey();
+ return !GetValue(&typeKey).IsNull();
+}
+
+// Insert a value not already in the hash table
+VOID EETypeHashTable::InsertValue(TypeHandle data)
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ PRECONDITION(IsUnsealed()); // If we are sealed then we should not be adding to this hashtable
+ PRECONDITION(CheckPointer(data));
+ PRECONDITION(!data.IsEncodedFixup());
+ PRECONDITION(!data.IsGenericTypeDefinition()); // Generic type defs live in typedef table (availableClasses)
+ PRECONDITION(data.HasInstantiation() || data.HasTypeParam() || data.IsFnPtrType()); // It's an instantiated type or an array/ptr/byref type
+ PRECONDITION(!m_pModule || m_pModule->IsTenured()); // Destruct won't destruct m_pAvailableParamTypes for non-tenured modules - so make sure no one tries to insert one before the Module has been tenured
+ }
+ CONTRACTL_END
+
+ EETypeHashEntry_t * pNewEntry = (EETypeHashEntry_t*)BaseAllocateEntry(NULL);
+
+ pNewEntry->SetTypeHandle(data);
+
+ BaseInsertEntry(HashTypeHandle(0, data), pNewEntry);
+}
+
+#ifdef FEATURE_NATIVE_IMAGE_GENERATION
+
+#ifdef _DEBUG
+void EETypeHashTableSeal(EETypeHashTable * pTable) { WRAPPER_NO_CONTRACT; pTable->Seal(); }
+void EETypeHashTableUnseal(EETypeHashTable * pTable) { WRAPPER_NO_CONTRACT; pTable->Unseal(); }
+typedef Wrapper<EETypeHashTable *, EETypeHashTableSeal, EETypeHashTableUnseal> EETypeHashTableSealHolder;
+#endif
+
+// Save the hash table and any type descriptors referenced by it
+// Method tables must be saved separately
+void EETypeHashTable::Save(DataImage *image, Module *module, CorProfileData *profileData)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(image->GetModule() == m_pModule);
+ }
+ CONTRACTL_END;
+
+#ifdef _DEBUG
+ // The table should not change while we are walking the buckets
+ EETypeHashTableSealHolder h(this);
+#endif
+
+ // The base class will call us back for every entry to see if it's considered hot. To determine this we
+ // have to walk through the profiling data. It's very inefficient for us to do this every time. Instead
+ // we'll walk the data once just now and mark each hot entry as we find it.
+ CORBBTPROF_TOKEN_INFO * pTypeProfilingData = profileData->GetTokenFlagsData(TypeProfilingData);
+ DWORD cTypeProfilingData = profileData->GetTokenFlagsCount(TypeProfilingData);
+
+ for (unsigned int i = 0; i < cTypeProfilingData; i++)
+ {
+ CORBBTPROF_TOKEN_INFO *entry = &pTypeProfilingData[i];
+ mdToken token = entry->token;
+ DWORD flags = entry->flags;
+
+ if (TypeFromToken(token) != ibcTypeSpec)
+ continue;
+
+ if ((flags & (1 << ReadTypeHashTable)) == 0)
+ continue;
+
+ CORBBTPROF_BLOB_ENTRY *pBlobEntry = profileData->GetBlobStream();
+ if (pBlobEntry)
+ {
+ while (pBlobEntry->TypeIsValid())
+ {
+ if (TypeFromToken(pBlobEntry->token) == ibcTypeSpec)
+ {
+ _ASSERTE(pBlobEntry->type == ParamTypeSpec);
+
+ CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY *) pBlobEntry;
+
+ if (pBlobEntry->token == token)
+ {
+ if (flags & (1<<ReadTypeHashTable))
+ {
+ TypeHandle th = m_pModule->LoadIBCTypeHelper(pBlobSigEntry);
+#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
+ g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_8);
+#endif
+ if (!th.IsNull())
+ {
+ // Found a hot type. See if we have it in our table.
+ DWORD dwHash = HashTypeHandle(0, th);
+ LookupContext sContext;
+ EETypeHashEntry_t *pSearch = BaseFindFirstEntryByHash(dwHash, &sContext);
+ while (pSearch)
+ {
+ if (pSearch->GetTypeHandle() == th)
+ {
+ // Found the corresponding entry in the table. Mark it as hot.
+ pSearch->MarkAsHot();
+ break;
+ }
+
+ pSearch = BaseFindNextEntryByHash(&sContext);
+ }
+ }
+ }
+ }
+ }
+ pBlobEntry = pBlobEntry->GetNextEntry();
+ }
+ }
+ }
+
+ BaseSave(image, profileData);
+}
+
+bool EETypeHashTable::ShouldSave(DataImage *pImage, EETypeHashEntry_t *pEntry)
+{
+ STANDARD_VM_CONTRACT;
+
+ return !!pImage->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(pEntry->GetTypeHandle().AsPtr()));
+}
+
+bool EETypeHashTable::IsHotEntry(EETypeHashEntry_t *pEntry, CorProfileData *pProfileData)
+{
+ STANDARD_VM_CONTRACT;
+
+ // EETypeHashTable::Save() will have marked the entry as hot if the profile data indicated this.
+ return pEntry->IsHot();
+}
+
+bool EETypeHashTable::SaveEntry(DataImage *pImage, CorProfileData *pProfileData, EETypeHashEntry_t *pOldEntry, EETypeHashEntry_t *pNewEntry, EntryMappingTable *pMap)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return false;
+}
+
+void EETypeHashTable::Fixup(DataImage *image)
+{
+ STANDARD_VM_CONTRACT;
+
+ BaseFixup(image);
+
+ image->ZeroPointerField(this, offsetof(EETypeHashTable, m_pAllocator));
+
+#ifdef _DEBUG
+ // The persisted table should be unsealed.
+ EETypeHashTable *pNewTable = (EETypeHashTable*) image->GetImagePointer(this);
+ pNewTable->InitUnseal();
+#endif
+}
+
+void EETypeHashTable::FixupEntry(DataImage *pImage, EETypeHashEntry_t *pEntry, void *pFixupBase, DWORD cbFixupOffset)
+{
+ STANDARD_VM_CONTRACT;
+
+ TypeHandle pType = pEntry->GetTypeHandle();
+ _ASSERTE(!pType.IsNull());
+
+ // Clear any hot entry marking in the data, it's not needed after the Save phase.
+ pEntry->SetTypeHandle(pType);
+
+ if (pType.IsTypeDesc())
+ {
+ pImage->FixupField(pFixupBase, cbFixupOffset + offsetof(EETypeHashEntry_t, m_data),
+ pType.AsTypeDesc(), 2);
+
+ pType.AsTypeDesc()->Fixup(pImage);
+ }
+ else
+ {
+ pImage->FixupField(pFixupBase, cbFixupOffset + offsetof(EETypeHashEntry_t, m_data),
+ pType.AsMethodTable());
+
+ pType.AsMethodTable()->Fixup(pImage);
+ }
+}
+#endif // FEATURE_NATIVE_IMAGE_GENERATION
+
+#endif // #ifndef DACCESS_COMPILE
+
+#ifdef DACCESS_COMPILE
+
+void
+EETypeHashTable::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+{
+ SUPPORTS_DAC;
+
+ BaseEnumMemoryRegions(flags);
+}
+
+void EETypeHashTable::EnumMemoryRegionsForEntry(EETypeHashEntry_t *pEntry, CLRDataEnumMemoryFlags flags)
+{
+ SUPPORTS_DAC;
+
+ pEntry->GetTypeHandle().EnumMemoryRegions(flags);
+}
+
+#endif // #ifdef DACCESS_COMPILE
+
+TypeHandle EETypeHashEntry::GetTypeHandle()
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ // Remove any hot entry indicator bit that may have been set as the result of Ngen saving.
+ return TypeHandle::FromTAddr(m_data & ~0x1);
+}
+
+void EETypeHashEntry::SetTypeHandle(TypeHandle handle)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ // We plan to steal the low-order bit of the handle for ngen purposes.
+ _ASSERTE((handle.AsTAddr() & 0x1) == 0);
+ m_data = handle.AsTAddr();
+}
+
+#ifdef FEATURE_PREJIT
+bool EETypeHashEntry::IsHot()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // Low order bit of data field indicates a hot entry.
+ return (m_data & 1) != 0;
+}
+
+void EETypeHashEntry::MarkAsHot()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // Low order bit of data field indicates a hot entry.
+ m_data |= 0x1;
+}
+#endif // FEATURE_PREJIT
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER: warning C4244