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