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
29template<typename PTR_TYPE>
30class RelativePointer
31{
32public:
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
179private:
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
202template<typename PTR_TYPE>
203class FixupPointer
204{
205public:
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
295private:
296 TADDR m_addr;
297};
298
299//----------------------------------------------------------------------------
300// RelativeFixupPointer is combination of RelativePointer and FixupPointer
301template<typename PTR_TYPE>
302class RelativeFixupPointer
303{
304public:
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
556private:
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.
572template<typename PTR_TYPE>
573class PlainPointer
574{
575public:
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 FALSE;
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 return FALSE;
599 }
600
601 // Returns value of the encoded pointer.
602 PTR_TYPE GetValue() const
603 {
604 LIMITED_METHOD_DAC_CONTRACT;
605 return dac_cast<PTR_TYPE>(m_ptr);
606 }
607
608#ifndef DACCESS_COMPILE
609 // Returns the pointer to the indirection cell.
610 PTR_TYPE * GetValuePtr() const
611 {
612 LIMITED_METHOD_CONTRACT;
613 return (PTR_TYPE *)&m_ptr;
614 }
615#endif // !DACCESS_COMPILE
616
617 // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
618 PTR_TYPE GetValue(TADDR base) const
619 {
620 LIMITED_METHOD_DAC_CONTRACT;
621 return dac_cast<PTR_TYPE>(m_ptr);
622 }
623
624 // Static version of GetValue. It is meant to simplify access to arrays of pointers.
625 FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base)
626 {
627 LIMITED_METHOD_DAC_CONTRACT;
628 return dac_cast<DPTR(PlainPointer<PTR_TYPE>)>(base)->GetValue(base);
629 }
630
631 // Returns value of the encoded pointer. The pointer can be NULL.
632 PTR_TYPE GetValueMaybeNull() const
633 {
634 LIMITED_METHOD_DAC_CONTRACT;
635 return dac_cast<PTR_TYPE>(m_ptr);
636 }
637
638 // Returns value of the encoded pointer. The pointer can be NULL.
639 PTR_TYPE GetValueMaybeNull(TADDR base) const
640 {
641 LIMITED_METHOD_DAC_CONTRACT;
642 return dac_cast<PTR_TYPE>(m_ptr);
643 }
644
645 // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
646 FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base)
647 {
648 LIMITED_METHOD_DAC_CONTRACT;
649 return dac_cast<DPTR(PlainPointer<PTR_TYPE>)>(base)->GetValueMaybeNull(base);
650 }
651
652 // Returns value of the encoded pointer.
653 // Allows the value to be tagged.
654 FORCEINLINE TADDR GetValueMaybeTagged() const
655 {
656 LIMITED_METHOD_DAC_CONTRACT;
657 return m_ptr;
658 }
659
660 // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
661 // Allows the value to be tagged.
662 FORCEINLINE TADDR GetValueMaybeTagged(TADDR base) const
663 {
664 LIMITED_METHOD_DAC_CONTRACT;
665 return m_ptr;
666 }
667
668 // Returns whether pointer is indirect. Assumes that the value is not NULL.
669 bool IsIndirectPtr(TADDR base) const
670 {
671 LIMITED_METHOD_DAC_CONTRACT;
672 return FALSE;
673 }
674
675#ifndef DACCESS_COMPILE
676 // Returns whether pointer is indirect. Assumes that the value is not NULL.
677 // Does not need explicit base and thus can be used in non-DAC builds only.
678 bool IsIndirectPtr() const
679 {
680 LIMITED_METHOD_CONTRACT;
681 return FALSE;
682 }
683#endif
684
685 // Returns whether pointer is indirect. The value can be NULL.
686 bool IsIndirectPtrMaybeNull(TADDR base) const
687 {
688 LIMITED_METHOD_DAC_CONTRACT;
689 return FALSE;
690 }
691
692#ifndef DACCESS_COMPILE
693 // Returns whether pointer is indirect. The value can be NULL.
694 // Does not need explicit base and thus can be used in non-DAC builds only.
695 bool IsIndirectPtrMaybeNull() const
696 {
697 LIMITED_METHOD_CONTRACT;
698 return FALSE;
699 }
700#endif
701
702#ifndef DACCESS_COMPILE
703 void SetValue(PTR_TYPE addr)
704 {
705 LIMITED_METHOD_CONTRACT;
706 m_ptr = dac_cast<TADDR>(addr);
707 }
708
709 // Set encoded value of the pointer. Assumes that the value is not NULL.
710 void SetValue(TADDR base, PTR_TYPE addr)
711 {
712 LIMITED_METHOD_CONTRACT;
713 m_ptr = dac_cast<TADDR>(addr);
714 }
715
716 // Static version of SetValue. It is meant to simplify access to arrays of pointers.
717 FORCEINLINE static void SetValueAtPtr(TADDR base, PTR_TYPE addr)
718 {
719 LIMITED_METHOD_CONTRACT;
720 dac_cast<DPTR(PlainPointer<PTR_TYPE>)>(base)->SetValue(base, addr);
721 }
722
723 // Set encoded value of the pointer. The value can be NULL.
724 void SetValueMaybeNull(TADDR base, PTR_TYPE addr)
725 {
726 LIMITED_METHOD_CONTRACT;
727 m_ptr = dac_cast<TADDR>(addr);
728 }
729
730 // Set encoded value of the pointer. The value can be NULL.
731 // Does not need explicit base and thus can be used in non-DAC builds only.
732 FORCEINLINE void SetValueMaybeNull(PTR_TYPE addr)
733 {
734 LIMITED_METHOD_CONTRACT;
735 return SetValueMaybeNull((TADDR)this, addr);
736 }
737
738 // Static version of SetValueMaybeNull. It is meant to simplify access to arrays of pointers.
739 FORCEINLINE static void SetValueMaybeNullAtPtr(TADDR base, PTR_TYPE addr)
740 {
741 LIMITED_METHOD_CONTRACT;
742 dac_cast<DPTR(PlainPointer<PTR_TYPE>)>(base)->SetValueMaybeNull(base, addr);
743 }
744
745 FORCEINLINE void SetValueVolatile(PTR_TYPE addr)
746 {
747 LIMITED_METHOD_CONTRACT;
748 VolatileStore((PTR_TYPE *)(&m_ptr), addr);
749 }
750#endif
751
752 static TADDR GetRelativeMaybeNull(TADDR base, TADDR addr)
753 {
754 LIMITED_METHOD_DAC_CONTRACT;
755 return addr;
756 }
757
758 static TADDR GetRelative(TADDR base, TADDR addr)
759 {
760 LIMITED_METHOD_DAC_CONTRACT;
761 PRECONDITION(addr != NULL);
762 return addr;
763 }
764
765private:
766 TADDR m_ptr;
767};
768
769#ifndef FEATURE_PREJIT
770
771#define FixupPointer PlainPointer
772#define RelativePointer PlainPointer
773#define RelativeFixupPointer PlainPointer
774
775#endif // !FEATURE_PREJIT
776
777//----------------------------------------------------------------------------
778// RelativePointer32 is pointer encoded as relative 32-bit offset. It is used
779// to reduce both the size of the pointer itself as well as size of relocation
780// section for pointers that live exlusively in NGen images.
781template<typename PTR_TYPE>
782class RelativePointer32
783{
784public:
785
786 static constexpr bool isRelative = true;
787 typedef PTR_TYPE type;
788
789 // Returns whether the encoded pointer is NULL.
790 BOOL IsNull() const
791 {
792 LIMITED_METHOD_DAC_CONTRACT;
793 // Pointer pointing to itself is treated as NULL
794 return m_delta == 0;
795 }
796
797 // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
798 PTR_TYPE GetValue(TADDR base) const
799 {
800 LIMITED_METHOD_DAC_CONTRACT;
801 PRECONDITION(!IsNull());
802 return dac_cast<PTR_TYPE>(base + m_delta);
803 }
804
805#ifndef DACCESS_COMPILE
806 // Returns value of the encoded pointer. Assumes that the pointer is not NULL.
807 // Does not need explicit base and thus can be used in non-DAC builds only.
808 FORCEINLINE PTR_TYPE GetValue() const
809 {
810 LIMITED_METHOD_CONTRACT;
811 return GetValue((TADDR)this);
812 }
813#endif
814
815 // Static version of GetValue. It is meant to simplify access to arrays of pointers.
816 FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base)
817 {
818 LIMITED_METHOD_DAC_CONTRACT;
819 return dac_cast<DPTR(RelativePointer<PTR_TYPE>)>(base)->GetValue(base);
820 }
821
822 // Returns value of the encoded pointer. The pointer can be NULL.
823 PTR_TYPE GetValueMaybeNull(TADDR base) const
824 {
825 LIMITED_METHOD_DAC_CONTRACT;
826
827 // Cache local copy of delta to avoid races when the value is changing under us.
828 TADDR delta = m_delta;
829
830 if (delta == 0)
831 return NULL;
832
833 return dac_cast<PTR_TYPE>(base + delta);
834 }
835
836#ifndef DACCESS_COMPILE
837 // Returns value of the encoded pointer. The pointer can be NULL.
838 // Does not need explicit base and thus can be used in non-DAC builds only.
839 FORCEINLINE PTR_TYPE GetValueMaybeNull() const
840 {
841 LIMITED_METHOD_CONTRACT;
842 return GetValueMaybeNull((TADDR)this);
843 }
844#endif
845
846 // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
847 FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base)
848 {
849 LIMITED_METHOD_DAC_CONTRACT;
850 return dac_cast<DPTR(RelativePointer<PTR_TYPE>)>(base)->GetValueMaybeNull(base);
851 }
852
853private:
854 INT32 m_delta;
855};
856
857//----------------------------------------------------------------------------
858// IndirectPointer is pointer with optional indirection, similar to FixupPointer and RelativeFixupPointer.
859//
860// In comparison to FixupPointer, IndirectPointer's indirection is handled from outside by isIndirect flag.
861// In comparison to RelativeFixupPointer, IndirectPointer's offset is a constant,
862// while RelativeFixupPointer's offset is an address.
863//
864// IndirectPointer can contain NULL only if it is not indirect.
865//
866template<typename PTR_TYPE>
867class IndirectPointer
868{
869public:
870
871 static constexpr bool isRelative = false;
872 typedef PTR_TYPE type;
873
874 // Returns whether the encoded pointer is NULL.
875 BOOL IsNull() const
876 {
877 LIMITED_METHOD_DAC_CONTRACT;
878 return m_addr == (TADDR)NULL;
879 }
880
881 // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet.
882 // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
883 FORCEINLINE BOOL IsTaggedIndirect(TADDR base, bool isIndirect, intptr_t offset) const
884 {
885 LIMITED_METHOD_DAC_CONTRACT;
886 TADDR addr = m_addr;
887 if (isIndirect)
888 {
889 _ASSERTE(!IsNull());
890 return (*PTR_TADDR(addr + offset) & 1) != 0;
891 }
892 return FALSE;
893 }
894
895 // Returns value of the encoded pointer.
896 // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
897 FORCEINLINE PTR_TYPE GetValueIndirect(bool isIndirect, intptr_t offset) const
898 {
899 LIMITED_METHOD_DAC_CONTRACT;
900 TADDR addr = m_addr;
901 if (isIndirect)
902 {
903 _ASSERTE(!IsNull());
904 addr = *PTR_TADDR(addr + offset);
905 }
906 return dac_cast<PTR_TYPE>(addr);
907 }
908
909#ifndef DACCESS_COMPILE
910 // Returns the pointer to the indirection cell.
911 // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
912 PTR_TYPE * GetValuePtrIndirect(bool isIndirect, intptr_t offset) const
913 {
914 LIMITED_METHOD_CONTRACT;
915 TADDR addr = m_addr;
916 if (isIndirect)
917 {
918 _ASSERTE(!IsNull());
919 return (PTR_TYPE *)(addr + offset);
920 }
921 return (PTR_TYPE *)&m_addr;
922 }
923#endif // !DACCESS_COMPILE
924
925 // Static version of GetValue. 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 GetValueAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset)
928 {
929 LIMITED_METHOD_DAC_CONTRACT;
930 return dac_cast<DPTR(IndirectPointer<PTR_TYPE>)>(base)->GetValueIndirect(isIndirect, offset);
931 }
932
933 // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers.
934 // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
935 FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset)
936 {
937 LIMITED_METHOD_DAC_CONTRACT;
938 return GetValueAtPtrIndirect(base, isIndirect, offset);
939 }
940
941#ifndef DACCESS_COMPILE
942 // Returns whether pointer is indirect. Assumes that the value is not NULL.
943 // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
944 bool IsIndirectPtrIndirect(bool isIndirect, intptr_t offset) const
945 {
946 LIMITED_METHOD_CONTRACT;
947 if (isIndirect)
948 _ASSERTE(!IsNull());
949 return isIndirect;
950 }
951
952 // Returns whether pointer is indirect. The value can be NULL.
953 // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset.
954 bool IsIndirectPtrMaybeNullIndirect(bool isIndirect, intptr_t offset) const
955 {
956 LIMITED_METHOD_CONTRACT;
957 return IsIndirectPtrIndirect(isIndirect, offset);
958 }
959#endif // !DACCESS_COMPILE
960
961#ifndef DACCESS_COMPILE
962 // Set encoded value of the pointer. Assumes that the value is not NULL.
963 void SetValue(PTR_TYPE addr)
964 {
965 LIMITED_METHOD_CONTRACT;
966 m_addr = dac_cast<TADDR>(addr);
967 }
968
969 // Set encoded value of the pointer. The value can be NULL.
970 void SetValueMaybeNull(PTR_TYPE addr)
971 {
972 LIMITED_METHOD_CONTRACT;
973 SetValue(addr);
974 }
975#endif // !DACCESS_COMPILE
976
977private:
978 TADDR m_addr;
979};
980
981template<bool isMaybeNull, typename T, typename PT>
982typename PT::type
983ReadPointer(const T *base, const PT T::* pPointerFieldMember)
984{
985 LIMITED_METHOD_DAC_CONTRACT;
986
987 uintptr_t offset = (uintptr_t) &(base->*pPointerFieldMember) - (uintptr_t) base;
988
989 if (isMaybeNull)
990 {
991 return PT::GetValueMaybeNullAtPtr(dac_cast<TADDR>(base) + offset);
992 }
993 else
994 {
995 return PT::GetValueAtPtr(dac_cast<TADDR>(base) + offset);
996 }
997}
998
999template<bool isMaybeNull, typename T, typename PT>
1000typename PT::type
1001ReadPointer(const T *base, const PT T::* pPointerFieldMember, bool isIndirect)
1002{
1003 LIMITED_METHOD_DAC_CONTRACT;
1004
1005 uintptr_t offset = (uintptr_t) &(base->*pPointerFieldMember) - (uintptr_t) base;
1006
1007 if (isMaybeNull)
1008 {
1009 return PT::GetValueMaybeNullAtPtrIndirect(dac_cast<TADDR>(base) + offset, isIndirect, offset);
1010 }
1011 else
1012 {
1013 return PT::GetValueAtPtrIndirect(dac_cast<TADDR>(base) + offset, isIndirect, offset);
1014 }
1015}
1016
1017template<typename T, typename PT>
1018typename PT::type
1019ReadPointerMaybeNull(const T *base, const PT T::* pPointerFieldMember)
1020{
1021 LIMITED_METHOD_DAC_CONTRACT;
1022
1023 return ReadPointer<true>(base, pPointerFieldMember);
1024}
1025
1026template<typename T, typename PT>
1027typename PT::type
1028ReadPointerMaybeNull(const T *base, const PT T::* pPointerFieldMember, bool isIndirect)
1029{
1030 LIMITED_METHOD_DAC_CONTRACT;
1031
1032 return ReadPointer<true>(base, pPointerFieldMember, isIndirect);
1033}
1034
1035template<typename T, typename PT>
1036typename PT::type
1037ReadPointer(const T *base, const PT T::* pPointerFieldMember)
1038{
1039 LIMITED_METHOD_DAC_CONTRACT;
1040
1041 return ReadPointer<false>(base, pPointerFieldMember);
1042}
1043
1044template<typename T, typename PT>
1045typename PT::type
1046ReadPointer(const T *base, const PT T::* pPointerFieldMember, bool isIndirect)
1047{
1048 LIMITED_METHOD_DAC_CONTRACT;
1049
1050 return ReadPointer<false>(base, pPointerFieldMember, isIndirect);
1051}
1052
1053template<bool isMaybeNull, typename T, typename C, typename PT>
1054typename PT::type
1055ReadPointer(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember)
1056{
1057 LIMITED_METHOD_DAC_CONTRACT;
1058
1059 const PT *ptr = &(base->*pFirstPointerFieldMember.*pSecondPointerFieldMember);
1060 uintptr_t offset = (uintptr_t) ptr - (uintptr_t) base;
1061
1062 if (isMaybeNull)
1063 {
1064 return PT::GetValueMaybeNullAtPtr(dac_cast<TADDR>(base) + offset);
1065 }
1066 else
1067 {
1068 return PT::GetValueAtPtr(dac_cast<TADDR>(base) + offset);
1069 }
1070}
1071
1072template<typename T, typename C, typename PT>
1073typename PT::type
1074ReadPointerMaybeNull(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember)
1075{
1076 LIMITED_METHOD_DAC_CONTRACT;
1077
1078 return ReadPointer<true>(base, pFirstPointerFieldMember, pSecondPointerFieldMember);
1079}
1080
1081template<typename T, typename C, typename PT>
1082typename PT::type
1083ReadPointer(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember)
1084{
1085 LIMITED_METHOD_DAC_CONTRACT;
1086
1087 return ReadPointer<false>(base, pFirstPointerFieldMember, pSecondPointerFieldMember);
1088}
1089
1090#endif //_FIXUPPOINTER_H
1091