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 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 | |
765 | private: |
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. |
781 | template<typename PTR_TYPE> |
782 | class RelativePointer32 |
783 | { |
784 | public: |
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 | |
853 | private: |
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 | // |
866 | template<typename PTR_TYPE> |
867 | class IndirectPointer |
868 | { |
869 | public: |
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 | |
977 | private: |
978 | TADDR m_addr; |
979 | }; |
980 | |
981 | template<bool isMaybeNull, typename T, typename PT> |
982 | typename PT::type |
983 | ReadPointer(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 | |
999 | template<bool isMaybeNull, typename T, typename PT> |
1000 | typename PT::type |
1001 | ReadPointer(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 | |
1017 | template<typename T, typename PT> |
1018 | typename PT::type |
1019 | ReadPointerMaybeNull(const T *base, const PT T::* pPointerFieldMember) |
1020 | { |
1021 | LIMITED_METHOD_DAC_CONTRACT; |
1022 | |
1023 | return ReadPointer<true>(base, pPointerFieldMember); |
1024 | } |
1025 | |
1026 | template<typename T, typename PT> |
1027 | typename PT::type |
1028 | ReadPointerMaybeNull(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 | |
1035 | template<typename T, typename PT> |
1036 | typename PT::type |
1037 | ReadPointer(const T *base, const PT T::* pPointerFieldMember) |
1038 | { |
1039 | LIMITED_METHOD_DAC_CONTRACT; |
1040 | |
1041 | return ReadPointer<false>(base, pPointerFieldMember); |
1042 | } |
1043 | |
1044 | template<typename T, typename PT> |
1045 | typename PT::type |
1046 | ReadPointer(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 | |
1053 | template<bool isMaybeNull, typename T, typename C, typename PT> |
1054 | typename PT::type |
1055 | ReadPointer(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 | |
1072 | template<typename T, typename C, typename PT> |
1073 | typename PT::type |
1074 | ReadPointerMaybeNull(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 | |
1081 | template<typename T, typename C, typename PT> |
1082 | typename PT::type |
1083 | ReadPointer(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 | |