1/*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013 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#pragma once
22
23#include <wtf/Assertions.h>
24#include <wtf/FastMalloc.h>
25#include <wtf/Noncopyable.h>
26
27namespace WTF {
28
29#if defined(NDEBUG) && !ENABLE(SECURITY_ASSERTIONS)
30#define CHECK_REF_COUNTED_LIFECYCLE 0
31#else
32#define CHECK_REF_COUNTED_LIFECYCLE 1
33#endif
34
35// This base class holds the non-template methods and attributes.
36// The RefCounted class inherits from it reducing the template bloat
37// generated by the compiler (technique called template hoisting).
38class RefCountedBase {
39public:
40 void ref() const
41 {
42#if CHECK_REF_COUNTED_LIFECYCLE
43 ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
44 ASSERT(!m_adoptionIsRequired);
45#endif
46 ++m_refCount;
47 }
48
49 bool hasOneRef() const
50 {
51#if CHECK_REF_COUNTED_LIFECYCLE
52 ASSERT(!m_deletionHasBegun);
53#endif
54 return m_refCount == 1;
55 }
56
57 unsigned refCount() const
58 {
59 return m_refCount;
60 }
61
62 void relaxAdoptionRequirement()
63 {
64#if CHECK_REF_COUNTED_LIFECYCLE
65 ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
66 ASSERT(m_adoptionIsRequired);
67 m_adoptionIsRequired = false;
68#endif
69 }
70
71protected:
72 RefCountedBase()
73 : m_refCount(1)
74#if CHECK_REF_COUNTED_LIFECYCLE
75 , m_deletionHasBegun(false)
76 , m_adoptionIsRequired(true)
77#endif
78 {
79 }
80
81 ~RefCountedBase()
82 {
83#if CHECK_REF_COUNTED_LIFECYCLE
84 ASSERT(m_deletionHasBegun);
85 ASSERT(!m_adoptionIsRequired);
86#endif
87 }
88
89 // Returns whether the pointer should be freed or not.
90 bool derefBase() const
91 {
92#if CHECK_REF_COUNTED_LIFECYCLE
93 ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
94 ASSERT(!m_adoptionIsRequired);
95#endif
96
97 ASSERT(m_refCount);
98 unsigned tempRefCount = m_refCount - 1;
99 if (!tempRefCount) {
100#if CHECK_REF_COUNTED_LIFECYCLE
101 m_deletionHasBegun = true;
102#endif
103 return true;
104 }
105 m_refCount = tempRefCount;
106 return false;
107 }
108
109#if CHECK_REF_COUNTED_LIFECYCLE
110 bool deletionHasBegun() const
111 {
112 return m_deletionHasBegun;
113 }
114#endif
115
116private:
117
118#if CHECK_REF_COUNTED_LIFECYCLE
119 friend void adopted(RefCountedBase*);
120#endif
121
122 mutable unsigned m_refCount;
123#if CHECK_REF_COUNTED_LIFECYCLE
124 mutable bool m_deletionHasBegun;
125 mutable bool m_adoptionIsRequired;
126#endif
127};
128
129#if CHECK_REF_COUNTED_LIFECYCLE
130inline void adopted(RefCountedBase* object)
131{
132 if (!object)
133 return;
134 ASSERT_WITH_SECURITY_IMPLICATION(!object->m_deletionHasBegun);
135 object->m_adoptionIsRequired = false;
136}
137#endif
138
139template<typename T> class RefCounted : public RefCountedBase {
140 WTF_MAKE_NONCOPYABLE(RefCounted); WTF_MAKE_FAST_ALLOCATED;
141public:
142 void deref() const
143 {
144 if (derefBase())
145 delete static_cast<const T*>(this);
146 }
147
148protected:
149 RefCounted() { }
150 ~RefCounted()
151 {
152 }
153};
154
155} // namespace WTF
156
157using WTF::RefCounted;
158