1/*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB.  If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 */
20
21#ifndef RefCounted_h
22#define RefCounted_h
23
24#include "wtf/Assertions.h"
25#include "wtf/FastAllocBase.h"
26#include "wtf/InstanceCounter.h"
27#include "wtf/Noncopyable.h"
28#include "wtf/WTFExport.h"
29
30#if ENABLE(ASSERT)
31#define CHECK_REF_COUNTED_LIFECYCLE 1
32#include "wtf/ThreadRestrictionVerifier.h"
33#else
34#define CHECK_REF_COUNTED_LIFECYCLE 0
35#endif
36
37namespace WTF {
38
39// This base class holds the non-template methods and attributes.
40// The RefCounted class inherits from it reducing the template bloat
41// generated by the compiler (technique called template hoisting).
42class WTF_EXPORT RefCountedBase {
43public:
44    void ref()
45    {
46#if CHECK_REF_COUNTED_LIFECYCLE
47        // Start thread verification as soon as the ref count gets to 2. This
48        // heuristic reflects the fact that items are often created on one thread
49        // and then given to another thread to be used.
50        // FIXME: Make this restriction tigher. Especially as we move to more
51        // common methods for sharing items across threads like CrossThreadCopier.h
52        // We should be able to add a "detachFromThread" method to make this explicit.
53        if (m_refCount == 1)
54            m_verifier.setShared(true);
55        // If this assert fires, it either indicates a thread safety issue or
56        // that the verification needs to change. See ThreadRestrictionVerifier for
57        // the different modes.
58        ASSERT(m_verifier.isSafeToUse());
59        ASSERT(!m_adoptionIsRequired);
60#endif
61        ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
62        ++m_refCount;
63    }
64
65    bool hasOneRef() const
66    {
67        ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
68#if CHECK_REF_COUNTED_LIFECYCLE
69        ASSERT(m_verifier.isSafeToUse());
70#endif
71        return m_refCount == 1;
72    }
73
74    int refCount() const
75    {
76#if CHECK_REF_COUNTED_LIFECYCLE
77        ASSERT(m_verifier.isSafeToUse());
78#endif
79        return m_refCount;
80    }
81
82protected:
83    RefCountedBase()
84        : m_refCount(1)
85#if ENABLE(SECURITY_ASSERT)
86        , m_deletionHasBegun(false)
87#endif
88#if CHECK_REF_COUNTED_LIFECYCLE
89        , m_adoptionIsRequired(true)
90#endif
91    {
92    }
93
94    ~RefCountedBase()
95    {
96        ASSERT_WITH_SECURITY_IMPLICATION(m_deletionHasBegun);
97#if CHECK_REF_COUNTED_LIFECYCLE
98        ASSERT(!m_adoptionIsRequired);
99#endif
100    }
101
102    // Returns whether the pointer should be freed or not.
103    bool derefBase()
104    {
105        ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
106#if CHECK_REF_COUNTED_LIFECYCLE
107        ASSERT(m_verifier.isSafeToUse());
108        ASSERT(!m_adoptionIsRequired);
109#endif
110
111        ASSERT(m_refCount > 0);
112        --m_refCount;
113        if (!m_refCount) {
114#if ENABLE(SECURITY_ASSERT)
115            m_deletionHasBegun = true;
116#endif
117            return true;
118        }
119
120#if CHECK_REF_COUNTED_LIFECYCLE
121        // Stop thread verification when the ref goes to 1 because it
122        // is safe to be passed to another thread at this point.
123        if (m_refCount == 1)
124            m_verifier.setShared(false);
125#endif
126        return false;
127    }
128
129#if CHECK_REF_COUNTED_LIFECYCLE
130    bool deletionHasBegun() const
131    {
132        return m_deletionHasBegun;
133    }
134#endif
135
136private:
137
138#if CHECK_REF_COUNTED_LIFECYCLE || ENABLE(SECURITY_ASSERT)
139    friend void adopted(RefCountedBase*);
140#endif
141
142    int m_refCount;
143#if ENABLE(SECURITY_ASSERT)
144    bool m_deletionHasBegun;
145#endif
146#if CHECK_REF_COUNTED_LIFECYCLE
147    bool m_adoptionIsRequired;
148    ThreadRestrictionVerifier m_verifier;
149#endif
150};
151
152#if CHECK_REF_COUNTED_LIFECYCLE || ENABLE(SECURITY_ASSERT)
153inline void adopted(RefCountedBase* object)
154{
155    if (!object)
156        return;
157    ASSERT_WITH_SECURITY_IMPLICATION(!object->m_deletionHasBegun);
158#if CHECK_REF_COUNTED_LIFECYCLE
159    object->m_adoptionIsRequired = false;
160#endif
161}
162#endif
163
164template<typename T> class RefCounted : public RefCountedBase {
165    WTF_MAKE_NONCOPYABLE(RefCounted);
166    WTF_MAKE_FAST_ALLOCATED;
167
168public:
169    void deref()
170    {
171        if (derefBase())
172            delete static_cast<T*>(this);
173    }
174
175protected:
176#ifdef ENABLE_INSTANCE_COUNTER
177    RefCounted()
178    {
179        incrementInstanceCount<T>(static_cast<T*>(this));
180    }
181
182    ~RefCounted()
183    {
184        decrementInstanceCount<T>(static_cast<T*>(this));
185    }
186#else
187    RefCounted()
188    {
189    }
190#endif
191};
192
193} // namespace WTF
194
195using WTF::RefCounted;
196
197#endif // RefCounted_h
198