Remove relocations for vtable chunks (#17147)
[platform/upstream/coreclr.git] / src / inc / fixuppointer.h
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 /*****************************************************************************\
5 *                                                                             *
6 * FixupPointer.h -  Fixup pointer holder types                                *
7 *                                                                             *
8 \*****************************************************************************/
9
10 #ifndef _FIXUPPOINTER_H
11 #define _FIXUPPOINTER_H
12
13 #include "daccess.h"
14
15 #ifdef FEATURE_PREJIT
16
17 //----------------------------------------------------------------------------
18 // RelativePointer is pointer encoded as relative offset. It is used to reduce size of
19 // relocation section in NGen images. Conversion from/to RelativePointer needs 
20 // address of the pointer ("this") converted to TADDR passed in from outside. 
21 // Converting "this" to TADDR is not possible in the DAC transparently because
22 // DAC is based on exact pointers, not ranges.
23 // There are several flavors of conversions from/to RelativePointer:
24 //  - GetValue/SetValue: The most common version. Assumes that the pointer is not NULL.
25 //  - GetValueMaybeNull/SetValueMaybeNull: Pointer can be NULL.
26 //  - GetValueAtPtr: Static version of GetValue. It is
27 //    meant to simplify access to arrays of RelativePointers.
28 //  - GetValueMaybeNullAtPtr
29 template<typename PTR_TYPE>
30 class RelativePointer
31 {
32 public:
33
34     static constexpr bool isRelative = true;
35     typedef PTR_TYPE type;
36
37 #ifndef DACCESS_COMPILE
38     RelativePointer()
39     {
40         m_delta = (TADDR)NULL;
41
42         _ASSERTE (IsNull());
43     }
44 #else // DACCESS_COMPILE
45     RelativePointer() =delete;
46 #endif // DACCESS_COMPILE
47
48     // Implicit copy/move is not allowed
49     // Bitwise copy is implemented by BitwiseCopyTo method
50     RelativePointer<PTR_TYPE>(const RelativePointer<PTR_TYPE> &) =delete;
51     RelativePointer<PTR_TYPE>(RelativePointer<PTR_TYPE> &&) =delete;
52     RelativePointer<PTR_TYPE>& operator = (const RelativePointer<PTR_TYPE> &) =delete;
53     RelativePointer<PTR_TYPE>& operator = (RelativePointer<PTR_TYPE> &&) =delete;
54
55     // Returns whether the encoded pointer is NULL.
56     BOOL IsNull() const
57     {
58         LIMITED_METHOD_DAC_CONTRACT;
59         // Pointer pointing to itself is treated as NULL
60         return m_delta == (TADDR)NULL;
61     }
62
63     // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
64     PTR_TYPE GetValue(TADDR base) const
65     {
66         LIMITED_METHOD_DAC_CONTRACT;
67         PRECONDITION(!IsNull());
68         return dac_cast<PTR_TYPE>(base + m_delta);
69     }
70
71 #ifndef DACCESS_COMPILE
72     // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
73     // Does not need explicit base and thus can be used in non-DAC builds only.
74     FORCEINLINE PTR_TYPE GetValue() const
75     {
76         LIMITED_METHOD_CONTRACT;
77         return GetValue((TADDR)this);
78     }
79 #endif
80
81     // Static version of GetValue. It is meant to simplify access to arrays of pointers.
82     FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base)
83     {
84         LIMITED_METHOD_DAC_CONTRACT;
85         return dac_cast<DPTR(RelativePointer<PTR_TYPE>)>(base)->GetValue(base);
86     }
87
88     // Returns value of the encoded pointer. The pointer can be NULL.
89     PTR_TYPE GetValueMaybeNull(TADDR base) const
90     {
91         LIMITED_METHOD_DAC_CONTRACT;
92
93         // Cache local copy of delta to avoid races when the value is changing under us.
94         TADDR delta = m_delta;
95
96         if (delta == 0)
97             return NULL;
98
99         return dac_cast<PTR_TYPE>(base + delta);
100     }
101
102 #ifndef DACCESS_COMPILE
103     // Returns value of the encoded pointer. The pointer can be NULL.
104     // Does not need explicit base and thus can be used in non-DAC builds only.
105     FORCEINLINE PTR_TYPE GetValueMaybeNull() const
106     {
107         LIMITED_METHOD_CONTRACT;
108         return GetValueMaybeNull((TADDR)this);
109     }
110 #endif
111
112     // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
113     FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base)
114     {
115         LIMITED_METHOD_DAC_CONTRACT;
116         return dac_cast<DPTR(RelativePointer<PTR_TYPE>)>(base)->GetValueMaybeNull(base);
117     }
118
119 #ifndef DACCESS_COMPILE
120     // Set encoded value of the pointer. Assumes that the value is not NULL.
121     FORCEINLINE void SetValue(PTR_TYPE addr)
122     {
123         LIMITED_METHOD_CONTRACT;
124         PRECONDITION(addr != NULL);
125         m_delta = (TADDR)addr - (TADDR)this;
126     }
127
128     // Set encoded value of the pointer. The value can be NULL.
129     void SetValueMaybeNull(TADDR base, PTR_TYPE addr)
130     {
131         LIMITED_METHOD_CONTRACT;
132         if (addr == NULL)
133             m_delta = NULL;
134         else
135             m_delta = (TADDR)addr - (TADDR)base;
136     }
137
138     // Set encoded value of the pointer. The value can be NULL.
139     FORCEINLINE void SetValueMaybeNull(PTR_TYPE addr)
140     {
141         LIMITED_METHOD_CONTRACT;
142         SetValueMaybeNull((TADDR)this, addr);
143     }
144
145     FORCEINLINE void SetValueVolatile(PTR_TYPE addr)
146     {
147         LIMITED_METHOD_CONTRACT;
148         SetValue(addr);
149     }
150 #endif
151
152 #ifndef DACCESS_COMPILE
153     void BitwiseCopyTo(RelativePointer<PTR_TYPE> &dest) const
154     {
155         dest.m_delta = m_delta;
156     }
157 #endif // DACCESS_COMPILE
158
159     static TADDR GetRelativeMaybeNull(TADDR base, TADDR addr)
160     {
161         LIMITED_METHOD_DAC_CONTRACT;
162         if (addr == NULL)
163         {
164             return NULL;
165         }
166         else
167         {
168             return addr - base;
169         }
170     }
171
172     static TADDR GetRelative(TADDR base, TADDR addr)
173     {
174         LIMITED_METHOD_DAC_CONTRACT;
175         PRECONDITION(addr != NULL);
176         return addr - base;
177     }
178
179 private:
180 #ifndef DACCESS_COMPILE
181     Volatile<TADDR> m_delta;
182 #else
183     TADDR m_delta;
184 #endif
185 };
186
187 //----------------------------------------------------------------------------
188 // FixupPointer is pointer with optional indirection. It is used to reduce number
189 // of private pages in NGen images - cross-module pointers that written to at runtime 
190 // are packed together and accessed via indirection.
191 //
192 // The direct flavor (lowest bit of m_addr is cleared) is user for intra-module pointers
193 // in NGen images, and in datastructuters allocated at runtime.
194 //
195 // The indirect mode (lowest bit of m_addr is set) is used for cross-module pointers
196 // in NGen images.
197 //
198
199 // Friendly name for lowest bit that marks the indirection
200 #define FIXUP_POINTER_INDIRECTION 1
201
202 template<typename PTR_TYPE>
203 class FixupPointer
204 {
205 public:
206
207     static constexpr bool isRelative = false;
208     typedef PTR_TYPE type;
209
210     // Returns whether the encoded pointer is NULL.
211     BOOL IsNull() const
212     {
213         LIMITED_METHOD_DAC_CONTRACT;
214         return m_addr == 0;
215     }
216
217     // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet.
218     FORCEINLINE BOOL IsTagged() const
219     {
220         LIMITED_METHOD_DAC_CONTRACT;
221         TADDR addr = m_addr;
222         if ((addr & FIXUP_POINTER_INDIRECTION) != 0)
223              return (*PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION) & 1) != 0;
224         return FALSE;
225     }
226
227     // Returns value of the encoded pointer.
228     FORCEINLINE PTR_TYPE GetValue() const
229     {
230         LIMITED_METHOD_DAC_CONTRACT;
231         TADDR addr = m_addr;
232         if ((addr & FIXUP_POINTER_INDIRECTION) != 0)
233             addr = *PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION);
234         return dac_cast<PTR_TYPE>(addr);
235     }
236
237     // Returns value of the encoded pointer.
238     FORCEINLINE PTR_TYPE GetValueMaybeNull() const
239     {
240         LIMITED_METHOD_DAC_CONTRACT;
241         return GetValue();
242     }
243
244 #ifndef DACCESS_COMPILE
245     // Returns the pointer to the indirection cell.
246     PTR_TYPE * GetValuePtr() const
247     {
248         LIMITED_METHOD_CONTRACT;
249         TADDR addr = m_addr;
250         if ((addr & FIXUP_POINTER_INDIRECTION) != 0)
251             return (PTR_TYPE *)(addr - FIXUP_POINTER_INDIRECTION);
252         return (PTR_TYPE *)&m_addr;
253     }
254 #endif // !DACCESS_COMPILE
255
256     // Static version of GetValue. It is meant to simplify access to arrays of pointers.
257     FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base)
258     {
259         LIMITED_METHOD_DAC_CONTRACT;
260         return dac_cast<DPTR(FixupPointer<PTR_TYPE>)>(base)->GetValue();
261     }
262
263     // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
264     FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base)
265     {
266         LIMITED_METHOD_DAC_CONTRACT;
267         return dac_cast<DPTR(FixupPointer<PTR_TYPE>)>(base)->GetValueMaybeNull();
268     }
269
270     // Returns value of the encoded pointer.
271     // Allows the value to be tagged.
272     FORCEINLINE TADDR GetValueMaybeTagged() const
273     {
274         LIMITED_METHOD_DAC_CONTRACT;
275         TADDR addr = m_addr;
276         if ((addr & FIXUP_POINTER_INDIRECTION) != 0)
277             addr = *PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION);
278         return addr;
279     }
280
281 #ifndef DACCESS_COMPILE
282     void SetValue(PTR_TYPE addr)
283     {
284         LIMITED_METHOD_CONTRACT;
285         m_addr = dac_cast<TADDR>(addr);
286     }
287
288     void SetValueMaybeNull(PTR_TYPE addr)
289     {
290         LIMITED_METHOD_CONTRACT;
291         SetValue(addr);
292     }
293 #endif // !DACCESS_COMPILE
294
295 private:
296     TADDR m_addr;
297 };
298
299 //----------------------------------------------------------------------------
300 // RelativeFixupPointer is combination of RelativePointer and FixupPointer
301 template<typename PTR_TYPE>
302 class RelativeFixupPointer
303 {
304 public:
305
306     static constexpr bool isRelative = true;
307     typedef PTR_TYPE type;
308
309 #ifndef DACCESS_COMPILE
310     RelativeFixupPointer()
311     {
312         SetValueMaybeNull(NULL);
313     }
314 #else // DACCESS_COMPILE
315     RelativeFixupPointer() =delete;
316 #endif // DACCESS_COMPILE
317
318     // Implicit copy/move is not allowed
319     RelativeFixupPointer<PTR_TYPE>(const RelativeFixupPointer<PTR_TYPE> &) =delete;
320     RelativeFixupPointer<PTR_TYPE>(RelativeFixupPointer<PTR_TYPE> &&) =delete;
321     RelativeFixupPointer<PTR_TYPE>& operator = (const RelativeFixupPointer<PTR_TYPE> &) =delete;
322     RelativeFixupPointer<PTR_TYPE>& operator = (RelativeFixupPointer<PTR_TYPE> &&) =delete;
323
324     // Returns whether the encoded pointer is NULL.
325     BOOL IsNull() const
326     {
327         LIMITED_METHOD_DAC_CONTRACT;
328         // Pointer pointing to itself is treated as NULL
329         return m_delta == (TADDR)NULL;
330     }
331
332     // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet.
333     FORCEINLINE BOOL IsTagged(TADDR base) const
334     {
335         LIMITED_METHOD_DAC_CONTRACT;
336         TADDR addr = base + m_delta;
337         if ((addr & FIXUP_POINTER_INDIRECTION) != 0)
338              return (*PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION) & 1) != 0;
339         return FALSE;
340     }
341
342     // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet.
343     // Ignores isIndirect and offset values.
344     FORCEINLINE BOOL IsTaggedIndirect(TADDR base, bool isIndirect, intptr_t offset) const
345     {
346         LIMITED_METHOD_DAC_CONTRACT;
347         return IsTagged(base);
348     }
349
350 #ifndef DACCESS_COMPILE
351     // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet.
352     // Does not need explicit base and thus can be used in non-DAC builds only.
353     FORCEINLINE BOOL IsTagged() const
354     {
355         LIMITED_METHOD_CONTRACT;
356         return IsTagged((TADDR)this);
357     }
358 #endif // !DACCESS_COMPILE
359
360     // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
361     FORCEINLINE PTR_TYPE GetValue(TADDR base) const
362     {
363         LIMITED_METHOD_DAC_CONTRACT;
364         PRECONDITION(!IsNull());
365         PRECONDITION(!IsTagged(base));
366         TADDR addr = base + m_delta;
367         if ((addr & FIXUP_POINTER_INDIRECTION) != 0)
368             addr = *PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION);
369         return dac_cast<PTR_TYPE>(addr);
370     }
371
372 #ifndef DACCESS_COMPILE
373     // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
374     // Does not need explicit base and thus can be used in non-DAC builds only.
375     FORCEINLINE PTR_TYPE GetValue() const
376     {
377         LIMITED_METHOD_CONTRACT;
378         return GetValue((TADDR)this);
379     }
380 #endif
381
382     // Static version of GetValue. It is meant to simplify access to arrays of pointers.
383     FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base)
384     {
385         LIMITED_METHOD_DAC_CONTRACT;
386         return dac_cast<DPTR(RelativeFixupPointer<PTR_TYPE>)>(base)->GetValue(base);
387     }
388
389     // Static version of GetValue. It is meant to simplify access to arrays of pointers.
390     // Ignores isIndirect and offset values.
391     FORCEINLINE static PTR_TYPE GetValueAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset)
392     {
393         LIMITED_METHOD_DAC_CONTRACT;
394         return GetValueAtPtr(base);
395     }
396
397     // Returns value of the encoded pointer. The pointer can be NULL.
398     PTR_TYPE GetValueMaybeNull(TADDR base) const
399     {
400         LIMITED_METHOD_DAC_CONTRACT;
401         PRECONDITION(!IsTagged(base));
402
403         // Cache local copy of delta to avoid races when the value is changing under us.
404         TADDR delta = m_delta;
405
406         if (delta == 0)
407             return NULL;
408
409         TADDR addr = base + delta;
410         if ((addr & FIXUP_POINTER_INDIRECTION) != 0)
411             addr = *PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION);
412         return dac_cast<PTR_TYPE>(addr);
413     }
414
415 #ifndef DACCESS_COMPILE
416     // Returns value of the encoded pointer. The pointer can be NULL.
417     // Does not need explicit base and thus can be used in non-DAC builds only.
418     FORCEINLINE PTR_TYPE GetValueMaybeNull() const
419     {
420         LIMITED_METHOD_CONTRACT;
421         return GetValueMaybeNull((TADDR)this);
422     }
423 #endif
424
425     // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
426     FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base)
427     {
428         LIMITED_METHOD_DAC_CONTRACT;
429         return dac_cast<DPTR(RelativeFixupPointer<PTR_TYPE>)>(base)->GetValueMaybeNull(base);
430     }
431
432     // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
433     // Ignores isIndirect and offset values.
434     FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset)
435     {
436         LIMITED_METHOD_DAC_CONTRACT;
437         return GetValueMaybeNullAtPtr(base);
438     }
439
440 #ifndef DACCESS_COMPILE
441     // Set encoded value of the pointer. Assumes that the value is not NULL.
442     FORCEINLINE void SetValue(PTR_TYPE addr)
443     {
444         LIMITED_METHOD_CONTRACT;
445         PRECONDITION(addr != NULL);
446         m_delta = dac_cast<TADDR>(addr) - (TADDR)this;
447     }
448
449     // Set encoded value of the pointer. The value can be NULL.
450     void SetValueMaybeNull(TADDR base, PTR_TYPE addr)
451     {
452         LIMITED_METHOD_CONTRACT;
453         if (addr == NULL)
454             m_delta = NULL;
455         else
456             m_delta = dac_cast<TADDR>(addr) - (TADDR)base;
457     }
458
459     // Set encoded value of the pointer. The value can be NULL.
460     FORCEINLINE void SetValueMaybeNull(PTR_TYPE addr)
461     {
462         LIMITED_METHOD_CONTRACT;
463         SetValueMaybeNull((TADDR)this, addr);
464     }
465 #endif
466
467 #ifndef DACCESS_COMPILE
468     // Returns the pointer to the indirection cell.
469     PTR_TYPE * GetValuePtr() const
470     {
471         LIMITED_METHOD_CONTRACT;
472         TADDR addr = ((TADDR)this) + m_delta;
473         _ASSERTE((addr & FIXUP_POINTER_INDIRECTION) != 0);
474         return (PTR_TYPE *)(addr - FIXUP_POINTER_INDIRECTION);
475     }
476
477     // Returns the pointer to the indirection cell.
478     // Ignores isIndirect and offset values.
479     PTR_TYPE * GetValuePtrIndirect(bool isIndirect, intptr_t offset) const
480     {
481         LIMITED_METHOD_CONTRACT;
482         return GetValuePtr();
483     }
484 #endif // !DACCESS_COMPILE
485
486     // Returns value of the encoded pointer. Assumes that the pointer is not NULL. 
487     // Allows the value to be tagged.
488     FORCEINLINE TADDR GetValueMaybeTagged(TADDR base) const
489     {
490         LIMITED_METHOD_DAC_CONTRACT;
491         PRECONDITION(!IsNull());
492         TADDR addr = base + m_delta;
493         if ((addr & FIXUP_POINTER_INDIRECTION) != 0)
494             addr = *PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION);
495         return addr;
496     }
497
498     // Returns whether pointer is indirect. Assumes that the value is not NULL.
499     bool IsIndirectPtr(TADDR base) const
500     {
501         LIMITED_METHOD_DAC_CONTRACT;
502         PRECONDITION(!IsNull());
503
504         TADDR addr = base + m_delta;
505
506         return (addr & FIXUP_POINTER_INDIRECTION) != 0;
507     }
508
509 #ifndef DACCESS_COMPILE
510     // Returns whether pointer is indirect. Assumes that the value is not NULL.
511     // Does not need explicit base and thus can be used in non-DAC builds only.
512     bool IsIndirectPtr() const
513     {
514         LIMITED_METHOD_CONTRACT;
515         return IsIndirectPtr((TADDR)this);
516     }
517
518     // Returns whether pointer is indirect. Assumes that the value is not NULL.
519     // Ignores isIndirect and offset values.
520     bool IsIndirectPtrIndirect(bool isIndirect, intptr_t offset) const
521     {
522         LIMITED_METHOD_DAC_CONTRACT;
523         return IsIndirectPtr();
524     }
525 #endif
526
527     // Returns whether pointer is indirect. The value can be NULL.
528     bool IsIndirectPtrMaybeNull(TADDR base) const
529     {
530         LIMITED_METHOD_DAC_CONTRACT;
531
532         if (m_delta == 0)
533             return false;
534
535         return IsIndirectPtr(base);
536     }
537
538 #ifndef DACCESS_COMPILE
539     // Returns whether pointer is indirect. The value can be NULL.
540     // Does not need explicit base and thus can be used in non-DAC builds only.
541     bool IsIndirectPtrMaybeNull() const
542     {
543         LIMITED_METHOD_CONTRACT;
544         return IsIndirectPtrMaybeNull((TADDR)this);
545     }
546
547     // Returns whether pointer is indirect. The value can be NULL.
548     // Ignores isIndirect and offset values.
549     bool IsIndirectPtrMaybeNullIndirect(bool isIndirect, intptr_t offset) const
550     {
551         LIMITED_METHOD_DAC_CONTRACT;
552         return IsIndirectPtrMaybeNull();
553     }
554 #endif
555
556 private:
557 #ifndef DACCESS_COMPILE
558     Volatile<TADDR> m_delta;
559 #else
560     TADDR m_delta;
561 #endif
562 };
563
564 // Fixup used for RelativePointer
565 #define IMAGE_REL_BASED_RelativePointer IMAGE_REL_BASED_RELPTR
566
567 #endif // FEATURE_PREJIT
568
569 //----------------------------------------------------------------------------
570 // PlainPointer is simple pointer wrapper to support compilation without indirections
571 // This is useful for building size-constrained runtime without NGen support.
572 template<typename PTR_TYPE>
573 class PlainPointer
574 {
575 public:
576
577     static constexpr bool isRelative = false;
578     typedef PTR_TYPE type;
579
580     // Returns whether the encoded pointer is NULL.
581     BOOL IsNull() const
582     {
583         LIMITED_METHOD_DAC_CONTRACT;
584         return m_ptr == NULL;
585     }
586
587     // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet.
588     BOOL IsTagged(TADDR base) const
589     {
590         LIMITED_METHOD_DAC_CONTRACT;
591         return IsTagged();
592     }
593
594     // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet.
595     BOOL IsTagged() const
596     {
597         LIMITED_METHOD_DAC_CONTRACT;
598         TADDR addr = m_ptr;
599         if ((addr & FIXUP_POINTER_INDIRECTION) != 0)
600              return (*PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION) & 1) != 0;
601         return FALSE;
602     }
603
604     // Returns value of the encoded pointer.
605     PTR_TYPE GetValue() const
606     {
607         LIMITED_METHOD_DAC_CONTRACT;
608         return dac_cast<PTR_TYPE>(m_ptr);
609     }
610
611 #ifndef DACCESS_COMPILE
612     // Returns the pointer to the indirection cell.
613     PTR_TYPE * GetValuePtr() const
614     {
615         LIMITED_METHOD_CONTRACT;
616         TADDR addr = m_ptr;
617         if ((addr & FIXUP_POINTER_INDIRECTION) != 0)
618             return (PTR_TYPE *)(addr - FIXUP_POINTER_INDIRECTION);
619         return (PTR_TYPE *)&m_ptr;
620     }
621 #endif // !DACCESS_COMPILE
622
623     // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
624     PTR_TYPE GetValue(TADDR base) const
625     {
626         LIMITED_METHOD_DAC_CONTRACT;
627         return dac_cast<PTR_TYPE>(m_ptr);
628     }
629
630     // Static version of GetValue. It is meant to simplify access to arrays of pointers.
631     FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base)
632     {
633         LIMITED_METHOD_DAC_CONTRACT;
634         return dac_cast<DPTR(PlainPointer<PTR_TYPE>)>(base)->GetValue(base);
635     }
636
637     // Returns value of the encoded pointer. The pointer can be NULL.
638     PTR_TYPE GetValueMaybeNull() const
639     {
640         LIMITED_METHOD_DAC_CONTRACT;
641         return dac_cast<PTR_TYPE>(m_ptr);
642     }
643
644     // Returns value of the encoded pointer. The pointer can be NULL.
645     PTR_TYPE GetValueMaybeNull(TADDR base) const
646     {
647         LIMITED_METHOD_DAC_CONTRACT;
648         return dac_cast<PTR_TYPE>(m_ptr);
649     }
650
651     // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
652     FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base)
653     {
654         LIMITED_METHOD_DAC_CONTRACT;
655         return dac_cast<DPTR(PlainPointer<PTR_TYPE>)>(base)->GetValueMaybeNull(base);
656     }
657
658     // Returns whether pointer is indirect. Assumes that the value is not NULL.
659     bool IsIndirectPtr(TADDR base) const
660     {
661         LIMITED_METHOD_DAC_CONTRACT;
662
663         return (m_ptr & FIXUP_POINTER_INDIRECTION) != 0;
664     }
665
666 #ifndef DACCESS_COMPILE
667     // Returns whether pointer is indirect. Assumes that the value is not NULL.
668     // Does not need explicit base and thus can be used in non-DAC builds only.
669     bool IsIndirectPtr() const
670     {
671         LIMITED_METHOD_CONTRACT;
672         return IsIndirectPtr((TADDR)this);
673     }
674 #endif
675
676     // Returns whether pointer is indirect. The value can be NULL.
677     bool IsIndirectPtrMaybeNull(TADDR base) const
678     {
679         LIMITED_METHOD_DAC_CONTRACT;
680
681         return IsIndirectPtr(base);
682     }
683
684 #ifndef DACCESS_COMPILE
685     // Returns whether pointer is indirect. The value can be NULL.
686     // Does not need explicit base and thus can be used in non-DAC builds only.
687     bool IsIndirectPtrMaybeNull() const
688     {
689         LIMITED_METHOD_CONTRACT;
690         return IsIndirectPtrMaybeNull((TADDR)this);
691     }
692 #endif
693
694 #ifndef DACCESS_COMPILE
695     void SetValue(PTR_TYPE addr)
696     {
697         LIMITED_METHOD_CONTRACT;
698         m_ptr = dac_cast<TADDR>(addr);
699     }
700
701     // Set encoded value of the pointer. Assumes that the value is not NULL.
702     void SetValue(TADDR base, PTR_TYPE addr)
703     {
704         LIMITED_METHOD_CONTRACT;
705         m_ptr = dac_cast<TADDR>(addr);
706     }
707
708     // Static version of SetValue. It is meant to simplify access to arrays of pointers.
709     FORCEINLINE static void SetValueAtPtr(TADDR base, PTR_TYPE addr)
710     {
711         LIMITED_METHOD_CONTRACT;
712         dac_cast<DPTR(PlainPointer<PTR_TYPE>)>(base)->SetValue(base, addr);
713     }
714
715     // Set encoded value of the pointer. The value can be NULL.
716     void SetValueMaybeNull(TADDR base, PTR_TYPE addr)
717     {
718         LIMITED_METHOD_CONTRACT;
719         m_ptr = dac_cast<TADDR>(addr);
720     }
721
722     // Set encoded value of the pointer. The value can be NULL.
723     // Does not need explicit base and thus can be used in non-DAC builds only.
724     FORCEINLINE void SetValueMaybeNull(PTR_TYPE addr)
725     {
726         LIMITED_METHOD_CONTRACT;
727         return SetValueMaybeNull((TADDR)this, addr);
728     }
729
730     // Static version of SetValueMaybeNull. It is meant to simplify access to arrays of pointers.
731     FORCEINLINE static void SetValueMaybeNullAtPtr(TADDR base, PTR_TYPE addr)
732     {
733         LIMITED_METHOD_CONTRACT;
734         dac_cast<DPTR(PlainPointer<PTR_TYPE>)>(base)->SetValueMaybeNull(base, addr);
735     }
736
737     FORCEINLINE void SetValueVolatile(PTR_TYPE addr)
738     {
739         LIMITED_METHOD_CONTRACT;
740         VolatileStore((PTR_TYPE *)(&m_ptr), addr);
741     }
742 #endif
743
744     static TADDR GetRelativeMaybeNull(TADDR base, TADDR addr)
745     {
746         LIMITED_METHOD_DAC_CONTRACT;
747         return addr;
748     }
749
750     static TADDR GetRelative(TADDR base, TADDR addr)
751     {
752         LIMITED_METHOD_DAC_CONTRACT;
753         PRECONDITION(addr != NULL);
754         return addr;
755     }
756
757 private:
758     TADDR m_ptr;
759 };
760
761 #ifndef FEATURE_PREJIT
762
763 #define FixupPointer PlainPointer
764 #define RelativePointer PlainPointer
765 #define RelativeFixupPointer PlainPointer
766
767 #endif // !FEATURE_PREJIT
768
769 //----------------------------------------------------------------------------
770 // RelativePointer32 is pointer encoded as relative 32-bit offset. It is used
771 // to reduce both the size of the pointer itself as well as size of relocation 
772 // section for pointers that live exlusively in NGen images.
773 template<typename PTR_TYPE>
774 class RelativePointer32
775 {
776 public:
777
778     static constexpr bool isRelative = true;
779     typedef PTR_TYPE type;
780
781     // Returns whether the encoded pointer is NULL.
782     BOOL IsNull() const
783     {
784         LIMITED_METHOD_DAC_CONTRACT;
785         // Pointer pointing to itself is treated as NULL
786         return m_delta == 0;
787     }
788
789     // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
790     PTR_TYPE GetValue(TADDR base) const
791     {
792         LIMITED_METHOD_DAC_CONTRACT;
793         PRECONDITION(!IsNull());
794         return dac_cast<PTR_TYPE>(base + m_delta);
795     }
796
797 #ifndef DACCESS_COMPILE
798     // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
799     // Does not need explicit base and thus can be used in non-DAC builds only.
800     FORCEINLINE PTR_TYPE GetValue() const
801     {
802         LIMITED_METHOD_CONTRACT;
803         return GetValue((TADDR)this);
804     }
805 #endif
806
807     // Static version of GetValue. It is meant to simplify access to arrays of pointers.
808     FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base)
809     {
810         LIMITED_METHOD_DAC_CONTRACT;
811         return dac_cast<DPTR(RelativePointer<PTR_TYPE>)>(base)->GetValue(base);
812     }
813
814     // Returns value of the encoded pointer. The pointer can be NULL.
815     PTR_TYPE GetValueMaybeNull(TADDR base) const
816     {
817         LIMITED_METHOD_DAC_CONTRACT;
818
819         // Cache local copy of delta to avoid races when the value is changing under us.
820         TADDR delta = m_delta;
821
822         if (delta == 0)
823             return NULL;
824
825         return dac_cast<PTR_TYPE>(base + delta);
826     }
827
828 #ifndef DACCESS_COMPILE
829     // Returns value of the encoded pointer. The pointer can be NULL.
830     // Does not need explicit base and thus can be used in non-DAC builds only.
831     FORCEINLINE PTR_TYPE GetValueMaybeNull() const
832     {
833         LIMITED_METHOD_CONTRACT;
834         return GetValueMaybeNull((TADDR)this);
835     }
836 #endif
837
838     // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
839     FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base)
840     {
841         LIMITED_METHOD_DAC_CONTRACT;
842         return dac_cast<DPTR(RelativePointer<PTR_TYPE>)>(base)->GetValueMaybeNull(base);
843     }
844
845 private:
846     INT32 m_delta;
847 };
848
849 //----------------------------------------------------------------------------
850 // IndirectPointer is pointer with optional indirection, similar to FixupPointer and RelativeFixupPointer.
851 //
852 // In comparison to FixupPointer, IndirectPointer's indirection is handled from outside by isIndirect flag.
853 // In comparison to RelativeFixupPointer, IndirectPointer's offset is a constant,
854 // while RelativeFixupPointer's offset is an address.
855 //
856 // IndirectPointer can contain NULL only if it is not indirect.
857 //
858 template<typename PTR_TYPE>
859 class IndirectPointer
860 {
861 public:
862
863     static constexpr bool isRelative = false;
864     typedef PTR_TYPE type;
865
866     // Returns whether the encoded pointer is NULL.
867     BOOL IsNull() const
868     {
869         LIMITED_METHOD_DAC_CONTRACT;
870         return m_addr == (TADDR)NULL;
871     }
872
873     // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet.
874     // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
875     FORCEINLINE BOOL IsTaggedIndirect(TADDR base, bool isIndirect, intptr_t offset) const
876     {
877         LIMITED_METHOD_DAC_CONTRACT;
878         TADDR addr = m_addr;
879         if (isIndirect)
880         {
881             _ASSERTE(!IsNull());
882             return (*PTR_TADDR(addr + offset) & 1) != 0;
883         }
884         return FALSE;
885     }
886
887     // Returns value of the encoded pointer.
888     // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
889     FORCEINLINE PTR_TYPE GetValueIndirect(bool isIndirect, intptr_t offset) const
890     {
891         LIMITED_METHOD_DAC_CONTRACT;
892         TADDR addr = m_addr;
893         if (isIndirect)
894         {
895             _ASSERTE(!IsNull());
896             addr = *PTR_TADDR(addr + offset);
897         }
898         return dac_cast<PTR_TYPE>(addr);
899     }
900
901 #ifndef DACCESS_COMPILE
902     // Returns the pointer to the indirection cell.
903     // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
904     PTR_TYPE * GetValuePtrIndirect(bool isIndirect, intptr_t offset) const
905     {
906         LIMITED_METHOD_CONTRACT;
907         TADDR addr = m_addr;
908         if (isIndirect)
909         {
910             _ASSERTE(!IsNull());
911             return (PTR_TYPE *)(addr + offset);
912         }
913         return (PTR_TYPE *)&m_addr;
914     }
915 #endif // !DACCESS_COMPILE
916
917     // Static version of GetValue. It is meant to simplify access to arrays of pointers.
918     // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
919     FORCEINLINE static PTR_TYPE GetValueAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset)
920     {
921         LIMITED_METHOD_DAC_CONTRACT;
922         return dac_cast<DPTR(IndirectPointer<PTR_TYPE>)>(base)->GetValueIndirect(isIndirect, offset);
923     }
924
925     // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
926     // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
927     FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset)
928     {
929         LIMITED_METHOD_DAC_CONTRACT;
930         return GetValueAtPtrIndirect(base, isIndirect, offset);
931     }
932
933 #ifndef DACCESS_COMPILE
934     // Returns whether pointer is indirect. Assumes that the value is not NULL.
935     // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
936     bool IsIndirectPtrIndirect(bool isIndirect, intptr_t offset) const
937     {
938         LIMITED_METHOD_CONTRACT;
939         if (isIndirect)
940             _ASSERTE(!IsNull());
941         return isIndirect;
942     }
943
944     // Returns whether pointer is indirect. The value can be NULL.
945     // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
946     bool IsIndirectPtrMaybeNullIndirect(bool isIndirect, intptr_t offset) const
947     {
948         LIMITED_METHOD_CONTRACT;
949         return IsIndirectPtrIndirect(isIndirect, offset);
950     }
951 #endif // !DACCESS_COMPILE
952
953 #ifndef DACCESS_COMPILE
954     // Set encoded value of the pointer. Assumes that the value is not NULL.
955     void SetValue(PTR_TYPE addr)
956     {
957         LIMITED_METHOD_CONTRACT;
958         m_addr = dac_cast<TADDR>(addr);
959     }
960
961     // Set encoded value of the pointer. The value can be NULL.
962     void SetValueMaybeNull(PTR_TYPE addr)
963     {
964         LIMITED_METHOD_CONTRACT;
965         SetValue(addr);
966     }
967 #endif // !DACCESS_COMPILE
968
969 private:
970     TADDR m_addr;
971 };
972
973 template<bool isMaybeNull, typename T, typename PT>
974 typename PT::type
975 ReadPointer(const T *base, const PT T::* pPointerFieldMember)
976 {
977     LIMITED_METHOD_DAC_CONTRACT;
978
979     uintptr_t offset = (uintptr_t) &(base->*pPointerFieldMember) - (uintptr_t) base;
980
981     if (isMaybeNull)
982     {
983         return PT::GetValueMaybeNullAtPtr(dac_cast<TADDR>(base) + offset);
984     }
985     else
986     {
987         return PT::GetValueAtPtr(dac_cast<TADDR>(base) + offset);
988     }
989 }
990
991 template<bool isMaybeNull, typename T, typename PT>
992 typename PT::type
993 ReadPointer(const T *base, const PT T::* pPointerFieldMember, bool isIndirect)
994 {
995     LIMITED_METHOD_DAC_CONTRACT;
996
997     uintptr_t offset = (uintptr_t) &(base->*pPointerFieldMember) - (uintptr_t) base;
998
999     if (isMaybeNull)
1000     {
1001         return PT::GetValueMaybeNullAtPtrIndirect(dac_cast<TADDR>(base) + offset, isIndirect, offset);
1002     }
1003     else
1004     {
1005         return PT::GetValueAtPtrIndirect(dac_cast<TADDR>(base) + offset, isIndirect, offset);
1006     }
1007 }
1008
1009 template<typename T, typename PT>
1010 typename PT::type
1011 ReadPointerMaybeNull(const T *base, const PT T::* pPointerFieldMember)
1012 {
1013     LIMITED_METHOD_DAC_CONTRACT;
1014
1015     return ReadPointer<true>(base, pPointerFieldMember);
1016 }
1017
1018 template<typename T, typename PT>
1019 typename PT::type
1020 ReadPointerMaybeNull(const T *base, const PT T::* pPointerFieldMember, bool isIndirect)
1021 {
1022     LIMITED_METHOD_DAC_CONTRACT;
1023
1024     return ReadPointer<true>(base, pPointerFieldMember, isIndirect);
1025 }
1026
1027 template<typename T, typename PT>
1028 typename PT::type
1029 ReadPointer(const T *base, const PT T::* pPointerFieldMember)
1030 {
1031     LIMITED_METHOD_DAC_CONTRACT;
1032
1033     return ReadPointer<false>(base, pPointerFieldMember);
1034 }
1035
1036 template<typename T, typename PT>
1037 typename PT::type
1038 ReadPointer(const T *base, const PT T::* pPointerFieldMember, bool isIndirect)
1039 {
1040     LIMITED_METHOD_DAC_CONTRACT;
1041
1042     return ReadPointer<false>(base, pPointerFieldMember, isIndirect);
1043 }
1044
1045 template<bool isMaybeNull, typename T, typename C, typename PT>
1046 typename PT::type
1047 ReadPointer(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember)
1048 {
1049     LIMITED_METHOD_DAC_CONTRACT;
1050
1051     const PT *ptr = &(base->*pFirstPointerFieldMember.*pSecondPointerFieldMember);
1052     uintptr_t offset = (uintptr_t) ptr - (uintptr_t) base;
1053
1054     if (isMaybeNull)
1055     {
1056         return PT::GetValueMaybeNullAtPtr(dac_cast<TADDR>(base) + offset);
1057     }
1058     else
1059     {
1060         return PT::GetValueAtPtr(dac_cast<TADDR>(base) + offset);
1061     }
1062 }
1063
1064 template<typename T, typename C, typename PT>
1065 typename PT::type
1066 ReadPointerMaybeNull(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember)
1067 {
1068     LIMITED_METHOD_DAC_CONTRACT;
1069
1070     return ReadPointer<true>(base, pFirstPointerFieldMember, pSecondPointerFieldMember);
1071 }
1072
1073 template<typename T, typename C, typename PT>
1074 typename PT::type
1075 ReadPointer(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember)
1076 {
1077     LIMITED_METHOD_DAC_CONTRACT;
1078
1079     return ReadPointer<false>(base, pFirstPointerFieldMember, pSecondPointerFieldMember);
1080 }
1081
1082 #endif //_FIXUPPOINTER_H