summaryrefslogtreecommitdiff
path: root/packaging/0024-Remove-relocations-for-MethodTable-m_pPerInstInfo-fo.patch
blob: 4bc117b4edfcb1514d3bd4060e80f0186eb0ff11 (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
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