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// helpers.h
6//
7
8//
9// public helpers for debugger.
10//*****************************************************************************
11
12#ifndef _HELPERS_H
13#define _HELPERS_H
14
15//-----------------------------------------------------------------------------
16// Smartpointer for internal Addref/Release
17// Using Wrapper / Holder infrastructure from src\inc\Holder.h
18//-----------------------------------------------------------------------------
19template <typename TYPE>
20inline void HolderRSRelease(TYPE *value)
21{
22 _ASSERTE(value != NULL);
23 value->InternalRelease();
24}
25
26template <typename TYPE>
27inline void HolderRSAddRef(TYPE *value)
28{
29 _ASSERTE(value != NULL);
30 value->InternalAddRef();
31}
32
33// Smart ptrs for external refs. External refs are important
34// b/c they may keep an object alive.
35template <typename TYPE>
36inline void HolderRSReleaseExternal(TYPE *value)
37{
38 _ASSERTE(value != NULL);
39 value->Release();
40}
41
42template <typename TYPE>
43inline void HolderRSAddRefExternal(TYPE *value)
44{
45 _ASSERTE(value != NULL);
46 value->AddRef();
47}
48
49// The CordbBase::m_pProcess backpointer needs to adjust the external reference count, but manipulate it from
50// within the RS. This means we need to skip debugging checks that ensure
51// that the external count is only manipulated from outside the RS. Since we're
52// skipping these checks, we call this an "Unsafe" pointer.
53template <typename TYPE>
54inline void HolderRSUnsafeExtRelease(TYPE *value)
55{
56 _ASSERTE(value != NULL);
57 value->BaseRelease();
58}
59template <typename TYPE>
60inline void HolderRSUnsafeExtAddRef(TYPE *value)
61{
62 _ASSERTE(value != NULL);
63 value->BaseAddRef();
64}
65
66//-----------------------------------------------------------------------------
67// Base Smart pointer implementation.
68// This abstracts out the AddRef + Release methods.
69//-----------------------------------------------------------------------------
70template <typename TYPE, void (*ACQUIREF)(TYPE*), void (*RELEASEF)(TYPE*)>
71class BaseSmartPtr
72{
73public:
74 BaseSmartPtr () {
75 // Ensure that these smart-ptrs are really ptr-sized.
76 static_assert_no_msg(sizeof(*this) == sizeof(void*));
77 m_ptr = NULL;
78 }
79 explicit BaseSmartPtr (TYPE * ptr) : m_ptr(NULL) {
80 if (ptr != NULL)
81 {
82 RawAcquire(ptr);
83 }
84 }
85
86 ~BaseSmartPtr() {
87 Clear();
88 }
89
90 FORCEINLINE void Assign(TYPE * ptr)
91 {
92 // Do the AddRef before the release to avoid the release pinging 0 if we assign to ourself.
93 if (ptr != NULL)
94 {
95 ACQUIREF(ptr);
96 }
97 if (m_ptr != NULL)
98 {
99 RELEASEF(m_ptr);
100 }
101 m_ptr = ptr;
102 };
103
104 FORCEINLINE void Clear()
105 {
106 if (m_ptr != NULL)
107 {
108 RawRelease();
109 }
110 }
111
112 FORCEINLINE operator TYPE*() const
113 {
114 return m_ptr;
115 }
116
117 FORCEINLINE TYPE* GetValue() const
118 {
119 return m_ptr;
120 }
121
122 FORCEINLINE TYPE** operator & ()
123 {
124 // We allow getting the address so we can pass it in as an outparam.
125 // BTW/@TODO: this is a subtle and dangerous thing to do, since it easily leads to situations
126 // when pointer gets assigned without the ref counter being incremented.
127 // This can cause premature freeing of the object after the pointer dtor was called.
128
129 // But if we have a non-null m_Ptr, then it may get silently overwritten,
130 // and thus we'll lose the chance to call release on it.
131 // So we'll just avoid that pattern and assert to enforce it.
132 _ASSERTE(m_ptr == NULL);
133 return &m_ptr;
134 }
135
136 // For legacy purposes, some pre smart-pointer code needs to be able to get the
137 // address of the pointer. This is needed for RSPtrArray::GetAddrOfIndex.
138 FORCEINLINE TYPE** UnsafeGetAddr()
139 {
140 return &m_ptr;
141 }
142
143 FORCEINLINE TYPE* operator->()
144 {
145 return m_ptr;
146 }
147
148 FORCEINLINE int operator==(TYPE* p)
149 {
150 return (m_ptr == p);
151 }
152
153 FORCEINLINE int operator!= (TYPE* p)
154 {
155 return (m_ptr != p);
156 }
157
158private:
159 TYPE * m_ptr;
160
161 // Don't allow copy ctor. Explicitly don't define body to force linker errors if they're called.
162 BaseSmartPtr(BaseSmartPtr<TYPE,ACQUIREF,RELEASEF> & other);
163 void operator=(BaseSmartPtr<TYPE,ACQUIREF,RELEASEF> & other);
164
165 void RawAcquire(TYPE * p)
166 {
167 _ASSERTE(m_ptr == NULL);
168 m_ptr= p;
169 ACQUIREF(m_ptr);
170 }
171 void RawRelease()
172 {
173 _ASSERTE(m_ptr != NULL);
174 RELEASEF(m_ptr);
175 m_ptr = NULL;
176 }
177
178};
179
180//-----------------------------------------------------------------------------
181// Helper to make it easy to declare new SmartPtrs
182//-----------------------------------------------------------------------------
183#define DECLARE_MY_NEW_HOLDER(NAME, ADDREF, RELEASE) \
184template<typename TYPE> \
185class NAME : public BaseSmartPtr<TYPE, ADDREF, RELEASE> { \
186public: \
187 NAME() { }; \
188 NAME(NAME & other) { this->Assign(other.GetValue()); } \
189 explicit NAME(TYPE * p) : BaseSmartPtr<TYPE, ADDREF, RELEASE>(p) { }; \
190 FORCEINLINE NAME * GetAddr() { return this; } \
191 void operator=(NAME & other) { this->Assign(other.GetValue()); } \
192}; \
193
194//-----------------------------------------------------------------------------
195// Declare the various smart ptrs.
196//-----------------------------------------------------------------------------
197DECLARE_MY_NEW_HOLDER(RSSmartPtr, HolderRSAddRef, HolderRSRelease);
198DECLARE_MY_NEW_HOLDER(RSExtSmartPtr, HolderRSAddRefExternal, HolderRSReleaseExternal);
199
200// The CordbBase::m_pProcess backpointer needs to adjust the external reference count, but manipulate it from
201// within the RS. This means we need to skip debugging checks that ensure
202// that the external count is only manipulated from outside the RS. Since we're
203// skipping these checks, we call this an "Unsafe" pointer.
204// This is purely used by CordbBase::m_pProcess.
205DECLARE_MY_NEW_HOLDER(RSUnsafeExternalSmartPtr, HolderRSUnsafeExtAddRef, HolderRSUnsafeExtRelease);
206
207
208
209#endif // _HELPERS_H
210
211