summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Chen (CLR) <jochen@microsoft.com>2016-04-25 01:55:00 -0700
committerJohnChen0 <jochen@microsoft.com>2016-04-30 22:44:50 -0700
commit9d2590dc37aea56bee9f03d2597eaa1ce1bb62c5 (patch)
tree72605919515280930e2f40b6dca7a9521cac3559
parentae0b815a0483ebdc861da14d41f3f4c10d3a477a (diff)
downloadcoreclr-9d2590dc37aea56bee9f03d2597eaa1ce1bb62c5.tar.gz
coreclr-9d2590dc37aea56bee9f03d2597eaa1ce1bb62c5.tar.bz2
coreclr-9d2590dc37aea56bee9f03d2597eaa1ce1bb62c5.zip
Support generic methods without generic dictionary
-rw-r--r--src/inc/corcompile.h4
-rw-r--r--src/inc/readytorun.h4
-rw-r--r--src/vm/CMakeLists.txt1
-rw-r--r--src/vm/compile.cpp21
-rw-r--r--src/vm/compile.h4
-rw-r--r--src/vm/crossgen/CMakeLists.txt1
-rw-r--r--src/vm/crossgen/wks_crossgen.nativeproj1
-rw-r--r--src/vm/dac/dacwks.targets1
-rw-r--r--src/vm/nativeformatreader.h15
-rw-r--r--src/vm/readytoruninfo.cpp203
-rw-r--r--src/vm/readytoruninfo.h1
-rw-r--r--src/vm/typehashingalgorithms.h85
-rw-r--r--src/vm/versionresilienthashcode.cpp131
-rw-r--r--src/vm/versionresilienthashcode.h9
-rw-r--r--src/vm/wks/wks.targets1
-rw-r--r--src/vm/zapsig.cpp35
-rw-r--r--src/zap/zapimage.cpp6
-rw-r--r--src/zap/zapinfo.cpp26
-rw-r--r--src/zap/zapreadytorun.cpp94
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)));
}