Bug 1891710: part 2) Enable <Element-outerHTML.html> WPT for Trusted Types. r=smaug
[gecko.git] / gfx / layers / AtomicRefCountedWithFinalize.h
blobcaae18921228edb71290d1786d2d8ae91c15098c
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
8 #define MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
10 #include "mozilla/RefPtr.h"
11 #include "mozilla/Likely.h"
12 #include "MainThreadUtils.h"
13 #include "base/message_loop.h"
14 #include "base/task.h"
15 #include "mozilla/gfx/Logging.h"
17 #define ADDREF_MANUALLY(obj) \
18 (obj)->AddRefManually(__FUNCTION__, __FILE__, __LINE__)
19 #define RELEASE_MANUALLY(obj) \
20 (obj)->ReleaseManually(__FUNCTION__, __FILE__, __LINE__)
22 namespace mozilla {
24 template <class U>
25 class StaticRefPtr;
27 namespace gl {
28 template <typename T>
29 class RefSet;
31 template <typename T>
32 class RefQueue;
33 } // namespace gl
35 template <typename T>
36 class AtomicRefCountedWithFinalize {
37 protected:
38 explicit AtomicRefCountedWithFinalize(const char* aName)
39 : mRecycleCallback(nullptr),
40 mClosure(nullptr),
41 mRefCount(0)
42 #ifdef DEBUG
44 mSpew(false),
45 mManualAddRefs(0),
46 mManualReleases(0)
47 #endif
48 #ifdef NS_BUILD_REFCNT_LOGGING
50 mName(aName)
51 #endif
55 ~AtomicRefCountedWithFinalize() {
56 if (mRefCount >= 0) {
57 gfxCriticalError() << "Deleting referenced object? " << mRefCount;
61 public:
62 // Mark user classes that are considered flawless.
63 template <class U>
64 friend class ::mozilla::StaticRefPtr;
66 template <class U>
67 friend struct mozilla::RefPtrTraits;
69 template <typename U>
70 friend class ::mozilla::gl::RefSet;
72 template <typename U>
73 friend class ::mozilla::gl::RefQueue;
75 // friend class mozilla::gl::SurfaceFactory;
77 void AddRefManually(const char* funcName, const char* fileName,
78 uint32_t lineNum) {
79 #ifdef DEBUG
80 uint32_t count = ++mManualAddRefs;
81 if (mSpew) {
82 printf_stderr("AddRefManually() #%u in %s at %s:%u\n", count, funcName,
83 fileName, lineNum);
85 #else
86 (void)funcName;
87 (void)fileName;
88 (void)lineNum;
89 #endif
90 AddRef();
93 void ReleaseManually(const char* funcName, const char* fileName,
94 uint32_t lineNum) {
95 #ifdef DEBUG
96 uint32_t count = ++mManualReleases;
97 if (mSpew) {
98 printf_stderr("ReleaseManually() #%u in %s at %s:%u\n", count, funcName,
99 fileName, lineNum);
101 #else
102 (void)funcName;
103 (void)fileName;
104 (void)lineNum;
105 #endif
106 Release();
109 private:
110 void AddRef() {
111 MOZ_ASSERT(mRefCount >= 0, "AddRef() during/after Finalize()/dtor.");
112 #ifdef NS_BUILD_REFCNT_LOGGING
113 int currCount = ++mRefCount;
114 NS_LOG_ADDREF(this, currCount, mName, sizeof(*this));
115 #else
116 ++mRefCount;
117 #endif
120 void Release() {
121 MOZ_ASSERT(mRefCount > 0, "Release() during/after Finalize()/dtor.");
122 // Read mRecycleCallback early so that it does not get set to
123 // deleted memory, if the object is goes away. See bug 994903.
124 // This saves us in the case where there is no callback, so that
125 // we can do the "else if" below.
126 RecycleCallback recycleCallback = mRecycleCallback;
127 int currCount = --mRefCount;
128 if (currCount < 0) {
129 gfxCriticalError() << "Invalid reference count release" << currCount;
130 ++mRefCount;
131 return;
133 #ifdef NS_BUILD_REFCNT_LOGGING
134 NS_LOG_RELEASE(this, currCount, mName);
135 #endif
137 if (0 == currCount) {
138 mRefCount = detail::DEAD;
139 MOZ_ASSERT(IsDead());
141 // Recycle listeners must call ClearRecycleCallback
142 // before releasing their strong reference.
143 if (mRecycleCallback) {
144 gfxCriticalError() << "About to release with valid callback";
145 mRecycleCallback = nullptr;
148 MOZ_ASSERT(mManualAddRefs == mManualReleases);
150 T* derived = static_cast<T*>(this);
151 derived->Finalize();
152 delete derived;
153 } else if (1 == currCount && recycleCallback) {
154 // There is nothing enforcing this in the code, except how the callers
155 // are being careful to never let the reference count go down if there
156 // is a callback.
157 MOZ_ASSERT(!IsDead());
158 T* derived = static_cast<T*>(this);
159 recycleCallback(derived, mClosure);
163 public:
164 typedef void (*RecycleCallback)(T* aObject, void* aClosure);
166 * Set a callback responsible for recycling this object
167 * before it is finalized.
169 void SetRecycleCallback(RecycleCallback aCallback, void* aClosure) {
170 MOZ_ASSERT(!IsDead());
171 mRecycleCallback = aCallback;
172 mClosure = aClosure;
174 void ClearRecycleCallback() {
175 MOZ_ASSERT(!IsDead());
176 SetRecycleCallback(nullptr, nullptr);
179 bool HasRecycleCallback() const {
180 MOZ_ASSERT(!IsDead());
181 return !!mRecycleCallback;
184 bool IsDead() const { return mRefCount < 0; }
186 bool HasOneRef() const { return mRefCount == 1; }
188 private:
189 RecycleCallback mRecycleCallback;
190 void* mClosure;
191 Atomic<int> mRefCount;
192 #ifdef DEBUG
193 public:
194 bool mSpew;
196 private:
197 Atomic<uint32_t> mManualAddRefs;
198 Atomic<uint32_t> mManualReleases;
199 #endif
200 #ifdef NS_BUILD_REFCNT_LOGGING
201 const char* mName;
202 #endif
205 } // namespace mozilla
207 #endif