Generic dictionary minor performance improvement and simplification for R2R (dotnet...
authorFadi Hanna <fadim@microsoft.com>
Tue, 21 Jun 2016 18:51:05 +0000 (11:51 -0700)
committerGitHub <noreply@github.com>
Tue, 21 Jun 2016 18:51:05 +0000 (11:51 -0700)
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)

Commit migrated from https://github.com/dotnet/coreclr/commit/b9f5ae88cc49836c8d31f07db7800707165cdb06

15 files changed:
src/coreclr/src/inc/corinfo.h
src/coreclr/src/vm/amd64/cgenamd64.cpp
src/coreclr/src/vm/arm64/stubs.cpp
src/coreclr/src/vm/codeman.cpp
src/coreclr/src/vm/codeman.h
src/coreclr/src/vm/crossgencompile.cpp
src/coreclr/src/vm/genericdict.cpp
src/coreclr/src/vm/genericdict.h
src/coreclr/src/vm/i386/cgenx86.cpp
src/coreclr/src/vm/jithelpers.cpp
src/coreclr/src/vm/jitinterface.cpp
src/coreclr/src/vm/jitinterface.h
src/coreclr/src/vm/prestub.cpp
src/coreclr/src/vm/readytoruninfo.h
src/coreclr/src/zap/zapinfo.cpp

index fbbc95e..baae699 100644 (file)
@@ -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
index f8bd458..d569800 100644 (file)
@@ -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);
             }
         }
 
index c662e0a..01a56e3 100644 (file)
@@ -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:
index 701f5da..7eea254 100644 (file)
@@ -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
index f0703f3..855c151 100644 (file)
@@ -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);
index bb5d7fa..36ba0f6 100644 (file)
@@ -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();
 }
index dfb9ea9..dda70b6 100644 (file)
@@ -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();
 
index e63b3c8..1cb172a 100644 (file)
@@ -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);
index a9c2967..48428a1 100644 (file)
@@ -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);
             }
         }
 
index fffc6ce..1626810 100644 (file)
@@ -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
 
index 99e987d..b72eaf3 100644 (file)
@@ -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);
         }
     }
 }
index c712c42..03983f2 100644 (file)
@@ -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);
 
index 83c4015..fe2694f 100644 (file)
@@ -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;
 
index 24bdae8..28efe01 100644 (file)
@@ -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_
index 831c61b..232570f 100644 (file)
@@ -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);