summaryrefslogtreecommitdiff
path: root/packaging/0024-Remove-relocations-for-MethodTable-m_pPerInstInfo-fo.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packaging/0024-Remove-relocations-for-MethodTable-m_pPerInstInfo-fo.patch')
-rw-r--r--packaging/0024-Remove-relocations-for-MethodTable-m_pPerInstInfo-fo.patch541
1 files changed, 541 insertions, 0 deletions
diff --git a/packaging/0024-Remove-relocations-for-MethodTable-m_pPerInstInfo-fo.patch b/packaging/0024-Remove-relocations-for-MethodTable-m_pPerInstInfo-fo.patch
new file mode 100644
index 0000000..4bc117b
--- /dev/null
+++ b/packaging/0024-Remove-relocations-for-MethodTable-m_pPerInstInfo-fo.patch
@@ -0,0 +1,541 @@
+From ca3a3d9695301697d9011f4187eefaa05595f9e7 Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Thu, 12 Apr 2018 12:49:39 +0300
+Subject: [PATCH 24/32] Remove relocations for MethodTable::m_pPerInstInfo for
+ Linux ARM
+
+FIX: fix No.4, manually applied patch due to code differencies
+---
+ .../superpmi/superpmi-shared/methodcontext.cpp | 6 +++
+ .../superpmi/superpmi-shared/methodcontext.h | 1 +
+ src/debug/daccess/nidump.cpp | 6 ++-
+ src/inc/corinfo.h | 7 ++++
+ src/jit/importer.cpp | 6 +--
+ src/vm/ceeload.cpp | 11 ++++-
+ src/vm/class.cpp | 7 +++-
+ src/vm/genericdict.cpp | 2 +-
+ src/vm/generics.cpp | 5 ++-
+ src/vm/jitinterface.cpp | 13 ++++++
+ src/vm/methodtable.cpp | 47 +++++++++++++++++-----
+ src/vm/methodtable.h | 29 +++++++++----
+ src/vm/methodtable.inl | 2 +-
+ src/vm/methodtablebuilder.cpp | 7 ++--
+ src/vm/prestub.cpp | 13 ++++++
+ 15 files changed, 129 insertions(+), 33 deletions(-)
+
+diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
+index 4c5fb61..4406b85 100644
+--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
++++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
+@@ -1574,6 +1574,7 @@ void MethodContext::recGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
+ value.stubLookup.runtimeLookup.testForNull = (DWORD)pResult->stubLookup.runtimeLookup.testForNull;
+ value.stubLookup.runtimeLookup.testForFixup = (DWORD)pResult->stubLookup.runtimeLookup.testForFixup;
+ value.stubLookup.runtimeLookup.indirectFirstOffset = (DWORD)pResult->stubLookup.runtimeLookup.indirectFirstOffset;
++ value.stubLookup.runtimeLookup.indirectSecondOffset = (DWORD)pResult->stubLookup.runtimeLookup.indirectSecondOffset;
+ for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
+ value.stubLookup.runtimeLookup.offsets[i] = (DWORDLONG)pResult->stubLookup.runtimeLookup.offsets[i];
+ }
+@@ -1585,6 +1586,7 @@ void MethodContext::recGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
+ value.stubLookup.runtimeLookup.testForNull = (DWORD)0;
+ value.stubLookup.runtimeLookup.testForFixup = (DWORD)0;
+ value.stubLookup.runtimeLookup.indirectFirstOffset = (DWORD)0;
++ value.stubLookup.runtimeLookup.indirectSecondOffset = (DWORD)0;
+ for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
+ value.stubLookup.runtimeLookup.offsets[i] = (DWORDLONG)0;
+
+@@ -1764,6 +1766,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];
+ }
+@@ -3222,6 +3225,7 @@ void MethodContext::recEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolve
+ value.lookup.runtimeLookup.testForNull = (DWORD)pResult->lookup.runtimeLookup.testForNull;
+ value.lookup.runtimeLookup.testForFixup = (DWORD)pResult->lookup.runtimeLookup.testForFixup;
+ value.lookup.runtimeLookup.indirectFirstOffset = (DWORD)pResult->lookup.runtimeLookup.indirectFirstOffset;
++ value.lookup.runtimeLookup.indirectSecondOffset = (DWORD)pResult->lookup.runtimeLookup.indirectSecondOffset;
+ for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
+ value.lookup.runtimeLookup.offsets[i] = (DWORDLONG)pResult->lookup.runtimeLookup.offsets[i];
+ }
+@@ -3233,6 +3237,7 @@ void MethodContext::recEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolve
+ value.lookup.runtimeLookup.testForNull = (DWORD)0;
+ value.lookup.runtimeLookup.testForFixup = (DWORD)0;
+ value.lookup.runtimeLookup.indirectFirstOffset = (DWORD)0;
++ value.lookup.runtimeLookup.indirectSecondOffset = (DWORD)0;
+ for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
+ value.lookup.runtimeLookup.offsets[i] = (DWORDLONG)0;
+ // copy the constLookup view of the union
+@@ -3311,6 +3316,7 @@ void MethodContext::repEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolve
+ pResult->lookup.runtimeLookup.testForNull = value.lookup.runtimeLookup.testForNull != 0;
+ pResult->lookup.runtimeLookup.testForFixup = value.lookup.runtimeLookup.testForFixup != 0;
+ pResult->lookup.runtimeLookup.indirectFirstOffset = value.lookup.runtimeLookup.indirectFirstOffset != 0;
++ pResult->lookup.runtimeLookup.indirectSecondOffset = value.lookup.runtimeLookup.indirectSecondOffset != 0;
+ for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
+ pResult->lookup.runtimeLookup.offsets[i] = (size_t)value.lookup.runtimeLookup.offsets[i];
+ }
+diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
+index 4887522..53227e4 100644
+--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
++++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
+@@ -241,6 +241,7 @@ public:
+ DWORD testForFixup;
+ DWORDLONG offsets[CORINFO_MAXINDIRECTIONS];
+ DWORD indirectFirstOffset;
++ DWORD indirectSecondOffset;
+ };
+ struct Agnostic_CORINFO_CONST_LOOKUP
+ {
+diff --git a/src/debug/daccess/nidump.cpp b/src/debug/daccess/nidump.cpp
+index 04d610e..d43e9f9 100644
+--- a/src/debug/daccess/nidump.cpp
++++ b/src/debug/daccess/nidump.cpp
+@@ -5106,7 +5106,9 @@ 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<TADDR>(&(mt->GetPerInstInfo()[numDicts-1]));
++ PTR_Dictionary dictionary( MethodTable::PerInstInfoElem_t::GetValueAtPtr(base) );
+ unsigned numArgs = mt->GetNumGenericArgs();
+
+ DictionaryToArgString( dictionary, numArgs, buf );
+@@ -7092,7 +7094,7 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name,
+ 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 a6acd71..58fcdf4 100644
+--- a/src/inc/corinfo.h
++++ b/src/inc/corinfo.h
+@@ -1331,6 +1331,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 c5f2970..62f1c13 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 43e2c14..9e5a525 100644
+--- a/src/vm/ceeload.cpp
++++ b/src/vm/ceeload.cpp
+@@ -9325,13 +9325,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 63d95a0..650caef 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<WORD>(pOldMT->GetNumDicts()));
+ _ASSERTE(FitsIn<WORD>(pOldMT->GetNumGenericArgs()));
+ pMT->SetDictInfo(static_cast<WORD>(pOldMT->GetNumDicts()), static_cast<WORD>(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 52db7c5..e0adf87 100644
+--- a/src/vm/jitinterface.cpp
++++ b/src/vm/jitinterface.cpp
+@@ -3149,6 +3149,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;
+@@ -3363,6 +3364,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 &&
+@@ -3610,6 +3617,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 e93f63d..4c1746e 100644
+--- a/src/vm/methodtable.cpp
++++ b/src/vm/methodtable.cpp
+@@ -4332,7 +4332,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
+ {
+@@ -4675,14 +4682,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
+ {
+@@ -5017,7 +5031,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())
+ {
+@@ -5030,10 +5044,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);
++ }
+ }
+ }
+ }
+@@ -6218,7 +6245,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;
+
+@@ -6226,7 +6253,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<TADDR>(&(GetPerInstInfo()[GetNumDicts()-1]));
++ return PerInstInfoElem_t::GetValueMaybeNullAtPtr(base);
+ }
+ else
+ {
+@@ -6243,7 +6271,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<TADDR>(&(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 63d35e6..81a9186 100644
+--- a/src/vm/methodtable.h
++++ b/src/vm/methodtable.h
+@@ -3008,12 +3008,20 @@ public:
+ // must have a dictionary entry. On the other hand, for instantiations shared with Dict<string,double> the opposite holds.
+ //
+
++#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++ typedef RelativePointer<PTR_Dictionary> PerInstInfoElem_t;
++ typedef RelativePointer<DPTR(PerInstInfoElem_t)> PerInstInfo_t;
++#else
++ typedef PlainPointer<PTR_Dictionary> PerInstInfoElem_t;
++ typedef PlainPointer<DPTR(PerInstInfoElem_t)> 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<DPTR(PTR_Dictionary)>(m_pMultipurposeSlot1);
++ return ReadPointer(this, &MethodTable::m_pPerInstInfo);
+ }
+ BOOL HasPerInstInfo()
+ {
+@@ -3021,15 +3029,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)
+ {
+@@ -3049,7 +3062,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
+ //
+@@ -4123,9 +4136,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 5d77463..792a19c 100644
+--- a/src/vm/methodtablebuilder.cpp
++++ b/src/vm/methodtablebuilder.cpp
+@@ -10050,7 +10050,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;
+ }
+
+@@ -10203,14 +10203,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 746e415..b31e8f7 100644
+--- a/src/vm/prestub.cpp
++++ b/src/vm/prestub.cpp
+@@ -2407,6 +2407,7 @@ void ProcessDynamicDictionaryLookup(TransitionBlock * pTransitionBlock
+ pResult->signature = NULL;
+
+ pResult->indirectFirstOffset = 0;
++ pResult->indirectSecondOffset = 0;
+
+ pResult->indirections = CORINFO_USEHELPER;
+
+@@ -2479,6 +2480,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;
+ }
+ }
+@@ -2524,6 +2531,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;
+ }
+ }
+--
+2.7.4
+