Merge pull request #10681 from BruceForstall/LinuxArmAltjit
[platform/upstream/coreclr.git] / src / debug / di / helpers.h
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 * GetAddr() { 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(RSSmartPtr, 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