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 | //----------------------------------------------------------------------------- |
19 | template <typename TYPE> |
20 | inline void HolderRSRelease(TYPE *value) |
21 | { |
22 | _ASSERTE(value != NULL); |
23 | value->InternalRelease(); |
24 | } |
25 | |
26 | template <typename TYPE> |
27 | inline 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. |
35 | template <typename TYPE> |
36 | inline void HolderRSReleaseExternal(TYPE *value) |
37 | { |
38 | _ASSERTE(value != NULL); |
39 | value->Release(); |
40 | } |
41 | |
42 | template <typename TYPE> |
43 | inline 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. |
53 | template <typename TYPE> |
54 | inline void HolderRSUnsafeExtRelease(TYPE *value) |
55 | { |
56 | _ASSERTE(value != NULL); |
57 | value->BaseRelease(); |
58 | } |
59 | template <typename TYPE> |
60 | inline 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 | //----------------------------------------------------------------------------- |
70 | template <typename TYPE, void (*ACQUIREF)(TYPE*), void (*RELEASEF)(TYPE*)> |
71 | class BaseSmartPtr |
72 | { |
73 | public: |
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 | |
158 | private: |
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) \ |
184 | template<typename TYPE> \ |
185 | class NAME : public BaseSmartPtr<TYPE, ADDREF, RELEASE> { \ |
186 | public: \ |
187 | NAME() { }; \ |
188 | NAME(NAME & other) { this->Assign(other.GetValue()); } \ |
189 | explicit NAME(TYPE * p) : BaseSmartPtr<TYPE, ADDREF, RELEASE>(p) { }; \ |
190 | FORCEINLINE NAME * () { return this; } \ |
191 | void operator=(NAME & other) { this->Assign(other.GetValue()); } \ |
192 | }; \ |
193 | |
194 | //----------------------------------------------------------------------------- |
195 | // Declare the various smart ptrs. |
196 | //----------------------------------------------------------------------------- |
197 | DECLARE_MY_NEW_HOLDER(, HolderRSAddRef, HolderRSRelease); |
198 | DECLARE_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. |
205 | DECLARE_MY_NEW_HOLDER(RSUnsafeExternalSmartPtr, HolderRSUnsafeExtAddRef, HolderRSUnsafeExtRelease); |
206 | |
207 | |
208 | |
209 | #endif // _HELPERS_H |
210 | |
211 | |