summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFadi Hanna <fadim@microsoft.com>2016-06-21 11:51:05 -0700
committerGitHub <noreply@github.com>2016-06-21 11:51:05 -0700
commitb9f5ae88cc49836c8d31f07db7800707165cdb06 (patch)
treec5d6246379b51c19e9c79489364da1e2a6fe79f5
parentfb79613c44df5ad80831dba1460ffb14dd6497a3 (diff)
downloadcoreclr-b9f5ae88cc49836c8d31f07db7800707165cdb06.tar.gz
coreclr-b9f5ae88cc49836c8d31f07db7800707165cdb06.tar.bz2
coreclr-b9f5ae88cc49836c8d31f07db7800707165cdb06.zip
Generic dictionary minor performance improvement and simplification for R2R (#5690)
A set of refactoring changes to slighly improve the performance of generic dictionary access on R2R images, and simplifying the codebase: 1) Removing dependency on CEEInfo::ComputeRuntimeLookupForSharedGenericTokenStatic (and deleting the API). 2) Stop parsing the generic type/method signatures when generating the R2R dictionary lookup assembly stub. 3) Avoid re-encoding the generic type/method signatures in a new in-memory blob using a SigBuilder (signatures used directly from the R2R image) 4) Moved the parsing/loading of type/method signatures to Dictionary::PopulateEntry() 5) Dictionary index and slot number are now encoded in the generated assembly stub instead of the signature (stub takes a pointer to a data blob, which contains the signature, the dictionary index and slot, and the module pointer)
-rw-r--r--src/inc/corinfo.h8
-rw-r--r--src/vm/amd64/cgenamd64.cpp24
-rw-r--r--src/vm/arm64/stubs.cpp24
-rw-r--r--src/vm/codeman.cpp34
-rw-r--r--src/vm/codeman.h1
-rw-r--r--src/vm/crossgencompile.cpp2
-rw-r--r--src/vm/genericdict.cpp504
-rw-r--r--src/vm/genericdict.h40
-rw-r--r--src/vm/i386/cgenx86.cpp24
-rw-r--r--src/vm/jithelpers.cpp105
-rw-r--r--src/vm/jitinterface.cpp366
-rw-r--r--src/vm/jitinterface.h27
-rw-r--r--src/vm/prestub.cpp236
-rw-r--r--src/vm/readytoruninfo.h2
-rw-r--r--src/zap/zapinfo.cpp10
15 files changed, 873 insertions, 534 deletions
diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h
index fbbc95e05c..baae699bcf 100644
--- a/src/inc/corinfo.h
+++ b/src/inc/corinfo.h
@@ -614,10 +614,10 @@ enum CorInfoHelpFunc
CORINFO_HELP_MEMSET, // Init block of memory
CORINFO_HELP_MEMCPY, // Copy block of memory
- CORINFO_HELP_RUNTIMEHANDLE_METHOD, // determine a type/field/method handle at run-time
- CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG,// determine a type/field/method handle at run-time, with IBC logging
- CORINFO_HELP_RUNTIMEHANDLE_CLASS, // determine a type/field/method handle at run-time
- CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG,// determine a type/field/method handle at run-time, with IBC logging
+ CORINFO_HELP_RUNTIMEHANDLE_METHOD, // determine a type/field/method handle at run-time
+ CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG, // determine a type/field/method handle at run-time, with IBC logging
+ CORINFO_HELP_RUNTIMEHANDLE_CLASS, // determine a type/field/method handle at run-time
+ CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG, // determine a type/field/method handle at run-time, with IBC logging
// These helpers are required for MDIL backward compatibility only. They are not used by current JITed code.
CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_OBSOLETE, // Convert from a TypeHandle (native structure pointer) to RuntimeTypeHandle at run-time
diff --git a/src/vm/amd64/cgenamd64.cpp b/src/vm/amd64/cgenamd64.cpp
index f8bd458a6a..d5698005be 100644
--- a/src/vm/amd64/cgenamd64.cpp
+++ b/src/vm/amd64/cgenamd64.cpp
@@ -20,6 +20,7 @@
#include "fcall.h"
#include "array.h"
#include "virtualcallstub.h"
+#include "jitinterface.h"
#ifdef FEATURE_COMINTEROP
#include "clrtocomcall.h"
@@ -1140,19 +1141,28 @@ PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADD
END_DYNAMIC_HELPER_EMIT();
}
-PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup)
+PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup, DWORD dictionaryIndexAndSlot, Module * pModule)
{
STANDARD_VM_CONTRACT;
+ PCODE helperAddress = (pLookup->helper == CORINFO_HELP_RUNTIMEHANDLE_METHOD ?
+ GetEEFuncEntryPoint(JIT_GenericHandleMethodWithSlotAndModule) :
+ GetEEFuncEntryPoint(JIT_GenericHandleClassWithSlotAndModule));
+
+ GenericHandleArgs * pArgs = (GenericHandleArgs *)(void *)pAllocator->GetDynamicHelpersHeap()->AllocAlignedMem(sizeof(GenericHandleArgs), DYNAMIC_HELPER_ALIGNMENT);
+ pArgs->dictionaryIndexAndSlot = dictionaryIndexAndSlot;
+ pArgs->signature = pLookup->signature;
+ pArgs->module = (CORINFO_MODULE_HANDLE)pModule;
+
// It's available only via the run-time helper function
if (pLookup->indirections == CORINFO_USEHELPER)
{
BEGIN_DYNAMIC_HELPER_EMIT(15);
// rcx/rdi contains the generic context parameter
- // mov rdx/rsi,pLookup->signature
- // jmp pLookup->helper
- EmitHelperWithArg(p, pAllocator, (TADDR)pLookup->signature, CEEJitInfo::getHelperFtnStatic(pLookup->helper));
+ // mov rdx/rsi,pArgs
+ // jmp helperAddress
+ EmitHelperWithArg(p, pAllocator, (TADDR)pArgs, helperAddress);
END_DYNAMIC_HELPER_EMIT();
}
@@ -1248,9 +1258,9 @@ PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator,
*(UINT32*)p = 0x00c18948; p += 3; // mov rcx,rax
#endif
- // mov rdx,pLookup->signature
- // jmp pLookup->helper
- EmitHelperWithArg(p, pAllocator, (TADDR)pLookup->signature, CEEJitInfo::getHelperFtnStatic(pLookup->helper));
+ // mov rdx,pArgs
+ // jmp helperAddress
+ EmitHelperWithArg(p, pAllocator, (TADDR)pArgs, helperAddress);
}
}
diff --git a/src/vm/arm64/stubs.cpp b/src/vm/arm64/stubs.cpp
index c662e0a5f9..01a56e39fc 100644
--- a/src/vm/arm64/stubs.cpp
+++ b/src/vm/arm64/stubs.cpp
@@ -13,6 +13,7 @@
#include "tls.h"
#include "asmconstants.h"
#include "virtualcallstub.h"
+#include "jitinterface.h"
#ifndef DACCESS_COMPILE
//-----------------------------------------------------------------------
@@ -2004,10 +2005,19 @@ PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADD
END_DYNAMIC_HELPER_EMIT();
}
-PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup)
+PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup, DWORD dictionaryIndexAndSlot, Module * pModule)
{
STANDARD_VM_CONTRACT;
+ PCODE helperAddress = (pLookup->helper == CORINFO_HELP_RUNTIMEHANDLE_METHOD ?
+ GetEEFuncEntryPoint(JIT_GenericHandleMethodWithSlotAndModule) :
+ GetEEFuncEntryPoint(JIT_GenericHandleClassWithSlotAndModule));
+
+ GenericHandleArgs * pArgs = (GenericHandleArgs *)(void *)pAllocator->GetDynamicHelpersHeap()->AllocAlignedMem(sizeof(GenericHandleArgs), DYNAMIC_HELPER_ALIGNMENT);
+ pArgs->dictionaryIndexAndSlot = dictionaryIndexAndSlot;
+ pArgs->signature = pLookup->signature;
+ pArgs->module = (CORINFO_MODULE_HANDLE)pModule;
+
// It's available only via the run-time helper function
if (pLookup->indirections == CORINFO_USEHELPER)
{
@@ -2015,9 +2025,9 @@ PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator,
// X0 already contains generic context parameter
// reuse EmitHelperWithArg for below two operations
- // X1 <- pLookup->signature
- // branch to pLookup->helper
- EmitHelperWithArg(p, pAllocator, (TADDR)pLookup->signature, CEEJitInfo::getHelperFtnStatic(pLookup->helper));
+ // X1 <- pArgs
+ // branch to helperAddress
+ EmitHelperWithArg(p, pAllocator, (TADDR)pArgs, helperAddress);
END_DYNAMIC_HELPER_EMIT();
}
@@ -2104,9 +2114,9 @@ PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator,
*(DWORD*)p = 0x91000120;
p += 4;
// reuse EmitHelperWithArg for below two operations
- // X1 <- pLookup->signature
- // branch to pLookup->helper
- EmitHelperWithArg(p, pAllocator, (TADDR)pLookup->signature, CEEJitInfo::getHelperFtnStatic(pLookup->helper));
+ // X1 <- pArgs
+ // branch to helperAddress
+ EmitHelperWithArg(p, pAllocator, (TADDR)pArgs, helperAddress);
}
// datalabel:
diff --git a/src/vm/codeman.cpp b/src/vm/codeman.cpp
index 701f5da392..7eea254646 100644
--- a/src/vm/codeman.cpp
+++ b/src/vm/codeman.cpp
@@ -4535,6 +4535,40 @@ PTR_Module ExecutionManager::FindZapModule(TADDR currentData)
}
/* static */
+PTR_Module ExecutionManager::FindReadyToRunModule(TADDR currentData)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ MODE_ANY;
+ STATIC_CONTRACT_HOST_CALLS;
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+#ifdef FEATURE_READYTORUN
+ ReaderLockHolder rlh;
+
+ RangeSection * pRS = GetRangeSection(currentData);
+ if (pRS == NULL)
+ return NULL;
+
+ if (pRS->flags & RangeSection::RANGE_SECTION_CODEHEAP)
+ return NULL;
+
+ if (pRS->flags & RangeSection::RANGE_SECTION_READYTORUN)
+ return dac_cast<PTR_Module>(pRS->pHeapListOrZapModule);;
+
+ return NULL;
+#else
+ return NULL;
+#endif
+}
+
+
+/* static */
PTR_Module ExecutionManager::FindModuleForGCRefMap(TADDR currentData)
{
CONTRACTL
diff --git a/src/vm/codeman.h b/src/vm/codeman.h
index f0703f363e..855c15125a 100644
--- a/src/vm/codeman.h
+++ b/src/vm/codeman.h
@@ -1298,6 +1298,7 @@ public:
}
static PTR_Module FindZapModule(TADDR currentData);
+ static PTR_Module FindReadyToRunModule(TADDR currentData);
// FindZapModule flavor to be used during GC to find GCRefMap
static PTR_Module FindModuleForGCRefMap(TADDR currentData);
diff --git a/src/vm/crossgencompile.cpp b/src/vm/crossgencompile.cpp
index bb5d7fa055..36ba0f6cbf 100644
--- a/src/vm/crossgencompile.cpp
+++ b/src/vm/crossgencompile.cpp
@@ -305,7 +305,7 @@ void CRemotingServices::DestroyThunk(MethodDesc* pMD)
}
#endif
-CORINFO_GENERIC_HANDLE JIT_GenericHandleWorker(MethodDesc * pMD, MethodTable * pMT, LPVOID signature)
+CORINFO_GENERIC_HANDLE JIT_GenericHandleWorker(MethodDesc * pMD, MethodTable * pMT, LPVOID signature, DWORD dictionaryIndexAndSlot, Module* pModule)
{
UNREACHABLE();
}
diff --git a/src/vm/genericdict.cpp b/src/vm/genericdict.cpp
index dfb9ea94dd..dda70b6296 100644
--- a/src/vm/genericdict.cpp
+++ b/src/vm/genericdict.cpp
@@ -108,21 +108,27 @@ DictionaryLayout::GetFirstDictionaryBucketSize(
//
// Optimize the case of a token being !i (for class dictionaries) or !!i (for method dictionaries)
//
-//static
+/* static */
BOOL
-DictionaryLayout::FindToken(
- LoaderAllocator * pAllocator,
- DWORD numGenericArgs,
- DictionaryLayout * pDictLayout,
- CORINFO_RUNTIME_LOOKUP * pResult,
- SigBuilder * pSigBuilder,
- int nFirstOffset)
+DictionaryLayout::FindTokenWorker(LoaderAllocator * pAllocator,
+ DWORD numGenericArgs,
+ DictionaryLayout * pDictLayout,
+ CORINFO_RUNTIME_LOOKUP * pResult,
+ SigBuilder * pSigBuilder,
+ BYTE * pSig,
+ DWORD cbSig,
+ int nFirstOffset,
+ DictionaryEntrySignatureSource signatureSource,
+ WORD * pSlotOut)
{
CONTRACTL
{
STANDARD_VM_CHECK;
PRECONDITION(numGenericArgs > 0);
PRECONDITION(CheckPointer(pDictLayout));
+ PRECONDITION(CheckPointer(pSlotOut));
+ PRECONDITION(CheckPointer(pSig));
+ PRECONDITION((pSigBuilder == NULL && cbSig == -1) || (CheckPointer(pSigBuilder) && cbSig > 0));
}
CONTRACTL_END
@@ -139,20 +145,34 @@ DictionaryLayout::FindToken(
BYTE * pCandidate = (BYTE *)pDictLayout->m_slots[iSlot].m_signature;
if (pCandidate != NULL)
{
- DWORD cbSig;
- BYTE * pSig = (BYTE *)pSigBuilder->GetSignature(&cbSig);
+ bool signaturesMatch = false;
- // Compare the signatures. We do not need to worry about the size of pCandidate.
- // As long as we are comparing one byte at a time we are guaranteed to not overrun.
- DWORD j;
- for (j = 0; j < cbSig; j++)
+ if (pSigBuilder != NULL)
{
- if (pCandidate[j] != pSig[j])
- break;
+ // JIT case: compare signatures by comparing the bytes in them. We exclude
+ // any ReadyToRun signatures from the JIT case.
+
+ if (pDictLayout->m_slots[iSlot].m_signatureSource != FromReadyToRunImage)
+ {
+ // Compare the signatures. We do not need to worry about the size of pCandidate.
+ // As long as we are comparing one byte at a time we are guaranteed to not overrun.
+ DWORD j;
+ for (j = 0; j < cbSig; j++)
+ {
+ if (pCandidate[j] != pSig[j])
+ break;
+ }
+ signaturesMatch = (j == cbSig);
+ }
+ }
+ else
+ {
+ // ReadyToRun case: compare signatures by comparing their pointer values
+ signaturesMatch = (pCandidate == pSig);
}
// We've found it
- if (j == cbSig)
+ if (signaturesMatch)
{
pResult->signature = pDictLayout->m_slots[iSlot].m_signature;
@@ -163,8 +183,9 @@ DictionaryLayout::FindToken(
return FALSE;
}
_ASSERTE(FitsIn<WORD>(nFirstOffset + 1));
- pResult->indirections = static_cast<WORD>(nFirstOffset+1);
+ pResult->indirections = static_cast<WORD>(nFirstOffset + 1);
pResult->offsets[nFirstOffset] = slot * sizeof(DictionaryEntry);
+ *pSlotOut = slot;
return TRUE;
}
}
@@ -177,15 +198,21 @@ DictionaryLayout::FindToken(
if (pDictLayout->m_slots[iSlot].m_signature != NULL)
goto RetryMatch;
- pSigBuilder->AppendData(isFirstBucket ? slot : 0);
+ PVOID pResultSignature = pSig;
+
+ if (pSigBuilder != NULL)
+ {
+ pSigBuilder->AppendData(isFirstBucket ? slot : 0);
- DWORD cbSig;
- PVOID pSig = pSigBuilder->GetSignature(&cbSig);
+ DWORD cbNewSig;
+ PVOID pNewSig = pSigBuilder->GetSignature(&cbNewSig);
- PVOID pPersisted = pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(cbSig));
- memcpy(pPersisted, pSig, cbSig);
+ pResultSignature = pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(cbNewSig));
+ memcpy(pResultSignature, pNewSig, cbNewSig);
+ }
- *EnsureWritablePages(&(pDictLayout->m_slots[iSlot].m_signature)) = pPersisted;
+ *EnsureWritablePages(&(pDictLayout->m_slots[iSlot].m_signature)) = pResultSignature;
+ *EnsureWritablePages(&(pDictLayout->m_slots[iSlot].m_signatureSource)) = signatureSource;
}
pResult->signature = pDictLayout->m_slots[iSlot].m_signature;
@@ -196,8 +223,9 @@ DictionaryLayout::FindToken(
return FALSE;
}
_ASSERTE(FitsIn<WORD>(nFirstOffset + 1));
- pResult->indirections = static_cast<WORD>(nFirstOffset+1);
+ pResult->indirections = static_cast<WORD>(nFirstOffset + 1);
pResult->offsets[nFirstOffset] = slot * sizeof(DictionaryEntry);
+ *pSlotOut = slot;
return TRUE;
}
slot++;
@@ -213,6 +241,38 @@ DictionaryLayout::FindToken(
isFirstBucket = FALSE;
}
} // DictionaryLayout::FindToken
+
+/* static */
+BOOL
+DictionaryLayout::FindToken(LoaderAllocator * pAllocator,
+ DWORD numGenericArgs,
+ DictionaryLayout * pDictLayout,
+ CORINFO_RUNTIME_LOOKUP * pResult,
+ SigBuilder * pSigBuilder,
+ int nFirstOffset,
+ DictionaryEntrySignatureSource signatureSource)
+{
+ DWORD cbSig;
+ BYTE * pSig = (BYTE *)pSigBuilder->GetSignature(&cbSig);
+
+ WORD slotDummy;
+ return FindTokenWorker(pAllocator, numGenericArgs, pDictLayout, pResult, pSigBuilder, pSig, cbSig, nFirstOffset, signatureSource, &slotDummy);
+}
+
+/* static */
+BOOL
+DictionaryLayout::FindToken(LoaderAllocator * pAllocator,
+ DWORD numGenericArgs,
+ DictionaryLayout * pDictLayout,
+ CORINFO_RUNTIME_LOOKUP * pResult,
+ BYTE * signature,
+ int nFirstOffset,
+ DictionaryEntrySignatureSource signatureSource,
+ WORD * pSlotOut)
+{
+ return FindTokenWorker(pAllocator, numGenericArgs, pDictLayout, pResult, NULL, signature, -1, nFirstOffset, signatureSource, pSlotOut);
+}
+
#endif //!DACCESS_COMPILE
//---------------------------------------------------------------------------------------
@@ -575,7 +635,9 @@ Dictionary::PopulateEntry(
MethodTable * pMT,
LPVOID signature,
BOOL nonExpansive,
- DictionaryEntry ** ppSlot)
+ DictionaryEntry ** ppSlot,
+ DWORD dictionaryIndexAndSlot, /* = -1 */
+ Module * pModule /* = NULL */)
{
CONTRACTL {
THROWS;
@@ -583,14 +645,73 @@ Dictionary::PopulateEntry(
} CONTRACTL_END;
CORINFO_GENERIC_HANDLE result = NULL;
+ Dictionary * pDictionary = NULL;
*ppSlot = NULL;
+ bool isReadyToRunModule = (pModule != NULL && pModule->IsReadyToRun());
+
+ ZapSig::Context zapSigContext(NULL, NULL, ZapSig::NormalTokens);
+ ZapSig::Context * pZapSigContext = NULL;
+
+ ULONG kind = DictionaryEntryKind::EmptySlot;
+
SigPointer ptr((PCCOR_SIGNATURE)signature);
- Dictionary * pDictionary = NULL;
+ if (isReadyToRunModule)
+ {
+ PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)signature;
- ULONG kind; // DictionaryEntryKind
- IfFailThrow(ptr.GetData(&kind));
+ BYTE fixupKind = *pBlob++;
+
+ Module * pInfoModule = pModule;
+ if (fixupKind & ENCODE_MODULE_OVERRIDE)
+ {
+ DWORD moduleIndex = CorSigUncompressData(pBlob);
+ pInfoModule = pModule->GetModuleFromIndex(moduleIndex);
+ fixupKind &= ~ENCODE_MODULE_OVERRIDE;
+ }
+
+ _ASSERTE(fixupKind == ENCODE_DICTIONARY_LOOKUP_THISOBJ ||
+ fixupKind == ENCODE_DICTIONARY_LOOKUP_TYPE ||
+ fixupKind == ENCODE_DICTIONARY_LOOKUP_METHOD);
+
+ if (fixupKind == ENCODE_DICTIONARY_LOOKUP_THISOBJ)
+ {
+ SigPointer p(pBlob);
+ p.SkipExactlyOne();
+ pBlob = p.GetPtr();
+ }
+
+ CORCOMPILE_FIXUP_BLOB_KIND signatureKind = (CORCOMPILE_FIXUP_BLOB_KIND)CorSigUncompressData(pBlob);
+ switch (signatureKind)
+ {
+ case ENCODE_TYPE_HANDLE: kind = TypeHandleSlot; break;
+ case ENCODE_METHOD_HANDLE: kind = MethodDescSlot; break;
+ case ENCODE_METHOD_ENTRY: kind = MethodEntrySlot; break;
+ case ENCODE_VIRTUAL_ENTRY: kind = DispatchStubAddrSlot; break;
+
+ default:
+ _ASSERTE(!"Unexpected CORCOMPILE_FIXUP_BLOB_KIND");
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+ }
+
+ ptr = SigPointer(pBlob);
+
+ zapSigContext = ZapSig::Context(pInfoModule, pModule, ZapSig::NormalTokens);
+ pZapSigContext = &zapSigContext;
+ }
+ else
+ {
+ ptr = SigPointer((PCCOR_SIGNATURE)signature);
+ IfFailThrow(ptr.GetData(&kind));
+
+ Module * pContainingZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(signature));
+
+ zapSigContext = ZapSig::Context(MscorlibBinder::GetModule(), (void *)pContainingZapModule, ZapSig::NormalTokens);
+ pZapSigContext = (pContainingZapModule != NULL) ? &zapSigContext : NULL;
+ }
+
+ Module * pLookupModule = (isReadyToRunModule) ? pZapSigContext->pInfoModule : MscorlibBinder::GetModule();
if (pMT != NULL)
{
@@ -601,11 +722,19 @@ Dictionary::PopulateEntry(
// prepare for every possible derived type of the type containing the method). So instead we have to locate the exactly
// instantiated (non-shared) super-type of the class passed in.
- ULONG dictionaryIndex = 0;
- IfFailThrow(ptr.GetData(&dictionaryIndex));
-
pDictionary = pMT->GetDictionary();
+ ULONG dictionaryIndex = 0;
+
+ if (isReadyToRunModule)
+ {
+ dictionaryIndex = dictionaryIndexAndSlot >> 16;
+ }
+ else
+ {
+ IfFailThrow(ptr.GetData(&dictionaryIndex));
+ }
+
// MethodTable is expected to be normalized
_ASSERTE(pDictionary == pMT->GetPerInstInfo()[dictionaryIndex]);
}
@@ -626,15 +755,6 @@ Dictionary::PopulateEntry(
SigTypeContext::InitTypeContext(pMD, &typeContext);
}
-
- Module * pContainingZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(signature));
-
- ZapSig::Context zapSigContext(
- MscorlibBinder::GetModule(),
- (void *)pContainingZapModule,
- ZapSig::NormalTokens);
- ZapSig::Context * pZapSigContext = (pContainingZapModule != NULL) ? &zapSigContext : NULL;
-
TypeHandle constraintType;
TypeHandle declaringType;
@@ -643,7 +763,7 @@ Dictionary::PopulateEntry(
case DeclaringTypeHandleSlot:
{
declaringType = ptr.GetTypeHandleThrowing(
- MscorlibBinder::GetModule(),
+ pLookupModule,
&typeContext,
(nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
CLASS_LOADED,
@@ -663,7 +783,7 @@ Dictionary::PopulateEntry(
case TypeHandleSlot:
{
TypeHandle th = ptr.GetTypeHandleThrowing(
- MscorlibBinder::GetModule(),
+ pLookupModule,
&typeContext,
(nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
CLASS_LOADED,
@@ -694,7 +814,7 @@ Dictionary::PopulateEntry(
case ConstrainedMethodEntrySlot:
{
constraintType = ptr.GetTypeHandleThrowing(
- MscorlibBinder::GetModule(),
+ pLookupModule,
&typeContext,
(nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
CLASS_LOADED,
@@ -715,110 +835,205 @@ Dictionary::PopulateEntry(
case DispatchStubAddrSlot:
case MethodEntrySlot:
{
- TypeHandle ownerType = ptr.GetTypeHandleThrowing(
- MscorlibBinder::GetModule(),
- &typeContext,
- (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
- CLASS_LOADED,
- FALSE,
- NULL,
- pZapSigContext);
- if (ownerType.IsNull())
- {
- _ASSERTE(nonExpansive);
- return NULL;
- }
- IfFailThrow(ptr.SkipExactlyOne());
+ TypeHandle ownerType;
+ MethodTable * pOwnerMT = NULL;
+ MethodDesc * pMethod = NULL;
- // <NICE> wsperf: Create a path that doesn't load types or create new handles if nonExpansive is set </NICE>
- if (nonExpansive)
- return NULL;
+ DWORD methodFlags = 0;
+ BOOL isInstantiatingStub = 0;
+ BOOL isUnboxingStub = 0;
+ BOOL fMethodNeedsInstantiation = 0;
- MethodTable * pOwnerMT = ownerType.GetMethodTable();
- _ASSERTE(pOwnerMT != NULL);
+ DWORD methodSlot = -1;
+ BOOL fRequiresDispatchStub = 0;
- DWORD methodFlags;
- IfFailThrow(ptr.GetData(&methodFlags));
+ if (isReadyToRunModule)
+ {
+ IfFailThrow(ptr.GetData(&methodFlags));
- BOOL isInstantiatingStub = ((methodFlags & ENCODE_METHOD_SIG_InstantiatingStub) != 0);
- BOOL isUnboxingStub = ((methodFlags & ENCODE_METHOD_SIG_UnboxingStub) != 0);
- BOOL fMethodNeedsInstantiation = ((methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) != 0);
+ isInstantiatingStub = ((methodFlags & ENCODE_METHOD_SIG_InstantiatingStub) != 0) || (kind == MethodEntrySlot);
+ isUnboxingStub = ((methodFlags & ENCODE_METHOD_SIG_UnboxingStub) != 0);
+ fMethodNeedsInstantiation = ((methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) != 0);
- MethodDesc * pMethod = NULL;
+ if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
+ {
+ ownerType = ptr.GetTypeHandleThrowing(
+ pZapSigContext->pInfoModule,
+ &typeContext,
+ ClassLoader::LoadTypes,
+ CLASS_LOADED,
+ FALSE,
+ NULL,
+ pZapSigContext);
- if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) != 0)
- {
- // get the method desc using slot number
- DWORD slot;
- IfFailThrow(ptr.GetData(&slot));
+ IfFailThrow(ptr.SkipExactlyOne());
+ }
- if (kind == DispatchStubAddrSlot)
+ if (methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken)
{
- if (NingenEnabled())
- return NULL;
+ // get the method desc using slot number
+ IfFailThrow(ptr.GetData(&methodSlot));
-#ifndef CROSSGEN_COMPILE
- // Generate a dispatch stub and store it in the dictionary.
+ _ASSERTE(!ownerType.IsNull());
+ pMethod = ownerType.GetMethodTable()->GetMethodDescForSlot(methodSlot);
+ }
+ else
+ {
//
- // We generate an indirection so we don't have to write to the dictionary
- // when we do updates, and to simplify stub indirect callsites. Stubs stored in
- // dictionaries use "RegisterIndirect" stub calling, e.g. "call [eax]",
- // i.e. here the register "eax" would contain the value fetched from the dictionary,
- // which in turn points to the stub indirection which holds the value the current stub
- // address itself. If we just used "call eax" then we wouldn't know which stub indirection
- // to update. If we really wanted to avoid the extra indirection we could return the _address_ of the
- // dictionary entry to the caller, still using "call [eax]", and then the
- // stub dispatch mechanism can update the dictitonary itself and we don't
- // need an indirection.
- LoaderAllocator * pDictLoaderAllocator = (pMT != NULL) ? pMT->GetLoaderAllocator() : pMD->GetLoaderAllocator();
-
- VirtualCallStubManager * pMgr = pDictLoaderAllocator->GetVirtualCallStubManager();
-
- // We indirect through a cell so that updates can take place atomically.
- // The call stub and the indirection cell have the same lifetime as the dictionary itself, i.e.
- // are allocated in the domain of the dicitonary.
+ // decode method token
//
- // In the case of overflow (where there is no dictionary, just a global hash table) then
- // the entry will be placed in the overflow hash table (JitGenericHandleCache). This
- // is partitioned according to domain, i.e. is scraped each time an AppDomain gets unloaded.
- PCODE addr = pMgr->GetCallStub(ownerType, slot);
+ RID rid;
+ IfFailThrow(ptr.GetData(&rid));
- result = (CORINFO_GENERIC_HANDLE)pMgr->GenerateStubIndirection(addr);
- break;
-#endif // CROSSGEN_COMPILE
+ if (methodFlags & ENCODE_METHOD_SIG_MemberRefToken)
+ {
+ if (ownerType.IsNull())
+ {
+ FieldDesc * pFDDummy = NULL;
+
+ MemberLoader::GetDescFromMemberRef(pZapSigContext->pInfoModule, TokenFromRid(rid, mdtMemberRef), &pMethod, &pFDDummy, NULL, FALSE, &ownerType);
+ _ASSERTE(pMethod != NULL && pFDDummy == NULL);
+ }
+ else
+ {
+ pMethod = MemberLoader::GetMethodDescFromMemberRefAndType(pZapSigContext->pInfoModule, TokenFromRid(rid, mdtMemberRef), ownerType.GetMethodTable());
+ }
+ }
+ else
+ {
+ pMethod = MemberLoader::GetMethodDescFromMethodDef(pZapSigContext->pInfoModule, TokenFromRid(rid, mdtMethodDef), FALSE);
+ }
}
- pMethod = pOwnerMT->GetMethodDescForSlot(slot);
+ if (ownerType.IsNull())
+ ownerType = pMethod->GetMethodTable();
+
+ _ASSERT(!ownerType.IsNull() && !nonExpansive);
+ pOwnerMT = ownerType.GetMethodTable();
+
+ if (methodFlags & ENCODE_METHOD_SIG_Constrained)
+ {
+ _ASSERTE(!"ReadyToRun: Constrained methods dictionary entries not yet supported.");
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+ }
+
+ if (kind == DispatchStubAddrSlot && pMethod->IsVtableMethod())
+ {
+ fRequiresDispatchStub = TRUE;
+ methodSlot = pMethod->GetSlot();
+ }
}
else
{
- // Decode type where the method token is defined
- TypeHandle thMethodDefType = ptr.GetTypeHandleThrowing(
- MscorlibBinder::GetModule(),
- &typeContext,
- (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
- CLASS_LOADED,
- FALSE,
- NULL,
+ ownerType = ptr.GetTypeHandleThrowing(
+ pLookupModule,
+ &typeContext,
+ (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
+ CLASS_LOADED,
+ FALSE,
+ NULL,
pZapSigContext);
- if (thMethodDefType.IsNull())
+ if (ownerType.IsNull())
{
_ASSERTE(nonExpansive);
return NULL;
}
IfFailThrow(ptr.SkipExactlyOne());
- MethodTable * pMethodDefMT = thMethodDefType.GetMethodTable();
- _ASSERTE(pMethodDefMT != NULL);
-
- // decode method token
- RID rid;
- IfFailThrow(ptr.GetData(&rid));
- mdMethodDef token = TokenFromRid(rid, mdtMethodDef);
-
- // The RID map should have been filled out if we fully loaded the class
- pMethod = pMethodDefMT->GetModule()->LookupMethodDef(token);
- _ASSERTE(pMethod != NULL);
- pMethod->CheckRestore();
+
+ // <NICE> wsperf: Create a path that doesn't load types or create new handles if nonExpansive is set </NICE>
+ if (nonExpansive)
+ return NULL;
+
+ pOwnerMT = ownerType.GetMethodTable();
+ _ASSERTE(pOwnerMT != NULL);
+
+ IfFailThrow(ptr.GetData(&methodFlags));
+
+ isInstantiatingStub = ((methodFlags & ENCODE_METHOD_SIG_InstantiatingStub) != 0);
+ isUnboxingStub = ((methodFlags & ENCODE_METHOD_SIG_UnboxingStub) != 0);
+ fMethodNeedsInstantiation = ((methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) != 0);
+
+ if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) != 0)
+ {
+ // get the method desc using slot number
+ IfFailThrow(ptr.GetData(&methodSlot));
+
+ if (kind == DispatchStubAddrSlot)
+ {
+ if (NingenEnabled())
+ return NULL;
+
+#ifndef CROSSGEN_COMPILE
+ fRequiresDispatchStub = TRUE;
+#endif
+ }
+
+ if (!fRequiresDispatchStub)
+ pMethod = pOwnerMT->GetMethodDescForSlot(methodSlot);
+ }
+ else
+ {
+ // Decode type where the method token is defined
+ TypeHandle thMethodDefType = ptr.GetTypeHandleThrowing(
+ pLookupModule,
+ &typeContext,
+ (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
+ CLASS_LOADED,
+ FALSE,
+ NULL,
+ pZapSigContext);
+ if (thMethodDefType.IsNull())
+ {
+ _ASSERTE(nonExpansive);
+ return NULL;
+ }
+ IfFailThrow(ptr.SkipExactlyOne());
+ MethodTable * pMethodDefMT = thMethodDefType.GetMethodTable();
+ _ASSERTE(pMethodDefMT != NULL);
+
+ // decode method token
+ RID rid;
+ IfFailThrow(ptr.GetData(&rid));
+ mdMethodDef token = TokenFromRid(rid, mdtMethodDef);
+
+ // The RID map should have been filled out if we fully loaded the class
+ pMethod = pMethodDefMT->GetModule()->LookupMethodDef(token);
+ _ASSERTE(pMethod != NULL);
+ pMethod->CheckRestore();
+ }
+ }
+
+ if (fRequiresDispatchStub)
+ {
+#ifndef CROSSGEN_COMPILE
+ // Generate a dispatch stub and store it in the dictionary.
+ //
+ // We generate an indirection so we don't have to write to the dictionary
+ // when we do updates, and to simplify stub indirect callsites. Stubs stored in
+ // dictionaries use "RegisterIndirect" stub calling, e.g. "call [eax]",
+ // i.e. here the register "eax" would contain the value fetched from the dictionary,
+ // which in turn points to the stub indirection which holds the value the current stub
+ // address itself. If we just used "call eax" then we wouldn't know which stub indirection
+ // to update. If we really wanted to avoid the extra indirection we could return the _address_ of the
+ // dictionary entry to the caller, still using "call [eax]", and then the
+ // stub dispatch mechanism can update the dictitonary itself and we don't
+ // need an indirection.
+ LoaderAllocator * pDictLoaderAllocator = (pMT != NULL) ? pMT->GetLoaderAllocator() : pMD->GetLoaderAllocator();
+
+ VirtualCallStubManager * pMgr = pDictLoaderAllocator->GetVirtualCallStubManager();
+
+ // We indirect through a cell so that updates can take place atomically.
+ // The call stub and the indirection cell have the same lifetime as the dictionary itself, i.e.
+ // are allocated in the domain of the dicitonary.
+ //
+ // In the case of overflow (where there is no dictionary, just a global hash table) then
+ // the entry will be placed in the overflow hash table (JitGenericHandleCache). This
+ // is partitioned according to domain, i.e. is scraped each time an AppDomain gets unloaded.
+ PCODE addr = pMgr->GetCallStub(ownerType, methodSlot);
+
+ result = (CORINFO_GENERIC_HANDLE)pMgr->GenerateStubIndirection(addr);
+ break;
+#endif // CROSSGEN_COMPILE
}
Instantiation inst;
@@ -833,17 +1048,17 @@ Dictionary::PopulateEntry(
if (!ClrSafeInt<SIZE_T>::multiply(nargs, sizeof(TypeHandle), cbMem/* passed by ref */))
ThrowHR(COR_E_OVERFLOW);
-
- TypeHandle * pInst = (TypeHandle*) _alloca(cbMem);
+
+ TypeHandle * pInst = (TypeHandle*)_alloca(cbMem);
for (DWORD i = 0; i < nargs; i++)
{
pInst[i] = ptr.GetTypeHandleThrowing(
- MscorlibBinder::GetModule(),
- &typeContext,
- ClassLoader::LoadTypes,
- CLASS_LOADED,
- FALSE,
- NULL,
+ pLookupModule,
+ &typeContext,
+ ClassLoader::LoadTypes,
+ CLASS_LOADED,
+ FALSE,
+ NULL,
pZapSigContext);
IfFailThrow(ptr.SkipExactlyOne());
}
@@ -859,14 +1074,17 @@ Dictionary::PopulateEntry(
// stub for static methods in generic classees if needed, also for BoxedEntryPointStubs
// in non-generic structs.
pMethod = MethodDesc::FindOrCreateAssociatedMethodDesc(
- pMethod,
- pOwnerMT,
- isUnboxingStub,
- inst,
+ pMethod,
+ pOwnerMT,
+ isUnboxingStub,
+ inst,
(!isInstantiatingStub && !isUnboxingStub));
if (kind == ConstrainedMethodEntrySlot)
{
+ // TODO: READYTORUN: Support for constrained method entry slots
+ _ASSERT(!isReadyToRunModule);
+
_ASSERTE(!constraintType.IsNull());
MethodDesc *pResolvedMD = constraintType.GetMethodTable()->TryResolveConstraintMethodApprox(ownerType, pMethod);
@@ -903,7 +1121,7 @@ Dictionary::PopulateEntry(
case FieldDescSlot:
{
TypeHandle th = ptr.GetTypeHandleThrowing(
- MscorlibBinder::GetModule(),
+ pLookupModule,
&typeContext,
(nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes),
CLASS_LOADED,
@@ -935,7 +1153,15 @@ Dictionary::PopulateEntry(
}
ULONG slotIndex;
- IfFailThrow(ptr.GetData(&slotIndex));
+ if (isReadyToRunModule)
+ {
+ _ASSERT(dictionaryIndexAndSlot != -1);
+ slotIndex = (ULONG)(dictionaryIndexAndSlot & 0xFFFF);
+ }
+ else
+ {
+ IfFailThrow(ptr.GetData(&slotIndex));
+ }
MemoryBarrier();
diff --git a/src/vm/genericdict.h b/src/vm/genericdict.h
index e63b3c8f03..1cb172a174 100644
--- a/src/vm/genericdict.h
+++ b/src/vm/genericdict.h
@@ -66,6 +66,13 @@ enum DictionaryEntryKind
DeclaringTypeHandleSlot = 7,
};
+enum DictionaryEntrySignatureSource : BYTE
+{
+ FromZapImage = 0,
+ FromReadyToRunImage = 1,
+ FromJIT = 2,
+};
+
class DictionaryEntryLayout
{
public:
@@ -75,6 +82,8 @@ public:
DictionaryEntryKind GetKind();
PTR_VOID m_signature;
+
+ DictionaryEntrySignatureSource m_signatureSource;
};
typedef DPTR(DictionaryEntryLayout) PTR_DictionaryEntryLayout;
@@ -99,7 +108,19 @@ private:
WORD m_numSlots;
// m_numSlots of these
- DictionaryEntryLayout m_slots[1];
+ DictionaryEntryLayout m_slots[1];
+
+ static BOOL FindTokenWorker(LoaderAllocator *pAllocator,
+ DWORD numGenericArgs,
+ DictionaryLayout *pDictLayout,
+ CORINFO_RUNTIME_LOOKUP *pResult,
+ SigBuilder * pSigBuilder,
+ BYTE * pSig,
+ DWORD cbSig,
+ int nFirstOffset,
+ DictionaryEntrySignatureSource signatureSource,
+ WORD * pSlotOut);
+
public:
// Create an initial dictionary layout with a single bucket containing numSlots slots
@@ -114,7 +135,17 @@ public:
DictionaryLayout *pDictLayout,
CORINFO_RUNTIME_LOOKUP *pResult,
SigBuilder * pSigBuilder,
- int nFirstOffset);
+ int nFirstOffset,
+ DictionaryEntrySignatureSource signatureSource);
+
+ static BOOL FindToken(LoaderAllocator * pAllocator,
+ DWORD numGenericArgs,
+ DictionaryLayout * pDictLayout,
+ CORINFO_RUNTIME_LOOKUP * pResult,
+ BYTE * signature,
+ int nFirstOffset,
+ DictionaryEntrySignatureSource signatureSource,
+ WORD * pSlotOut);
DWORD GetMaxSlots();
DWORD GetNumUsedSlots();
@@ -253,7 +284,10 @@ class Dictionary
MethodTable * pMT,
LPVOID signature,
BOOL nonExpansive,
- DictionaryEntry ** ppSlot);
+ DictionaryEntry ** ppSlot,
+ DWORD dictionaryIndexAndSlot = -1,
+ Module * pModule = NULL);
+
void PrepopulateDictionary(MethodDesc * pMD,
MethodTable * pMT,
BOOL nonExpansive);
diff --git a/src/vm/i386/cgenx86.cpp b/src/vm/i386/cgenx86.cpp
index a9c2967c68..48428a1c61 100644
--- a/src/vm/i386/cgenx86.cpp
+++ b/src/vm/i386/cgenx86.cpp
@@ -34,6 +34,7 @@
#include "class.h"
#include "virtualcallstub.h"
#include "mdaassistants.h"
+#include "jitinterface.h"
#ifdef FEATURE_COMINTEROP
#include "comtoclrcall.h"
@@ -2153,19 +2154,28 @@ PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADD
END_DYNAMIC_HELPER_EMIT();
}
-PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup)
+PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup, DWORD dictionaryIndexAndSlot, Module * pModule)
{
STANDARD_VM_CONTRACT;
+ PCODE helperAddress = (pLookup->helper == CORINFO_HELP_RUNTIMEHANDLE_METHOD ?
+ GetEEFuncEntryPoint(JIT_GenericHandleMethodWithSlotAndModule) :
+ GetEEFuncEntryPoint(JIT_GenericHandleClassWithSlotAndModule));
+
+ GenericHandleArgs * pArgs = (GenericHandleArgs *)(void *)pAllocator->GetDynamicHelpersHeap()->AllocAlignedMem(sizeof(GenericHandleArgs), DYNAMIC_HELPER_ALIGNMENT);
+ pArgs->dictionaryIndexAndSlot = dictionaryIndexAndSlot;
+ pArgs->signature = pLookup->signature;
+ pArgs->module = (CORINFO_MODULE_HANDLE)pModule;
+
// It's available only via the run-time helper function
if (pLookup->indirections == CORINFO_USEHELPER)
{
BEGIN_DYNAMIC_HELPER_EMIT(10);
// ecx contains the generic context parameter
- // mov edx,pLookup->signature
- // jmp pLookup->helper
- EmitHelperWithArg(p, pAllocator, (TADDR)pLookup->signature, CEEJitInfo::getHelperFtnStatic(pLookup->helper));
+ // mov edx,pArgs
+ // jmp helperAddress
+ EmitHelperWithArg(p, pAllocator, (TADDR)pArgs, helperAddress);
END_DYNAMIC_HELPER_EMIT();
}
@@ -2232,9 +2242,9 @@ PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator,
// mov ecx,eax
*(UINT16*)p = 0xc189; p += 2;
- // mov edx,pLookup->signature
- // jmp pLookup->helper
- EmitHelperWithArg(p, pAllocator, (TADDR)pLookup->signature, CEEJitInfo::getHelperFtnStatic(pLookup->helper));
+ // mov edx,pArgs
+ // jmp helperAddress
+ EmitHelperWithArg(p, pAllocator, (TADDR)pArgs, helperAddress);
}
}
diff --git a/src/vm/jithelpers.cpp b/src/vm/jithelpers.cpp
index fffc6ceece..1626810758 100644
--- a/src/vm/jithelpers.cpp
+++ b/src/vm/jithelpers.cpp
@@ -3994,11 +3994,7 @@ void ClearJitGenericHandleCache(AppDomain *pDomain)
// Factored out most of the body of JIT_GenericHandle so it could be called easily from the CER reliability code to pre-populate the
// cache.
-CORINFO_GENERIC_HANDLE
-JIT_GenericHandleWorker(
- MethodDesc * pMD,
- MethodTable * pMT,
- LPVOID signature)
+CORINFO_GENERIC_HANDLE JIT_GenericHandleWorker(MethodDesc * pMD, MethodTable * pMT, LPVOID signature, DWORD dictionaryIndexAndSlot, Module* pModule)
{
CONTRACTL {
THROWS;
@@ -4009,20 +4005,34 @@ JIT_GenericHandleWorker(
if (pMT != NULL)
{
- SigPointer ptr((PCCOR_SIGNATURE)signature);
+ ULONG dictionaryIndex = 0;
- ULONG kind; // DictionaryEntryKind
- IfFailThrow(ptr.GetData(&kind));
+ if (pModule != NULL)
+ {
+#ifdef _DEBUG
+ // Only in R2R mode are the module, dictionary index and dictionary slot provided as an input
+ _ASSERTE(dictionaryIndexAndSlot != -1);
+ _ASSERT(ExecutionManager::FindReadyToRunModule(dac_cast<TADDR>(signature)) == pModule);
+#endif
+ dictionaryIndex = (dictionaryIndexAndSlot >> 16);
+ }
+ else
+ {
+ SigPointer ptr((PCCOR_SIGNATURE)signature);
- // We need to normalize the class passed in (if any) for reliability purposes. That's because preparation of a code region that
- // contains these handle lookups depends on being able to predict exactly which lookups are required (so we can pre-cache the
- // answers and remove any possibility of failure at runtime). This is hard to do if the lookup (in this case the lookup of the
- // dictionary overflow cache) is keyed off the somewhat arbitrary type of the instance on which the call is made (we'd need to
- // prepare for every possible derived type of the type containing the method). So instead we have to locate the exactly
- // instantiated (non-shared) super-type of the class passed in.
+ ULONG kind; // DictionaryEntryKind
+ IfFailThrow(ptr.GetData(&kind));
- ULONG dictionaryIndex = 0;
- IfFailThrow(ptr.GetData(&dictionaryIndex));
+ // We need to normalize the class passed in (if any) for reliability purposes. That's because preparation of a code region that
+ // contains these handle lookups depends on being able to predict exactly which lookups are required (so we can pre-cache the
+ // answers and remove any possibility of failure at runtime). This is hard to do if the lookup (in this case the lookup of the
+ // dictionary overflow cache) is keyed off the somewhat arbitrary type of the instance on which the call is made (we'd need to
+ // prepare for every possible derived type of the type containing the method). So instead we have to locate the exactly
+ // instantiated (non-shared) super-type of the class passed in.
+
+ _ASSERTE(dictionaryIndexAndSlot == -1);
+ IfFailThrow(ptr.GetData(&dictionaryIndex));
+ }
pDeclaringMT = pMT;
for (;;)
@@ -4049,7 +4059,7 @@ JIT_GenericHandleWorker(
}
DictionaryEntry * pSlot;
- CORINFO_GENERIC_HANDLE result = (CORINFO_GENERIC_HANDLE)Dictionary::PopulateEntry(pMD, pDeclaringMT, signature, FALSE, &pSlot);
+ CORINFO_GENERIC_HANDLE result = (CORINFO_GENERIC_HANDLE)Dictionary::PopulateEntry(pMD, pDeclaringMT, signature, FALSE, &pSlot, dictionaryIndexAndSlot, pModule);
if (pSlot == NULL)
{
@@ -4076,10 +4086,12 @@ JIT_GenericHandleWorker(
/*********************************************************************/
// slow helper to tail call from the fast one
-NOINLINE HCIMPL3(CORINFO_GENERIC_HANDLE, JIT_GenericHandle_Framed,
- CORINFO_CLASS_HANDLE classHnd,
- CORINFO_METHOD_HANDLE methodHnd,
- LPVOID signature)
+NOINLINE HCIMPL5(CORINFO_GENERIC_HANDLE, JIT_GenericHandle_Framed,
+ CORINFO_CLASS_HANDLE classHnd,
+ CORINFO_METHOD_HANDLE methodHnd,
+ LPVOID signature,
+ DWORD dictionaryIndexAndSlot,
+ CORINFO_MODULE_HANDLE moduleHnd)
{
CONTRACTL {
FCALL_CHECK;
@@ -4092,11 +4104,12 @@ NOINLINE HCIMPL3(CORINFO_GENERIC_HANDLE, JIT_GenericHandle_Framed,
MethodDesc * pMD = GetMethod(methodHnd);
MethodTable * pMT = TypeHandle(classHnd).AsMethodTable();
+ Module * pModule = GetModule(moduleHnd);
// Set up a frame
HELPER_METHOD_FRAME_BEGIN_RET_0();
- result = JIT_GenericHandleWorker(pMD, pMT, signature);
+ result = JIT_GenericHandleWorker(pMD, pMT, signature, dictionaryIndexAndSlot, pModule);
HELPER_METHOD_FRAME_END();
@@ -4125,7 +4138,27 @@ HCIMPL2(CORINFO_GENERIC_HANDLE, JIT_GenericHandleMethod, CORINFO_METHOD_HANDLE
// Tailcall to the slow helper
ENDFORBIDGC();
- return HCCALL3(JIT_GenericHandle_Framed, NULL, methodHnd, signature);
+ return HCCALL5(JIT_GenericHandle_Framed, NULL, methodHnd, signature, -1, NULL);
+}
+HCIMPLEND
+
+HCIMPL2(CORINFO_GENERIC_HANDLE, JIT_GenericHandleMethodWithSlotAndModule, CORINFO_METHOD_HANDLE methodHnd, GenericHandleArgs * pArgs)
+{
+ CONTRACTL{
+ FCALL_CHECK;
+ PRECONDITION(CheckPointer(methodHnd));
+ PRECONDITION(GetMethod(methodHnd)->IsRestored());
+ PRECONDITION(CheckPointer(pArgs));
+ } CONTRACTL_END;
+
+ JitGenericHandleCacheKey key(NULL, methodHnd, pArgs->signature);
+ HashDatum res;
+ if (g_pJitGenericHandleCache->GetValueSpeculative(&key, &res))
+ return (CORINFO_GENERIC_HANDLE)(DictionaryEntry)res;
+
+ // Tailcall to the slow helper
+ ENDFORBIDGC();
+ return HCCALL5(JIT_GenericHandle_Framed, NULL, methodHnd, pArgs->signature, pArgs->dictionaryIndexAndSlot, pArgs->module);
}
HCIMPLEND
#include <optdefault.h>
@@ -4149,7 +4182,7 @@ HCIMPL2(CORINFO_GENERIC_HANDLE, JIT_GenericHandleMethodLogging, CORINFO_METHOD_H
// Tailcall to the slow helper
ENDFORBIDGC();
- return HCCALL3(JIT_GenericHandle_Framed, NULL, methodHnd, signature);
+ return HCCALL5(JIT_GenericHandle_Framed, NULL, methodHnd, signature, -1, NULL);
}
HCIMPLEND
@@ -4171,7 +4204,27 @@ HCIMPL2(CORINFO_GENERIC_HANDLE, JIT_GenericHandleClass, CORINFO_CLASS_HANDLE cla
// Tailcall to the slow helper
ENDFORBIDGC();
- return HCCALL3(JIT_GenericHandle_Framed, classHnd, NULL, signature);
+ return HCCALL5(JIT_GenericHandle_Framed, classHnd, NULL, signature, -1, NULL);
+}
+HCIMPLEND
+
+HCIMPL2(CORINFO_GENERIC_HANDLE, JIT_GenericHandleClassWithSlotAndModule, CORINFO_CLASS_HANDLE classHnd, GenericHandleArgs * pArgs)
+{
+ CONTRACTL{
+ FCALL_CHECK;
+ PRECONDITION(CheckPointer(classHnd));
+ PRECONDITION(TypeHandle(classHnd).IsRestored());
+ PRECONDITION(CheckPointer(pArgs));
+ } CONTRACTL_END;
+
+ JitGenericHandleCacheKey key(classHnd, NULL, pArgs->signature);
+ HashDatum res;
+ if (g_pJitGenericHandleCache->GetValueSpeculative(&key, &res))
+ return (CORINFO_GENERIC_HANDLE)(DictionaryEntry)res;
+
+ // Tailcall to the slow helper
+ ENDFORBIDGC();
+ return HCCALL5(JIT_GenericHandle_Framed, classHnd, NULL, pArgs->signature, pArgs->dictionaryIndexAndSlot, pArgs->module);
}
HCIMPLEND
#include <optdefault.h>
@@ -4195,7 +4248,7 @@ HCIMPL2(CORINFO_GENERIC_HANDLE, JIT_GenericHandleClassLogging, CORINFO_CLASS_HAN
// Tailcall to the slow helper
ENDFORBIDGC();
- return HCCALL3(JIT_GenericHandle_Framed, classHnd, NULL, signature);
+ return HCCALL5(JIT_GenericHandle_Framed, classHnd, NULL, signature, -1, NULL);
}
HCIMPLEND
diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
index 99e987d7dc..b72eaf3826 100644
--- a/src/vm/jitinterface.cpp
+++ b/src/vm/jitinterface.cpp
@@ -3064,6 +3064,7 @@ static BOOL IsTypeSpecForTypicalInstantiation(SigPointer sigptr)
return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_VAR, ntypars);
}
+
void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entryKind,
CORINFO_RESOLVED_TOKEN * pResolvedToken,
CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
@@ -3081,15 +3082,58 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entr
pResultLookup->lookupKind.needsRuntimeLookup = true;
pResultLookup->lookupKind.runtimeLookupFlags = 0;
+
+ CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup;
+ pResult->signature = NULL;
+
+ // Unless we decide otherwise, just do the lookup via a helper function
+ pResult->indirections = CORINFO_USEHELPER;
+
+ MethodDesc *pContextMD = GetMethodFromContext(pResolvedToken->tokenContext);
+ MethodTable *pContextMT = pContextMD->GetMethodTable();
+
+ // Do not bother computing the runtime lookup if we are inlining. The JIT is going
+ // to abort the inlining attempt anyway.
+ if (pContextMD != m_pMethodBeingCompiled)
+ {
+ return;
+ }
+
+ // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup.
+ // All callers of ComputeRuntimeLookupForSharedGenericToken have to filter out this case. We can't do much about it here.
+ _ASSERTE(pContextMD->IsSharedByGenericInstantiations());
+
+ BOOL fInstrument = FALSE;
+
+#ifdef FEATURE_NATIVE_IMAGE_GENERATION
+ // This will make sure that when IBC logging is turned on we will go through a version
+ // of JIT_GenericHandle which logs the access. Note that we still want the dictionaries
+ // to be populated to prepopulate the types at NGen time.
+ if (IsCompilingForNGen() &&
+ GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
+ {
+ fInstrument = TRUE;
+ }
+#endif // FEATURE_NATIVE_IMAGE_GENERATION
+
+ if (pContextMD->RequiresInstMethodDescArg())
+ {
+ pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
+ }
+ else
+ {
+ if (pContextMD->RequiresInstMethodTableArg())
+ pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
+ else
+ pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
+ }
+
#ifdef FEATURE_READYTORUN_COMPILER
if (IsReadyToRunCompilation())
{
#if defined(_TARGET_ARM_)
- // TODO
- ThrowHR(E_NOTIMPL);
+ ThrowHR(E_NOTIMPL); /* TODO - NYI */
#endif
-
-
switch (entryKind)
{
case TypeHandleSlot:
@@ -3126,191 +3170,138 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entr
_ASSERTE(!"Unknown dictionary entry kind!");
IfFailThrow(E_FAIL);
}
+
+ // For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a
+ // different way that is more version resilient... plus we can't have pointers to existing MTs/MDs in the sigs)
+ return;
}
#endif
+ // If we've got a method type parameter of any kind then we must look in the method desc arg
+ if (pContextMD->RequiresInstMethodDescArg())
+ {
+ pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG : CORINFO_HELP_RUNTIMEHANDLE_METHOD;
- CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup;
- pResult->signature = NULL;
+ if (fInstrument)
+ goto NoSpecialCase;
- // Unless we decide otherwise, just do the lookup via a helper function
- pResult->indirections = CORINFO_USEHELPER;
+ // Special cases:
+ // (1) Naked method type variable: look up directly in instantiation hanging off runtime md
+ // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)>
+ if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
+ {
+ SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
+ CorElementType type;
+ IfFailThrow(sigptr.GetElemType(&type));
+ if (type == ELEMENT_TYPE_MVAR)
+ {
+ pResult->indirections = 2;
+ pResult->testForNull = 0;
+#ifdef FEATURE_PREJIT
+ pResult->testForFixup = 1;
+#else
+ pResult->testForFixup = 0;
+#endif
+ pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
- MethodDesc *pContextMD = GetMethodFromContext(pResolvedToken->tokenContext);
- MethodTable *pContextMT = pContextMD->GetMethodTable();
+ ULONG data;
+ IfFailThrow(sigptr.GetData(&data));
+ pResult->offsets[1] = sizeof(TypeHandle) * data;
- // Do not bother computing the runtime lookup if we are inlining. The JIT is going
- // to abort the inlining attempt anyway.
- if (pContextMD != m_pMethodBeingCompiled)
- {
- return;
- }
+ return;
+ }
+ }
+ else if (entryKind == MethodDescSlot)
+ {
+ // It's the context itself (i.e. a recursive call)
+ if (!pTemplateMD->HasSameMethodDefAs(pContextMD))
+ goto NoSpecialCase;
- // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup.
- // All callers of ComputeRuntimeLookupForSharedGenericToken have to filter out this case. We can't do much about it here.
- _ASSERTE(pContextMD->IsSharedByGenericInstantiations());
+ // Now just check that the instantiation is (!!0, ..., !!(n-1))
+ if (!IsMethodSpecForTypicalInstantation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)))
+ goto NoSpecialCase;
- BOOL fInstrument = FALSE;
+ // Type instantiation has to match too if there is one
+ if (pContextMT->HasInstantiation())
+ {
+ TypeHandle thTemplate(pResolvedToken->hClass);
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- // This will make sure that when IBC logging is turned on we will go through a version
- // of JIT_GenericHandle which logs the access. Note that we still want the dictionaries
- // to be populated to prepopulate the types at NGen time.
- if (IsCompilingForNGen() &&
- GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
- {
- fInstrument = TRUE;
- }
-#endif // FEATURE_NATIVE_IMAGE_GENERATION
+ if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
+ goto NoSpecialCase;
- DWORD numGenericArgs;
- DictionaryLayout* pDictionaryLayout;
- LoaderAllocator* pAllocator;
+ // This check filters out method instantiation on generic type definition, like G::M<!!0>()
+ // We may not ever get it here. Filter it out just to be sure...
+ if (pResolvedToken->pTypeSpec == NULL)
+ goto NoSpecialCase;
- if (pContextMD->RequiresInstMethodDescArg())
- {
- pAllocator = pContextMD->GetLoaderAllocator();
- numGenericArgs = pContextMD->GetNumGenericMethodArgs();
- pDictionaryLayout = pContextMD->GetDictionaryLayout();
+ if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
+ goto NoSpecialCase;
+ }
- pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
- pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG : CORINFO_HELP_RUNTIMEHANDLE_METHOD;
+ // Just use the method descriptor that was passed in!
+ pResult->indirections = 0;
+ pResult->testForNull = 0;
+ pResult->testForFixup = 0;
+
+ return;
+ }
}
+ // Otherwise we must just have class type variables
else
{
- pAllocator = pContextMT->GetLoaderAllocator();
- numGenericArgs = pContextMT->GetNumGenericArgs();
- pDictionaryLayout = pContextMT->GetClass()->GetDictionaryLayout();
+ _ASSERTE(pContextMT->GetNumGenericArgs() > 0);
if (pContextMD->RequiresInstMethodTableArg())
{
// If we've got a vtable extra argument, go through that
- pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
}
// If we've got an object, go through its vtable
else
{
_ASSERTE(pContextMD->AcquiresInstMethodTableFromThis());
- pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
}
- }
- ComputeRuntimeLookupForSharedGenericTokenStatic(
- entryKind,
- pResolvedToken,
- pConstrainedResolvedToken,
- pTemplateMD,
- pAllocator,
- numGenericArgs,
- pDictionaryLayout,
- (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM ? 0 : pContextMT->GetNumDicts()),
- pResultLookup,
- TRUE,
- fInstrument,
- TRUE);
-}
-
-void CEEInfo::ComputeRuntimeLookupForSharedGenericTokenStatic(DictionaryEntryKind entryKind,
- CORINFO_RESOLVED_TOKEN * pResolvedToken,
- CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken /* for ConstrainedMethodEntrySlot */,
- MethodDesc * pTemplateMD /* for method-based slots */,
- LoaderAllocator* pAllocator,
- DWORD numGenericArgs,
- DictionaryLayout* pDictionaryLayout,
- DWORD typeDictionaryIndex,
- CORINFO_LOOKUP *pResultLookup,
- BOOL fEnableTypeHandleLookupOptimization,
- BOOL fInstrument,
- BOOL fMethodSpecContainsCallingConventionFlag)
-{
- CONTRACTL{
- STANDARD_VM_CHECK;
- PRECONDITION(CheckPointer(pResultLookup));
- } CONTRACTL_END;
-
- pResultLookup->lookupKind.needsRuntimeLookup = true;
-
- CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup;
- pResult->signature = NULL;
+ if (fInstrument)
+ goto NoSpecialCase;
- // Unless we decide otherwise, just do the lookup via a helper function
- pResult->indirections = CORINFO_USEHELPER;
-
- // For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a
- // different way that is more version resilient... plus we can't have pointers to existing MTs/MDs in the sigs)
- if (IsReadyToRunCompilation())
- return;
-
- if (fEnableTypeHandleLookupOptimization)
- {
- MethodDesc *pContextMD = GetMethodFromContext(pResolvedToken->tokenContext);
- MethodTable *pContextMT = pContextMD->GetMethodTable();
-
- // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup.
- // All callers of ComputeRuntimeLookupForSharedGenericToken have to filter out this case. We can't do much about it here.
- _ASSERTE(pContextMD->IsSharedByGenericInstantiations());
-
- // If we've got a method type parameter of any kind then we must look in the method desc arg
- if (pContextMD->RequiresInstMethodDescArg())
+ // Special cases:
+ // (1) Naked class type variable: look up directly in instantiation hanging off vtable
+ // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr
+ if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
{
- if (fInstrument)
- goto NoSpecialCase;
-
- // Special cases:
- // (1) Naked method type variable: look up directly in instantiation hanging off runtime md
- // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)>
- if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
+ SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
+ CorElementType type;
+ IfFailThrow(sigptr.GetElemType(&type));
+ if (type == ELEMENT_TYPE_VAR)
{
- SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
- CorElementType type;
- IfFailThrow(sigptr.GetElemType(&type));
- if (type == ELEMENT_TYPE_MVAR)
- {
- pResult->indirections = 2;
- pResult->testForNull = 0;
+ pResult->indirections = 3;
+ pResult->testForNull = 0;
#ifdef FEATURE_PREJIT
- pResult->testForFixup = 1;
+ pResult->testForFixup = 1;
#else
- pResult->testForFixup = 0;
+ pResult->testForFixup = 0;
#endif
- pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
+ pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
+ pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
+ ULONG data;
+ IfFailThrow(sigptr.GetData(&data));
+ pResult->offsets[2] = sizeof(TypeHandle) * data;
- ULONG data;
- IfFailThrow(sigptr.GetData(&data));
- pResult->offsets[1] = sizeof(TypeHandle) * data;
-
- return;
- }
+ return;
}
- else if (entryKind == MethodDescSlot)
+ else if (type == ELEMENT_TYPE_GENERICINST &&
+ (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM))
{
- // It's the context itself (i.e. a recursive call)
- if (!pTemplateMD->HasSameMethodDefAs(pContextMD))
- goto NoSpecialCase;
+ TypeHandle thTemplate(pResolvedToken->hClass);
- // Now just check that the instantiation is (!!0, ..., !!(n-1))
- if (!IsMethodSpecForTypicalInstantation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)))
+ if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
goto NoSpecialCase;
- // Type instantiation has to match too if there is one
- if (pContextMT->HasInstantiation())
- {
- TypeHandle thTemplate(pResolvedToken->hClass);
-
- if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
- goto NoSpecialCase;
-
- // This check filters out method instantiation on generic type definition, like G::M<!!0>()
- // We may not ever get it here. Filter it out just to be sure...
- if (pResolvedToken->pTypeSpec == NULL)
- goto NoSpecialCase;
-
- if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
- goto NoSpecialCase;
- }
+ if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
+ goto NoSpecialCase;
- // Just use the method descriptor that was passed in!
+ // Just use the vtable pointer itself!
pResult->indirections = 0;
pResult->testForNull = 0;
pResult->testForFixup = 0;
@@ -3318,59 +3309,6 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericTokenStatic(DictionaryEntryKin
return;
}
}
- // Otherwise we must just have class type variables
- else
- {
- _ASSERTE(pContextMT->GetNumGenericArgs() > 0);
-
- if (fInstrument)
- goto NoSpecialCase;
-
- // Special cases:
- // (1) Naked class type variable: look up directly in instantiation hanging off vtable
- // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr
- if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
- {
- SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
- CorElementType type;
- IfFailThrow(sigptr.GetElemType(&type));
- if (type == ELEMENT_TYPE_VAR)
- {
- pResult->indirections = 3;
- pResult->testForNull = 0;
-#ifdef FEATURE_PREJIT
- pResult->testForFixup = 1;
-#else
- pResult->testForFixup = 0;
-#endif
- pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
- pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
- ULONG data;
- IfFailThrow(sigptr.GetData(&data));
- pResult->offsets[2] = sizeof(TypeHandle) * data;
-
- return;
- }
- else if (type == ELEMENT_TYPE_GENERICINST &&
- (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM))
- {
- TypeHandle thTemplate(pResolvedToken->hClass);
-
- if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
- goto NoSpecialCase;
-
- if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
- goto NoSpecialCase;
-
- // Just use the vtable pointer itself!
- pResult->indirections = 0;
- pResult->testForNull = 0;
- pResult->testForFixup = 0;
-
- return;
- }
- }
- }
}
NoSpecialCase:
@@ -3381,8 +3319,8 @@ NoSpecialCase:
if (pResultLookup->lookupKind.runtimeLookupKind != CORINFO_LOOKUP_METHODPARAM)
{
- _ASSERTE(typeDictionaryIndex > 0);
- sigBuilder.AppendData(typeDictionaryIndex - 1);
+ _ASSERTE(pContextMT->GetNumDicts() > 0);
+ sigBuilder.AppendData(pContextMT->GetNumDicts() - 1);
}
Module * pModule = (Module *)pResolvedToken->tokenScope;
@@ -3508,14 +3446,11 @@ NoSpecialCase:
{
SigPointer sigptr(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
- if (fMethodSpecContainsCallingConventionFlag)
- {
- BYTE etype;
- IfFailThrow(sigptr.GetByte(&etype));
+ BYTE etype;
+ IfFailThrow(sigptr.GetByte(&etype));
- // Load the generic method instantiation
- THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, pModule);
- }
+ // Load the generic method instantiation
+ THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, pModule);
DWORD nGenericMethodArgs;
IfFailThrow(sigptr.GetData(&nGenericMethodArgs));
@@ -3557,10 +3492,15 @@ NoSpecialCase:
_ASSERTE(false);
}
+ DictionaryEntrySignatureSource signatureSource = (IsCompilationProcess() ? FromZapImage : FromJIT);
+
// It's a method dictionary lookup
if (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM)
{
- if (DictionaryLayout::FindToken(pAllocator, numGenericArgs, pDictionaryLayout, pResult, &sigBuilder, 1))
+ _ASSERTE(pContextMD != NULL);
+ _ASSERTE(pContextMD->HasMethodInstantiation());
+
+ if (DictionaryLayout::FindToken(pContextMD->GetLoaderAllocator(), pContextMD->GetNumGenericMethodArgs(), pContextMD->GetDictionaryLayout(), pResult, &sigBuilder, 1, signatureSource))
{
pResult->testForNull = 1;
pResult->testForFixup = 0;
@@ -3573,7 +3513,7 @@ NoSpecialCase:
// It's a class dictionary lookup (CORINFO_LOOKUP_CLASSPARAM or CORINFO_LOOKUP_THISOBJ)
else
{
- if (DictionaryLayout::FindToken(pAllocator, numGenericArgs, pDictionaryLayout, pResult, &sigBuilder, 2))
+ if (DictionaryLayout::FindToken(pContextMT->GetLoaderAllocator(), pContextMT->GetNumGenericArgs(), pContextMT->GetClass()->GetDictionaryLayout(), pResult, &sigBuilder, 2, signatureSource))
{
pResult->testForNull = 1;
pResult->testForFixup = 0;
@@ -3582,7 +3522,7 @@ NoSpecialCase:
pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
// Next indirect through the dictionary appropriate to this instantiated type
- pResult->offsets[1] = sizeof(TypeHandle*) * (typeDictionaryIndex - 1);
+ pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
}
}
}
diff --git a/src/vm/jitinterface.h b/src/vm/jitinterface.h
index c712c42723..03983f2d3e 100644
--- a/src/vm/jitinterface.h
+++ b/src/vm/jitinterface.h
@@ -1151,19 +1151,6 @@ public:
MethodDesc * pTemplateMD /* for method-based slots */,
CORINFO_LOOKUP *pResultLookup);
- static void ComputeRuntimeLookupForSharedGenericTokenStatic(DictionaryEntryKind entryKind,
- CORINFO_RESOLVED_TOKEN * pResolvedToken,
- CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken /* for ConstrainedMethodEntrySlot */,
- MethodDesc * pTemplateMD /* for method-based slots */,
- LoaderAllocator* pAllocator,
- DWORD numGenericArgs,
- DictionaryLayout* pDictionaryLayout,
- DWORD typeDictionaryIndex,
- CORINFO_LOOKUP *pResultLookup,
- BOOL fEnableTypeHandleLookupOptimization,
- BOOL fInstrument,
- BOOL fMethodSpecContainsCallingConventionFlag);
-
protected:
// NGen provides its own modifications to EE-JIT interface. From technical reason it cannot simply inherit
// from code:CEEInfo class (because it has dependencies on VM that NGen does not want).
@@ -1667,9 +1654,21 @@ struct StaticFieldAddressArgs
FCDECL1(TADDR, JIT_StaticFieldAddress_Dynamic, StaticFieldAddressArgs * pArgs);
FCDECL1(TADDR, JIT_StaticFieldAddressUnbox_Dynamic, StaticFieldAddressArgs * pArgs);
+struct GenericHandleArgs
+{
+ LPVOID signature;
+ CORINFO_MODULE_HANDLE module;
+ DWORD dictionaryIndexAndSlot;
+};
+
+FCDECL2(CORINFO_GENERIC_HANDLE, JIT_GenericHandleMethodWithSlotAndModule, CORINFO_METHOD_HANDLE methodHnd, GenericHandleArgs * pArgs);
+FCDECL2(CORINFO_GENERIC_HANDLE, JIT_GenericHandleClassWithSlotAndModule, CORINFO_CLASS_HANDLE classHnd, GenericHandleArgs * pArgs);
+
CORINFO_GENERIC_HANDLE JIT_GenericHandleWorker(MethodDesc *pMD,
MethodTable *pMT,
- LPVOID signature);
+ LPVOID signature,
+ DWORD dictionaryIndexAndSlot = -1,
+ Module * pModule = NULL);
void ClearJitGenericHandleCache(AppDomain *pDomain);
diff --git a/src/vm/prestub.cpp b/src/vm/prestub.cpp
index 83c4015f41..fe2694f26a 100644
--- a/src/vm/prestub.cpp
+++ b/src/vm/prestub.cpp
@@ -2289,6 +2289,130 @@ TADDR GetFirstArgumentRegisterValuePtr(TransitionBlock * pTransitionBlock)
return pArgument;
}
+void ProcessDynamicDictionaryLookup(TransitionBlock * pTransitionBlock,
+ Module * pModule,
+ Module * pInfoModule,
+ BYTE kind,
+ PCCOR_SIGNATURE pBlob,
+ PCCOR_SIGNATURE pBlobStart,
+ CORINFO_RUNTIME_LOOKUP * pResult,
+ DWORD * pDictionaryIndexAndSlot)
+{
+ TADDR genericContextPtr = *(TADDR*)GetFirstArgumentRegisterValuePtr(pTransitionBlock);
+
+ pResult->testForFixup = pResult->testForNull = false;
+ pResult->signature = NULL;
+ pResult->indirections = CORINFO_USEHELPER;
+
+ DWORD numGenericArgs = 0;
+ MethodTable* pContextMT = NULL;
+ MethodDesc* pContextMD = NULL;
+
+ if (kind == ENCODE_DICTIONARY_LOOKUP_METHOD)
+ {
+ pContextMD = (MethodDesc*)genericContextPtr;
+ numGenericArgs = pContextMD->GetNumGenericMethodArgs();
+ pResult->helper = CORINFO_HELP_RUNTIMEHANDLE_METHOD;
+ }
+ else
+ {
+ pContextMT = (MethodTable*)genericContextPtr;
+
+ if (kind == ENCODE_DICTIONARY_LOOKUP_THISOBJ)
+ {
+ TypeHandle contextTypeHandle = ZapSig::DecodeType(pModule, pInfoModule, pBlob);
+
+ SigPointer p(pBlob);
+ p.SkipExactlyOne();
+ pBlob = p.GetPtr();
+
+ pContextMT = pContextMT->GetMethodTableMatchingParentClass(contextTypeHandle.AsMethodTable());
+ }
+
+ numGenericArgs = pContextMT->GetNumGenericArgs();
+ pResult->helper = CORINFO_HELP_RUNTIMEHANDLE_CLASS;
+ }
+
+ _ASSERTE(numGenericArgs > 0);
+
+ CORCOMPILE_FIXUP_BLOB_KIND signatureKind = (CORCOMPILE_FIXUP_BLOB_KIND)CorSigUncompressData(pBlob);
+
+ //
+ // Optimization cases
+ //
+ if (signatureKind == ENCODE_TYPE_HANDLE)
+ {
+ SigPointer sigptr(pBlob, -1);
+
+ CorElementType type;
+ IfFailThrow(sigptr.GetElemType(&type));
+
+ if ((type == ELEMENT_TYPE_MVAR) && (kind == ENCODE_DICTIONARY_LOOKUP_METHOD))
+ {
+ pResult->indirections = 2;
+ pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
+
+ ULONG data;
+ IfFailThrow(sigptr.GetData(&data));
+ pResult->offsets[1] = sizeof(TypeHandle) * data;
+
+ return;
+ }
+ else if ((type == ELEMENT_TYPE_VAR) && (kind != ENCODE_DICTIONARY_LOOKUP_METHOD))
+ {
+ pResult->indirections = 3;
+ pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
+ pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
+
+ ULONG data;
+ IfFailThrow(sigptr.GetData(&data));
+ pResult->offsets[2] = sizeof(TypeHandle) * data;
+
+ return;
+ }
+ }
+
+ if (pContextMT != NULL && pContextMT->GetNumDicts() > 0xFFFF)
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+
+ // Dictionary index and slot number are encoded in a 32-bit DWORD. The higher 16 bits
+ // are used for the dictionary index, and the lower 16 bits for the slot number.
+ *pDictionaryIndexAndSlot = (pContextMT == NULL ? 0 : pContextMT->GetNumDicts() - 1);
+ *pDictionaryIndexAndSlot <<= 16;
+
+ WORD dictionarySlot;
+
+ if (kind == ENCODE_DICTIONARY_LOOKUP_METHOD)
+ {
+ if (DictionaryLayout::FindToken(pModule->GetLoaderAllocator(), numGenericArgs, pContextMD->GetDictionaryLayout(), pResult, (BYTE*)pBlobStart, 1, FromReadyToRunImage, &dictionarySlot))
+ {
+ pResult->testForNull = 1;
+
+ // Indirect through dictionary table pointer in InstantiatedMethodDesc
+ pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
+
+ *pDictionaryIndexAndSlot |= dictionarySlot;
+ }
+ }
+
+ // It's a class dictionary lookup (CORINFO_LOOKUP_CLASSPARAM or CORINFO_LOOKUP_THISOBJ)
+ else
+ {
+ if (DictionaryLayout::FindToken(pModule->GetLoaderAllocator(), numGenericArgs, pContextMT->GetClass()->GetDictionaryLayout(), pResult, (BYTE*)pBlobStart, 2, FromReadyToRunImage, &dictionarySlot))
+ {
+ pResult->testForNull = 1;
+
+ // Indirect through dictionary table pointer in vtable
+ pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
+
+ // Next indirect through the dictionary appropriate to this instantiated type
+ pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
+
+ *pDictionaryIndexAndSlot |= dictionarySlot;
+ }
+ }
+}
+
PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWORD sectionIndex, Module * pModule, CORCOMPILE_FIXUP_BLOB_KIND * pKind, TypeHandle * pTH, MethodDesc ** ppMD, FieldDesc ** ppFD)
{
STANDARD_VM_CONTRACT;
@@ -2307,6 +2431,7 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR
PTR_DWORD pSignatures = dac_cast<PTR_DWORD>(pNativeImage->GetRvaData(pImportSection->Signatures));
PCCOR_SIGNATURE pBlob = (BYTE *)pNativeImage->GetRvaData(pSignatures[index]);
+ PCCOR_SIGNATURE pBlobStart = pBlob;
BYTE kind = *pBlob++;
@@ -2322,7 +2447,8 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR
TypeHandle th;
MethodDesc * pMD = NULL;
FieldDesc * pFD = NULL;
- CORINFO_GENERICHANDLE_RESULT embedInfo;
+ CORINFO_RUNTIME_LOOKUP genericLookup;
+ DWORD dictionaryIndexAndSlot;
switch (kind)
{
@@ -2377,111 +2503,7 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR
case ENCODE_DICTIONARY_LOOKUP_THISOBJ:
case ENCODE_DICTIONARY_LOOKUP_TYPE:
case ENCODE_DICTIONARY_LOOKUP_METHOD:
- {
- TADDR genericContextPtr = *(TADDR*)GetFirstArgumentRegisterValuePtr(pTransitionBlock);
-
- DWORD numGenericArgs = 0;
- MethodTable* pContextMT = NULL;
- MethodDesc* pContextMD = NULL;
- MethodDesc* pTemplateMD = NULL;
- DictionaryLayout* pDictionaryLayout = NULL;
- SigTypeContext typeOrMethodContext;
-
- if (kind == ENCODE_DICTIONARY_LOOKUP_METHOD)
- {
- pContextMD = (MethodDesc*)genericContextPtr;
- numGenericArgs = pContextMD->GetNumGenericMethodArgs();
- pDictionaryLayout = pContextMD->GetDictionaryLayout();
- typeOrMethodContext = SigTypeContext(pContextMD);
- embedInfo.lookup.lookupKind.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
- embedInfo.lookup.runtimeLookup.helper = CORINFO_HELP_RUNTIMEHANDLE_METHOD;
- }
- else
- {
- pContextMT = (MethodTable*)genericContextPtr;
-
- if (kind == ENCODE_DICTIONARY_LOOKUP_THISOBJ)
- {
- TypeHandle contextTypeHandle = ZapSig::DecodeType(pModule, pInfoModule, pBlob);
-
- SigPointer p(pBlob);
- p.SkipExactlyOne();
- pBlob = p.GetPtr();
-
- pContextMT = pContextMT->GetMethodTableMatchingParentClass(contextTypeHandle.AsMethodTable());
- embedInfo.lookup.lookupKind.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
- }
- else
- {
- embedInfo.lookup.lookupKind.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
- }
-
- numGenericArgs = pContextMT->GetNumGenericArgs();
- pDictionaryLayout = pContextMT->GetClass()->GetDictionaryLayout();
- typeOrMethodContext = SigTypeContext(pContextMT);
- embedInfo.lookup.runtimeLookup.helper = CORINFO_HELP_RUNTIMEHANDLE_CLASS;
- }
-
- CORINFO_RESOLVED_TOKEN resolvedToken;
- INDEBUG(memset(&resolvedToken, 0xCC, sizeof(resolvedToken)));
- resolvedToken.tokenType = CORINFO_TOKENKIND_Ldtoken; // Reasonable default value to use that works
- resolvedToken.tokenScope = (CORINFO_MODULE_HANDLE)pModule;
- resolvedToken.pMethodSpec = resolvedToken.pTypeSpec = NULL;
- resolvedToken.cbMethodSpec = resolvedToken.cbTypeSpec = -1;
-
- DictionaryEntryKind entryKind = EmptySlot;
- CORCOMPILE_FIXUP_BLOB_KIND signatureKind = (CORCOMPILE_FIXUP_BLOB_KIND)CorSigUncompressData(pBlob);
-
- switch (signatureKind)
- {
- case ENCODE_TYPE_HANDLE:
- {
- entryKind = TypeHandleSlot;
- resolvedToken.pTypeSpec = pBlob;
- }
- break;
-
- case ENCODE_METHOD_HANDLE:
- case ENCODE_METHOD_ENTRY:
- case ENCODE_VIRTUAL_ENTRY:
- {
- if (signatureKind == ENCODE_METHOD_HANDLE)
- entryKind = MethodDescSlot;
- else if (signatureKind == ENCODE_METHOD_ENTRY)
- entryKind = MethodEntrySlot;
- else
- entryKind = DispatchStubAddrSlot;
-
- pTemplateMD = ZapSig::DecodeMethod(pModule, pInfoModule, pBlob, &typeOrMethodContext, &th, &resolvedToken.pTypeSpec, &resolvedToken.pMethodSpec);
- resolvedToken.hMethod = (CORINFO_METHOD_HANDLE)pTemplateMD;
- resolvedToken.hClass = (CORINFO_CLASS_HANDLE)pTemplateMD->GetMethodTable_NoLogging();
- }
- break;
-
- // TODO: Support for the rest of the dictionary signature kinds
-
- default:
- _ASSERTE(!"Unexpected CORCOMPILE_FIXUP_BLOB_KIND");
- ThrowHR(COR_E_BADIMAGEFORMAT);
- }
-
- CEEInfo::ComputeRuntimeLookupForSharedGenericTokenStatic(
- entryKind,
- &resolvedToken,
- NULL, // pConstrainedResolvedToken for ConstrainedMethodEntrySlot
- pTemplateMD,
- pModule->GetLoaderAllocator(),
- numGenericArgs,
- pDictionaryLayout,
- pContextMT == NULL ? 0 : pContextMT->GetNumDicts(),
- &embedInfo.lookup,
- FALSE, // fEnableTypeHandleLookupOptimization,
- FALSE, // fInstrument
- FALSE // fMethodSpecContainsCallingConventionFlag
- );
-
- _ASSERTE(embedInfo.lookup.lookupKind.needsRuntimeLookup);
- }
+ ProcessDynamicDictionaryLookup(pTransitionBlock, pModule, pInfoModule, kind, pBlob, pBlobStart, &genericLookup, &dictionaryIndexAndSlot);
break;
default:
@@ -2693,7 +2715,7 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR
case ENCODE_DICTIONARY_LOOKUP_TYPE:
case ENCODE_DICTIONARY_LOOKUP_METHOD:
{
- pHelper = DynamicHelpers::CreateDictionaryLookupHelper(pModule->GetLoaderAllocator(), &embedInfo.lookup.runtimeLookup);
+ pHelper = DynamicHelpers::CreateDictionaryLookupHelper(pModule->GetLoaderAllocator(), &genericLookup, dictionaryIndexAndSlot, pModule);
}
break;
diff --git a/src/vm/readytoruninfo.h b/src/vm/readytoruninfo.h
index 24bdae89b9..28efe01e8d 100644
--- a/src/vm/readytoruninfo.h
+++ b/src/vm/readytoruninfo.h
@@ -138,7 +138,7 @@ public:
static PCODE CreateReturnIndirConst(LoaderAllocator * pAllocator, TADDR arg, INT8 offset);
static PCODE CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADDR arg, PCODE target);
static PCODE CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADDR arg, TADDR arg2, PCODE target);
- static PCODE CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup);
+ static PCODE CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup, DWORD dictionaryIndexAndSlot, Module * pModule);
};
#endif // _READYTORUNINFO_H_
diff --git a/src/zap/zapinfo.cpp b/src/zap/zapinfo.cpp
index 831c61b4b2..232570f09d 100644
--- a/src/zap/zapinfo.cpp
+++ b/src/zap/zapinfo.cpp
@@ -3487,11 +3487,11 @@ bool ZapInfo::getReadyToRunHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken,
pImport = m_pImage->GetImportTable()->GetDictionaryLookupCell(
(CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_DICTIONARY_LOOKUP_METHOD | fAtypicalCallsite), pResolvedToken, pGenericLookupKind);
}
- else if (pGenericLookupKind->runtimeLookupKind == CORINFO_LOOKUP_THISOBJ)
- {
- pImport = m_pImage->GetImportTable()->GetDictionaryLookupCell(
- (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_DICTIONARY_LOOKUP_THISOBJ | fAtypicalCallsite), pResolvedToken, pGenericLookupKind);
-}
+ else if (pGenericLookupKind->runtimeLookupKind == CORINFO_LOOKUP_THISOBJ)
+ {
+ pImport = m_pImage->GetImportTable()->GetDictionaryLookupCell(
+ (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_DICTIONARY_LOOKUP_THISOBJ | fAtypicalCallsite), pResolvedToken, pGenericLookupKind);
+ }
else
{
_ASSERTE(pGenericLookupKind->runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM);