From: Gleb Balykov Date: Thu, 22 Jun 2017 18:14:04 +0000 (+0300) Subject: Remove relocations for MethodTable::m_pPerInstInfo for Linux ARM X-Git-Tag: accepted/tizen/base/20180629.140029~670^2~387^2~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7a107e9622ff5803987add587414610014eeca4e;p=platform%2Fupstream%2Fcoreclr.git Remove relocations for MethodTable::m_pPerInstInfo for Linux ARM --- diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp index f522265..ed5799f 100644 --- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp @@ -1504,6 +1504,7 @@ void MethodContext::repGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, pResult->stubLookup.runtimeLookup.testForNull = value.stubLookup.runtimeLookup.testForNull != 0; pResult->stubLookup.runtimeLookup.testForFixup = value.stubLookup.runtimeLookup.testForFixup != 0; pResult->stubLookup.runtimeLookup.indirectFirstOffset = value.stubLookup.runtimeLookup.indirectFirstOffset != 0; + pResult->stubLookup.runtimeLookup.indirectSecondOffset = value.stubLookup.runtimeLookup.indirectSecondOffset != 0; for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++) pResult->stubLookup.runtimeLookup.offsets[i] = (SIZE_T)value.stubLookup.runtimeLookup.offsets[i]; } diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h index 4b42fa7..aa5cd85 100644 --- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h +++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h @@ -211,6 +211,7 @@ public: DWORD testForFixup; DWORDLONG offsets[CORINFO_MAXINDIRECTIONS]; DWORD indirectFirstOffset; + DWORD indirectSecondOffset; }; struct Agnostic_CORINFO_LOOKUP { diff --git a/src/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h b/src/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h index 0030a2b..c3988f8 100644 --- a/src/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h +++ b/src/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h @@ -297,6 +297,7 @@ inline MethodContext::Agnostic_CORINFO_RUNTIME_LOOKUP SpmiRecordsHelper::StoreAg runtimeLookup.testForNull = (DWORD)pLookup->testForNull; runtimeLookup.testForFixup = (DWORD)pLookup->testForFixup; runtimeLookup.indirectFirstOffset = (DWORD)pLookup->indirectFirstOffset; + runtimeLookup.indirectSecondOffset = (DWORD)pLookup->indirectSecondOffset; for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++) runtimeLookup.offsets[i] = (DWORDLONG)pLookup->offsets[i]; return runtimeLookup; @@ -312,6 +313,7 @@ inline CORINFO_RUNTIME_LOOKUP SpmiRecordsHelper::RestoreCORINFO_RUNTIME_LOOKUP( runtimeLookup.testForNull = lookup.testForNull != 0; runtimeLookup.testForFixup = lookup.testForFixup != 0; runtimeLookup.indirectFirstOffset = lookup.indirectFirstOffset != 0; + runtimeLookup.indirectSecondOffset = lookup.indirectSecondOffset != 0; for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++) runtimeLookup.offsets[i] = (size_t)lookup.offsets[i]; return CORINFO_RUNTIME_LOOKUP(); diff --git a/src/debug/daccess/nidump.cpp b/src/debug/daccess/nidump.cpp index e1cf166..eec4c43 100644 --- a/src/debug/daccess/nidump.cpp +++ b/src/debug/daccess/nidump.cpp @@ -5084,7 +5084,10 @@ void NativeImageDumper::MethodTableToString( PTR_MethodTable mt, SString& buf ) { numDicts = (DWORD)CountDictionariesInClass(token, dependency->pImport); } - PTR_Dictionary dictionary( mt->GetPerInstInfo()[numDicts-1] ); + + TADDR base = dac_cast(&(mt->GetPerInstInfo()[numDicts-1])); + + PTR_Dictionary dictionary( MethodTable::PerInstInfoElem_t::GetValueAtPtr(base) ); unsigned numArgs = mt->GetNumGenericArgs(); DictionaryToArgString( dictionary, numArgs, buf ); @@ -7049,8 +7052,7 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name, GenericsDictInfo, METHODTABLES); DisplayEndStructure( METHODTABLES ); //GenericsDictInfo - - DPTR(PTR_Dictionary) perInstInfo = mt->GetPerInstInfo(); + DPTR(MethodTable::PerInstInfoElem_t) perInstInfo = mt->GetPerInstInfo(); DisplayStartStructure( "PerInstInfo", DPtrToPreferredAddr(perInstInfo), diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h index 4af22e5..9c2e08b 100644 --- a/src/inc/corinfo.h +++ b/src/inc/corinfo.h @@ -1332,6 +1332,13 @@ struct CORINFO_RUNTIME_LOOKUP // 1 means that value stored at first offset (offsets[0]) from pointer is offset1, and the next pointer is // stored at pointer+offsets[0]+offset1. bool indirectFirstOffset; + + // If set, second offset is indirect. + // 0 means that value stored at second offset (offsets[1]) from pointer is next pointer, to which the next offset + // (offsets[2]) is added and so on. + // 1 means that value stored at second offset (offsets[1]) from pointer is offset2, and the next pointer is + // stored at pointer+offsets[1]+offset2. + bool indirectSecondOffset; } ; // Result of calling embedGenericHandle diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index b618478..c5e9b68 100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -1980,10 +1980,10 @@ GenTreePtr Compiler::impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedTok // Applied repeated indirections for (WORD i = 0; i < pRuntimeLookup->indirections; i++) { - if (i == 1 && pRuntimeLookup->indirectFirstOffset) + if ((i == 1 && pRuntimeLookup->indirectFirstOffset) || (i == 2 && pRuntimeLookup->indirectSecondOffset)) { indOffTree = impCloneExpr(slotPtrTree, &slotPtrTree, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL, - nullptr DEBUGARG("impRuntimeLookup indirectFirstOffset")); + nullptr DEBUGARG("impRuntimeLookup indirectOffset")); } if (i != 0) @@ -1993,7 +1993,7 @@ GenTreePtr Compiler::impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedTok slotPtrTree->gtFlags |= GTF_IND_INVARIANT; } - if (i == 1 && pRuntimeLookup->indirectFirstOffset) + if ((i == 1 && pRuntimeLookup->indirectFirstOffset) || (i == 2 && pRuntimeLookup->indirectSecondOffset)) { slotPtrTree = gtNewOperNode(GT_ADD, TYP_I_IMPL, indOffTree, slotPtrTree); } diff --git a/src/vm/ceeload.cpp b/src/vm/ceeload.cpp index ff8c17e..ea93e5c 100644 --- a/src/vm/ceeload.cpp +++ b/src/vm/ceeload.cpp @@ -9289,13 +9289,20 @@ void Module::PlaceType(DataImage *image, TypeHandle th, DWORD profilingFlags) { if (pMT->HasPerInstInfo()) { - Dictionary ** pPerInstInfo = pMT->GetPerInstInfo(); + DPTR(MethodTable::PerInstInfoElem_t) pPerInstInfo = pMT->GetPerInstInfo(); BOOL fIsEagerBound = pMT->CanEagerBindToParentDictionaries(image, NULL); if (fIsEagerBound) { - image->PlaceInternedStructureForAddress(pPerInstInfo, CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT); + if (MethodTable::PerInstInfoElem_t::isRelative) + { + image->PlaceStructureForAddress(pPerInstInfo, CORCOMPILE_SECTION_READONLY_HOT); + } + else + { + image->PlaceInternedStructureForAddress(pPerInstInfo, CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT); + } } else { diff --git a/src/vm/class.cpp b/src/vm/class.cpp index 6697b23..c1519a2 100644 --- a/src/vm/class.cpp +++ b/src/vm/class.cpp @@ -908,8 +908,11 @@ ClassLoader::LoadExactParentAndInterfacesTransitively(MethodTable *pMT) DWORD nDicts = pParentMT->GetNumDicts(); for (DWORD iDict = 0; iDict < nDicts; iDict++) { - if (pMT->GetPerInstInfo()[iDict] != pParentMT->GetPerInstInfo()[iDict]) - *EnsureWritablePages(&pMT->GetPerInstInfo()[iDict]) = pParentMT->GetPerInstInfo()[iDict]; + if (pMT->GetPerInstInfo()[iDict].GetValueMaybeNull() != pParentMT->GetPerInstInfo()[iDict].GetValueMaybeNull()) + { + EnsureWritablePages(&pMT->GetPerInstInfo()[iDict]); + pMT->GetPerInstInfo()[iDict].SetValueMaybeNull(pParentMT->GetPerInstInfo()[iDict].GetValueMaybeNull()); + } } } diff --git a/src/vm/genericdict.cpp b/src/vm/genericdict.cpp index c93e583..5fad30f 100644 --- a/src/vm/genericdict.cpp +++ b/src/vm/genericdict.cpp @@ -742,7 +742,7 @@ Dictionary::PopulateEntry( } // MethodTable is expected to be normalized - _ASSERTE(pDictionary == pMT->GetPerInstInfo()[dictionaryIndex]); + _ASSERTE(pDictionary == pMT->GetPerInstInfo()[dictionaryIndex].GetValueMaybeNull()); } else { diff --git a/src/vm/generics.cpp b/src/vm/generics.cpp index 51e6d7b..d1a511f 100644 --- a/src/vm/generics.cpp +++ b/src/vm/generics.cpp @@ -499,7 +499,7 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation( _ASSERTE(pOldMT->HasPerInstInfo()); // Fill in per-inst map pointer (which points to the array of generic dictionary pointers) - pMT->SetPerInstInfo ((Dictionary**) (pMemory + cbMT + cbOptional + cbIMap + sizeof(GenericsDictInfo))); + pMT->SetPerInstInfo((MethodTable::PerInstInfoElem_t *) (pMemory + cbMT + cbOptional + cbIMap + sizeof(GenericsDictInfo))); _ASSERTE(FitsIn(pOldMT->GetNumDicts())); _ASSERTE(FitsIn(pOldMT->GetNumGenericArgs())); pMT->SetDictInfo(static_cast(pOldMT->GetNumDicts()), static_cast(pOldMT->GetNumGenericArgs())); @@ -508,7 +508,8 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation( // The others are filled in by LoadExactParents which copied down any inherited generic // dictionary pointers. Dictionary * pDict = (Dictionary*) (pMemory + cbMT + cbOptional + cbIMap + cbPerInst); - *(pMT->GetPerInstInfo() + (pOldMT->GetNumDicts()-1)) = pDict; + MethodTable::PerInstInfoElem_t *pPInstInfo = (MethodTable::PerInstInfoElem_t *) (pMT->GetPerInstInfo() + (pOldMT->GetNumDicts()-1)); + pPInstInfo->SetValueMaybeNull(pDict); // Fill in the instantiation section of the generic dictionary. The remainder of the // generic dictionary will be zeroed, which is the correct initial state. diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp index 2fc5e09..67e3656 100644 --- a/src/vm/jitinterface.cpp +++ b/src/vm/jitinterface.cpp @@ -3093,6 +3093,7 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entr pResult->signature = NULL; pResult->indirectFirstOffset = 0; + pResult->indirectSecondOffset = 0; // Unless we decide otherwise, just do the lookup via a helper function pResult->indirections = CORINFO_USEHELPER; @@ -3307,6 +3308,12 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entr IfFailThrow(sigptr.GetData(&data)); pResult->offsets[2] = sizeof(TypeHandle) * data; + if (MethodTable::IsPerInstInfoRelative()) + { + pResult->indirectFirstOffset = 1; + pResult->indirectSecondOffset = 1; + } + return; } else if (type == ELEMENT_TYPE_GENERICINST && @@ -3554,6 +3561,12 @@ NoSpecialCase: // Next indirect through the dictionary appropriate to this instantiated type pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1); + + if (MethodTable::IsPerInstInfoRelative()) + { + pResult->indirectFirstOffset = 1; + pResult->indirectSecondOffset = 1; + } } } } diff --git a/src/vm/methodtable.cpp b/src/vm/methodtable.cpp index b26ff85..d60f565 100644 --- a/src/vm/methodtable.cpp +++ b/src/vm/methodtable.cpp @@ -4331,7 +4331,14 @@ void MethodTable::Save(DataImage *image, DWORD profilingFlags) ZapStoredStructure * pPerInstInfoNode; if (CanEagerBindToParentDictionaries(image, NULL)) { - pPerInstInfoNode = image->StoreInternedStructure((BYTE *)GetPerInstInfo() - sizeof(GenericsDictInfo), GetPerInstInfoSize() + sizeof(GenericsDictInfo), DataImage::ITEM_DICTIONARY); + if (PerInstInfoElem_t::isRelative) + { + pPerInstInfoNode = image->StoreStructure((BYTE *)GetPerInstInfo() - sizeof(GenericsDictInfo), GetPerInstInfoSize() + sizeof(GenericsDictInfo), DataImage::ITEM_DICTIONARY); + } + else + { + pPerInstInfoNode = image->StoreInternedStructure((BYTE *)GetPerInstInfo() - sizeof(GenericsDictInfo), GetPerInstInfoSize() + sizeof(GenericsDictInfo), DataImage::ITEM_DICTIONARY); + } } else { @@ -4678,14 +4685,21 @@ BOOL MethodTable::IsWriteable() // target module. Thus we want to call CanEagerBindToMethodTable // to check we can hardbind to the containing structure. static -void HardBindOrClearDictionaryPointer(DataImage *image, MethodTable *pMT, void * p, SSIZE_T offset) +void HardBindOrClearDictionaryPointer(DataImage *image, MethodTable *pMT, void * p, SSIZE_T offset, bool isRelative) { WRAPPER_NO_CONTRACT; if (image->CanEagerBindToMethodTable(pMT) && image->CanHardBindToZapModule(pMT->GetLoaderModule())) { - image->FixupPointerField(p, offset); + if (isRelative) + { + image->FixupRelativePointerField(p, offset); + } + else + { + image->FixupPointerField(p, offset); + } } else { @@ -5020,7 +5034,7 @@ void MethodTable::Fixup(DataImage *image) if (HasPerInstInfo()) { // Fixup the pointer to the per-inst table - image->FixupPointerField(this, offsetof(MethodTable, m_pPerInstInfo)); + image->FixupPlainOrRelativePointerField(this, &MethodTable::m_pPerInstInfo); for (MethodTable *pChain = this; pChain != NULL; pChain = pChain->GetParentMethodTable()) { @@ -5033,10 +5047,23 @@ void MethodTable::Fixup(DataImage *image) // We special-case the dictionary for this method table because we must always // hard bind to it even if it's not in its preferred zap module + size_t sizeDict = sizeof(PerInstInfoElem_t); + if (pChain == this) - image->FixupPointerField(GetPerInstInfo(), dictNum * sizeof(Dictionary *)); + { + if (PerInstInfoElem_t::isRelative) + { + image->FixupRelativePointerField(GetPerInstInfo(), dictNum * sizeDict); + } + else + { + image->FixupPointerField(GetPerInstInfo(), dictNum * sizeDict); + } + } else - HardBindOrClearDictionaryPointer(image, pChain, GetPerInstInfo(), dictNum * sizeof(Dictionary *)); + { + HardBindOrClearDictionaryPointer(image, pChain, GetPerInstInfo(), dictNum * sizeDict, PerInstInfoElem_t::isRelative); + } } } } @@ -6221,7 +6248,7 @@ BOOL MethodTable::IsWinRTObjectType() //========================================================================================== // Return a pointer to the dictionary for an instantiated type // Return NULL if not instantiated -Dictionary* MethodTable::GetDictionary() +PTR_Dictionary MethodTable::GetDictionary() { LIMITED_METHOD_DAC_CONTRACT; @@ -6229,7 +6256,8 @@ Dictionary* MethodTable::GetDictionary() { // The instantiation for this class is stored in the type slots table // *after* any inherited slots - return GetPerInstInfo()[GetNumDicts()-1]; + TADDR base = dac_cast(&(GetPerInstInfo()[GetNumDicts()-1])); + return PerInstInfoElem_t::GetValueMaybeNullAtPtr(base); } else { @@ -6246,7 +6274,8 @@ Instantiation MethodTable::GetInstantiation() if (HasInstantiation()) { PTR_GenericsDictInfo pDictInfo = GetGenericsDictInfo(); - return Instantiation(GetPerInstInfo()[pDictInfo->m_wNumDicts-1]->GetInstantiation(), pDictInfo->m_wNumTyPars); + TADDR base = dac_cast(&(GetPerInstInfo()[pDictInfo->m_wNumDicts-1])); + return Instantiation(PerInstInfoElem_t::GetValueMaybeNullAtPtr(base)->GetInstantiation(), pDictInfo->m_wNumTyPars); } else { diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h index 7bf5432..bf811aa 100644 --- a/src/vm/methodtable.h +++ b/src/vm/methodtable.h @@ -3007,12 +3007,20 @@ public: // must have a dictionary entry. On the other hand, for instantiations shared with Dict the opposite holds. // +#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_) + typedef RelativePointer PerInstInfoElem_t; + typedef RelativePointer PerInstInfo_t; +#else + typedef PlainPointer PerInstInfoElem_t; + typedef PlainPointer PerInstInfo_t; +#endif + // Return a pointer to the per-instantiation information. See field itself for comments. - DPTR(PTR_Dictionary) GetPerInstInfo() + DPTR(PerInstInfoElem_t) GetPerInstInfo() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(HasPerInstInfo()); - return dac_cast(m_pMultipurposeSlot1); + return ReadPointer(this, &MethodTable::m_pPerInstInfo); } BOOL HasPerInstInfo() { @@ -3020,15 +3028,20 @@ public: return GetFlag(enum_flag_HasPerInstInfo) && !IsArray(); } #ifndef DACCESS_COMPILE + static inline bool IsPerInstInfoRelative() + { + LIMITED_METHOD_CONTRACT; + return decltype(m_pPerInstInfo)::isRelative; + } static inline DWORD GetOffsetOfPerInstInfo() { LIMITED_METHOD_CONTRACT; return offsetof(MethodTable, m_pPerInstInfo); } - void SetPerInstInfo(Dictionary** pPerInstInfo) + void SetPerInstInfo(PerInstInfoElem_t *pPerInstInfo) { LIMITED_METHOD_CONTRACT; - m_pPerInstInfo = pPerInstInfo; + m_pPerInstInfo.SetValue(pPerInstInfo); } void SetDictInfo(WORD numDicts, WORD numTyPars) { @@ -3048,7 +3061,7 @@ public: // Get a pointer to the dictionary for this instantiated type // (The instantiation is stored in the initial slots of the dictionary) // If not instantiated, return NULL - Dictionary* GetDictionary(); + PTR_Dictionary GetDictionary(); #ifdef FEATURE_PREJIT // @@ -4108,9 +4121,9 @@ private: union { - PTR_Dictionary * m_pPerInstInfo; - TADDR m_ElementTypeHnd; - TADDR m_pMultipurposeSlot1; + PerInstInfo_t m_pPerInstInfo; + TADDR m_ElementTypeHnd; + TADDR m_pMultipurposeSlot1; }; public: union diff --git a/src/vm/methodtable.inl b/src/vm/methodtable.inl index 4c808ee..b69513d 100644 --- a/src/vm/methodtable.inl +++ b/src/vm/methodtable.inl @@ -1256,7 +1256,7 @@ inline BOOL MethodTable::HasExplicitSize() inline DWORD MethodTable::GetPerInstInfoSize() { LIMITED_METHOD_DAC_CONTRACT; - return GetNumDicts() * sizeof(TypeHandle*); + return GetNumDicts() * sizeof(PerInstInfoElem_t); } //========================================================================================== diff --git a/src/vm/methodtablebuilder.cpp b/src/vm/methodtablebuilder.cpp index 87de930..d7e9818 100644 --- a/src/vm/methodtablebuilder.cpp +++ b/src/vm/methodtablebuilder.cpp @@ -9842,7 +9842,7 @@ MethodTable * MethodTableBuilder::AllocateNewMT(Module *pLoaderModule, if (dwNumDicts != 0) { cbTotalSize += sizeof(GenericsDictInfo); - cbTotalSize += S_SIZE_T(dwNumDicts) * S_SIZE_T(sizeof(TypeHandle*)); + cbTotalSize += S_SIZE_T(dwNumDicts) * S_SIZE_T(sizeof(MethodTable::PerInstInfoElem_t)); cbTotalSize += cbInstAndDict; } @@ -9995,14 +9995,15 @@ MethodTable * MethodTableBuilder::AllocateNewMT(Module *pLoaderModule, // the dictionary pointers follow the interface map if (dwNumDicts) { - Dictionary** pPerInstInfo = (Dictionary**)(pData + offsetOfInstAndDict.Value() + sizeof(GenericsDictInfo)); + MethodTable::PerInstInfoElem_t *pPerInstInfo = (MethodTable::PerInstInfoElem_t *)(pData + offsetOfInstAndDict.Value() + sizeof(GenericsDictInfo)); pMT->SetPerInstInfo ( pPerInstInfo); // Fill in the dictionary for this type, if it's instantiated if (cbInstAndDict) { - *(pPerInstInfo + (dwNumDicts-1)) = (Dictionary*) (pPerInstInfo + dwNumDicts); + MethodTable::PerInstInfoElem_t *pPInstInfo = (MethodTable::PerInstInfoElem_t *)(pPerInstInfo + (dwNumDicts-1)); + pPInstInfo->SetValueMaybeNull((Dictionary*) (pPerInstInfo + dwNumDicts)); } } diff --git a/src/vm/prestub.cpp b/src/vm/prestub.cpp index 31a5670..a2580b2 100644 --- a/src/vm/prestub.cpp +++ b/src/vm/prestub.cpp @@ -2385,6 +2385,7 @@ void ProcessDynamicDictionaryLookup(TransitionBlock * pTransitionBlock pResult->signature = NULL; pResult->indirectFirstOffset = 0; + pResult->indirectSecondOffset = 0; pResult->indirections = CORINFO_USEHELPER; @@ -2457,6 +2458,12 @@ void ProcessDynamicDictionaryLookup(TransitionBlock * pTransitionBlock IfFailThrow(sigptr.GetData(&data)); pResult->offsets[2] = sizeof(TypeHandle) * data; + if (MethodTable::IsPerInstInfoRelative()) + { + pResult->indirectFirstOffset = 1; + pResult->indirectSecondOffset = 1; + } + return; } } @@ -2502,6 +2509,12 @@ void ProcessDynamicDictionaryLookup(TransitionBlock * pTransitionBlock // Next indirect through the dictionary appropriate to this instantiated type pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1); + if (MethodTable::IsPerInstInfoRelative()) + { + pResult->indirectFirstOffset = 1; + pResult->indirectSecondOffset = 1; + } + *pDictionaryIndexAndSlot |= dictionarySlot; } }