diff options
Diffstat (limited to 'packaging/0015-Partially-remove-relocations-from-Class-section-of-N.patch')
-rw-r--r-- | packaging/0015-Partially-remove-relocations-from-Class-section-of-N.patch | 1105 |
1 files changed, 1105 insertions, 0 deletions
diff --git a/packaging/0015-Partially-remove-relocations-from-Class-section-of-N.patch b/packaging/0015-Partially-remove-relocations-from-Class-section-of-N.patch new file mode 100644 index 0000000000..69b7fb70be --- /dev/null +++ b/packaging/0015-Partially-remove-relocations-from-Class-section-of-N.patch @@ -0,0 +1,1105 @@ +From cb4f4da84d36ec631f69a1e9007035a62a6c1738 Mon Sep 17 00:00:00 2001 +From: Ruben Ayrapetyan <ruben-ayrapetyan@users.noreply.github.com> +Date: Wed, 28 Jun 2017 09:16:01 +0300 +Subject: [PATCH 15/32] Partially remove relocations from Class section of + NGEN-ed images (#11962) + +* Remove relocations for ParamTypeDesc::m_TemplateMT. + +* Remove relocations for LayoutEEClass::m_LayoutInfo.m_pFieldMarshalers. + +* Prepare RelativeFixupPointer. + +* Remove relocations for FieldMarshaler::m_pFD and FieldMarshaler_*::m_*. +--- + src/debug/daccess/nidump.cpp | 8 +- + src/inc/fixuppointer.h | 31 ++++++- + src/vm/ceeload.cpp | 7 +- + src/vm/ceeload.h | 3 +- + src/vm/class.cpp | 8 +- + src/vm/class.h | 15 +++- + src/vm/fieldmarshaler.cpp | 19 ++-- + src/vm/fieldmarshaler.h | 197 ++++++++++++++++++++++++++++++++++++------ + src/vm/methodtablebuilder.cpp | 8 +- + src/vm/typedesc.cpp | 22 ++--- + src/vm/typedesc.h | 23 +++-- + src/vm/typedesc.inl | 2 +- + 12 files changed, 269 insertions(+), 74 deletions(-) + +diff --git a/src/debug/daccess/nidump.cpp b/src/debug/daccess/nidump.cpp +index 42705a5..2ec5d9a 100644 +--- a/src/debug/daccess/nidump.cpp ++++ b/src/debug/daccess/nidump.cpp +@@ -4767,7 +4767,7 @@ void NativeImageDumper::TraverseTypeHashEntry(void *pContext, PTR_EETypeHashEntr + * all that much harm here (bloats m_discoveredMTs though, + * but not by a huge amount. + */ +- PTR_MethodTable mt(ptd->m_TemplateMT.GetValue()); ++ PTR_MethodTable mt(ptd->GetTemplateMethodTableInternal()); + if (isInRange(PTR_TO_TADDR(mt))) + { + m_discoveredMTs.AppendEx(mt); +@@ -6243,7 +6243,7 @@ void NativeImageDumper::TypeDescToString( PTR_TypeDesc td, SString& buf ) + if( td->IsArray() ) + { + //td->HasTypeParam() may also be true. +- PTR_MethodTable mt = ptd->m_TemplateMT.GetValue(); ++ PTR_MethodTable mt = ptd->GetTemplateMethodTableInternal(); + _ASSERTE( PTR_TO_TADDR(mt) ); + if( CORCOMPILE_IS_POINTER_TAGGED(PTR_TO_TADDR(mt)) ) + { +@@ -8493,7 +8493,7 @@ NativeImageDumper::DumpEEClassForMethodTable( PTR_MethodTable mt ) + VERBOSE_TYPES ); + DisplayWriteFieldInt( m_numCTMFields, eecli->m_numCTMFields, + EEClassLayoutInfo, VERBOSE_TYPES ); +- PTR_FieldMarshaler fmArray( TO_TADDR(eecli->m_pFieldMarshalers) ); ++ PTR_FieldMarshaler fmArray = eecli->GetFieldMarshalers(); + DisplayWriteFieldAddress( m_pFieldMarshalers, + DPtrToPreferredAddr(fmArray), + eecli->m_numCTMFields +@@ -8840,7 +8840,7 @@ void NativeImageDumper::DumpTypeDesc( PTR_TypeDesc td ) + { + PTR_ParamTypeDesc ptd(td); + DisplayStartVStructure( "ParamTypeDesc", TYPEDESCS ); +- WriteFieldMethodTable( m_TemplateMT, ptd->m_TemplateMT.GetValue(), ++ WriteFieldMethodTable( m_TemplateMT, ptd->GetTemplateMethodTableInternal(), + ParamTypeDesc, TYPEDESCS ); + WriteFieldTypeHandle( m_Arg, ptd->m_Arg, + ParamTypeDesc, TYPEDESCS ); +diff --git a/src/inc/fixuppointer.h b/src/inc/fixuppointer.h +index 38ae348..83ff20e 100644 +--- a/src/inc/fixuppointer.h ++++ b/src/inc/fixuppointer.h +@@ -249,6 +249,15 @@ public: + static constexpr bool isRelative = true; + typedef PTR_TYPE type; + ++#ifndef DACCESS_COMPILE ++ RelativeFixupPointer() ++ { ++ SetValueMaybeNull(NULL); ++ } ++#else // DACCESS_COMPILE ++ RelativeFixupPointer() =delete; ++#endif // DACCESS_COMPILE ++ + // Implicit copy/move is not allowed + RelativeFixupPointer<PTR_TYPE>(const RelativeFixupPointer<PTR_TYPE> &) =delete; + RelativeFixupPointer<PTR_TYPE>(RelativeFixupPointer<PTR_TYPE> &&) =delete; +@@ -273,6 +282,15 @@ public: + return FALSE; + } + ++#ifndef DACCESS_COMPILE ++ FORCEINLINE BOOL IsTagged() const ++ { ++ LIMITED_METHOD_CONTRACT; ++ TADDR base = (TADDR) this; ++ return IsTagged(base); ++ } ++#endif // !DACCESS_COMPILE ++ + // Returns value of the encoded pointer. Assumes that the pointer is not NULL. + FORCEINLINE PTR_TYPE GetValue(TADDR base) const + { +@@ -343,7 +361,7 @@ public: + { + LIMITED_METHOD_CONTRACT; + PRECONDITION(addr != NULL); +- m_delta = (TADDR)addr - (TADDR)this; ++ m_delta = dac_cast<TADDR>(addr) - (TADDR)this; + } + + // Set encoded value of the pointer. The value can be NULL. +@@ -353,7 +371,7 @@ public: + if (addr == NULL) + m_delta = NULL; + else +- m_delta = (TADDR)addr - (TADDR)base; ++ m_delta = dac_cast<TADDR>(addr) - (TADDR)base; + } + + // Set encoded value of the pointer. The value can be NULL. +@@ -373,6 +391,15 @@ public: + return dac_cast<DPTR(PTR_TYPE)>(addr - FIXUP_POINTER_INDIRECTION); + } + ++#ifndef DACCESS_COMPILE ++ PTR_TYPE * GetValuePtr() const ++ { ++ LIMITED_METHOD_CONTRACT; ++ TADDR base = (TADDR) this; ++ return GetValuePtr(base); ++ } ++#endif // !DACCESS_COMPILE ++ + // Returns value of the encoded pointer. Assumes that the pointer is not NULL. + // Allows the value to be tagged. + FORCEINLINE TADDR GetValueMaybeTagged(TADDR base) const +diff --git a/src/vm/ceeload.cpp b/src/vm/ceeload.cpp +index f995343..cd40ad7 100644 +--- a/src/vm/ceeload.cpp ++++ b/src/vm/ceeload.cpp +@@ -10749,7 +10749,7 @@ void Module::RestoreMethodDescPointer(RelativeFixupPointer<PTR_MethodDesc> * ppM + } + + /*static*/ +-void Module::RestoreFieldDescPointer(FixupPointer<PTR_FieldDesc> * ppFD) ++void Module::RestoreFieldDescPointer(RelativeFixupPointer<PTR_FieldDesc> * ppFD) + { + CONTRACTL + { +@@ -10759,6 +10759,9 @@ void Module::RestoreFieldDescPointer(FixupPointer<PTR_FieldDesc> * ppFD) + } + CONTRACTL_END; + ++ if (!ppFD->IsTagged()) ++ return; ++ + PTR_FieldDesc * ppValue = ppFD->GetValuePtr(); + + // Ensure that the compiler won't fetch the value twice +@@ -10770,7 +10773,7 @@ void Module::RestoreFieldDescPointer(FixupPointer<PTR_FieldDesc> * ppFD) + CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0); + #endif + +- Module * pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppValue)); ++ Module * pContainingModule = ExecutionManager::FindZapModule((TADDR)ppValue); + PREFIX_ASSUME(pContainingModule != NULL); + + RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup); +diff --git a/src/vm/ceeload.h b/src/vm/ceeload.h +index dc21eec..fa61089 100644 +--- a/src/vm/ceeload.h ++++ b/src/vm/ceeload.h +@@ -2904,8 +2904,7 @@ public: + static void RestoreMethodDescPointer(RelativeFixupPointer<PTR_MethodDesc> * ppMD, + Module *pContainingModule = NULL, + ClassLoadLevel level = CLASS_LOADED); +- +- static void RestoreFieldDescPointer(FixupPointer<PTR_FieldDesc> * ppFD); ++ static void RestoreFieldDescPointer(RelativeFixupPointer<PTR_FieldDesc> * ppFD); + + static void RestoreModulePointer(RelativeFixupPointer<PTR_Module> * ppModule, Module *pContainingModule); + +diff --git a/src/vm/class.cpp b/src/vm/class.cpp +index 0259b1e..6697b23 100644 +--- a/src/vm/class.cpp ++++ b/src/vm/class.cpp +@@ -2818,13 +2818,13 @@ void EEClass::Save(DataImage *image, MethodTable *pMT) + + if (pInfo->m_numCTMFields > 0) + { +- ZapStoredStructure * pNode = image->StoreStructure(pInfo->m_pFieldMarshalers, ++ ZapStoredStructure * pNode = image->StoreStructure(pInfo->GetFieldMarshalers(), + pInfo->m_numCTMFields * MAXFIELDMARSHALERSIZE, + DataImage::ITEM_FIELD_MARSHALERS); + + for (UINT iField = 0; iField < pInfo->m_numCTMFields; iField++) + { +- FieldMarshaler *pFM = (FieldMarshaler*)((BYTE *)pInfo->m_pFieldMarshalers + iField * MAXFIELDMARSHALERSIZE); ++ FieldMarshaler *pFM = (FieldMarshaler*)((BYTE *)pInfo->GetFieldMarshalers() + iField * MAXFIELDMARSHALERSIZE); + pFM->Save(image); + + if (iField > 0) +@@ -3029,11 +3029,11 @@ void EEClass::Fixup(DataImage *image, MethodTable *pMT) + + if (HasLayout()) + { +- image->FixupPointerField(this, offsetof(LayoutEEClass, m_LayoutInfo.m_pFieldMarshalers)); ++ image->FixupRelativePointerField(this, offsetof(LayoutEEClass, m_LayoutInfo.m_pFieldMarshalers)); + + EEClassLayoutInfo *pInfo = &((LayoutEEClass*)this)->m_LayoutInfo; + +- FieldMarshaler *pFM = pInfo->m_pFieldMarshalers; ++ FieldMarshaler *pFM = pInfo->GetFieldMarshalers(); + FieldMarshaler *pFMEnd = (FieldMarshaler*) ((BYTE *)pFM + pInfo->m_numCTMFields*MAXFIELDMARSHALERSIZE); + while (pFM < pFMEnd) + { +diff --git a/src/vm/class.h b/src/vm/class.h +index 13b2e50..1d5f9a2 100644 +--- a/src/vm/class.h ++++ b/src/vm/class.h +@@ -110,6 +110,7 @@ class LoaderAllocator; + class ComCallWrapperTemplate; + + typedef DPTR(DictionaryLayout) PTR_DictionaryLayout; ++typedef DPTR(FieldMarshaler) PTR_FieldMarshaler; + + + //--------------------------------------------------------------------------------- +@@ -440,7 +441,7 @@ class EEClassLayoutInfo + // An array of FieldMarshaler data blocks, used to drive call-time + // marshaling of NStruct reference parameters. The number of elements + // equals m_numCTMFields. +- FieldMarshaler *m_pFieldMarshalers; ++ RelativePointer<PTR_FieldMarshaler> m_pFieldMarshalers; + + + public: +@@ -469,12 +470,20 @@ class EEClassLayoutInfo + return m_numCTMFields; + } + +- FieldMarshaler *GetFieldMarshalers() const ++ PTR_FieldMarshaler GetFieldMarshalers() const + { + LIMITED_METHOD_CONTRACT; +- return m_pFieldMarshalers; ++ return ReadPointerMaybeNull(this, &EEClassLayoutInfo::m_pFieldMarshalers); + } + ++#ifndef DACCESS_COMPILE ++ void SetFieldMarshalers(FieldMarshaler *pFieldMarshallers) ++ { ++ LIMITED_METHOD_CONTRACT; ++ m_pFieldMarshalers.SetValueMaybeNull(pFieldMarshallers); ++ } ++#endif // DACCESS_COMPILE ++ + BOOL IsBlittable() const + { + LIMITED_METHOD_CONTRACT; +diff --git a/src/vm/fieldmarshaler.cpp b/src/vm/fieldmarshaler.cpp +index 0de71b5..9415b94 100644 +--- a/src/vm/fieldmarshaler.cpp ++++ b/src/vm/fieldmarshaler.cpp +@@ -1318,7 +1318,7 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( + } + + pEEClassLayoutInfoOut->m_numCTMFields = fHasNonTrivialParent ? pParentMT->GetLayoutInfo()->m_numCTMFields : 0; +- pEEClassLayoutInfoOut->m_pFieldMarshalers = NULL; ++ pEEClassLayoutInfoOut->SetFieldMarshalers(NULL); + pEEClassLayoutInfoOut->SetIsBlittable(TRUE); + if (fHasNonTrivialParent) + pEEClassLayoutInfoOut->SetIsBlittable(pParentMT->IsBlittable()); +@@ -1599,7 +1599,7 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( + + if (pEEClassLayoutInfoOut->m_numCTMFields) + { +- pEEClassLayoutInfoOut->m_pFieldMarshalers = (FieldMarshaler*)(pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(MAXFIELDMARSHALERSIZE) * S_SIZE_T(pEEClassLayoutInfoOut->m_numCTMFields)))); ++ pEEClassLayoutInfoOut->SetFieldMarshalers((FieldMarshaler*)(pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(MAXFIELDMARSHALERSIZE) * S_SIZE_T(pEEClassLayoutInfoOut->m_numCTMFields))))); + + // Bring in the parent's fieldmarshalers + if (fHasNonTrivialParent) +@@ -1608,8 +1608,8 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( + PREFAST_ASSUME(pParentLayoutInfo != NULL); // See if (fParentHasLayout) branch above + + UINT numChildCTMFields = pEEClassLayoutInfoOut->m_numCTMFields - pParentLayoutInfo->m_numCTMFields; +- memcpyNoGCRefs( ((BYTE*)pEEClassLayoutInfoOut->m_pFieldMarshalers) + MAXFIELDMARSHALERSIZE*numChildCTMFields, +- pParentLayoutInfo->m_pFieldMarshalers, ++ memcpyNoGCRefs( ((BYTE*)pEEClassLayoutInfoOut->GetFieldMarshalers()) + MAXFIELDMARSHALERSIZE*numChildCTMFields, ++ pParentLayoutInfo->GetFieldMarshalers(), + MAXFIELDMARSHALERSIZE * (pParentLayoutInfo->m_numCTMFields) ); + } + +@@ -3726,7 +3726,7 @@ VOID FieldMarshaler_SafeArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNa + pSafeArray = (LPSAFEARRAY*)pNativeValue; + + VARTYPE vt = m_vt; +- MethodTable* pMT = m_pMT.GetValue(); ++ MethodTable* pMT = m_pMT.GetValueMaybeNull(); + + GCPROTECT_BEGIN(pArray) + { +@@ -3771,7 +3771,7 @@ VOID FieldMarshaler_SafeArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF + } + + VARTYPE vt = m_vt; +- MethodTable* pMT = m_pMT.GetValue(); ++ MethodTable* pMT = m_pMT.GetValueMaybeNull(); + + // If we have an empty vartype, get it from the safearray vartype + if (vt == VT_EMPTY) +@@ -4868,3 +4868,10 @@ IMPLEMENT_FieldMarshaler_METHOD(void, Restore, + (), + , + ()) ++ ++#ifndef DACCESS_COMPILE ++IMPLEMENT_FieldMarshaler_METHOD(VOID, CopyTo, ++ (VOID *pDest, SIZE_T destSize) const, ++ , ++ (pDest, destSize)) ++#endif // !DACCESS_COMPILE +diff --git a/src/vm/fieldmarshaler.h b/src/vm/fieldmarshaler.h +index 287da41..f11c81b 100644 +--- a/src/vm/fieldmarshaler.h ++++ b/src/vm/fieldmarshaler.h +@@ -253,6 +253,28 @@ VOID FmtValueTypeUpdateCLR(LPVOID pProtectedManagedData, MethodTable *pMT, BYTE + } \ + ELEMENT_SIZE_IMPL(NativeSize, AlignmentReq) + ++#define COPY_TO_IMPL_BASE_STRUCT_ONLY() \ ++ VOID CopyToImpl(VOID *pDest, SIZE_T destSize) \ ++ { \ ++ static_assert(sizeof(*this) == sizeof(FieldMarshaler), \ ++ "Please, implement CopyToImpl for correct copy of field values"); \ ++ \ ++ FieldMarshaler::CopyToImpl(pDest, destSize); \ ++ } ++ ++#define START_COPY_TO_IMPL(CLASS_NAME) \ ++ VOID CopyToImpl(VOID *pDest, SIZE_T destSize) const \ ++ { \ ++ FieldMarshaler::CopyToImpl(pDest, destSize); \ ++ \ ++ CLASS_NAME *pDestFieldMarshaller = (std::remove_const<std::remove_pointer<decltype(this)>::type>::type *) pDest; \ ++ _ASSERTE(sizeof(*pDestFieldMarshaller) <= destSize); \ ++ ++#define END_COPY_TO_IMPL(CLASS_NAME) \ ++ static_assert(std::is_same<CLASS_NAME *, decltype(pDestFieldMarshaller)>::value, \ ++ "Structure's name is required"); \ ++ } ++ + + //======================================================================= + // +@@ -278,6 +300,7 @@ public: + VOID ScalarUpdateCLR(const VOID *pNative, LPVOID pCLR) const; + VOID NestedValueClassUpdateNative(const VOID **ppProtectedCLR, SIZE_T startoffset, LPVOID pNative, OBJECTREF *ppCleanupWorkListOnStack) const; + VOID NestedValueClassUpdateCLR(const VOID *pNative, LPVOID *ppProtectedCLR, SIZE_T startoffset) const; ++ VOID CopyTo(VOID *pDest, SIZE_T destSize) const; + #ifdef FEATURE_PREJIT + void Save(DataImage *image); + void Fixup(DataImage *image); +@@ -351,10 +374,21 @@ public: + #endif // FEATURE_PREJIT + } + ++ void CopyToImpl(VOID *pDest, SIZE_T destSize) const ++ { ++ FieldMarshaler *pDestFieldMarshaller = (FieldMarshaler *) pDest; ++ ++ _ASSERTE(sizeof(*pDestFieldMarshaller) <= destSize); ++ ++ pDestFieldMarshaller->SetFieldDesc(GetFieldDesc()); ++ pDestFieldMarshaller->SetExternalOffset(GetExternalOffset()); ++ pDestFieldMarshaller->SetNStructFieldType(GetNStructFieldType()); ++ } ++ + void SetFieldDesc(FieldDesc* pFD) + { + LIMITED_METHOD_CONTRACT; +- m_pFD.SetValue(pFD); ++ m_pFD.SetValueMaybeNull(pFD); + } + + FieldDesc* GetFieldDesc() const +@@ -369,7 +403,7 @@ public: + } + CONTRACT_END; + +- RETURN m_pFD.GetValue(); ++ RETURN m_pFD.GetValueMaybeNull(); + } + + void SetExternalOffset(UINT32 dwExternalOffset) +@@ -394,7 +428,7 @@ protected: + #endif + } + +- static inline void RestoreHelper(FixupPointer<PTR_MethodTable> *ppMT) ++ static inline void RestoreHelper(RelativeFixupPointer<PTR_MethodTable> *ppMT) + { + CONTRACTL + { +@@ -414,7 +448,7 @@ protected: + } + + #ifdef _DEBUG +- static inline BOOL IsRestoredHelper(FixupPointer<PTR_MethodTable> pMT) ++ static inline BOOL IsRestoredHelper(const RelativeFixupPointer<PTR_MethodTable> &pMT) + { + WRAPPER_NO_CONTRACT; + +@@ -428,7 +462,7 @@ protected: + #endif // _DEBUG + + +- FixupPointer<PTR_FieldDesc> m_pFD; // FieldDesc ++ RelativeFixupPointer<PTR_FieldDesc> m_pFD; // FieldDesc + UINT32 m_dwExternalOffset; // offset of field in the fixed portion + NStructFieldType m_nft; + }; +@@ -449,6 +483,7 @@ public: + VOID DestroyNativeImpl(LPVOID pNativeValue) const; + + ELEMENT_SIZE_IMPL(sizeof(BSTR), sizeof(BSTR)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + }; + + //======================================================================= +@@ -462,6 +497,7 @@ public: + VOID DestroyNativeImpl(LPVOID pNativeValue) const; + + ELEMENT_SIZE_IMPL(sizeof(HSTRING), sizeof(HSTRING)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + }; + + //======================================================================= +@@ -473,7 +509,7 @@ public: + + FieldMarshaler_Nullable(MethodTable* pMT) + { +- m_pNullableTypeMT.SetValue(pMT); ++ m_pNullableTypeMT.SetValueMaybeNull(pMT); + } + + BOOL IsNullableMarshalerImpl() const +@@ -526,6 +562,12 @@ public: + FieldMarshaler::RestoreImpl(); + } + ++ START_COPY_TO_IMPL(FieldMarshaler_Nullable) ++ { ++ pDestFieldMarshaller->m_pNullableTypeMT.SetValueMaybeNull(GetMethodTable()); ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_Nullable) ++ + #ifdef _DEBUG + BOOL IsRestored() const + { +@@ -550,7 +592,7 @@ public: + } + + private: +- FixupPointer<PTR_MethodTable> m_pNullableTypeMT; ++ RelativeFixupPointer<PTR_MethodTable> m_pNullableTypeMT; + }; + + +@@ -565,6 +607,7 @@ public: + VOID DestroyNativeImpl(LPVOID pNativeValue) const; + + ELEMENT_SIZE_IMPL(sizeof(HSTRING), sizeof(HSTRING)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + }; + + //======================================================================= +@@ -578,6 +621,7 @@ public: + VOID UpdateCLRImpl(const VOID * pNativeValue, OBJECTREF * ppProtectedCLRValue, OBJECTREF * ppProtectedOldCLRValue) const; + + ELEMENT_SIZE_IMPL(sizeof(HRESULT), sizeof(HRESULT)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + }; + + #endif // FEATURE_COMINTEROP +@@ -593,7 +637,7 @@ public: + FieldMarshaler_NestedLayoutClass(MethodTable *pMT) + { + WRAPPER_NO_CONTRACT; +- m_pNestedMethodTable.SetValue(pMT); ++ m_pNestedMethodTable.SetValueMaybeNull(pMT); + } + + VOID UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const; +@@ -629,6 +673,12 @@ public: + FieldMarshaler::RestoreImpl(); + } + ++ START_COPY_TO_IMPL(FieldMarshaler_NestedLayoutClass) ++ { ++ pDestFieldMarshaller->m_pNestedMethodTable.SetValueMaybeNull(GetMethodTable()); ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_NestedLayoutClass) ++ + #ifdef _DEBUG + BOOL IsRestored() const + { +@@ -649,12 +699,12 @@ public: + } + CONTRACTL_END; + +- return m_pNestedMethodTable.GetValue(); ++ return m_pNestedMethodTable.GetValueMaybeNull(); + } + + private: + // MethodTable of nested FieldMarshaler. +- FixupPointer<PTR_MethodTable> m_pNestedMethodTable; ++ RelativeFixupPointer<PTR_MethodTable> m_pNestedMethodTable; + }; + + +@@ -667,7 +717,7 @@ public: + FieldMarshaler_NestedValueClass(MethodTable *pMT) + { + WRAPPER_NO_CONTRACT; +- m_pNestedMethodTable.SetValue(pMT); ++ m_pNestedMethodTable.SetValueMaybeNull(pMT); + } + + BOOL IsNestedValueClassMarshalerImpl() const +@@ -712,6 +762,12 @@ public: + FieldMarshaler::RestoreImpl(); + } + ++ START_COPY_TO_IMPL(FieldMarshaler_NestedValueClass) ++ { ++ pDestFieldMarshaller->m_pNestedMethodTable.SetValueMaybeNull(GetMethodTable()); ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_NestedValueClass) ++ + #ifdef _DEBUG + BOOL IsRestored() const + { +@@ -738,13 +794,13 @@ public: + } + CONTRACTL_END; + +- return m_pNestedMethodTable.GetValue(); ++ return m_pNestedMethodTable.GetValueMaybeNull(); + } + + + private: + // MethodTable of nested NStruct. +- FixupPointer<PTR_MethodTable> m_pNestedMethodTable; ++ RelativeFixupPointer<PTR_MethodTable> m_pNestedMethodTable; + }; + + +@@ -760,6 +816,7 @@ public: + VOID DestroyNativeImpl(LPVOID pNativeValue) const; + + ELEMENT_SIZE_IMPL(sizeof(LPWSTR), sizeof(LPWSTR)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + }; + + //======================================================================= +@@ -774,6 +831,7 @@ public: + VOID DestroyNativeImpl(LPVOID pNativeValue) const; + + ELEMENT_SIZE_IMPL(sizeof(LPSTR), sizeof(LPSTR)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + }; + + //======================================================================= +@@ -806,6 +864,13 @@ public: + return m_ThrowOnUnmappableChar; + } + ++ START_COPY_TO_IMPL(FieldMarshaler_StringAnsi) ++ { ++ pDestFieldMarshaller->m_BestFitMap = m_BestFitMap; ++ pDestFieldMarshaller->m_ThrowOnUnmappableChar = m_ThrowOnUnmappableChar; ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_StringAnsi) ++ + private: + bool m_BestFitMap:1; + bool m_ThrowOnUnmappableChar:1; +@@ -829,6 +894,12 @@ public: + m_numchar = numChar; + } + ++ START_COPY_TO_IMPL(FieldMarshaler_FixedStringUni) ++ { ++ pDestFieldMarshaller->m_numchar = m_numchar; ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_FixedStringUni) ++ + private: + // # of characters for fixed strings + UINT32 m_numchar; +@@ -864,6 +935,14 @@ public: + return m_ThrowOnUnmappableChar; + } + ++ START_COPY_TO_IMPL(FieldMarshaler_FixedStringAnsi) ++ { ++ pDestFieldMarshaller->m_numchar = m_numchar; ++ pDestFieldMarshaller->m_BestFitMap = m_BestFitMap; ++ pDestFieldMarshaller->m_ThrowOnUnmappableChar = m_ThrowOnUnmappableChar; ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_FixedStringAnsi) ++ + private: + // # of characters for fixed strings + UINT32 m_numchar; +@@ -901,6 +980,14 @@ public: + return m_ThrowOnUnmappableChar; + } + ++ START_COPY_TO_IMPL(FieldMarshaler_FixedCharArrayAnsi) ++ { ++ pDestFieldMarshaller->m_numElems = m_numElems; ++ pDestFieldMarshaller->m_BestFitMap = m_BestFitMap; ++ pDestFieldMarshaller->m_ThrowOnUnmappableChar = m_ThrowOnUnmappableChar; ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_FixedCharArrayAnsi) ++ + private: + // # of elements for fixedchararray + UINT32 m_numElems; +@@ -980,6 +1067,16 @@ public: + FieldMarshaler::RestoreImpl(); + } + ++ START_COPY_TO_IMPL(FieldMarshaler_FixedArray) ++ { ++ pDestFieldMarshaller->m_arrayType.SetValueMaybeNull(m_arrayType.GetValueMaybeNull()); ++ pDestFieldMarshaller->m_numElems = m_numElems; ++ pDestFieldMarshaller->m_vt = m_vt; ++ pDestFieldMarshaller->m_BestFitMap = m_BestFitMap; ++ pDestFieldMarshaller->m_ThrowOnUnmappableChar = m_ThrowOnUnmappableChar; ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_FixedArray) ++ + #ifdef _DEBUG + BOOL IsRestored() const + { +@@ -994,7 +1091,7 @@ public: + #endif + + private: +- FixupPointer<TypeHandle> m_arrayType; ++ RelativeFixupPointer<TypeHandle> m_arrayType; + UINT32 m_numElems; + VARTYPE m_vt; + bool m_BestFitMap:1; // Note: deliberately use small bools to save on working set - this is the largest FieldMarshaler and dominates the cost of the FieldMarshaler array +@@ -1020,7 +1117,7 @@ public: + { + WRAPPER_NO_CONTRACT; + m_vt = vt; +- m_pMT.SetValue(pMT); ++ m_pMT.SetValueMaybeNull(pMT); + } + + #ifdef FEATURE_PREJIT +@@ -1049,6 +1146,13 @@ public: + FieldMarshaler::RestoreImpl(); + } + ++ START_COPY_TO_IMPL(FieldMarshaler_SafeArray) ++ { ++ pDestFieldMarshaller->m_pMT.SetValueMaybeNull(m_pMT.GetValueMaybeNull()); ++ pDestFieldMarshaller->m_vt = m_vt; ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_SafeArray) ++ + #ifdef _DEBUG + BOOL IsRestored() const + { +@@ -1079,7 +1183,7 @@ public: + } + + private: +- FixupPointer<PTR_MethodTable> m_pMT; ++ RelativeFixupPointer<PTR_MethodTable> m_pMT; + VARTYPE m_vt; + }; + #endif //FEATURE_CLASSIC_COMINTEROP +@@ -1094,7 +1198,7 @@ public: + FieldMarshaler_Delegate(MethodTable* pMT) + { + WRAPPER_NO_CONTRACT; +- m_pNestedMethodTable.SetValue(pMT); ++ m_pNestedMethodTable.SetValueMaybeNull(pMT); + } + + VOID UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const; +@@ -1128,6 +1232,12 @@ public: + FieldMarshaler::RestoreImpl(); + } + ++ START_COPY_TO_IMPL(FieldMarshaler_Delegate) ++ { ++ pDestFieldMarshaller->m_pNestedMethodTable.SetValueMaybeNull(m_pNestedMethodTable.GetValueMaybeNull()); ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_Delegate) ++ + #ifdef _DEBUG + BOOL IsRestored() const + { +@@ -1148,10 +1258,10 @@ public: + } + CONTRACTL_END; + +- return m_pNestedMethodTable.GetValue(); ++ return m_pNestedMethodTable.GetValueMaybeNull(); + } + +- FixupPointer<PTR_MethodTable> m_pNestedMethodTable; ++ RelativeFixupPointer<PTR_MethodTable> m_pNestedMethodTable; + }; + + +@@ -1168,6 +1278,7 @@ public: + VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const; + + ELEMENT_SIZE_IMPL(sizeof(LPVOID), sizeof(LPVOID)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + }; + + +@@ -1184,6 +1295,7 @@ public: + VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const; + + ELEMENT_SIZE_IMPL(sizeof(LPVOID), sizeof(LPVOID)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + }; + + #ifdef FEATURE_COMINTEROP +@@ -1204,8 +1316,8 @@ public: + FieldMarshaler_Interface(MethodTable *pClassMT, MethodTable *pItfMT, DWORD dwFlags) + { + WRAPPER_NO_CONTRACT; +- m_pClassMT.SetValue(pClassMT); +- m_pItfMT.SetValue(pItfMT); ++ m_pClassMT.SetValueMaybeNull(pClassMT); ++ m_pItfMT.SetValueMaybeNull(pItfMT); + m_dwFlags = dwFlags; + } + +@@ -1237,6 +1349,14 @@ public: + FieldMarshaler::RestoreImpl(); + } + ++ START_COPY_TO_IMPL(FieldMarshaler_Interface) ++ { ++ pDestFieldMarshaller->m_pClassMT.SetValueMaybeNull(m_pClassMT.GetValueMaybeNull()); ++ pDestFieldMarshaller->m_pItfMT.SetValueMaybeNull(m_pItfMT.GetValueMaybeNull()); ++ pDestFieldMarshaller->m_dwFlags = m_dwFlags; ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_Interface) ++ + #ifdef _DEBUG + BOOL IsRestored() const + { +@@ -1275,7 +1395,7 @@ public: + } + CONTRACTL_END; + +- return m_pClassMT.GetValue(); ++ return m_pClassMT.GetValueMaybeNull(); + } + + MethodTable *GetInterfaceMethodTable() const +@@ -1289,12 +1409,12 @@ public: + } + CONTRACTL_END; + +- return m_pItfMT.GetValue(); ++ return m_pItfMT.GetValueMaybeNull(); + } + + private: +- FixupPointer<PTR_MethodTable> m_pClassMT; +- FixupPointer<PTR_MethodTable> m_pItfMT; ++ RelativeFixupPointer<PTR_MethodTable> m_pClassMT; ++ RelativeFixupPointer<PTR_MethodTable> m_pItfMT; + DWORD m_dwFlags; + }; + +@@ -1328,6 +1448,7 @@ public: + VOID DestroyNativeImpl(LPVOID pNativeValue) const; + + ELEMENT_SIZE_IMPL(sizeof(VARIANT), 8) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + }; + + #endif // FEATURE_COMINTEROP +@@ -1352,7 +1473,13 @@ public: + VOID ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const; + + SCALAR_MARSHALER_IMPL(1, 1) +- ++ ++ START_COPY_TO_IMPL(FieldMarshaler_Illegal) ++ { ++ pDestFieldMarshaller->m_resIDWhy = m_resIDWhy; ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_Illegal) ++ + private: + UINT m_resIDWhy; + }; +@@ -1369,6 +1496,7 @@ public: + UNUSED_METHOD_IMPL(VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const) + + SCALAR_MARSHALER_IMPL(1, 1) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + + VOID ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const + { +@@ -1413,6 +1541,7 @@ public: + UNUSED_METHOD_IMPL(VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const) + + SCALAR_MARSHALER_IMPL(2, 2) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + + VOID ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const + { +@@ -1456,6 +1585,7 @@ public: + UNUSED_METHOD_IMPL(VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const) + + SCALAR_MARSHALER_IMPL(4, 4) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + + VOID ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const + { +@@ -1499,6 +1629,7 @@ public: + UNUSED_METHOD_IMPL(VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const) + + SCALAR_MARSHALER_IMPL(8, 8) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + + VOID ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const + { +@@ -1599,6 +1730,13 @@ public: + return m_ThrowOnUnmappableChar; + } + ++ START_COPY_TO_IMPL(FieldMarshaler_Ansi) ++ { ++ pDestFieldMarshaller->m_BestFitMap = m_BestFitMap; ++ pDestFieldMarshaller->m_ThrowOnUnmappableChar = m_ThrowOnUnmappableChar; ++ } ++ END_COPY_TO_IMPL(FieldMarshaler_Ansi) ++ + private: + bool m_BestFitMap:1; + bool m_ThrowOnUnmappableChar:1; +@@ -1614,6 +1752,7 @@ public: + UNUSED_METHOD_IMPL(VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const) + + SCALAR_MARSHALER_IMPL(sizeof(BOOL), sizeof(BOOL)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + + VOID ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const + { +@@ -1661,6 +1800,7 @@ public: + UNUSED_METHOD_IMPL(VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const) + + SCALAR_MARSHALER_IMPL(sizeof(VARIANT_BOOL), sizeof(VARIANT_BOOL)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + + VOID ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const + { +@@ -1711,6 +1851,7 @@ public: + UNUSED_METHOD_IMPL(VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const) + + SCALAR_MARSHALER_IMPL(1, 1) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + + VOID ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const + { +@@ -1752,6 +1893,7 @@ public: + UNUSED_METHOD_IMPL(VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const) + + SCALAR_MARSHALER_IMPL(sizeof(DECIMAL), 8); ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + + VOID ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const + { +@@ -1793,6 +1935,7 @@ public: + UNUSED_METHOD_IMPL(VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const) + + SCALAR_MARSHALER_IMPL(sizeof(DATE), sizeof(DATE)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + + VOID ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const; + VOID ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const; +@@ -1811,6 +1954,7 @@ public: + UNUSED_METHOD_IMPL(VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const) + + SCALAR_MARSHALER_IMPL(sizeof(CURRENCY), sizeof(CURRENCY)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + + VOID ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const; + VOID ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const; +@@ -1825,6 +1969,7 @@ public: + UNUSED_METHOD_IMPL(VOID UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const) + + SCALAR_MARSHALER_IMPL(sizeof(INT64), sizeof(INT64)) ++ COPY_TO_IMPL_BASE_STRUCT_ONLY() + + VOID ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const; + VOID ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const; +diff --git a/src/vm/methodtablebuilder.cpp b/src/vm/methodtablebuilder.cpp +index a1e9095..e8f3b9c 100644 +--- a/src/vm/methodtablebuilder.cpp ++++ b/src/vm/methodtablebuilder.cpp +@@ -4206,11 +4206,11 @@ VOID MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList, + { + if (pwalk->m_MD == bmtMetaData->pFields[i]) + { +- + pLayoutFieldInfo = pwalk; +- CopyMemory(pNextFieldMarshaler, +- &(pwalk->m_FieldMarshaler), +- MAXFIELDMARSHALERSIZE); ++ ++ const FieldMarshaler *pSrcFieldMarshaler = (const FieldMarshaler *) &pwalk->m_FieldMarshaler; ++ ++ pSrcFieldMarshaler->CopyTo(pNextFieldMarshaler, MAXFIELDMARSHALERSIZE); + + pNextFieldMarshaler->SetFieldDesc(pFD); + pNextFieldMarshaler->SetExternalOffset(pwalk->m_offset); +diff --git a/src/vm/typedesc.cpp b/src/vm/typedesc.cpp +index 6718068..7da1c84 100644 +--- a/src/vm/typedesc.cpp ++++ b/src/vm/typedesc.cpp +@@ -40,7 +40,7 @@ BOOL ParamTypeDesc::Verify() { + STATIC_CONTRACT_DEBUG_ONLY; + STATIC_CONTRACT_SUPPORTS_DAC; + +- _ASSERTE(m_TemplateMT.IsNull() || m_TemplateMT.GetValue()->SanityCheck()); ++ _ASSERTE(m_TemplateMT.IsNull() || GetTemplateMethodTableInternal()->SanityCheck()); + _ASSERTE(!GetTypeParam().IsNull()); + BAD_FORMAT_NOTHROW_ASSERT(GetTypeParam().IsTypeDesc() || !GetTypeParam().AsMethodTable()->IsArray()); + BAD_FORMAT_NOTHROW_ASSERT(CorTypeInfo::IsModifier_NoThrow(GetInternalCorElementType()) || +@@ -59,7 +59,7 @@ BOOL ArrayTypeDesc::Verify() { + STATIC_CONTRACT_SUPPORTS_DAC; + + // m_TemplateMT == 0 may be null when building types involving TypeVarTypeDesc's +- BAD_FORMAT_NOTHROW_ASSERT(m_TemplateMT.IsNull() || m_TemplateMT.GetValue()->IsArray()); ++ BAD_FORMAT_NOTHROW_ASSERT(m_TemplateMT.IsNull() || GetTemplateMethodTable()->IsArray()); + BAD_FORMAT_NOTHROW_ASSERT(CorTypeInfo::IsArray_NoThrow(GetInternalCorElementType())); + ParamTypeDesc::Verify(); + return(true); +@@ -844,7 +844,7 @@ OBJECTREF ParamTypeDesc::GetManagedClassObject() + if (OwnsTemplateMethodTable()) + { + // Set the handle on template methodtable as well to make Object.GetType for arrays take the fast path +- EnsureWritablePages(m_TemplateMT.GetValue()->GetWriteableDataForWrite())->m_hExposedClassObject = m_hExposedClassObject; ++ EnsureWritablePages(GetTemplateMethodTableInternal()->GetWriteableDataForWrite())->m_hExposedClassObject = m_hExposedClassObject; + } + + // Log the TypeVarTypeDesc access +@@ -1011,7 +1011,7 @@ void TypeDesc::DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel le + // Fully load the template method table + if (!pPTD->m_TemplateMT.IsNull()) + { +- pPTD->m_TemplateMT.GetValue()->DoFullyLoad(&newVisited, level, pPending, &fBailed, pInstContext); ++ pPTD->GetTemplateMethodTableInternal()->DoFullyLoad(&newVisited, level, pPending, &fBailed, pInstContext); + } + } + +@@ -1189,8 +1189,8 @@ void ParamTypeDesc::Save(DataImage *image) + if (OwnsTemplateMethodTable()) + { + // This TypeDesc should be the only one saving this MT +- _ASSERTE(!image->IsStored(m_TemplateMT.GetValue())); +- Module::SaveMethodTable(image, m_TemplateMT.GetValue(), 0); ++ _ASSERTE(!image->IsStored(GetTemplateMethodTableInternal())); ++ Module::SaveMethodTable(image, GetTemplateMethodTableInternal(), 0); + } + + } +@@ -1219,8 +1219,8 @@ void ParamTypeDesc::Fixup(DataImage *image) + // TypeDesc and the MT are "tightly-knit") In other words if one is present in + // an NGEN image then then other will be, and if one is "used" at runtime then + // the other will be too. +- image->FixupPointerField(this, offsetof(ParamTypeDesc, m_TemplateMT)); +- m_TemplateMT.GetValue()->Fixup(image); ++ image->FixupMethodTablePointer(this, &m_TemplateMT); ++ GetTemplateMethodTableInternal()->Fixup(image); + } + else + { +@@ -1275,14 +1275,14 @@ BOOL ParamTypeDesc::ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisit + { + if (OwnsTemplateMethodTable()) + { +- if (m_TemplateMT.GetValue()->ComputeNeedsRestore(image, pVisited)) ++ if (GetTemplateMethodTableInternal()->ComputeNeedsRestore(image, pVisited)) + { + res = TRUE; + } + } + else + { +- if (!image->CanPrerestoreEagerBindToMethodTable(m_TemplateMT.GetValue(), pVisited)) ++ if (!image->CanPrerestoreEagerBindToMethodTable(GetTemplateMethodTableInternal(), pVisited)) + { + res = TRUE; + } +@@ -2419,7 +2419,7 @@ ParamTypeDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) + SUPPORTS_DAC; + DAC_ENUM_DTHIS(); + +- PTR_MethodTable pTemplateMT = m_TemplateMT.GetValue(); ++ PTR_MethodTable pTemplateMT = GetTemplateMethodTableInternal(); + if (pTemplateMT.IsValid()) + { + pTemplateMT->EnumMemoryRegions(flags); +diff --git a/src/vm/typedesc.h b/src/vm/typedesc.h +index a8b1c25..3e8b0e6 100644 +--- a/src/vm/typedesc.h ++++ b/src/vm/typedesc.h +@@ -254,7 +254,7 @@ public: + + LIMITED_METHOD_CONTRACT; + +- m_TemplateMT.SetValue(pMT); ++ m_TemplateMT.SetValueMaybeNull(pMT); + + // ParamTypeDescs start out life not fully loaded + m_typeAndFlags |= TypeDesc::enum_flag_IsNotFullyLoaded; +@@ -323,8 +323,13 @@ public: + friend class ArrayOpLinker; + #endif + protected: ++ PTR_MethodTable GetTemplateMethodTableInternal() { ++ WRAPPER_NO_CONTRACT; ++ return ReadPointerMaybeNull(this, &ParamTypeDesc::m_TemplateMT); ++ } ++ + // the m_typeAndFlags field in TypeDesc tell what kind of parameterized type we have +- FixupPointer<PTR_MethodTable> m_TemplateMT; // The shared method table, some variants do not use this field (it is null) ++ RelativeFixupPointer<PTR_MethodTable> m_TemplateMT; // The shared method table, some variants do not use this field (it is null) + TypeHandle m_Arg; // The type that is being modified + LOADERHANDLE m_hExposedClassObject; // handle back to the internal reflection Type object + }; +@@ -380,8 +385,8 @@ public: + WRAPPER_NO_CONTRACT; + + _ASSERTE(!m_TemplateMT.IsNull()); +- _ASSERTE(m_TemplateMT.GetValue()->IsArray()); +- _ASSERTE(m_TemplateMT.GetValue()->ParentEquals(g_pArrayClass)); ++ _ASSERTE(GetTemplateMethodTableInternal()->IsArray()); ++ _ASSERTE(GetTemplateMethodTableInternal()->ParentEquals(g_pArrayClass)); + + return g_pArrayClass; + } +@@ -416,16 +421,16 @@ public: + void Fixup(DataImage *image); + #endif + +- MethodTable * GetTemplateMethodTable() { ++ PTR_MethodTable GetTemplateMethodTable() { + WRAPPER_NO_CONTRACT; +- MethodTable * pTemplateMT = m_TemplateMT.GetValue(); +- _ASSERTE(pTemplateMT->IsArray()); +- return pTemplateMT; ++ PTR_MethodTable ptrTemplateMT = GetTemplateMethodTableInternal(); ++ _ASSERTE(ptrTemplateMT->IsArray()); ++ return ptrTemplateMT; + } + + TADDR GetTemplateMethodTableMaybeTagged() { + WRAPPER_NO_CONTRACT; +- return m_TemplateMT.GetValueMaybeTagged(); ++ return m_TemplateMT.GetValueMaybeTagged(dac_cast<TADDR>(this) + offsetof(ArrayTypeDesc, m_TemplateMT)); + } + + #ifdef FEATURE_COMINTEROP +diff --git a/src/vm/typedesc.inl b/src/vm/typedesc.inl +index 4d7416e..312270e 100644 +--- a/src/vm/typedesc.inl ++++ b/src/vm/typedesc.inl +@@ -31,7 +31,7 @@ inline PTR_MethodTable TypeDesc::GetMethodTable() { + if (GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE) + return dac_cast<PTR_MethodTable>(asParam->m_Arg.AsMethodTable()); + else +- return(asParam->m_TemplateMT.GetValue()); ++ return(asParam->GetTemplateMethodTableInternal()); + } + + inline TypeHandle TypeDesc::GetTypeParam() { +-- +2.7.4 + |