// 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 inline void HolderRSRelease(TYPE *value) { _ASSERTE(value != NULL); value->InternalRelease(); } template 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 inline void HolderRSReleaseExternal(TYPE *value) { _ASSERTE(value != NULL); value->Release(); } template 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 inline void HolderRSUnsafeExtRelease(TYPE *value) { _ASSERTE(value != NULL); value->BaseRelease(); } template inline void HolderRSUnsafeExtAddRef(TYPE *value) { _ASSERTE(value != NULL); value->BaseAddRef(); } //----------------------------------------------------------------------------- // Base Smart pointer implementation. // This abstracts out the AddRef + Release methods. //----------------------------------------------------------------------------- template 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 & other); void operator=(BaseSmartPtr & 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 \ class NAME : public BaseSmartPtr { \ public: \ NAME() { }; \ NAME(NAME & other) { this->Assign(other.GetValue()); } \ explicit NAME(TYPE * p) : BaseSmartPtr(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