diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/inc/corcompile.h | 4 | ||||
-rw-r--r-- | src/inc/readytorun.h | 4 | ||||
-rw-r--r-- | src/vm/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/vm/compile.cpp | 21 | ||||
-rw-r--r-- | src/vm/compile.h | 4 | ||||
-rw-r--r-- | src/vm/crossgen/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/vm/crossgen/wks_crossgen.nativeproj | 1 | ||||
-rw-r--r-- | src/vm/dac/dacwks.targets | 1 | ||||
-rw-r--r-- | src/vm/nativeformatreader.h | 15 | ||||
-rw-r--r-- | src/vm/readytoruninfo.cpp | 203 | ||||
-rw-r--r-- | src/vm/readytoruninfo.h | 1 | ||||
-rw-r--r-- | src/vm/typehashingalgorithms.h | 85 | ||||
-rw-r--r-- | src/vm/versionresilienthashcode.cpp | 131 | ||||
-rw-r--r-- | src/vm/versionresilienthashcode.h | 9 | ||||
-rw-r--r-- | src/vm/wks/wks.targets | 1 | ||||
-rw-r--r-- | src/vm/zapsig.cpp | 35 | ||||
-rw-r--r-- | src/zap/zapimage.cpp | 6 | ||||
-rw-r--r-- | src/zap/zapinfo.cpp | 26 | ||||
-rw-r--r-- | src/zap/zapreadytorun.cpp | 94 |
19 files changed, 533 insertions, 110 deletions
diff --git a/src/inc/corcompile.h b/src/inc/corcompile.h index 9120e5aafb..fd728212bc 100644 --- a/src/inc/corcompile.h +++ b/src/inc/corcompile.h @@ -1867,6 +1867,10 @@ class ICorCompileInfo virtual void EncodeTypeLayout(CORINFO_CLASS_HANDLE classHandle, SigBuilder * pSigBuilder) = 0; virtual BOOL AreAllClassesFullyLoaded(CORINFO_MODULE_HANDLE moduleHandle) = 0; + + virtual int GetVersionResilientTypeHashCode(CORINFO_MODULE_HANDLE moduleHandle, mdToken token) = 0; + + virtual int GetVersionResilientMethodHashCode(CORINFO_METHOD_HANDLE methodHandle) = 0; #endif virtual BOOL HasCustomAttribute(CORINFO_METHOD_HANDLE method, LPCSTR customAttributeName) = 0; diff --git a/src/inc/readytorun.h b/src/inc/readytorun.h index 2d6d34229f..7a82ec4016 100644 --- a/src/inc/readytorun.h +++ b/src/inc/readytorun.h @@ -54,7 +54,9 @@ enum ReadyToRunSectionType READYTORUN_SECTION_EXCEPTION_INFO = 104, READYTORUN_SECTION_DEBUG_INFO = 105, READYTORUN_SECTION_DELAYLOAD_METHODCALL_THUNKS = 106, - READYTORUN_SECTION_AVAILABLE_TYPES = 107, + // 107 used by an older format of READYTORUN_SECTION_AVAILABLE_TYPES + READYTORUN_SECTION_AVAILABLE_TYPES = 108, + READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS = 109, }; // diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index f6804e11f5..29c18bec52 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -113,6 +113,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON typestring.cpp util.cpp vars.cpp + versionresilienthashcode.cpp virtualcallstub.cpp win32threadpool.cpp zapsig.cpp diff --git a/src/vm/compile.cpp b/src/vm/compile.cpp index b17b6a15c6..36bba43c10 100644 --- a/src/vm/compile.cpp +++ b/src/vm/compile.cpp @@ -76,6 +76,8 @@ #include "argdestination.h" +#include "versionresilienthashcode.h" + #ifdef CROSSGEN_COMPILE CompilationDomain * theDomain; #endif @@ -2522,6 +2524,20 @@ BOOL CEECompileInfo::AreAllClassesFullyLoaded(CORINFO_MODULE_HANDLE moduleHandle return ((Module *)moduleHandle)->AreAllClassesFullyLoaded(); } +int CEECompileInfo::GetVersionResilientTypeHashCode(CORINFO_MODULE_HANDLE moduleHandle, mdToken token) +{ + STANDARD_VM_CONTRACT; + + return ::GetVersionResilientTypeHashCode(((Module *)moduleHandle)->GetMDImport(), token); +} + +int CEECompileInfo::GetVersionResilientMethodHashCode(CORINFO_METHOD_HANDLE methodHandle) +{ + STANDARD_VM_CONTRACT; + + return ::GetVersionResilientMethodHashCode(GetMethod(methodHandle)); +} + #endif // FEATURE_READYTORUN_COMPILER BOOL CEECompileInfo::HasCustomAttribute(CORINFO_METHOD_HANDLE method, LPCSTR customAttributeName) @@ -6885,9 +6901,10 @@ CORINFO_METHOD_HANDLE CEEPreloader::LookupMethodDef(mdMethodDef token) token, FALSE); - // READYTORUN: FUTURE: Generics if (IsReadyToRunCompilation() && pMD->HasClassOrMethodInstantiation()) - return NULL; + { + _ASSERTE(IsCompilationProcess() && pMD->GetModule_NoLogging() == GetAppDomain()->ToCompilationDomain()->GetTargetModule()); + } pMD = pMD->FindOrCreateTypicalSharedInstantiation(); diff --git a/src/vm/compile.h b/src/vm/compile.h index 6898c159b2..9ebb55b96e 100644 --- a/src/vm/compile.h +++ b/src/vm/compile.h @@ -397,6 +397,10 @@ class CEECompileInfo : public ICorCompileInfo void EncodeTypeLayout(CORINFO_CLASS_HANDLE classHandle, SigBuilder * pSigBuilder); BOOL AreAllClassesFullyLoaded(CORINFO_MODULE_HANDLE moduleHandle); + + int GetVersionResilientTypeHashCode(CORINFO_MODULE_HANDLE moduleHandle, mdToken token); + + int GetVersionResilientMethodHashCode(CORINFO_METHOD_HANDLE methodHandle); #endif BOOL HasCustomAttribute(CORINFO_METHOD_HANDLE method, LPCSTR customAttributeName); diff --git a/src/vm/crossgen/CMakeLists.txt b/src/vm/crossgen/CMakeLists.txt index 928d9deb0f..3a20675ef1 100644 --- a/src/vm/crossgen/CMakeLists.txt +++ b/src/vm/crossgen/CMakeLists.txt @@ -90,6 +90,7 @@ set(VM_CROSSGEN_SOURCES ../typestring.cpp ../util.cpp ../vars.cpp + ../versionresilienthashcode.cpp ../zapsig.cpp ../dbggcinfodecoder.cpp ../gcinfodecoder.cpp diff --git a/src/vm/crossgen/wks_crossgen.nativeproj b/src/vm/crossgen/wks_crossgen.nativeproj index bdd2b95db8..31404a3d66 100644 --- a/src/vm/crossgen/wks_crossgen.nativeproj +++ b/src/vm/crossgen/wks_crossgen.nativeproj @@ -115,6 +115,7 @@ <CppCompile Include="$(VmSourcesDir)\typestring.cpp" /> <CppCompile Include="$(VmSourcesDir)\util.cpp" /> <CppCompile Include="$(VmSourcesDir)\vars.cpp" /> + <CppCompile Include="$(VmSourcesDir)\versionresilienthashcode.cpp" /> <CppCompile Include="$(VmSourcesDir)\zapsig.cpp" /> </ItemGroup> diff --git a/src/vm/dac/dacwks.targets b/src/vm/dac/dacwks.targets index 155098fd67..121b14ec90 100644 --- a/src/vm/dac/dacwks.targets +++ b/src/vm/dac/dacwks.targets @@ -80,6 +80,7 @@ <CppCompile Include="$(ClrSrcDirectory)\vm\typeString.cpp" /> <CppCompile Include="$(ClrSrcDirectory)\vm\util.cpp" /> <CppCompile Include="$(ClrSrcDirectory)\vm\vars.cpp" /> + <CppCompile Include="$(ClrSrcDirectory)\vm\versionresilienthashcode.cpp" /> <CppCompile Include="$(ClrSrcDirectory)\vm\VirtualCallStub.cpp" /> <CppCompile Include="$(ClrSrcDirectory)\vm\ThreadPoolRequest.cpp" /> <CppCompile Include="$(ClrSrcDirectory)\vm\ThreadStatics.cpp" /> diff --git a/src/vm/nativeformatreader.h b/src/vm/nativeformatreader.h index fc5391ca05..4182b032c4 100644 --- a/src/vm/nativeformatreader.h +++ b/src/vm/nativeformatreader.h @@ -224,6 +224,14 @@ namespace NativeFormat return offset; } } + +#ifndef DACCESS_COMPILE + const BYTE* GetBlob(uint offset) + { + EnsureOffsetInRange(offset, 0); + return _base + offset; + } +#endif #ifdef _MSC_VER #pragma warning(pop) #endif @@ -287,6 +295,13 @@ namespace NativeFormat return pos + (uint)delta; } +#ifndef DACCESS_COMPILE + const BYTE * GetBlob() + { + return _pReader->GetBlob(_offset); + } +#endif + void SkipInteger() { _offset = _pReader->SkipInteger(_offset); diff --git a/src/vm/readytoruninfo.cpp b/src/vm/readytoruninfo.cpp index ada502a417..3dd8fd3197 100644 --- a/src/vm/readytoruninfo.cpp +++ b/src/vm/readytoruninfo.cpp @@ -13,6 +13,8 @@ #include "dbginterface.h" #include "compile.h" +#include "versionresilienthashcode.h" +#include "typehashingalgorithms.h" using namespace NativeFormat; @@ -99,84 +101,62 @@ BOOL ReadyToRunInfo::TryLookupTypeTokenFromName(NameHandle *pName, mdToken * pFo // // Compute the hashcode of the type (hashcode based on type name and namespace name) // - DWORD dwHashCode = 0; - { - if (pName->GetTypeToken() == mdtBaseType) - { - // Name-based lookups (ex: Type.GetType()). - - pszName = pName->GetName(); - pszNameSpace = ""; - - if (pName->GetNameSpace() != NULL) - { - pszNameSpace = pName->GetNameSpace(); - } - else - { - LPCUTF8 p; - CQuickBytes szNamespace; - - if ((p = ns::FindSep(pszName)) != NULL) - { - SIZE_T d = p - pszName; + int dwHashCode = 0; - FAULT_NOT_FATAL(); - pszNameSpace = szNamespace.SetStringNoThrow(pszName, d); + if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL) + { + // Name-based lookups (ex: Type.GetType()). - if (pszNameSpace == NULL) - return FALSE; + pszName = pName->GetName(); + pszNameSpace = ""; - pszName = (p + 1); - } - } - - _ASSERT(pszNameSpace != NULL); - dwHashCode = ((dwHashCode << 5) + dwHashCode) ^ HashStringA(pszName); - dwHashCode = ((dwHashCode << 5) + dwHashCode) ^ HashStringA(pszNameSpace); + if (pName->GetNameSpace() != NULL) + { + pszNameSpace = pName->GetNameSpace(); + } + else + { + LPCUTF8 p; + CQuickBytes szNamespace; - // Bucket is not 'null' for a nested type, and it will have information about the nested type's encloser - if (!pName->GetBucket().IsNull()) + if ((p = ns::FindSep(pszName)) != NULL) { - // Must be a token based bucket that we found earlier in the R2R types hashtable - _ASSERT(pName->GetBucket().GetEntryType() == HashedTypeEntry::IsHashedTokenEntry); - - const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue(); + SIZE_T d = p - pszName; - // Token must be a typedef token that we previously resolved (we shouldn't get here with an exported type token) - _ASSERT(TypeFromToken(tokenBasedEncloser.m_TypeToken) == mdtTypeDef); + FAULT_NOT_FATAL(); + pszNameSpace = szNamespace.SetStringNoThrow(pszName, d); - mdToken mdCurrentTypeToken = tokenBasedEncloser.m_TypeToken; - do - { - LPCUTF8 pszNameTemp; - LPCUTF8 pszNameSpaceTemp; - if (!GetTypeNameFromToken(tokenBasedEncloser.m_pModule->GetMDImport(), mdCurrentTypeToken, &pszNameTemp, &pszNameSpaceTemp)) - return FALSE; - - dwHashCode = ((dwHashCode << 5) + dwHashCode) ^ HashStringA(pszNameTemp); - dwHashCode = ((dwHashCode << 5) + dwHashCode) ^ HashStringA(pszNameSpaceTemp == NULL ? "" : pszNameSpaceTemp); - - } while (GetEnclosingToken(tokenBasedEncloser.m_pModule->GetMDImport(), mdCurrentTypeToken, &mdCurrentTypeToken)); + if (pszNameSpace == NULL) + return FALSE; + pszName = (p + 1); } } - else + + _ASSERT(pszNameSpace != NULL); + dwHashCode ^= ComputeNameHashCode(pszNameSpace, pszName); + + // Bucket is not 'null' for a nested type, and it will have information about the nested type's encloser + if (!pName->GetBucket().IsNull()) { - // Token based lookups (ex: tokens from IL code) + // Must be a token based bucket that we found earlier in the R2R types hashtable + _ASSERT(pName->GetBucket().GetEntryType() == HashedTypeEntry::IsHashedTokenEntry); - mdToken mdCurrentTypeToken = pName->GetTypeToken(); - do - { - if (!GetTypeNameFromToken(pName->GetTypeModule()->GetMDImport(), mdCurrentTypeToken, &pszName, &pszNameSpace)) - return FALSE; + const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue(); - dwHashCode = ((dwHashCode << 5) + dwHashCode) ^ HashStringA(pszName); - dwHashCode = ((dwHashCode << 5) + dwHashCode) ^ HashStringA(pszNameSpace == NULL ? "" : pszNameSpace); + // Token must be a typedef token that we previously resolved (we shouldn't get here with an exported type token) + _ASSERT(TypeFromToken(tokenBasedEncloser.m_TypeToken) == mdtTypeDef); - } while (GetEnclosingToken(pName->GetTypeModule()->GetMDImport(), mdCurrentTypeToken, &mdCurrentTypeToken)); + mdToken mdCurrentTypeToken = tokenBasedEncloser.m_TypeToken; + dwHashCode ^= GetVersionResilientTypeHashCode(tokenBasedEncloser.m_pModule->GetMDImport(), mdCurrentTypeToken); } } + else + { + // Token based lookups (ex: tokens from IL code) + + dwHashCode = GetVersionResilientTypeHashCode(pName->GetTypeModule()->GetMDImport(), pName->GetTypeToken()); + } // @@ -191,7 +171,7 @@ BOOL ReadyToRunInfo::TryLookupTypeTokenFromName(NameHandle *pName, mdToken * pFo mdToken cl = ((ridAndFlag & 1) ? ((ridAndFlag >> 1) | mdtExportedType) : ((ridAndFlag >> 1) | mdtTypeDef)); _ASSERT(RidFromToken(cl) != 0); - if (pName->GetTypeToken() == mdtBaseType) + if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL) { // Compare type name and namespace name LPCUTF8 pszFoundName; @@ -456,6 +436,13 @@ ReadyToRunInfo::ReadyToRunInfo(Module * pModule, PEImageLayout * pLayout, READYT m_methodDefEntryPoints = NativeArray(&m_nativeReader, pEntryPointsDir->VirtualAddress); } + IMAGE_DATA_DIRECTORY * pinstMethodsDir = FindSection(READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS); + if (pinstMethodsDir != NULL) + { + NativeParser parser = NativeParser(&m_nativeReader, pinstMethodsDir->VirtualAddress); + m_instMethodEntryPoints = NativeHashtable(parser); + } + IMAGE_DATA_DIRECTORY * pAvailableTypesDir = FindSection(READYTORUN_SECTION_AVAILABLE_TYPES); if (pAvailableTypesDir != NULL) { @@ -469,13 +456,61 @@ ReadyToRunInfo::ReadyToRunInfo(Module * pModule, PEImageLayout * pLayout, READYT } } -PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, BOOL fFixups /*=TRUE*/) +static bool SigMatchesMethodDesc(MethodDesc* pMD, SigPointer &sig, Module * pModule) { STANDARD_VM_CONTRACT; - // READYTORUN: FUTURE: Support for generics - if (pMD->HasClassOrMethodInstantiation()) - return NULL; + ZapSig::Context zapSigContext(pModule, (void *)pModule, ZapSig::NormalTokens); + ZapSig::Context * pZapSigContext = &zapSigContext; + + DWORD methodFlags; + IfFailThrow(sig.GetData(&methodFlags)); + + if (methodFlags & ENCODE_METHOD_SIG_OwnerType) + { + PCCOR_SIGNATURE pSigType; + DWORD cbSigType; + sig.GetSignature(&pSigType, &cbSigType); + if (!ZapSig::CompareSignatureToTypeHandle(pSigType, pModule, TypeHandle(pMD->GetMethodTable()), pZapSigContext)) + return false; + + IfFailThrow(sig.SkipExactlyOne()); + } + + _ASSERTE((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0); + _ASSERTE((methodFlags & ENCODE_METHOD_SIG_MemberRefToken) == 0); + + RID rid; + IfFailThrow(sig.GetData(&rid)); + if (RidFromToken(pMD->GetMemberDef()) != rid) + return false; + + if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) + { + DWORD numGenericArgs; + IfFailThrow(sig.GetData(&numGenericArgs)); + Instantiation inst = pMD->GetMethodInstantiation(); + if (numGenericArgs != inst.GetNumArgs()) + return false; + + for (DWORD i = 0; i < numGenericArgs; i++) + { + PCCOR_SIGNATURE pSigArg; + DWORD cbSigArg; + sig.GetSignature(&pSigArg, &cbSigArg); + if (!ZapSig::CompareSignatureToTypeHandle(pSigArg, pModule, inst[i], pZapSigContext)) + return false; + + IfFailThrow(sig.SkipExactlyOne()); + } + } + + return true; +} + +PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, BOOL fFixups /*=TRUE*/) +{ + STANDARD_VM_CONTRACT; mdToken token = pMD->GetMemberDef(); int rid = RidFromToken(token); @@ -483,8 +518,38 @@ PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, BOOL fFixups /*=TRUE*/) return NULL; uint offset; - if (!m_methodDefEntryPoints.TryGetAt(rid - 1, &offset)) - return NULL; + if (pMD->HasClassOrMethodInstantiation()) + { + if (m_instMethodEntryPoints.IsNull()) + return NULL; + + NativeHashtable::Enumerator lookup = m_instMethodEntryPoints.Lookup(GetVersionResilientMethodHashCode(pMD)); + NativeParser entryParser; + offset = -1; + while (lookup.GetNext(entryParser)) + { + PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)entryParser.GetBlob(); + SigPointer sig(pBlob); + if (SigMatchesMethodDesc(pMD, sig, m_pModule)) + { + // Get the updated SigPointer location, so we can calculate the size of the blob, + // in order to skip the blob and find the entry point data. + PCCOR_SIGNATURE pSigNew; + DWORD cbSigNew; + sig.GetSignature(&pSigNew, &cbSigNew); + offset = entryParser.GetOffset() + (uint)(pSigNew - pBlob); + break; + } + } + + if (offset == -1) + return NULL; + } + else + { + if (!m_methodDefEntryPoints.TryGetAt(rid - 1, &offset)) + return NULL; + } uint id; offset = m_nativeReader.DecodeUnsigned(offset, &id); diff --git a/src/vm/readytoruninfo.h b/src/vm/readytoruninfo.h index ae903ced9c..f2a7a1ec49 100644 --- a/src/vm/readytoruninfo.h +++ b/src/vm/readytoruninfo.h @@ -34,6 +34,7 @@ class ReadyToRunInfo NativeFormat::NativeReader m_nativeReader; NativeFormat::NativeArray m_methodDefEntryPoints; + NativeFormat::NativeHashtable m_instMethodEntryPoints; NativeFormat::NativeHashtable m_availableTypesHashtable; Crst m_Crst; diff --git a/src/vm/typehashingalgorithms.h b/src/vm/typehashingalgorithms.h new file mode 100644 index 0000000000..9f3f3cd37a --- /dev/null +++ b/src/vm/typehashingalgorithms.h @@ -0,0 +1,85 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// --------------------------------------------------------------------------- +// Generic functions to compute the hashcode value of types +// --------------------------------------------------------------------------- + +#pragma once +#include <stdlib.h> + +// +// Returns the hashcode value of the 'src' string +// +inline static int ComputeNameHashCode(LPCUTF8 src) +{ + if (src == NULL || *src == '\0') + return 0; + + int hash1 = 0x6DA3B944; + int hash2 = 0; + + // DIFFERENT FROM CORERT: We hash UTF-8 bytes here, while CoreRT hashes UTF-16 characters. + + for (COUNT_T i = 0; src[i] != '\0'; i += 2) + { + hash1 = (hash1 + _rotl(hash1, 5)) ^ src[i]; + if (src[i + 1] != '\0') + hash2 = (hash2 + _rotl(hash2, 5)) ^ src[i + 1]; + else + break; + } + + hash1 += _rotl(hash1, 8); + hash2 += _rotl(hash2, 8); + + return hash1 ^ hash2; +} + +inline static int ComputeNameHashCode(LPCUTF8 pszNamespace, LPCUTF8 pszName) +{ + // DIFFERENT FROM CORERT: CoreRT hashes the full name as one string ("namespace.name"), + // as the full name is already available. In CoreCLR we normally only have separate + // strings for namespace and name, thus we hash them separately. + return ComputeNameHashCode(pszNamespace) ^ ComputeNameHashCode(pszName); +} + +inline static int ComputeArrayTypeHashCode(int elementTypeHashcode, int rank) +{ + // DIFFERENT FROM CORERT: This is much simplified compared to CoreRT, to avoid converting.rank to string. + // For single-dimensinal array, the result is identical to CoreRT. + int hashCode = 0xd5313556 + rank; + if (rank == 1) + _ASSERTE(hashCode == ComputeNameHashCode("System.Array`1")); + + hashCode = (hashCode + _rotl(hashCode, 13)) ^ elementTypeHashcode; + return (hashCode + _rotl(hashCode, 15)); +} + +inline static int ComputePointerTypeHashCode(int pointeeTypeHashcode) +{ + return (pointeeTypeHashcode + _rotl(pointeeTypeHashcode, 5)) ^ 0x12D0; +} + +inline static int ComputeByrefTypeHashCode(int parameterTypeHashcode) +{ + return (parameterTypeHashcode + _rotl(parameterTypeHashcode, 7)) ^ 0x4C85; +} + +inline static int ComputeNestedTypeHashCode(int enclosingTypeHashcode, int nestedTypeNameHash) +{ + return (enclosingTypeHashcode + _rotl(enclosingTypeHashcode, 11)) ^ nestedTypeNameHash; +} + +template <typename TA, typename TB> +inline static int ComputeGenericInstanceHashCode(int definitionHashcode, int arity, const TA& genericTypeArguments, int (*getHashCode)(TB)) +{ + int hashcode = definitionHashcode; + for (int i = 0; i < arity; i++) + { + int argumentHashCode = getHashCode(genericTypeArguments[i]); + hashcode = (hashcode + _rotl(hashcode, 13)) ^ argumentHashCode; + } + return (hashcode + _rotl(hashcode, 15)); +} diff --git a/src/vm/versionresilienthashcode.cpp b/src/vm/versionresilienthashcode.cpp new file mode 100644 index 0000000000..277bb93655 --- /dev/null +++ b/src/vm/versionresilienthashcode.cpp @@ -0,0 +1,131 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "common.h" +#include "versionresilienthashcode.h" +#include "typehashingalgorithms.h" + +int GetVersionResilientTypeHashCode(IMDInternalImport *pMDImport, mdExportedType token) +{ + _ASSERTE(TypeFromToken(token) == mdtTypeDef || + TypeFromToken(token) == mdtTypeRef || + TypeFromToken(token) == mdtExportedType); + _ASSERTE(!IsNilToken(token)); + + HRESULT hr; + LPCUTF8 szNamespace; + LPCUTF8 szName; + bool hasTypeToken = true; + int hashcode = 0; + + while (hasTypeToken) + { + if (IsNilToken(token)) + ThrowHR(COR_E_BADIMAGEFORMAT); + + switch (TypeFromToken(token)) + { + case mdtTypeDef: + if (FAILED(pMDImport->GetNameOfTypeDef(token, &szName, &szNamespace))) + ThrowHR(COR_E_BADIMAGEFORMAT); + hr = pMDImport->GetNestedClassProps(token, &token); + if (hr == CLDB_E_RECORD_NOTFOUND) + hasTypeToken = false; + else if (FAILED(hr)) + ThrowHR(COR_E_BADIMAGEFORMAT); + break; + + case mdtTypeRef: + if (FAILED(pMDImport->GetNameOfTypeRef(token, &szNamespace, &szName))) + ThrowHR(COR_E_BADIMAGEFORMAT); + if (FAILED(pMDImport->GetResolutionScopeOfTypeRef(token, &token))) + ThrowHR(COR_E_BADIMAGEFORMAT); + hasTypeToken = (TypeFromToken(token) == mdtTypeRef); + break; + + case mdtExportedType: + if (FAILED(pMDImport->GetExportedTypeProps(token, &szNamespace, &szName, &token, NULL, NULL))) + ThrowHR(COR_E_BADIMAGEFORMAT); + hasTypeToken = (TypeFromToken(token) == mdtExportedType); + break; + + default: + ThrowHR(COR_E_BADIMAGEFORMAT); + } + + hashcode ^= ComputeNameHashCode(szNamespace, szName); + } + + return hashcode; +} + +#ifndef DACCESS_COMPILE +int GetVersionResilientTypeHashCode(TypeHandle type) +{ + 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); + + MethodTable *pMTEnclosing = pMT->LoadEnclosingMethodTable(CLASS_LOAD_UNRESTOREDTYPEKEY); + if (pMTEnclosing != NULL) + { + hashcode = ComputeNestedTypeHashCode(GetVersionResilientTypeHashCode(TypeHandle(pMTEnclosing)), hashcode); + } + + if (!pMT->IsGenericTypeDefinition() && pMT->HasInstantiation()) + { + return ComputeGenericInstanceHashCode(hashcode, + pMT->GetInstantiation().GetNumArgs(), pMT->GetInstantiation(), GetVersionResilientTypeHashCode); + } + else + { + return hashcode; + } + } + else + if (type.IsArray()) + { + ArrayTypeDesc *pArray = type.AsArray(); + return ComputeArrayTypeHashCode(GetVersionResilientTypeHashCode(pArray->GetArrayElementTypeHandle()), pArray->GetRank()); + } + else + if (type.IsPointer()) + { + return ComputePointerTypeHashCode(GetVersionResilientTypeHashCode(type.AsTypeDesc()->GetTypeParam())); + } + else + if (type.IsByRef()) + { + return ComputeByrefTypeHashCode(GetVersionResilientTypeHashCode(type.AsTypeDesc()->GetTypeParam())); + } + + assert(false); + return 0; +} + +int GetVersionResilientMethodHashCode(MethodDesc *pMD) +{ + int hashCode = GetVersionResilientTypeHashCode(TypeHandle(pMD->GetMethodTable())); + + // Todo: Add signature to hash. + if (pMD->GetNumGenericMethodArgs() > 0) + { + hashCode ^= ComputeGenericInstanceHashCode(ComputeNameHashCode(pMD->GetName()), pMD->GetNumGenericMethodArgs(), pMD->GetMethodInstantiation(), GetVersionResilientTypeHashCode); + } + else + { + hashCode ^= ComputeNameHashCode(pMD->GetName()); + } + + return hashCode; +} +#endif // DACCESS_COMPILE diff --git a/src/vm/versionresilienthashcode.h b/src/vm/versionresilienthashcode.h new file mode 100644 index 0000000000..03a1c0c8b7 --- /dev/null +++ b/src/vm/versionresilienthashcode.h @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +int GetVersionResilientTypeHashCode(TypeHandle type); + +int GetVersionResilientTypeHashCode(IMDInternalImport *pMDImport, mdExportedType token); + +int GetVersionResilientMethodHashCode(MethodDesc *pMD); diff --git a/src/vm/wks/wks.targets b/src/vm/wks/wks.targets index 6a269537ca..b9f57e882e 100644 --- a/src/vm/wks/wks.targets +++ b/src/vm/wks/wks.targets @@ -226,6 +226,7 @@ <CppCompile Include="$(VmSourcesDir)\validator.cpp" Condition="'$(FeatureCoreclr)' != 'true'"/> <CppCompile Include="$(VmSourcesDir)\vars.cpp" /> <CppCompile Include="$(VmSourcesDir)\verifier.cpp" /> + <CppCompile Include="$(VmSourcesDir)\versionresilienthashcode.cpp" /> <CppCompile Include="$(VmSourcesDir)\VirtualCallStub.cpp" /> <CppCompile Include="$(VmSourcesDir)\WeakReferenceNative.cpp" /> <CppCompile Include="$(VmSourcesDir)\Win32Threadpool.cpp" /> diff --git a/src/vm/zapsig.cpp b/src/vm/zapsig.cpp index 4ecc7ac9a8..7d3b73f0f1 100644 --- a/src/vm/zapsig.cpp +++ b/src/vm/zapsig.cpp @@ -441,6 +441,21 @@ BOOL ZapSig::GetSignatureForTypeHandle(TypeHandle handle, case ELEMENT_TYPE_CLASS: { CorSigUncompressToken(pSig, &tk); + if (TypeFromToken(tk) == mdtTypeRef) + { + BOOL resolved = FALSE; + EX_TRY + { + ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); + resolved = ClassLoader::ResolveTokenToTypeDefThrowing(pModule, tk, &pModule, &tk, Loader::DontLoad); + } + EX_CATCH + { + } + EX_END_CATCH(SwallowAllExceptions); + if (!resolved) + RETURN(FALSE); + } _ASSERTE(TypeFromToken(tk) == mdtTypeDef); RETURN (sigType == handleType && !handle.HasInstantiation() && pModule == handle.GetModule() && handle.GetCl() == tk); } @@ -487,6 +502,21 @@ BOOL ZapSig::GetSignatureForTypeHandle(TypeHandle handle, RETURN(FALSE); pSig += CorSigUncompressToken(pSig, &tk); + if (TypeFromToken(tk) == mdtTypeRef) + { + BOOL resolved = FALSE; + EX_TRY + { + ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); + resolved = ClassLoader::ResolveTokenToTypeDefThrowing(pModule, tk, &pModule, &tk, Loader::DontLoad); + } + EX_CATCH + { + } + EX_END_CATCH(SwallowAllExceptions); + if (!resolved) + RETURN(FALSE); + } _ASSERTE(TypeFromToken(tk) == mdtTypeDef); if (pModule != handle.GetModule() || tk != handle.GetCl()) RETURN(FALSE); @@ -1157,7 +1187,10 @@ BOOL ZapSig::EncodeMethod( { case mdtMethodDef: _ASSERTE(pResolvedToken->pTypeSpec == NULL); - methodFlags &= ~ENCODE_METHOD_SIG_OwnerType; + if (!ownerType.HasInstantiation() || ownerType.IsTypicalTypeDefinition()) + { + methodFlags &= ~ENCODE_METHOD_SIG_OwnerType; + } break; case mdtMemberRef: diff --git a/src/zap/zapimage.cpp b/src/zap/zapimage.cpp index a9c582cf42..3ce7cd6d3c 100644 --- a/src/zap/zapimage.cpp +++ b/src/zap/zapimage.cpp @@ -2099,9 +2099,11 @@ ZapImage::CompileStatus ZapImage::TryCompileMethodDef(mdMethodDef md, unsigned m ZapImage::CompileStatus ZapImage::TryCompileInstantiatedMethod(CORINFO_METHOD_HANDLE handle, unsigned methodProfilingDataFlags) { - // READYTORUN: FUTURE: Generics if (IsReadyToRunCompilation()) - return COMPILE_EXCLUDED; + { + if (!GetCompileInfo()->IsInCurrentVersionBubble(m_zapper->m_pEEJitInfo->getMethodModule(handle))) + return COMPILE_EXCLUDED; + } if (!ShouldCompileInstantiatedMethod(handle)) return COMPILE_EXCLUDED; diff --git a/src/zap/zapinfo.cpp b/src/zap/zapinfo.cpp index 2e0ddb569a..40695c9c21 100644 --- a/src/zap/zapinfo.cpp +++ b/src/zap/zapinfo.cpp @@ -1677,7 +1677,7 @@ void ZapInfo::embedGenericSignature(CORINFO_LOOKUP * pLookup) if (IsReadyToRunCompilation()) { - _ASSERTE(!"embedGenericSignature"); + m_zapper->Warning(W("ReadyToRun: embedGenericSignature not yet supported\n")); ThrowHR(E_NOTIMPL); } @@ -2210,6 +2210,14 @@ void ZapInfo::getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken, #ifdef FEATURE_READYTORUN_COMPILER if (IsReadyToRunCompilation()) { + if ((pResult->classFlags & CORINFO_FLG_SHAREDINST) != 0 || + (pResult->methodFlags & CORINFO_FLG_SHAREDINST) != 0) + { + // READYTORUN: FUTURE: Generics + m_zapper->Warning(W("ReadyToRun: Generic dictionary lookup required\n")); + ThrowHR(E_NOTIMPL); + } + DWORD fAtypicalCallsite = (flags & CORINFO_CALLINFO_ATYPICAL_CALLSITE) ? CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE : 0; ZapImport * pImport = m_pImage->GetImportTable()->GetDynamicHelperCell( @@ -2237,7 +2245,7 @@ void ZapInfo::getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken, if (pResult->exactContextNeedsRuntimeLookup) { // READYTORUN: FUTURE: Generics - _ASSERTE(!"Generics"); + m_zapper->Warning(W("ReadyToRun: Generic dictionary lookup not yet supported\n")); ThrowHR(E_NOTIMPL); } else @@ -2995,7 +3003,7 @@ void ZapInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, case CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER: // READYTORUN: FUTURE: Generics - _ASSERTE(!"Generics"); + m_zapper->Warning(W("ReadyToRun: Shared generic static field access not yet supported\n")); ThrowHR(E_NOTIMPL); break; @@ -3398,11 +3406,23 @@ void ZapInfo::getReadyToRunHelper( switch (id) { case CORINFO_HELP_READYTORUN_NEW: + if ((getClassAttribs(pResolvedToken->hClass) & CORINFO_FLG_SHAREDINST) != 0) + { + // READYTORUN: FUTURE: Generics + m_zapper->Warning(W("ReadyToRun: Generic dictionary lookup required\n")); + ThrowHR(E_NOTIMPL); + } pImport = m_pImage->GetImportTable()->GetDynamicHelperCell( (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_NEW_HELPER | fAtypicalCallsite), pResolvedToken->hClass); break; case CORINFO_HELP_READYTORUN_NEWARR_1: + if ((getClassAttribs(pResolvedToken->hClass) & CORINFO_FLG_SHAREDINST) != 0) + { + // READYTORUN: FUTURE: Generics + m_zapper->Warning(W("ReadyToRun: Generic dictionary lookup required\n")); + ThrowHR(E_NOTIMPL); + } pImport = m_pImage->GetImportTable()->GetDynamicHelperCell( (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_NEW_ARRAY_HELPER | fAtypicalCallsite), pResolvedToken->hClass); break; diff --git a/src/zap/zapreadytorun.cpp b/src/zap/zapreadytorun.cpp index 9f21e80992..06ba5f6ab7 100644 --- a/src/zap/zapreadytorun.cpp +++ b/src/zap/zapreadytorun.cpp @@ -175,16 +175,37 @@ public: } }; +class EntryPointWithBlobVertex : public EntryPointVertex +{ + BlobVertex * m_pBlob; + +public: + EntryPointWithBlobVertex(DWORD methodIndex, BlobVertex * pFixups, BlobVertex * pBlob) + : EntryPointVertex(methodIndex, pFixups), m_pBlob(pBlob) + { + } + + virtual void Save(NativeWriter * pWriter) + { + m_pBlob->Save(pWriter); + EntryPointVertex::Save(pWriter); + } +}; + void ZapImage::OutputEntrypointsTableForReadyToRun() { BeginRegion(CORINFO_REGION_COLD); - NativeWriter writer; + NativeWriter arrayWriter; + NativeWriter hashtableWriter; - NativeSection * pSection = writer.NewSection(); + NativeSection * pArraySection = arrayWriter.NewSection(); + NativeSection * pHashtableSection = hashtableWriter.NewSection(); - VertexArray vertexArray(pSection); - pSection->Place(&vertexArray); + VertexArray vertexArray(pArraySection); + pArraySection->Place(&vertexArray); + VertexHashtable vertexHashtable; + pHashtableSection->Place(&vertexHashtable); bool fEmpty = true; @@ -196,6 +217,8 @@ void ZapImage::OutputEntrypointsTableForReadyToRun() ZapMethodHeader * pMethod = m_MethodCompilationOrder[i]; mdMethodDef token = GetJitInfo()->getMethodDefFromMethod(pMethod->GetHandle()); + CORINFO_SIG_INFO sig; + GetJitInfo()->getMethodSig(pMethod->GetHandle(), &sig); int rid = RidFromToken(token); _ASSERTE(rid != 0); @@ -221,7 +244,31 @@ void ZapImage::OutputEntrypointsTableForReadyToRun() } } - vertexArray.Set(rid - 1, new (GetHeap()) EntryPointVertex(pMethod->GetMethodIndex(), pFixupBlob)); + if (sig.sigInst.classInstCount > 0 || sig.sigInst.methInstCount > 0) + { + CORINFO_MODULE_HANDLE module = GetJitInfo()->getClassModule(pMethod->GetClassHandle()); + _ASSERTE(GetCompileInfo()->IsInCurrentVersionBubble(module)); + SigBuilder sigBuilder; + CORINFO_RESOLVED_TOKEN resolvedToken = {}; + resolvedToken.tokenScope = module; + resolvedToken.token = token; + resolvedToken.hClass = pMethod->GetClassHandle(); + resolvedToken.hMethod = pMethod->GetHandle(); + GetCompileInfo()->EncodeMethod(module, pMethod->GetHandle(), &sigBuilder, NULL, NULL, &resolvedToken); + + DWORD cbBlob; + PVOID pBlob = sigBuilder.GetSignature(&cbBlob); + void * pMemory = new (GetHeap()) BYTE[sizeof(BlobVertex) + cbBlob]; + BlobVertex * pSigBlob = new (pMemory) BlobVertex(cbBlob); + memcpy(pSigBlob->GetData(), pBlob, cbBlob); + + int dwHash = GetCompileInfo()->GetVersionResilientMethodHashCode(pMethod->GetHandle()); + vertexHashtable.Append(dwHash, pHashtableSection->Place(new (GetHeap()) EntryPointWithBlobVertex(pMethod->GetMethodIndex(), pFixupBlob, pSigBlob))); + } + else + { + vertexArray.Set(rid - 1, new (GetHeap()) EntryPointVertex(pMethod->GetMethodIndex(), pFixupBlob)); + } fEmpty = false; } @@ -231,13 +278,17 @@ void ZapImage::OutputEntrypointsTableForReadyToRun() vertexArray.ExpandLayout(); - vector<byte>& blob = writer.Save(); + vector<byte>& arrayBlob = arrayWriter.Save(); + ZapNode * pArrayBlob = ZapBlob::NewBlob(this, &arrayBlob[0], arrayBlob.size()); + m_pCodeMethodDescsSection->Place(pArrayBlob); - ZapNode * pBlob = ZapBlob::NewBlob(this, &blob[0], blob.size()); - m_pCodeMethodDescsSection->Place(pBlob); + vector<byte>& hashtableBlob = hashtableWriter.Save(); + ZapNode * pHashtableBlob = ZapBlob::NewBlob(this, &hashtableBlob[0], hashtableBlob.size()); + m_pCodeMethodDescsSection->Place(pHashtableBlob); ZapReadyToRunHeader * pReadyToRunHeader = GetReadyToRunHeader(); - pReadyToRunHeader->RegisterSection(READYTORUN_SECTION_METHODDEF_ENTRYPOINTS, pBlob); + pReadyToRunHeader->RegisterSection(READYTORUN_SECTION_METHODDEF_ENTRYPOINTS, pArrayBlob); + pReadyToRunHeader->RegisterSection(READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS, pHashtableBlob); pReadyToRunHeader->RegisterSection(READYTORUN_SECTION_RUNTIME_FUNCTIONS, m_pRuntimeFunctionSection); if (m_pImportSectionsTable->GetSize() != 0) @@ -354,18 +405,8 @@ void ZapImage::OutputTypesTableForReadyToRun(IMDInternalImport * pMDImport) mdToken mdTypeToken; while (pMDImport->EnumNext(&hEnum, &mdTypeToken)) { - DWORD dwHash = 0; mdTypeDef mdCurrentToken = mdTypeToken; - - do - { - if (FAILED(pMDImport->GetNameOfTypeDef(mdCurrentToken, &pszName, &pszNameSpace))) - ThrowHR(COR_E_BADIMAGEFORMAT); - - dwHash = ((dwHash << 5) + dwHash) ^ HashStringA(pszName); - dwHash = ((dwHash << 5) + dwHash) ^ HashStringA(pszNameSpace == NULL ? "" : pszNameSpace); - - } while (SUCCEEDED(pMDImport->GetNestedClassProps(mdCurrentToken, &mdCurrentToken))); + DWORD dwHash = GetCompileInfo()->GetVersionResilientTypeHashCode(GetModuleHandle(), mdTypeToken); typesHashtable.Append(dwHash, pSection->Place(new UnsignedConstant(RidFromToken(mdTypeToken) << 1))); } @@ -379,18 +420,7 @@ void ZapImage::OutputTypesTableForReadyToRun(IMDInternalImport * pMDImport) mdToken mdTypeToken; while (pMDImport->EnumNext(&hEnum, &mdTypeToken)) { - DWORD dwHash = 0; - mdTypeDef mdCurrentToken = mdTypeToken; - - do - { - if (FAILED(pMDImport->GetExportedTypeProps(mdCurrentToken, &pszNameSpace, &pszName, &mdCurrentToken, NULL, NULL))) - ThrowHR(COR_E_BADIMAGEFORMAT); - - dwHash = ((dwHash << 5) + dwHash) ^ HashStringA(pszName); - dwHash = ((dwHash << 5) + dwHash) ^ HashStringA(pszNameSpace == NULL ? "" : pszNameSpace); - - } while (TypeFromToken(mdCurrentToken) == mdtExportedType); + DWORD dwHash = GetCompileInfo()->GetVersionResilientTypeHashCode(GetModuleHandle(), mdTypeToken); typesHashtable.Append(dwHash, pSection->Place(new UnsignedConstant((RidFromToken(mdTypeToken) << 1) | 1))); } |