diff options
Diffstat (limited to 'src/debug/di/helpers.h')
-rw-r--r-- | src/debug/di/helpers.h | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/src/debug/di/helpers.h b/src/debug/di/helpers.h new file mode 100644 index 0000000000..3c6b73cdd7 --- /dev/null +++ b/src/debug/di/helpers.h @@ -0,0 +1,210 @@ +// 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. +//***************************************************************************** +// helpers.h +// + +// +// public helpers for debugger. +//***************************************************************************** + +#ifndef _HELPERS_H +#define _HELPERS_H + +//----------------------------------------------------------------------------- +// Smartpointer for internal Addref/Release +// Using Wrapper / Holder infrastructure from src\inc\Holder.h +//----------------------------------------------------------------------------- +template <typename TYPE> +inline void HolderRSRelease(TYPE *value) +{ + _ASSERTE(value != NULL); + value->InternalRelease(); +} + +template <typename TYPE> +inline void HolderRSAddRef(TYPE *value) +{ + _ASSERTE(value != NULL); + value->InternalAddRef(); +} + +// Smart ptrs for external refs. External refs are important +// b/c they may keep an object alive. +template <typename TYPE> +inline void HolderRSReleaseExternal(TYPE *value) +{ + _ASSERTE(value != NULL); + value->Release(); +} + +template <typename TYPE> +inline void HolderRSAddRefExternal(TYPE *value) +{ + _ASSERTE(value != NULL); + value->AddRef(); +} + +// The CordbBase::m_pProcess backpointer needs to adjust the external reference count, but manipulate it from +// within the RS. This means we need to skip debugging checks that ensure +// that the external count is only manipulated from outside the RS. Since we're +// skipping these checks, we call this an "Unsafe" pointer. +template <typename TYPE> +inline void HolderRSUnsafeExtRelease(TYPE *value) +{ + _ASSERTE(value != NULL); + value->BaseRelease(); +} +template <typename TYPE> +inline void HolderRSUnsafeExtAddRef(TYPE *value) +{ + _ASSERTE(value != NULL); + value->BaseAddRef(); +} + +//----------------------------------------------------------------------------- +// Base Smart pointer implementation. +// This abstracts out the AddRef + Release methods. +//----------------------------------------------------------------------------- +template <typename TYPE, void (*ACQUIREF)(TYPE*), void (*RELEASEF)(TYPE*)> +class BaseSmartPtr +{ +public: + BaseSmartPtr () { + // Ensure that these smart-ptrs are really ptr-sized. + static_assert_no_msg(sizeof(*this) == sizeof(void*)); + m_ptr = NULL; + } + explicit BaseSmartPtr (TYPE * ptr) : m_ptr(NULL) { + if (ptr != NULL) + { + RawAcquire(ptr); + } + } + + ~BaseSmartPtr() { + Clear(); + } + + FORCEINLINE void Assign(TYPE * ptr) + { + // Do the AddRef before the release to avoid the release pinging 0 if we assign to ourself. + if (ptr != NULL) + { + ACQUIREF(ptr); + } + if (m_ptr != NULL) + { + RELEASEF(m_ptr); + } + m_ptr = ptr; + }; + + FORCEINLINE void Clear() + { + if (m_ptr != NULL) + { + RawRelease(); + } + } + + FORCEINLINE operator TYPE*() const + { + return m_ptr; + } + + FORCEINLINE TYPE* GetValue() const + { + return m_ptr; + } + + FORCEINLINE TYPE** operator & () + { + // We allow getting the address so we can pass it in as an outparam. + // BTW/@TODO: this is a subtle and dangerous thing to do, since it easily leads to situations + // when pointer gets assigned without the ref counter being incremented. + // This can cause premature freeing of the object after the pointer dtor was called. + + // But if we have a non-null m_Ptr, then it may get silently overwritten, + // and thus we'll lose the chance to call release on it. + // So we'll just avoid that pattern and assert to enforce it. + _ASSERTE(m_ptr == NULL); + return &m_ptr; + } + + // For legacy purposes, some pre smart-pointer code needs to be able to get the + // address of the pointer. This is needed for RSPtrArray::GetAddrOfIndex. + FORCEINLINE TYPE** UnsafeGetAddr() + { + return &m_ptr; + } + + FORCEINLINE TYPE* operator->() + { + return m_ptr; + } + + FORCEINLINE int operator==(TYPE* p) + { + return (m_ptr == p); + } + + FORCEINLINE int operator!= (TYPE* p) + { + return (m_ptr != p); + } + +private: + TYPE * m_ptr; + + // Don't allow copy ctor. Explicitly don't define body to force linker errors if they're called. + BaseSmartPtr(BaseSmartPtr<TYPE,ACQUIREF,RELEASEF> & other); + void operator=(BaseSmartPtr<TYPE,ACQUIREF,RELEASEF> & other); + + void RawAcquire(TYPE * p) + { + _ASSERTE(m_ptr == NULL); + m_ptr= p; + ACQUIREF(m_ptr); + } + void RawRelease() + { + _ASSERTE(m_ptr != NULL); + RELEASEF(m_ptr); + m_ptr = NULL; + } + +}; + +//----------------------------------------------------------------------------- +// Helper to make it easy to declare new SmartPtrs +//----------------------------------------------------------------------------- +#define DECLARE_MY_NEW_HOLDER(NAME, ADDREF, RELEASE) \ +template<typename TYPE> \ +class NAME : public BaseSmartPtr<TYPE, ADDREF, RELEASE> { \ +public: \ + NAME() { }; \ + NAME(NAME & other) { this->Assign(other.GetValue()); } \ + explicit NAME(TYPE * p) : BaseSmartPtr<TYPE, ADDREF, RELEASE>(p) { }; \ + FORCEINLINE NAME * GetAddr() { return this; } \ + void operator=(NAME & other) { this->Assign(other.GetValue()); } \ +}; \ + +//----------------------------------------------------------------------------- +// Declare the various smart ptrs. +//----------------------------------------------------------------------------- +DECLARE_MY_NEW_HOLDER(RSSmartPtr, HolderRSAddRef, HolderRSRelease); +DECLARE_MY_NEW_HOLDER(RSExtSmartPtr, HolderRSAddRefExternal, HolderRSReleaseExternal); + +// The CordbBase::m_pProcess backpointer needs to adjust the external reference count, but manipulate it from +// within the RS. This means we need to skip debugging checks that ensure +// that the external count is only manipulated from outside the RS. Since we're +// skipping these checks, we call this an "Unsafe" pointer. +// This is purely used by CordbBase::m_pProcess. +DECLARE_MY_NEW_HOLDER(RSUnsafeExternalSmartPtr, HolderRSUnsafeExtAddRef, HolderRSUnsafeExtRelease); + + + +#endif // _HELPERS_H + |