// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. /*****************************************************************************\ * * * FixupPointer.h - Fixup pointer holder types * * * \*****************************************************************************/ #ifndef _FIXUPPOINTER_H #define _FIXUPPOINTER_H #include "daccess.h" #ifdef FEATURE_PREJIT //---------------------------------------------------------------------------- // RelativePointer is pointer encoded as relative offset. It is used to reduce size of // relocation section in NGen images. Conversion from/to RelativePointer needs // address of the pointer ("this") converted to TADDR passed in from outside. // Converting "this" to TADDR is not possible in the DAC transparently because // DAC is based on exact pointers, not ranges. // There are several flavors of conversions from/to RelativePointer: // - GetValue/SetValue: The most common version. Assumes that the pointer is not NULL. // - GetValueMaybeNull/SetValueMaybeNull: Pointer can be NULL. // - GetValueAtPtr: Static version of GetValue. It is // meant to simplify access to arrays of RelativePointers. // - GetValueMaybeNullAtPtr template class RelativePointer { public: static constexpr bool isRelative = true; typedef PTR_TYPE type; #ifndef DACCESS_COMPILE RelativePointer() { m_delta = (TADDR)NULL; _ASSERTE (IsNull()); } #else // DACCESS_COMPILE RelativePointer() =delete; #endif // DACCESS_COMPILE // Implicit copy/move is not allowed // Bitwise copy is implemented by BitwiseCopyTo method RelativePointer(const RelativePointer &) =delete; RelativePointer(RelativePointer &&) =delete; RelativePointer& operator = (const RelativePointer &) =delete; RelativePointer& operator = (RelativePointer &&) =delete; // Returns whether the encoded pointer is NULL. BOOL IsNull() const { LIMITED_METHOD_DAC_CONTRACT; // Pointer pointing to itself is treated as NULL return m_delta == (TADDR)NULL; } // Returns value of the encoded pointer. Assumes that the pointer is not NULL. PTR_TYPE GetValue(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; PRECONDITION(!IsNull()); return dac_cast(base + m_delta); } #ifndef DACCESS_COMPILE // Returns value of the encoded pointer. Assumes that the pointer is not NULL. // Does not need explicit base and thus can be used in non-DAC builds only. FORCEINLINE PTR_TYPE GetValue() const { LIMITED_METHOD_CONTRACT; return GetValue((TADDR)this); } #endif // Static version of GetValue. It is meant to simplify access to arrays of pointers. FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base) { LIMITED_METHOD_DAC_CONTRACT; return dac_cast)>(base)->GetValue(base); } // Returns value of the encoded pointer. The pointer can be NULL. PTR_TYPE GetValueMaybeNull(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; // Cache local copy of delta to avoid races when the value is changing under us. TADDR delta = m_delta; if (delta == 0) return NULL; return dac_cast(base + delta); } #ifndef DACCESS_COMPILE // Returns value of the encoded pointer. The pointer can be NULL. // Does not need explicit base and thus can be used in non-DAC builds only. FORCEINLINE PTR_TYPE GetValueMaybeNull() const { LIMITED_METHOD_CONTRACT; return GetValueMaybeNull((TADDR)this); } #endif // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers. FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base) { LIMITED_METHOD_DAC_CONTRACT; return dac_cast)>(base)->GetValueMaybeNull(base); } #ifndef DACCESS_COMPILE // Set encoded value of the pointer. Assumes that the value is not NULL. FORCEINLINE void SetValue(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; PRECONDITION(addr != NULL); m_delta = (TADDR)addr - (TADDR)this; } // Set encoded value of the pointer. The value can be NULL. void SetValueMaybeNull(TADDR base, PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; if (addr == NULL) m_delta = NULL; else m_delta = (TADDR)addr - (TADDR)base; } // Set encoded value of the pointer. The value can be NULL. FORCEINLINE void SetValueMaybeNull(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; SetValueMaybeNull((TADDR)this, addr); } FORCEINLINE void SetValueVolatile(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; SetValue(addr); } #endif #ifndef DACCESS_COMPILE void BitwiseCopyTo(RelativePointer &dest) const { dest.m_delta = m_delta; } #endif // DACCESS_COMPILE static TADDR GetRelativeMaybeNull(TADDR base, TADDR addr) { LIMITED_METHOD_DAC_CONTRACT; if (addr == NULL) { return NULL; } else { return addr - base; } } static TADDR GetRelative(TADDR base, TADDR addr) { LIMITED_METHOD_DAC_CONTRACT; PRECONDITION(addr != NULL); return addr - base; } private: #ifndef DACCESS_COMPILE Volatile m_delta; #else TADDR m_delta; #endif }; //---------------------------------------------------------------------------- // FixupPointer is pointer with optional indirection. It is used to reduce number // of private pages in NGen images - cross-module pointers that written to at runtime // are packed together and accessed via indirection. // // The direct flavor (lowest bit of m_addr is cleared) is user for intra-module pointers // in NGen images, and in datastructuters allocated at runtime. // // The indirect mode (lowest bit of m_addr is set) is used for cross-module pointers // in NGen images. // // Friendly name for lowest bit that marks the indirection #define FIXUP_POINTER_INDIRECTION 1 template class FixupPointer { public: static constexpr bool isRelative = false; typedef PTR_TYPE type; // Returns whether the encoded pointer is NULL. BOOL IsNull() const { LIMITED_METHOD_DAC_CONTRACT; return m_addr == 0; } // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet. FORCEINLINE BOOL IsTagged() const { LIMITED_METHOD_DAC_CONTRACT; TADDR addr = m_addr; if ((addr & FIXUP_POINTER_INDIRECTION) != 0) return (*PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION) & 1) != 0; return FALSE; } // Returns value of the encoded pointer. FORCEINLINE PTR_TYPE GetValue() const { LIMITED_METHOD_DAC_CONTRACT; TADDR addr = m_addr; if ((addr & FIXUP_POINTER_INDIRECTION) != 0) addr = *PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION); return dac_cast(addr); } // Returns value of the encoded pointer. FORCEINLINE PTR_TYPE GetValueMaybeNull() const { LIMITED_METHOD_DAC_CONTRACT; return GetValue(); } #ifndef DACCESS_COMPILE // Returns the pointer to the indirection cell. PTR_TYPE * GetValuePtr() const { LIMITED_METHOD_CONTRACT; TADDR addr = m_addr; if ((addr & FIXUP_POINTER_INDIRECTION) != 0) return (PTR_TYPE *)(addr - FIXUP_POINTER_INDIRECTION); return (PTR_TYPE *)&m_addr; } #endif // !DACCESS_COMPILE // Static version of GetValue. It is meant to simplify access to arrays of pointers. FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base) { LIMITED_METHOD_DAC_CONTRACT; return dac_cast)>(base)->GetValue(); } // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers. FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base) { LIMITED_METHOD_DAC_CONTRACT; return dac_cast)>(base)->GetValueMaybeNull(); } // Returns value of the encoded pointer. // Allows the value to be tagged. FORCEINLINE TADDR GetValueMaybeTagged() const { LIMITED_METHOD_DAC_CONTRACT; TADDR addr = m_addr; if ((addr & FIXUP_POINTER_INDIRECTION) != 0) addr = *PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION); return addr; } #ifndef DACCESS_COMPILE void SetValue(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; m_addr = dac_cast(addr); } void SetValueMaybeNull(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; SetValue(addr); } #endif // !DACCESS_COMPILE private: TADDR m_addr; }; //---------------------------------------------------------------------------- // RelativeFixupPointer is combination of RelativePointer and FixupPointer template class RelativeFixupPointer { public: static constexpr bool isRelative = true; typedef PTR_TYPE type; #ifndef DACCESS_COMPILE RelativeFixupPointer() { SetValueMaybeNull(NULL); } #else // DACCESS_COMPILE RelativeFixupPointer() =delete; #endif // DACCESS_COMPILE // Implicit copy/move is not allowed RelativeFixupPointer(const RelativeFixupPointer &) =delete; RelativeFixupPointer(RelativeFixupPointer &&) =delete; RelativeFixupPointer& operator = (const RelativeFixupPointer &) =delete; RelativeFixupPointer& operator = (RelativeFixupPointer &&) =delete; // Returns whether the encoded pointer is NULL. BOOL IsNull() const { LIMITED_METHOD_DAC_CONTRACT; // Pointer pointing to itself is treated as NULL return m_delta == (TADDR)NULL; } // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet. FORCEINLINE BOOL IsTagged(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; TADDR addr = base + m_delta; if ((addr & FIXUP_POINTER_INDIRECTION) != 0) return (*PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION) & 1) != 0; return FALSE; } // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet. // Ignores isIndirect and offset values. FORCEINLINE BOOL IsTaggedIndirect(TADDR base, bool isIndirect, intptr_t offset) const { LIMITED_METHOD_DAC_CONTRACT; return IsTagged(base); } #ifndef DACCESS_COMPILE // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet. // Does not need explicit base and thus can be used in non-DAC builds only. FORCEINLINE BOOL IsTagged() const { LIMITED_METHOD_CONTRACT; return IsTagged((TADDR)this); } #endif // !DACCESS_COMPILE // Returns value of the encoded pointer. Assumes that the pointer is not NULL. FORCEINLINE PTR_TYPE GetValue(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; PRECONDITION(!IsNull()); PRECONDITION(!IsTagged(base)); TADDR addr = base + m_delta; if ((addr & FIXUP_POINTER_INDIRECTION) != 0) addr = *PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION); return dac_cast(addr); } #ifndef DACCESS_COMPILE // Returns value of the encoded pointer. Assumes that the pointer is not NULL. // Does not need explicit base and thus can be used in non-DAC builds only. FORCEINLINE PTR_TYPE GetValue() const { LIMITED_METHOD_CONTRACT; return GetValue((TADDR)this); } #endif // Static version of GetValue. It is meant to simplify access to arrays of pointers. FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base) { LIMITED_METHOD_DAC_CONTRACT; return dac_cast)>(base)->GetValue(base); } // Static version of GetValue. It is meant to simplify access to arrays of pointers. // Ignores isIndirect and offset values. FORCEINLINE static PTR_TYPE GetValueAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset) { LIMITED_METHOD_DAC_CONTRACT; return GetValueAtPtr(base); } // Returns value of the encoded pointer. The pointer can be NULL. PTR_TYPE GetValueMaybeNull(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; PRECONDITION(!IsTagged(base)); // Cache local copy of delta to avoid races when the value is changing under us. TADDR delta = m_delta; if (delta == 0) return NULL; TADDR addr = base + delta; if ((addr & FIXUP_POINTER_INDIRECTION) != 0) addr = *PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION); return dac_cast(addr); } #ifndef DACCESS_COMPILE // Returns value of the encoded pointer. The pointer can be NULL. // Does not need explicit base and thus can be used in non-DAC builds only. FORCEINLINE PTR_TYPE GetValueMaybeNull() const { LIMITED_METHOD_CONTRACT; return GetValueMaybeNull((TADDR)this); } #endif // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers. FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base) { LIMITED_METHOD_DAC_CONTRACT; return dac_cast)>(base)->GetValueMaybeNull(base); } // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers. // Ignores isIndirect and offset values. FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset) { LIMITED_METHOD_DAC_CONTRACT; return GetValueMaybeNullAtPtr(base); } #ifndef DACCESS_COMPILE // Set encoded value of the pointer. Assumes that the value is not NULL. FORCEINLINE void SetValue(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; PRECONDITION(addr != NULL); m_delta = dac_cast(addr) - (TADDR)this; } // Set encoded value of the pointer. The value can be NULL. void SetValueMaybeNull(TADDR base, PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; if (addr == NULL) m_delta = NULL; else m_delta = dac_cast(addr) - (TADDR)base; } // Set encoded value of the pointer. The value can be NULL. FORCEINLINE void SetValueMaybeNull(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; SetValueMaybeNull((TADDR)this, addr); } #endif #ifndef DACCESS_COMPILE // Returns the pointer to the indirection cell. PTR_TYPE * GetValuePtr() const { LIMITED_METHOD_CONTRACT; TADDR addr = ((TADDR)this) + m_delta; _ASSERTE((addr & FIXUP_POINTER_INDIRECTION) != 0); return (PTR_TYPE *)(addr - FIXUP_POINTER_INDIRECTION); } // Returns the pointer to the indirection cell. // Ignores isIndirect and offset values. PTR_TYPE * GetValuePtrIndirect(bool isIndirect, intptr_t offset) const { LIMITED_METHOD_CONTRACT; return GetValuePtr(); } #endif // !DACCESS_COMPILE // Returns value of the encoded pointer. Assumes that the pointer is not NULL. // Allows the value to be tagged. FORCEINLINE TADDR GetValueMaybeTagged(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; PRECONDITION(!IsNull()); TADDR addr = base + m_delta; if ((addr & FIXUP_POINTER_INDIRECTION) != 0) addr = *PTR_TADDR(addr - FIXUP_POINTER_INDIRECTION); return addr; } // Returns whether pointer is indirect. Assumes that the value is not NULL. bool IsIndirectPtr(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; PRECONDITION(!IsNull()); TADDR addr = base + m_delta; return (addr & FIXUP_POINTER_INDIRECTION) != 0; } #ifndef DACCESS_COMPILE // Returns whether pointer is indirect. Assumes that the value is not NULL. // Does not need explicit base and thus can be used in non-DAC builds only. bool IsIndirectPtr() const { LIMITED_METHOD_CONTRACT; return IsIndirectPtr((TADDR)this); } // Returns whether pointer is indirect. Assumes that the value is not NULL. // Ignores isIndirect and offset values. bool IsIndirectPtrIndirect(bool isIndirect, intptr_t offset) const { LIMITED_METHOD_DAC_CONTRACT; return IsIndirectPtr(); } #endif // Returns whether pointer is indirect. The value can be NULL. bool IsIndirectPtrMaybeNull(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; if (m_delta == 0) return false; return IsIndirectPtr(base); } #ifndef DACCESS_COMPILE // Returns whether pointer is indirect. The value can be NULL. // Does not need explicit base and thus can be used in non-DAC builds only. bool IsIndirectPtrMaybeNull() const { LIMITED_METHOD_CONTRACT; return IsIndirectPtrMaybeNull((TADDR)this); } // Returns whether pointer is indirect. The value can be NULL. // Ignores isIndirect and offset values. bool IsIndirectPtrMaybeNullIndirect(bool isIndirect, intptr_t offset) const { LIMITED_METHOD_DAC_CONTRACT; return IsIndirectPtrMaybeNull(); } #endif private: #ifndef DACCESS_COMPILE Volatile m_delta; #else TADDR m_delta; #endif }; // Fixup used for RelativePointer #define IMAGE_REL_BASED_RelativePointer IMAGE_REL_BASED_RELPTR #endif // FEATURE_PREJIT //---------------------------------------------------------------------------- // PlainPointer is simple pointer wrapper to support compilation without indirections // This is useful for building size-constrained runtime without NGen support. template class PlainPointer { public: static constexpr bool isRelative = false; typedef PTR_TYPE type; // Returns whether the encoded pointer is NULL. BOOL IsNull() const { LIMITED_METHOD_DAC_CONTRACT; return m_ptr == NULL; } // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet. BOOL IsTagged(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; return FALSE; } // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet. BOOL IsTagged() const { LIMITED_METHOD_DAC_CONTRACT; return FALSE; } // Returns value of the encoded pointer. PTR_TYPE GetValue() const { LIMITED_METHOD_DAC_CONTRACT; return dac_cast(m_ptr); } #ifndef DACCESS_COMPILE // Returns the pointer to the indirection cell. PTR_TYPE * GetValuePtr() const { LIMITED_METHOD_CONTRACT; return (PTR_TYPE *)&m_ptr; } #endif // !DACCESS_COMPILE // Returns value of the encoded pointer. Assumes that the pointer is not NULL. PTR_TYPE GetValue(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; return dac_cast(m_ptr); } // Static version of GetValue. It is meant to simplify access to arrays of pointers. FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base) { LIMITED_METHOD_DAC_CONTRACT; return dac_cast)>(base)->GetValue(base); } // Returns value of the encoded pointer. The pointer can be NULL. PTR_TYPE GetValueMaybeNull() const { LIMITED_METHOD_DAC_CONTRACT; return dac_cast(m_ptr); } // Returns value of the encoded pointer. The pointer can be NULL. PTR_TYPE GetValueMaybeNull(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; return dac_cast(m_ptr); } // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers. FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base) { LIMITED_METHOD_DAC_CONTRACT; return dac_cast)>(base)->GetValueMaybeNull(base); } // Returns value of the encoded pointer. // Allows the value to be tagged. FORCEINLINE TADDR GetValueMaybeTagged() const { LIMITED_METHOD_DAC_CONTRACT; return m_ptr; } // Returns value of the encoded pointer. Assumes that the pointer is not NULL. // Allows the value to be tagged. FORCEINLINE TADDR GetValueMaybeTagged(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; return m_ptr; } // Returns whether pointer is indirect. Assumes that the value is not NULL. bool IsIndirectPtr(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; return FALSE; } #ifndef DACCESS_COMPILE // Returns whether pointer is indirect. Assumes that the value is not NULL. // Does not need explicit base and thus can be used in non-DAC builds only. bool IsIndirectPtr() const { LIMITED_METHOD_CONTRACT; return FALSE; } #endif // Returns whether pointer is indirect. The value can be NULL. bool IsIndirectPtrMaybeNull(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; return FALSE; } #ifndef DACCESS_COMPILE // Returns whether pointer is indirect. The value can be NULL. // Does not need explicit base and thus can be used in non-DAC builds only. bool IsIndirectPtrMaybeNull() const { LIMITED_METHOD_CONTRACT; return FALSE; } #endif #ifndef DACCESS_COMPILE void SetValue(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; m_ptr = dac_cast(addr); } // Set encoded value of the pointer. Assumes that the value is not NULL. void SetValue(TADDR base, PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; m_ptr = dac_cast(addr); } // Static version of SetValue. It is meant to simplify access to arrays of pointers. FORCEINLINE static void SetValueAtPtr(TADDR base, PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; dac_cast)>(base)->SetValue(base, addr); } // Set encoded value of the pointer. The value can be NULL. void SetValueMaybeNull(TADDR base, PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; m_ptr = dac_cast(addr); } // Set encoded value of the pointer. The value can be NULL. // Does not need explicit base and thus can be used in non-DAC builds only. FORCEINLINE void SetValueMaybeNull(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; return SetValueMaybeNull((TADDR)this, addr); } // Static version of SetValueMaybeNull. It is meant to simplify access to arrays of pointers. FORCEINLINE static void SetValueMaybeNullAtPtr(TADDR base, PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; dac_cast)>(base)->SetValueMaybeNull(base, addr); } FORCEINLINE void SetValueVolatile(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; VolatileStore((PTR_TYPE *)(&m_ptr), addr); } #endif static TADDR GetRelativeMaybeNull(TADDR base, TADDR addr) { LIMITED_METHOD_DAC_CONTRACT; return addr; } static TADDR GetRelative(TADDR base, TADDR addr) { LIMITED_METHOD_DAC_CONTRACT; PRECONDITION(addr != NULL); return addr; } private: TADDR m_ptr; }; #ifndef FEATURE_PREJIT #define FixupPointer PlainPointer #define RelativePointer PlainPointer #define RelativeFixupPointer PlainPointer #endif // !FEATURE_PREJIT //---------------------------------------------------------------------------- // RelativePointer32 is pointer encoded as relative 32-bit offset. It is used // to reduce both the size of the pointer itself as well as size of relocation // section for pointers that live exlusively in NGen images. template class RelativePointer32 { public: static constexpr bool isRelative = true; typedef PTR_TYPE type; // Returns whether the encoded pointer is NULL. BOOL IsNull() const { LIMITED_METHOD_DAC_CONTRACT; // Pointer pointing to itself is treated as NULL return m_delta == 0; } // Returns value of the encoded pointer. Assumes that the pointer is not NULL. PTR_TYPE GetValue(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; PRECONDITION(!IsNull()); return dac_cast(base + m_delta); } #ifndef DACCESS_COMPILE // Returns value of the encoded pointer. Assumes that the pointer is not NULL. // Does not need explicit base and thus can be used in non-DAC builds only. FORCEINLINE PTR_TYPE GetValue() const { LIMITED_METHOD_CONTRACT; return GetValue((TADDR)this); } #endif // Static version of GetValue. It is meant to simplify access to arrays of pointers. FORCEINLINE static PTR_TYPE GetValueAtPtr(TADDR base) { LIMITED_METHOD_DAC_CONTRACT; return dac_cast)>(base)->GetValue(base); } // Returns value of the encoded pointer. The pointer can be NULL. PTR_TYPE GetValueMaybeNull(TADDR base) const { LIMITED_METHOD_DAC_CONTRACT; // Cache local copy of delta to avoid races when the value is changing under us. TADDR delta = m_delta; if (delta == 0) return NULL; return dac_cast(base + delta); } #ifndef DACCESS_COMPILE // Returns value of the encoded pointer. The pointer can be NULL. // Does not need explicit base and thus can be used in non-DAC builds only. FORCEINLINE PTR_TYPE GetValueMaybeNull() const { LIMITED_METHOD_CONTRACT; return GetValueMaybeNull((TADDR)this); } #endif // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers. FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtr(TADDR base) { LIMITED_METHOD_DAC_CONTRACT; return dac_cast)>(base)->GetValueMaybeNull(base); } private: INT32 m_delta; }; //---------------------------------------------------------------------------- // IndirectPointer is pointer with optional indirection, similar to FixupPointer and RelativeFixupPointer. // // In comparison to FixupPointer, IndirectPointer's indirection is handled from outside by isIndirect flag. // In comparison to RelativeFixupPointer, IndirectPointer's offset is a constant, // while RelativeFixupPointer's offset is an address. // // IndirectPointer can contain NULL only if it is not indirect. // template class IndirectPointer { public: static constexpr bool isRelative = false; typedef PTR_TYPE type; // Returns whether the encoded pointer is NULL. BOOL IsNull() const { LIMITED_METHOD_DAC_CONTRACT; return m_addr == (TADDR)NULL; } // Returns whether the indirection cell contain fixup that has not been converted to real pointer yet. // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset. FORCEINLINE BOOL IsTaggedIndirect(TADDR base, bool isIndirect, intptr_t offset) const { LIMITED_METHOD_DAC_CONTRACT; TADDR addr = m_addr; if (isIndirect) { _ASSERTE(!IsNull()); return (*PTR_TADDR(addr + offset) & 1) != 0; } return FALSE; } // Returns value of the encoded pointer. // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset. FORCEINLINE PTR_TYPE GetValueIndirect(bool isIndirect, intptr_t offset) const { LIMITED_METHOD_DAC_CONTRACT; TADDR addr = m_addr; if (isIndirect) { _ASSERTE(!IsNull()); addr = *PTR_TADDR(addr + offset); } return dac_cast(addr); } #ifndef DACCESS_COMPILE // Returns the pointer to the indirection cell. // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset. PTR_TYPE * GetValuePtrIndirect(bool isIndirect, intptr_t offset) const { LIMITED_METHOD_CONTRACT; TADDR addr = m_addr; if (isIndirect) { _ASSERTE(!IsNull()); return (PTR_TYPE *)(addr + offset); } return (PTR_TYPE *)&m_addr; } #endif // !DACCESS_COMPILE // Static version of GetValue. It is meant to simplify access to arrays of pointers. // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset. FORCEINLINE static PTR_TYPE GetValueAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset) { LIMITED_METHOD_DAC_CONTRACT; return dac_cast)>(base)->GetValueIndirect(isIndirect, offset); } // Static version of GetValueMaybeNull. It is meant to simplify access to arrays of pointers. // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset. FORCEINLINE static PTR_TYPE GetValueMaybeNullAtPtrIndirect(TADDR base, bool isIndirect, intptr_t offset) { LIMITED_METHOD_DAC_CONTRACT; return GetValueAtPtrIndirect(base, isIndirect, offset); } #ifndef DACCESS_COMPILE // Returns whether pointer is indirect. Assumes that the value is not NULL. // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset. bool IsIndirectPtrIndirect(bool isIndirect, intptr_t offset) const { LIMITED_METHOD_CONTRACT; if (isIndirect) _ASSERTE(!IsNull()); return isIndirect; } // Returns whether pointer is indirect. The value can be NULL. // Uses isIndirect to identify, whether pointer is indirect or not. If it is, uses offset. bool IsIndirectPtrMaybeNullIndirect(bool isIndirect, intptr_t offset) const { LIMITED_METHOD_CONTRACT; return IsIndirectPtrIndirect(isIndirect, offset); } #endif // !DACCESS_COMPILE #ifndef DACCESS_COMPILE // Set encoded value of the pointer. Assumes that the value is not NULL. void SetValue(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; m_addr = dac_cast(addr); } // Set encoded value of the pointer. The value can be NULL. void SetValueMaybeNull(PTR_TYPE addr) { LIMITED_METHOD_CONTRACT; SetValue(addr); } #endif // !DACCESS_COMPILE private: TADDR m_addr; }; template typename PT::type ReadPointer(const T *base, const PT T::* pPointerFieldMember) { LIMITED_METHOD_DAC_CONTRACT; uintptr_t offset = (uintptr_t) &(base->*pPointerFieldMember) - (uintptr_t) base; if (isMaybeNull) { return PT::GetValueMaybeNullAtPtr(dac_cast(base) + offset); } else { return PT::GetValueAtPtr(dac_cast(base) + offset); } } template typename PT::type ReadPointer(const T *base, const PT T::* pPointerFieldMember, bool isIndirect) { LIMITED_METHOD_DAC_CONTRACT; uintptr_t offset = (uintptr_t) &(base->*pPointerFieldMember) - (uintptr_t) base; if (isMaybeNull) { return PT::GetValueMaybeNullAtPtrIndirect(dac_cast(base) + offset, isIndirect, offset); } else { return PT::GetValueAtPtrIndirect(dac_cast(base) + offset, isIndirect, offset); } } template typename PT::type ReadPointerMaybeNull(const T *base, const PT T::* pPointerFieldMember) { LIMITED_METHOD_DAC_CONTRACT; return ReadPointer(base, pPointerFieldMember); } template typename PT::type ReadPointerMaybeNull(const T *base, const PT T::* pPointerFieldMember, bool isIndirect) { LIMITED_METHOD_DAC_CONTRACT; return ReadPointer(base, pPointerFieldMember, isIndirect); } template typename PT::type ReadPointer(const T *base, const PT T::* pPointerFieldMember) { LIMITED_METHOD_DAC_CONTRACT; return ReadPointer(base, pPointerFieldMember); } template typename PT::type ReadPointer(const T *base, const PT T::* pPointerFieldMember, bool isIndirect) { LIMITED_METHOD_DAC_CONTRACT; return ReadPointer(base, pPointerFieldMember, isIndirect); } template typename PT::type ReadPointer(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember) { LIMITED_METHOD_DAC_CONTRACT; const PT *ptr = &(base->*pFirstPointerFieldMember.*pSecondPointerFieldMember); uintptr_t offset = (uintptr_t) ptr - (uintptr_t) base; if (isMaybeNull) { return PT::GetValueMaybeNullAtPtr(dac_cast(base) + offset); } else { return PT::GetValueAtPtr(dac_cast(base) + offset); } } template typename PT::type ReadPointerMaybeNull(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember) { LIMITED_METHOD_DAC_CONTRACT; return ReadPointer(base, pFirstPointerFieldMember, pSecondPointerFieldMember); } template typename PT::type ReadPointer(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember) { LIMITED_METHOD_DAC_CONTRACT; return ReadPointer(base, pFirstPointerFieldMember, pSecondPointerFieldMember); } #endif //_FIXUPPOINTER_H