summaryrefslogtreecommitdiff
path: root/packaging/0030-Remove-relocations-for-MethodTable-m_pParentMethodTa.patch
blob: 9dae3204ee4cd37e106df3e8ea3efe34b2a2070b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
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