summaryrefslogtreecommitdiff
path: root/src/debug/di/helpers.h
blob: 3c6b73cdd78c51643c58db591a9cad5a097d792e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
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