summaryrefslogtreecommitdiff
path: root/packaging/0030-Remove-relocations-for-MethodTable-m_pParentMethodTa.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packaging/0030-Remove-relocations-for-MethodTable-m_pParentMethodTa.patch')
-rw-r--r--packaging/0030-Remove-relocations-for-MethodTable-m_pParentMethodTa.patch563
1 files changed, 563 insertions, 0 deletions
diff --git a/packaging/0030-Remove-relocations-for-MethodTable-m_pParentMethodTa.patch b/packaging/0030-Remove-relocations-for-MethodTable-m_pParentMethodTa.patch
new file mode 100644
index 0000000000..9dae3204ee
--- /dev/null
+++ b/packaging/0030-Remove-relocations-for-MethodTable-m_pParentMethodTa.patch
@@ -0,0 +1,563 @@
+From 52707bd377553ce6c42b1baa0b924dc7413e93ea Mon Sep 17 00:00:00 2001
+From: gbalykov <g.balykov@samsung.com>
+Date: Thu, 22 Feb 2018 20:47:46 +0300
+Subject: [PATCH 30/32] Remove relocations for
+ MethodTable::m_pParentMethodTable for Linux ARM (#15915)
+
+---
+ src/debug/daccess/nidump.cpp | 4 +-
+ src/inc/fixuppointer.h | 208 +++++++++++++++++++++++++++++++++++++++
+ src/vm/class.cpp | 10 +-
+ src/vm/generics.cpp | 1 +
+ src/vm/methodtable.cpp | 35 ++++---
+ src/vm/methodtable.h | 69 ++++++++++---
+ src/vm/proftoeeinterfaceimpl.cpp | 2 +-
+ 7 files changed, 299 insertions(+), 30 deletions(-)
+
+diff --git a/src/debug/daccess/nidump.cpp b/src/debug/daccess/nidump.cpp
+index 2732c9e..ef4725f 100644
+--- a/src/debug/daccess/nidump.cpp
++++ b/src/debug/daccess/nidump.cpp
+@@ -6053,7 +6053,7 @@ PTR_MethodTable NativeImageDumper::GetParent( PTR_MethodTable mt )
+ /* REVISIT_TODO Thu 12/01/2005
+ * Handle fixups
+ */
+- PTR_MethodTable parent( mt->m_pParentMethodTable );
++ PTR_MethodTable parent( ReadPointerMaybeNull((MethodTable*) mt, &MethodTable::m_pParentMethodTable, mt->GetFlagHasIndirectParent()) );
+ _ASSERTE(!CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(parent)));
+ return parent;
+ }
+@@ -7027,7 +7027,7 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name,
+
+
+
+- PTR_MethodTable parent = mt->m_pParentMethodTable;
++ PTR_MethodTable parent = ReadPointerMaybeNull((MethodTable*) mt, &MethodTable::m_pParentMethodTable, mt->GetFlagHasIndirectParent());
+ if( parent == NULL )
+ {
+ DisplayWriteFieldPointer( m_pParentMethodTable, NULL, MethodTable,
+diff --git a/src/inc/fixuppointer.h b/src/inc/fixuppointer.h
+index a711418..5a897e4 100644
+--- a/src/inc/fixuppointer.h
++++ b/src/inc/fixuppointer.h
+@@ -319,6 +319,14 @@ public:
+ return FALSE;
+ }
+
++ // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet.
++ // Ignores isIndirect and offset values.
++ FORCEINLINE BOOL IsTaggedIndirect(TADDR base, bool isIndirect, intptr_t offset) const
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ return IsTagged(base);
++ }
++
+ #ifndef DACCESS_COMPILE
+ // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet.
+ // Does not need explicit base and thus can be used in non-DAC builds only.
+@@ -358,6 +366,14 @@ public:
+ return dac_cast<DPTR(RelativeFixupPointer<PTR_TYPE>)>(base)->GetValue(base);
+ }
+
++ // Static version of GetValue. It is meant to simplify access to arrays of pointers.
++ // Ignores isIndirect and offset values.
++ FORCEINLINE static PTR_TYPE GetValueAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset)
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ return GetValueAtPtr(base);
++ }
++
+ // Returns value of the encoded pointer. The pointer can be NULL.
+ PTR_TYPE GetValueMaybeNull(TADDR base) const
+ {
+@@ -393,6 +409,14 @@ public:
+ return dac_cast<DPTR(RelativeFixupPointer<PTR_TYPE>)>(base)->GetValueMaybeNull(base);
+ }
+
++ // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
++ // Ignores isIndirect and offset values.
++ FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset)
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ return GetValueMaybeNullAtPtr(base);
++ }
++
+ #ifndef DACCESS_COMPILE
+ // Set encoded value of the pointer. Assumes that the value is not NULL.
+ FORCEINLINE void SetValue(PTR_TYPE addr)
+@@ -429,6 +453,14 @@ public:
+ _ASSERTE((addr & FIXUP_POINTER_INDIRECTION) != 0);
+ return (PTR_TYPE *)(addr - FIXUP_POINTER_INDIRECTION);
+ }
++
++ // Returns the pointer to the indirection cell.
++ // Ignores isIndirect and offset values.
++ PTR_TYPE * GetValuePtrIndirect(bool isIndirect, intptr_t offset) const
++ {
++ LIMITED_METHOD_CONTRACT;
++ return GetValuePtr();
++ }
+ #endif // !DACCESS_COMPILE
+
+ // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
+@@ -462,6 +494,14 @@ public:
+ LIMITED_METHOD_CONTRACT;
+ return IsIndirectPtr((TADDR)this);
+ }
++
++ // Returns whether pointer is indirect. Assumes that the value is not NULL.
++ // Ignores isIndirect and offset values.
++ bool IsIndirectPtrIndirect(bool isIndirect, intptr_t offset) const
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ return IsIndirectPtr();
++ }
+ #endif
+
+ // Returns whether pointer is indirect. The value can be NULL.
+@@ -483,6 +523,14 @@ public:
+ LIMITED_METHOD_CONTRACT;
+ return IsIndirectPtrMaybeNull((TADDR)this);
+ }
++
++ // Returns whether pointer is indirect. The value can be NULL.
++ // Ignores isIndirect and offset values.
++ bool IsIndirectPtrMaybeNullIndirect(bool isIndirect, intptr_t offset) const
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ return IsIndirectPtrMaybeNull();
++ }
+ #endif
+
+ private:
+@@ -765,6 +813,130 @@ private:
+ INT32 m_delta;
+ };
+
++//----------------------------------------------------------------------------
++// IndirectPointer is pointer with optional indirection, similar to FixupPointer and RelativeFixupPointer.
++//
++// In comparison to FixupPointer, IndirectPointer's indirection is handled from outside by isIndirect flag.
++// In comparison to RelativeFixupPointer, IndirectPointer's offset is a constant,
++// while RelativeFixupPointer's offset is an address.
++//
++// IndirectPointer can contain NULL only if it is not indirect.
++//
++template<typename PTR_TYPE>
++class IndirectPointer
++{
++public:
++
++ static constexpr bool isRelative = false;
++ typedef PTR_TYPE type;
++
++ // Returns whether the encoded pointer is NULL.
++ BOOL IsNull() const
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ return m_addr == (TADDR)NULL;
++ }
++
++ // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet.
++ // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
++ FORCEINLINE BOOL IsTaggedIndirect(TADDR base, bool isIndirect, intptr_t offset) const
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ TADDR addr = m_addr;
++ if (isIndirect)
++ {
++ _ASSERTE(!IsNull());
++ return (*PTR_TADDR(addr + offset) & 1) != 0;
++ }
++ return FALSE;
++ }
++
++ // Returns value of the encoded pointer.
++ // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
++ FORCEINLINE PTR_TYPE GetValueIndirect(bool isIndirect, intptr_t offset) const
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ TADDR addr = m_addr;
++ if (isIndirect)
++ {
++ _ASSERTE(!IsNull());
++ addr = *PTR_TADDR(addr + offset);
++ }
++ return dac_cast<PTR_TYPE>(addr);
++ }
++
++#ifndef DACCESS_COMPILE
++ // Returns the pointer to the indirection cell.
++ // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
++ PTR_TYPE * GetValuePtrIndirect(bool isIndirect, intptr_t offset) const
++ {
++ LIMITED_METHOD_CONTRACT;
++ TADDR addr = m_addr;
++ if (isIndirect)
++ {
++ _ASSERTE(!IsNull());
++ return (PTR_TYPE *)(addr + offset);
++ }
++ return (PTR_TYPE *)&m_addr;
++ }
++#endif // !DACCESS_COMPILE
++
++ // Static version of GetValue. It is meant to simplify access to arrays of pointers.
++ // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
++ FORCEINLINE static PTR_TYPE GetValueAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset)
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ return dac_cast<DPTR(IndirectPointer<PTR_TYPE>)>(base)->GetValueIndirect(isIndirect, offset);
++ }
++
++ // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
++ // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
++ FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset)
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ return GetValueAtPtrIndirect(base, isIndirect, offset);
++ }
++
++#ifndef DACCESS_COMPILE
++ // Returns whether pointer is indirect. Assumes that the value is not NULL.
++ // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
++ bool IsIndirectPtrIndirect(bool isIndirect, intptr_t offset) const
++ {
++ LIMITED_METHOD_CONTRACT;
++ if (isIndirect)
++ _ASSERTE(!IsNull());
++ return isIndirect;
++ }
++
++ // Returns whether pointer is indirect. The value can be NULL.
++ // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
++ bool IsIndirectPtrMaybeNullIndirect(bool isIndirect, intptr_t offset) const
++ {
++ LIMITED_METHOD_CONTRACT;
++ return IsIndirectPtrIndirect(isIndirect, offset);
++ }
++#endif // !DACCESS_COMPILE
++
++#ifndef DACCESS_COMPILE
++ // Set encoded value of the pointer. Assumes that the value is not NULL.
++ void SetValue(PTR_TYPE addr)
++ {
++ LIMITED_METHOD_CONTRACT;
++ m_addr = dac_cast<TADDR>(addr);
++ }
++
++ // Set encoded value of the pointer. The value can be NULL.
++ void SetValueMaybeNull(PTR_TYPE addr)
++ {
++ LIMITED_METHOD_CONTRACT;
++ SetValue(addr);
++ }
++#endif // !DACCESS_COMPILE
++
++private:
++ TADDR m_addr;
++};
++
+ template<bool isMaybeNull, typename T, typename PT>
+ typename PT::type
+ ReadPointer(const T *base, const PT T::* pPointerFieldMember)
+@@ -783,6 +955,24 @@ ReadPointer(const T *base, const PT T::* pPointerFieldMember)
+ }
+ }
+
++template<bool isMaybeNull, typename T, typename PT>
++typename PT::type
++ReadPointer(const T *base, const PT T::* pPointerFieldMember, bool isIndirect)
++{
++ LIMITED_METHOD_DAC_CONTRACT;
++
++ uintptr_t offset = (uintptr_t) &(base->*pPointerFieldMember) - (uintptr_t) base;
++
++ if (isMaybeNull)
++ {
++ return PT::GetValueMaybeNullAtPtrIndirect(dac_cast<TADDR>(base) + offset, isIndirect, offset);
++ }
++ else
++ {
++ return PT::GetValueAtPtrIndirect(dac_cast<TADDR>(base) + offset, isIndirect, offset);
++ }
++}
++
+ template<typename T, typename PT>
+ typename PT::type
+ ReadPointerMaybeNull(const T *base, const PT T::* pPointerFieldMember)
+@@ -794,6 +984,15 @@ ReadPointerMaybeNull(const T *base, const PT T::* pPointerFieldMember)
+
+ template<typename T, typename PT>
+ typename PT::type
++ReadPointerMaybeNull(const T *base, const PT T::* pPointerFieldMember, bool isIndirect)
++{
++ LIMITED_METHOD_DAC_CONTRACT;
++
++ return ReadPointer<true>(base, pPointerFieldMember, isIndirect);
++}
++
++template<typename T, typename PT>
++typename PT::type
+ ReadPointer(const T *base, const PT T::* pPointerFieldMember)
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+@@ -801,6 +1000,15 @@ ReadPointer(const T *base, const PT T::* pPointerFieldMember)
+ return ReadPointer<false>(base, pPointerFieldMember);
+ }
+
++template<typename T, typename PT>
++typename PT::type
++ReadPointer(const T *base, const PT T::* pPointerFieldMember, bool isIndirect)
++{
++ LIMITED_METHOD_DAC_CONTRACT;
++
++ return ReadPointer<false>(base, pPointerFieldMember, isIndirect);
++}
++
+ template<bool isMaybeNull, typename T, typename C, typename PT>
+ typename PT::type
+ ReadPointer(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember)
+diff --git a/src/vm/class.cpp b/src/vm/class.cpp
+index c1519a2..7b2885b 100644
+--- a/src/vm/class.cpp
++++ b/src/vm/class.cpp
+@@ -889,7 +889,15 @@ ClassLoader::LoadExactParentAndInterfacesTransitively(MethodTable *pMT)
+ LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Replaced approximate parent %s with exact parent %s from token %x\n", pParentMT->GetDebugClassName(), pNewParentMT->GetDebugClassName(), crExtends));
+
+ // SetParentMethodTable is not used here since we want to update the indirection cell in the NGen case
+- *EnsureWritablePages(pMT->GetParentMethodTablePtr()) = pNewParentMT;
++ if (pMT->IsParentMethodTableIndirectPointerMaybeNull())
++ {
++ *EnsureWritablePages(pMT->GetParentMethodTableValuePtr()) = pNewParentMT;
++ }
++ else
++ {
++ EnsureWritablePages(pMT->GetParentMethodTablePointerPtr());
++ pMT->GetParentMethodTablePointerPtr()->SetValueMaybeNull(pNewParentMT);
++ }
+
+ pParentMT = pNewParentMT;
+ }
+diff --git a/src/vm/generics.cpp b/src/vm/generics.cpp
+index b110184..61a1de5 100644
+--- a/src/vm/generics.cpp
++++ b/src/vm/generics.cpp
+@@ -365,6 +365,7 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation(
+ pMT->ClearFlag(MethodTable::enum_flag_IsPreRestored);
+
+ pMT->ClearFlag(MethodTable::enum_flag_HasIndirectParent);
++ pMT->m_pParentMethodTable.SetValueMaybeNull(NULL);
+
+ // Non non-virtual slots
+ pMT->ClearFlag(MethodTable::enum_flag_HasSingleNonVirtualSlot);
+diff --git a/src/vm/methodtable.cpp b/src/vm/methodtable.cpp
+index 75db911..b097406 100644
+--- a/src/vm/methodtable.cpp
++++ b/src/vm/methodtable.cpp
+@@ -4778,7 +4778,17 @@ void MethodTable::Fixup(DataImage *image)
+ #endif // _DEBUG
+
+ MethodTable * pParentMT = GetParentMethodTable();
+- _ASSERTE(!pNewMT->GetFlag(enum_flag_HasIndirectParent));
++ _ASSERTE(!pNewMT->IsParentMethodTableIndirectPointerMaybeNull());
++
++ ZapRelocationType relocType;
++ if (decltype(MethodTable::m_pParentMethodTable)::isRelative)
++ {
++ relocType = IMAGE_REL_BASED_RELPTR;
++ }
++ else
++ {
++ relocType = IMAGE_REL_BASED_PTR;
++ }
+
+ if (pParentMT != NULL)
+ {
+@@ -4790,7 +4800,8 @@ void MethodTable::Fixup(DataImage *image)
+ {
+ if (image->CanHardBindToZapModule(pParentMT->GetLoaderModule()))
+ {
+- image->FixupPointerField(this, offsetof(MethodTable, m_pParentMethodTable));
++ _ASSERTE(!IsParentMethodTableIndirectPointer());
++ image->FixupField(this, offsetof(MethodTable, m_pParentMethodTable), pParentMT, 0, relocType);
+ }
+ else
+ {
+@@ -4826,7 +4837,7 @@ void MethodTable::Fixup(DataImage *image)
+
+ if (pImport != NULL)
+ {
+- image->FixupFieldToNode(this, offsetof(MethodTable, m_pParentMethodTable), pImport, -(SSIZE_T)offsetof(MethodTable, m_pParentMethodTable));
++ image->FixupFieldToNode(this, offsetof(MethodTable, m_pParentMethodTable), pImport, -PARENT_MT_FIXUP_OFFSET, relocType);
+ pNewMT->SetFlag(enum_flag_HasIndirectParent);
+ }
+ }
+@@ -6091,7 +6102,15 @@ void MethodTable::Restore()
+ //
+ // Restore parent method table
+ //
+- Module::RestoreMethodTablePointerRaw(GetParentMethodTablePtr(), GetLoaderModule(), CLASS_LOAD_APPROXPARENTS);
++ if (IsParentMethodTableIndirectPointerMaybeNull())
++ {
++ Module::RestoreMethodTablePointerRaw(GetParentMethodTableValuePtr(), GetLoaderModule(), CLASS_LOAD_APPROXPARENTS);
++ }
++ else
++ {
++ ClassLoader::EnsureLoaded(ReadPointer(this, &MethodTable::m_pParentMethodTable, GetFlagHasIndirectParent()),
++ CLASS_LOAD_APPROXPARENTS);
++ }
+
+ //
+ // Restore interface classes
+@@ -7849,13 +7868,7 @@ BOOL MethodTable::IsParentMethodTablePointerValid()
+ if (!GetWriteableData_NoLogging()->IsParentMethodTablePointerValid())
+ return FALSE;
+
+- if (!GetFlag(enum_flag_HasIndirectParent))
+- {
+- return TRUE;
+- }
+- TADDR pMT;
+- pMT = *PTR_TADDR(m_pParentMethodTable + offsetof(MethodTable, m_pParentMethodTable));
+- return !CORCOMPILE_IS_POINTER_TAGGED(pMT);
++ return !IsParentMethodTableTagged(dac_cast<PTR_MethodTable>(this));
+ }
+ #endif
+
+diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h
+index 8c15d2e..c2c2564 100644
+--- a/src/vm/methodtable.h
++++ b/src/vm/methodtable.h
+@@ -2127,6 +2127,14 @@ public:
+ // THE METHOD TABLE PARENT (SUPERCLASS/BASE CLASS)
+ //
+
++#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++#define PARENT_MT_FIXUP_OFFSET (-FIXUP_POINTER_INDIRECTION)
++ typedef RelativeFixupPointer<PTR_MethodTable> ParentMT_t;
++#else
++#define PARENT_MT_FIXUP_OFFSET ((SSIZE_T)offsetof(MethodTable, m_pParentMethodTable))
++ typedef IndirectPointer<PTR_MethodTable> ParentMT_t;
++#endif
++
+ BOOL HasApproxParent()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+@@ -2145,33 +2153,63 @@ public:
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ PRECONDITION(IsParentMethodTablePointerValid());
+-
+- TADDR pMT = m_pParentMethodTable;
+-#ifdef FEATURE_PREJIT
+- if (GetFlag(enum_flag_HasIndirectParent))
+- pMT = *PTR_TADDR(m_pParentMethodTable + offsetof(MethodTable, m_pParentMethodTable));
+-#endif
+- return PTR_MethodTable(pMT);
++ return ReadPointerMaybeNull(this, &MethodTable::m_pParentMethodTable, GetFlagHasIndirectParent());
+ }
+
+ inline static PTR_VOID GetParentMethodTableOrIndirection(PTR_VOID pMT)
+ {
+ WRAPPER_NO_CONTRACT;
++#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++ PTR_MethodTable pMethodTable = dac_cast<PTR_MethodTable>(pMT);
++ PTR_MethodTable pParentMT = ReadPointerMaybeNull((MethodTable*) pMethodTable, &MethodTable::m_pParentMethodTable);
++ return dac_cast<PTR_VOID>(pParentMT);
++#else
+ return PTR_VOID(*PTR_TADDR(dac_cast<TADDR>(pMT) + offsetof(MethodTable, m_pParentMethodTable)));
++#endif
+ }
+
+- inline MethodTable ** GetParentMethodTablePtr()
++ inline static bool IsParentMethodTableTagged(PTR_MethodTable pMT)
+ {
+- WRAPPER_NO_CONTRACT;
++ LIMITED_METHOD_CONTRACT;
++ TADDR base = dac_cast<TADDR>(pMT) + offsetof(MethodTable, m_pParentMethodTable);
++ return pMT->m_pParentMethodTable.IsTaggedIndirect(base, pMT->GetFlagHasIndirectParent(), PARENT_MT_FIXUP_OFFSET);
++ }
+
++ bool GetFlagHasIndirectParent()
++ {
+ #ifdef FEATURE_PREJIT
+- return GetFlag(enum_flag_HasIndirectParent) ?
+- (MethodTable **)(m_pParentMethodTable + offsetof(MethodTable, m_pParentMethodTable)) :(MethodTable **)&m_pParentMethodTable;
++ return GetFlag(enum_flag_HasIndirectParent);
+ #else
+- return (MethodTable **)&m_pParentMethodTable;
++ return FALSE;
+ #endif
+ }
+
++#ifndef DACCESS_COMPILE
++ inline ParentMT_t * GetParentMethodTablePointerPtr()
++ {
++ LIMITED_METHOD_CONTRACT;
++ return &m_pParentMethodTable;
++ }
++
++ inline bool IsParentMethodTableIndirectPointerMaybeNull()
++ {
++ LIMITED_METHOD_CONTRACT;
++ return m_pParentMethodTable.IsIndirectPtrMaybeNullIndirect(GetFlagHasIndirectParent(), PARENT_MT_FIXUP_OFFSET);
++ }
++
++ inline bool IsParentMethodTableIndirectPointer()
++ {
++ LIMITED_METHOD_CONTRACT;
++ return m_pParentMethodTable.IsIndirectPtrIndirect(GetFlagHasIndirectParent(), PARENT_MT_FIXUP_OFFSET);
++ }
++
++ inline MethodTable ** GetParentMethodTableValuePtr()
++ {
++ LIMITED_METHOD_CONTRACT;
++ return m_pParentMethodTable.GetValuePtrIndirect(GetFlagHasIndirectParent(), PARENT_MT_FIXUP_OFFSET);
++ }
++#endif // !DACCESS_COMPILE
++
+ // Is the parent method table pointer equal to the given argument?
+ BOOL ParentEquals(PTR_MethodTable pMT)
+ {
+@@ -2189,8 +2227,8 @@ public:
+ void SetParentMethodTable (MethodTable *pParentMethodTable)
+ {
+ LIMITED_METHOD_CONTRACT;
+- PRECONDITION(!GetFlag(enum_flag_HasIndirectParent));
+- m_pParentMethodTable = (TADDR)pParentMethodTable;
++ PRECONDITION(!IsParentMethodTableIndirectPointerMaybeNull());
++ m_pParentMethodTable.SetValueMaybeNull(pParentMethodTable);
+ #ifdef _DEBUG
+ GetWriteableDataForWrite_NoLogging()->SetParentMethodTablePointerValid();
+ #endif
+@@ -4095,11 +4133,12 @@ private:
+ LPCUTF8 debug_m_szClassName;
+ #endif //_DEBUG
+
++ // On Linux ARM is a RelativeFixupPointer. Otherwise,
+ // Parent PTR_MethodTable if enum_flag_HasIndirectParent is not set. Pointer to indirection cell
+ // if enum_flag_enum_flag_HasIndirectParent is set. The indirection is offset by offsetof(MethodTable, m_pParentMethodTable).
+ // It allows casting helpers to go through parent chain natually. Casting helper do not need need the explicit check
+ // for enum_flag_HasIndirectParentMethodTable.
+- TADDR m_pParentMethodTable;
++ ParentMT_t m_pParentMethodTable;
+
+ RelativePointer<PTR_Module> m_pLoaderModule; // LoaderModule. It is equal to the ZapModule in ngened images
+
+diff --git a/src/vm/proftoeeinterfaceimpl.cpp b/src/vm/proftoeeinterfaceimpl.cpp
+index cfd99ad..972a0eb 100644
+--- a/src/vm/proftoeeinterfaceimpl.cpp
++++ b/src/vm/proftoeeinterfaceimpl.cpp
+@@ -6832,7 +6832,7 @@ HRESULT ProfToEEInterfaceImpl::GetClassLayout(ClassID classID,
+ // running into - attempting to get the class layout for all types at module load time.
+ // If we don't detect this the runtime will AV during the field iteration below. Feel
+ // free to eliminate this check when a more complete solution is available.
+- if (CORCOMPILE_IS_POINTER_TAGGED(*(typeHandle.AsMethodTable()->GetParentMethodTablePtr())))
++ if (MethodTable::IsParentMethodTableTagged(typeHandle.AsMethodTable()))
+ {
+ return CORPROF_E_DATAINCOMPLETE;
+ }
+--
+2.7.4
+