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/. */
6 // IWYU pragma: private, include "nsISupports.h"
8 #ifndef nsISupportsImpl_h__
9 #define nsISupportsImpl_h__
12 #include "nsISupports.h"
13 #include "nsISupportsUtils.h"
15 #if !defined(XPCOM_GLUE_AVOID_NSPR)
16 # include "prthread.h" /* needed for cargo-culting headers */
22 #include <type_traits>
23 #include "mozilla/Attributes.h"
24 #include "mozilla/Assertions.h"
25 #include "mozilla/Atomics.h"
26 #include "mozilla/Compiler.h"
27 #include "mozilla/Likely.h"
28 #include "mozilla/MacroArgs.h"
29 #include "mozilla/MacroForEach.h"
31 #define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X) \
32 static_assert(!std::is_destructible_v<X>, \
33 "Reference-counted class " #X \
34 " should not have a public destructor. " \
35 "Make this class's destructor non-public");
37 inline nsISupports
* ToSupports(decltype(nullptr)) { return nullptr; }
39 inline nsISupports
* ToSupports(nsISupports
* aSupports
) { return aSupports
; }
41 ////////////////////////////////////////////////////////////////////////////////
42 // Macros to help detect thread-safety:
44 #ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
46 # include "prthread.h" /* needed for thread-safety checks */
48 class nsAutoOwningThread
{
52 // We move the actual assertion checks out-of-line to minimize code bloat,
53 // but that means we have to pass a non-literal string to MOZ_CRASH_UNSAFE.
54 // To make that more safe, the public interface requires a literal string
55 // and passes that to the private interface; we can then be assured that we
56 // effectively are passing a literal string to MOZ_CRASH_UNSAFE.
58 void AssertOwnership(const char (&aMsg
)[N
]) const {
59 AssertCurrentThreadOwnsMe(aMsg
);
62 bool IsCurrentThread() const;
65 void AssertCurrentThreadOwnsMe(const char* aMsg
) const;
70 class nsISerialEventTarget
;
71 class nsAutoOwningEventTarget
{
73 nsAutoOwningEventTarget();
74 ~nsAutoOwningEventTarget();
76 // We move the actual assertion checks out-of-line to minimize code bloat,
77 // but that means we have to pass a non-literal string to MOZ_CRASH_UNSAFE.
78 // To make that more safe, the public interface requires a literal string
79 // and passes that to the private interface; we can then be assured that we
80 // effectively are passing a literal string to MOZ_CRASH_UNSAFE.
82 void AssertOwnership(const char (&aMsg
)[N
]) const {
83 AssertCurrentThreadOwnsMe(aMsg
);
86 bool IsCurrentThread() const;
89 void AssertCurrentThreadOwnsMe(const char* aMsg
) const;
91 nsISerialEventTarget
* mTarget
;
94 # define NS_DECL_OWNINGTHREAD nsAutoOwningThread _mOwningThread;
95 # define NS_DECL_OWNINGEVENTTARGET nsAutoOwningEventTarget _mOwningThread;
96 # define NS_ASSERT_OWNINGTHREAD(_class) \
97 _mOwningThread.AssertOwnership(#_class " not thread-safe")
98 #else // !MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
100 # define NS_DECL_OWNINGTHREAD /* nothing */
101 # define NS_DECL_OWNINGEVENTTARGET /* nothing */
102 # define NS_ASSERT_OWNINGTHREAD(_class) ((void)0)
104 #endif // MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
106 // Macros for reference-count and constructor logging
108 #if defined(NS_BUILD_REFCNT_LOGGING)
110 # define NS_LOG_ADDREF(_p, _rc, _type, _size) \
111 NS_LogAddRef((_p), (_rc), (_type), (uint32_t)(_size))
113 # define NS_LOG_RELEASE(_p, _rc, _type) NS_LogRelease((_p), (_rc), (_type))
115 # define MOZ_ASSERT_CLASSNAME(_type) \
116 static_assert(std::is_class_v<_type>, \
117 "Token '" #_type "' is not a class type.")
119 # define MOZ_ASSERT_NOT_ISUPPORTS(_type) \
120 static_assert(!std::is_base_of<nsISupports, _type>::value, \
121 "nsISupports classes don't need to call MOZ_COUNT_CTOR or " \
124 // Note that the following constructor/destructor logging macros are redundant
125 // for refcounted objects that log via the NS_LOG_ADDREF/NS_LOG_RELEASE macros.
126 // Refcount logging is preferred.
127 # define MOZ_COUNT_CTOR(_type) \
129 MOZ_ASSERT_CLASSNAME(_type); \
130 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
131 NS_LogCtor((void*)this, #_type, sizeof(*this)); \
134 # define MOZ_COUNT_CTOR_INHERITED(_type, _base) \
136 MOZ_ASSERT_CLASSNAME(_type); \
137 MOZ_ASSERT_CLASSNAME(_base); \
138 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
139 NS_LogCtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
142 # define MOZ_LOG_CTOR(_ptr, _name, _size) \
144 NS_LogCtor((void*)_ptr, _name, _size); \
147 # define MOZ_COUNT_DTOR(_type) \
149 MOZ_ASSERT_CLASSNAME(_type); \
150 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
151 NS_LogDtor((void*)this, #_type, sizeof(*this)); \
154 # define MOZ_COUNT_DTOR_INHERITED(_type, _base) \
156 MOZ_ASSERT_CLASSNAME(_type); \
157 MOZ_ASSERT_CLASSNAME(_base); \
158 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
159 NS_LogDtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
162 # define MOZ_LOG_DTOR(_ptr, _name, _size) \
164 NS_LogDtor((void*)_ptr, _name, _size); \
167 # define MOZ_COUNTED_DEFAULT_CTOR(_type) \
168 _type() { MOZ_COUNT_CTOR(_type); }
170 # define MOZ_COUNTED_DTOR_META(_type, _prefix, _postfix) \
171 _prefix ~_type() _postfix { MOZ_COUNT_DTOR(_type); }
172 # define MOZ_COUNTED_DTOR_NESTED(_type, _nestedName) \
173 ~_type() { MOZ_COUNT_DTOR(_nestedName); }
175 /* nsCOMPtr.h allows these macros to be defined by clients
176 * These logging functions require dynamic_cast<void*>, so they don't
177 * do anything useful if we don't have dynamic_cast<void*>.
178 * Note: The explicit comparison to nullptr is needed to avoid warnings
179 * when _p is a nullptr itself. */
180 # define NSCAP_LOG_ASSIGNMENT(_c, _p) \
181 if (_p != nullptr) NS_LogCOMPtrAddRef((_c), ToSupports(_p))
183 # define NSCAP_LOG_RELEASE(_c, _p) \
184 if (_p) NS_LogCOMPtrRelease((_c), ToSupports(_p))
186 #else /* !NS_BUILD_REFCNT_LOGGING */
188 # define NS_LOG_ADDREF(_p, _rc, _type, _size)
189 # define NS_LOG_RELEASE(_p, _rc, _type)
190 # define MOZ_COUNT_CTOR(_type)
191 # define MOZ_COUNT_CTOR_INHERITED(_type, _base)
192 # define MOZ_LOG_CTOR(_ptr, _name, _size)
193 # define MOZ_COUNT_DTOR(_type)
194 # define MOZ_COUNT_DTOR_INHERITED(_type, _base)
195 # define MOZ_LOG_DTOR(_ptr, _name, _size)
196 # define MOZ_COUNTED_DEFAULT_CTOR(_type) _type() = default;
197 # define MOZ_COUNTED_DTOR_META(_type, _prefix, _postfix) \
198 _prefix ~_type() _postfix = default;
199 # define MOZ_COUNTED_DTOR_NESTED(_type, _nestedName) ~_type() = default;
201 #endif /* NS_BUILD_REFCNT_LOGGING */
203 #define MOZ_COUNTED_DTOR(_type) MOZ_COUNTED_DTOR_META(_type, , )
204 #define MOZ_COUNTED_DTOR_OVERRIDE(_type) \
205 MOZ_COUNTED_DTOR_META(_type, , override)
206 #define MOZ_COUNTED_DTOR_FINAL(_type) MOZ_COUNTED_DTOR_META(_type, , final)
207 #define MOZ_COUNTED_DTOR_VIRTUAL(_type) MOZ_COUNTED_DTOR_META(_type, virtual, )
209 // Support for ISupports classes which interact with cycle collector.
211 #define NS_NUMBER_OF_FLAGS_IN_REFCNT 2
212 #define NS_IN_PURPLE_BUFFER (1 << 0)
213 #define NS_IS_PURPLE (1 << 1)
214 #define NS_REFCOUNT_CHANGE (1 << NS_NUMBER_OF_FLAGS_IN_REFCNT)
215 #define NS_REFCOUNT_VALUE(_val) (_val >> NS_NUMBER_OF_FLAGS_IN_REFCNT)
217 class nsCycleCollectingAutoRefCnt
{
219 typedef void (*Suspect
)(void* aPtr
, nsCycleCollectionParticipant
* aCp
,
220 nsCycleCollectingAutoRefCnt
* aRefCnt
,
221 bool* aShouldDelete
);
223 nsCycleCollectingAutoRefCnt() : mRefCntAndFlags(0) {}
225 explicit nsCycleCollectingAutoRefCnt(uintptr_t aValue
)
226 : mRefCntAndFlags(aValue
<< NS_NUMBER_OF_FLAGS_IN_REFCNT
) {}
228 nsCycleCollectingAutoRefCnt(const nsCycleCollectingAutoRefCnt
&) = delete;
229 void operator=(const nsCycleCollectingAutoRefCnt
&) = delete;
231 template <Suspect suspect
= NS_CycleCollectorSuspect3
>
232 MOZ_ALWAYS_INLINE
uintptr_t incr(nsISupports
* aOwner
) {
233 return incr
<suspect
>(aOwner
, nullptr);
236 template <Suspect suspect
= NS_CycleCollectorSuspect3
>
237 MOZ_ALWAYS_INLINE
uintptr_t incr(void* aOwner
,
238 nsCycleCollectionParticipant
* aCp
) {
239 mRefCntAndFlags
+= NS_REFCOUNT_CHANGE
;
240 mRefCntAndFlags
&= ~NS_IS_PURPLE
;
241 // For incremental cycle collection, use the purple buffer to track objects
242 // that have been AddRef'd.
243 if (!IsInPurpleBuffer()) {
244 mRefCntAndFlags
|= NS_IN_PURPLE_BUFFER
;
245 // Refcount isn't zero, so Suspect won't delete anything.
246 MOZ_ASSERT(get() > 0);
247 suspect(aOwner
, aCp
, this, nullptr);
249 return NS_REFCOUNT_VALUE(mRefCntAndFlags
);
252 MOZ_ALWAYS_INLINE
void stabilizeForDeletion() {
253 // Set refcnt to 1 and mark us to be in the purple buffer.
254 // This way decr won't call suspect again.
255 mRefCntAndFlags
= NS_REFCOUNT_CHANGE
| NS_IN_PURPLE_BUFFER
;
258 template <Suspect suspect
= NS_CycleCollectorSuspect3
>
259 MOZ_ALWAYS_INLINE
uintptr_t decr(nsISupports
* aOwner
,
260 bool* aShouldDelete
= nullptr) {
261 return decr
<suspect
>(aOwner
, nullptr, aShouldDelete
);
264 template <Suspect suspect
= NS_CycleCollectorSuspect3
>
265 MOZ_ALWAYS_INLINE
uintptr_t decr(void* aOwner
,
266 nsCycleCollectionParticipant
* aCp
,
267 bool* aShouldDelete
= nullptr) {
268 MOZ_ASSERT(get() > 0);
269 if (!IsInPurpleBuffer()) {
270 mRefCntAndFlags
-= NS_REFCOUNT_CHANGE
;
271 mRefCntAndFlags
|= (NS_IN_PURPLE_BUFFER
| NS_IS_PURPLE
);
272 uintptr_t retval
= NS_REFCOUNT_VALUE(mRefCntAndFlags
);
273 // Suspect may delete 'aOwner' and 'this'!
274 suspect(aOwner
, aCp
, this, aShouldDelete
);
277 mRefCntAndFlags
-= NS_REFCOUNT_CHANGE
;
278 mRefCntAndFlags
|= (NS_IN_PURPLE_BUFFER
| NS_IS_PURPLE
);
279 return NS_REFCOUNT_VALUE(mRefCntAndFlags
);
282 MOZ_ALWAYS_INLINE
void RemovePurple() {
283 MOZ_ASSERT(IsPurple(), "must be purple");
284 mRefCntAndFlags
&= ~NS_IS_PURPLE
;
287 MOZ_ALWAYS_INLINE
void RemoveFromPurpleBuffer() {
288 MOZ_ASSERT(IsInPurpleBuffer());
289 mRefCntAndFlags
&= ~(NS_IS_PURPLE
| NS_IN_PURPLE_BUFFER
);
292 MOZ_ALWAYS_INLINE
bool IsPurple() const {
293 return !!(mRefCntAndFlags
& NS_IS_PURPLE
);
296 MOZ_ALWAYS_INLINE
bool IsInPurpleBuffer() const {
297 return !!(mRefCntAndFlags
& NS_IN_PURPLE_BUFFER
);
300 MOZ_ALWAYS_INLINE nsrefcnt
get() const {
301 return NS_REFCOUNT_VALUE(mRefCntAndFlags
);
304 MOZ_ALWAYS_INLINE
operator nsrefcnt() const { return get(); }
307 uintptr_t mRefCntAndFlags
;
312 nsAutoRefCnt() : mValue(0) {}
313 explicit nsAutoRefCnt(nsrefcnt aValue
) : mValue(aValue
) {}
315 nsAutoRefCnt(const nsAutoRefCnt
&) = delete;
316 void operator=(const nsAutoRefCnt
&) = delete;
318 // only support prefix increment/decrement
319 nsrefcnt
operator++() { return ++mValue
; }
320 nsrefcnt
operator--() { return --mValue
; }
322 nsrefcnt
operator=(nsrefcnt aValue
) { return (mValue
= aValue
); }
323 operator nsrefcnt() const { return mValue
; }
324 nsrefcnt
get() const { return mValue
; }
326 static const bool isThreadSafe
= false;
329 nsrefcnt
operator++(int) = delete;
330 nsrefcnt
operator--(int) = delete;
335 class ThreadSafeAutoRefCnt
{
337 ThreadSafeAutoRefCnt() : mValue(0) {}
338 explicit ThreadSafeAutoRefCnt(nsrefcnt aValue
) : mValue(aValue
) {}
340 ThreadSafeAutoRefCnt(const ThreadSafeAutoRefCnt
&) = delete;
341 void operator=(const ThreadSafeAutoRefCnt
&) = delete;
343 // only support prefix increment/decrement
344 MOZ_ALWAYS_INLINE nsrefcnt
operator++() {
345 // Memory synchronization is not required when incrementing a
346 // reference count. The first increment of a reference count on a
347 // thread is not important, since the first use of the object on a
348 // thread can happen before it. What is important is the transfer
349 // of the pointer to that thread, which may happen prior to the
350 // first increment on that thread. The necessary memory
351 // synchronization is done by the mechanism that transfers the
352 // pointer between threads.
353 return mValue
.fetch_add(1, std::memory_order_relaxed
) + 1;
355 MOZ_ALWAYS_INLINE nsrefcnt
operator--() {
356 // Since this may be the last release on this thread, we need
357 // release semantics so that prior writes on this thread are visible
358 // to the thread that destroys the object when it reads mValue with
359 // acquire semantics.
360 nsrefcnt result
= mValue
.fetch_sub(1, std::memory_order_release
) - 1;
362 // We're going to destroy the object on this thread, so we need
363 // acquire semantics to synchronize with the memory released by
364 // the last release on other threads, that is, to ensure that
365 // writes prior to that release are now visible on this thread.
367 // TSan doesn't understand std::atomic_thread_fence, so in order
368 // to avoid a false positive for every time a refcounted object
369 // is deleted, we replace the fence with an atomic operation.
370 mValue
.load(std::memory_order_acquire
);
372 std::atomic_thread_fence(std::memory_order_acquire
);
378 MOZ_ALWAYS_INLINE nsrefcnt
operator=(nsrefcnt aValue
) {
379 // Use release semantics since we're not sure what the caller is
381 mValue
.store(aValue
, std::memory_order_release
);
384 MOZ_ALWAYS_INLINE
operator nsrefcnt() const { return get(); }
385 MOZ_ALWAYS_INLINE nsrefcnt
get() const {
386 // Use acquire semantics since we're not sure what the caller is
388 return mValue
.load(std::memory_order_acquire
);
391 static const bool isThreadSafe
= true;
394 nsrefcnt
operator++(int) = delete;
395 nsrefcnt
operator--(int) = delete;
396 std::atomic
<nsrefcnt
> mValue
;
401 // Type trait indicating whether a given XPCOM interface class may only be
402 // implemented by types with threadsafe refcounts. This is specialized for
403 // classes with the `rust_sync` annotation within XPIDL-generated header files,
404 // and checked within macro-generated QueryInterface implementations.
405 template <typename T
>
406 class InterfaceNeedsThreadSafeRefCnt
: public std::false_type
{};
409 } // namespace mozilla
411 ///////////////////////////////////////////////////////////////////////////////
414 * Declare the reference count variable and the implementations of the
415 * AddRef and QueryInterface methods.
418 #define NS_DECL_ISUPPORTS \
420 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
421 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
422 NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
423 using HasThreadSafeRefCnt = std::false_type; \
426 nsAutoRefCnt mRefCnt; \
427 NS_DECL_OWNINGTHREAD \
430 #define NS_DECL_ISUPPORTS_ONEVENTTARGET \
432 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
433 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
434 NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
435 using HasThreadSafeRefCnt = std::false_type; \
438 nsAutoRefCnt mRefCnt; \
439 NS_DECL_OWNINGEVENTTARGET \
442 #define NS_DECL_THREADSAFE_ISUPPORTS \
444 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
445 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
446 NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
447 using HasThreadSafeRefCnt = std::true_type; \
450 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
451 NS_DECL_OWNINGTHREAD \
454 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \
455 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(override) \
456 NS_IMETHOD_(void) DeleteCycleCollectable(void); \
460 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL \
461 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(final) \
462 NS_IMETHOD_(void) DeleteCycleCollectable(void); \
466 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL_DELETECYCLECOLLECTABLE \
467 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(override) \
468 NS_IMETHOD_(void) DeleteCycleCollectable(void) final; \
472 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(...) \
474 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) __VA_ARGS__; \
475 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) __VA_ARGS__; \
476 NS_IMETHOD_(MozExternalRefCountType) Release(void) __VA_ARGS__; \
477 using HasThreadSafeRefCnt = std::false_type; \
480 nsCycleCollectingAutoRefCnt mRefCnt; \
481 NS_DECL_OWNINGTHREAD \
484 ///////////////////////////////////////////////////////////////////////////////
487 * Implementation of AddRef and Release for non-nsISupports (ie "native")
488 * cycle-collected classes that use the purple buffer to avoid leaks.
491 #define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
492 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
493 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
494 NS_ASSERT_OWNINGTHREAD(_class); \
496 mRefCnt.incr(static_cast<void*>(this), \
497 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
498 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
501 #define NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_ADDREF_BODY(_class) \
502 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
503 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
504 NS_ASSERT_OWNINGTHREAD(_class); \
505 nsrefcnt count = mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>( \
506 static_cast<void*>(this), \
507 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
508 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
511 #define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
512 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
513 NS_ASSERT_OWNINGTHREAD(_class); \
515 mRefCnt.decr(static_cast<void*>(this), \
516 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
517 NS_LOG_RELEASE(this, count, #_class); \
520 #define NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_RELEASE_BODY(_class) \
521 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
522 NS_ASSERT_OWNINGTHREAD(_class); \
523 nsrefcnt count = mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>( \
524 static_cast<void*>(this), \
525 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
526 NS_LOG_RELEASE(this, count, #_class); \
529 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(_class) \
530 NS_METHOD_(MozExternalRefCountType) _class::AddRef(void) { \
531 NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
534 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(_class, \
536 NS_METHOD_(MozExternalRefCountType) _class::Release(void) { \
537 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
538 NS_ASSERT_OWNINGTHREAD(_class); \
539 bool shouldDelete = false; \
541 mRefCnt.decr(static_cast<void*>(this), \
542 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant(), \
544 NS_LOG_RELEASE(this, count, #_class); \
546 mRefCnt.incr(static_cast<void*>(this), \
547 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
549 mRefCnt.decr(static_cast<void*>(this), \
550 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
551 if (shouldDelete) { \
552 mRefCnt.stabilizeForDeletion(); \
553 DeleteCycleCollectable(); \
559 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(_class) \
560 NS_METHOD_(MozExternalRefCountType) _class::Release(void) { \
561 NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
564 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(_class) \
565 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_METHOD_)
567 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_VIRTUAL(_class) \
568 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_IMETHOD_)
570 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_INHERITED(_class) \
571 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_METHOD_, \
574 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, _decl, \
577 _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__{ \
578 NS_IMPL_CC_NATIVE_ADDREF_BODY(_class)} _decl(MozExternalRefCountType) \
579 Release(void) __VA_ARGS__ { \
580 NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
582 using HasThreadSafeRefCnt = std::false_type; \
585 nsCycleCollectingAutoRefCnt mRefCnt; \
586 NS_DECL_OWNINGTHREAD \
589 #define NS_INLINE_DECL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_NATIVE_REFCOUNTING( \
592 NS_METHOD_(MozExternalRefCountType) \
593 AddRef(void){NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_ADDREF_BODY( \
594 _class)} NS_METHOD_(MozExternalRefCountType) Release(void) { \
595 NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_RELEASE_BODY(_class) \
597 using HasThreadSafeRefCnt = std::false_type; \
600 nsCycleCollectingAutoRefCnt mRefCnt; \
601 NS_DECL_OWNINGTHREAD \
604 ///////////////////////////////////////////////////////////////////////////////
607 * Use this macro to declare and implement the AddRef & Release methods for a
608 * given non-XPCOM <i>_class</i>.
610 * @param _class The name of the class implementing the method
611 * @param _destroy A statement that is executed when the object's
612 * refcount drops to zero.
613 * @param _decl Name of the macro to be used for the return type of the
614 * AddRef & Release methods (typically NS_IMETHOD_ or NS_METHOD_).
615 * @param optional override Mark the AddRef & Release methods as overrides.
617 #define NS_INLINE_DECL_REFCOUNTING_META(_class, _decl, _destroy, _owning, ...) \
619 _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
620 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
621 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
622 NS_ASSERT_OWNINGTHREAD(_class); \
624 NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
627 _decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
628 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
629 NS_ASSERT_OWNINGTHREAD(_class); \
631 NS_LOG_RELEASE(this, mRefCnt, #_class); \
632 if (mRefCnt == 0) { \
633 mRefCnt = 1; /* stabilize */ \
639 using HasThreadSafeRefCnt = std::false_type; \
642 nsAutoRefCnt mRefCnt; \
646 * Use this macro to declare and implement the AddRef & Release methods for a
647 * given non-XPCOM <i>_class</i>.
649 * @param _class The name of the class implementing the method
650 * @param _destroy A statement that is executed when the object's
651 * refcount drops to zero.
652 * @param optional override Mark the AddRef & Release methods as overrides.
654 #define NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \
655 NS_INLINE_DECL_REFCOUNTING_META(_class, NS_METHOD_, _destroy, \
656 NS_DECL_OWNINGTHREAD, __VA_ARGS__)
659 * Like NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY with AddRef & Release declared
662 #define NS_INLINE_DECL_VIRTUAL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \
663 NS_INLINE_DECL_REFCOUNTING_META(_class, NS_IMETHOD_, _destroy, \
664 NS_DECL_OWNINGTHREAD, __VA_ARGS__)
667 * Use this macro to declare and implement the AddRef & Release methods for a
668 * given non-XPCOM <i>_class</i>.
670 * @param _class The name of the class implementing the method
671 * @param optional override Mark the AddRef & Release methods as overrides.
673 #define NS_INLINE_DECL_REFCOUNTING(_class, ...) \
674 NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, delete (this), __VA_ARGS__)
677 * Like NS_INLINE_DECL_REFCOUNTING, however the thread safety check will work
678 * with any nsISerialEventTarget. This is a workaround until bug 1648031 is
679 * properly resolved. Once this is done, it will be possible to use
680 * NS_INLINE_DECL_REFCOUNTING under all circumstances.
682 #define NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(_class, ...) \
683 NS_INLINE_DECL_REFCOUNTING_META(_class, NS_METHOD_, delete (this), \
684 NS_DECL_OWNINGEVENTTARGET, __VA_ARGS__)
686 #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, _decl, _destroy, \
689 _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
690 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
691 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
692 nsrefcnt count = ++mRefCnt; \
693 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
694 return (nsrefcnt)count; \
696 _decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
697 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
698 nsrefcnt count = --mRefCnt; \
699 NS_LOG_RELEASE(this, count, #_class); \
706 using HasThreadSafeRefCnt = std::true_type; \
709 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
714 * Use this macro to declare and implement the AddRef & Release methods for a
715 * given non-XPCOM <i>_class</i> in a threadsafe manner.
717 * DOES NOT DO REFCOUNT STABILIZATION!
719 * @param _class The name of the class implementing the method
720 * @param _destroy A statement that is executed when the object's
721 * refcount drops to zero.
722 * @param optional override Mark the AddRef & Release methods as overrides.
724 #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(_class, _destroy, \
726 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_METHOD_, _destroy, \
730 * Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY with AddRef & Release
733 #define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING_WITH_DESTROY( \
734 _class, _destroy, ...) \
735 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_IMETHOD_, _destroy, \
739 * Use this macro to declare and implement the AddRef & Release methods for a
740 * given non-XPCOM <i>_class</i> in a threadsafe manner.
742 * DOES NOT DO REFCOUNT STABILIZATION!
744 * @param _class The name of the class implementing the method
745 * @param optional override Mark the AddRef & Release methods as overrides.
747 #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING(_class, ...) \
748 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(_class, delete (this), \
752 * Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING with AddRef & Release declared
755 #define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING(_class, ...) \
756 NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING_WITH_DESTROY( \
757 _class, delete (this), __VA_ARGS__)
759 #if !defined(XPCOM_GLUE_AVOID_NSPR)
760 class nsISerialEventTarget
;
762 // Forward-declare `GetMainThreadSerialEventTarget`, as `nsISupportsImpl.h`
763 // cannot include `nsThreadUtils.h`.
764 nsISerialEventTarget
* GetMainThreadSerialEventTarget();
767 using DeleteVoidFunction
= void(void*);
768 void ProxyDeleteVoid(const char* aRunnableName
,
769 nsISerialEventTarget
* aEventTarget
, void* aSelf
,
770 DeleteVoidFunction
* aDeleteFunc
);
771 } // namespace detail
772 } // namespace mozilla
775 * Helper for _WITH_DELETE_ON_EVENT_TARGET threadsafe refcounting macros which
776 * provides an implementation of `_destroy`
778 # define NS_PROXY_DELETE_TO_EVENT_TARGET(_class, _target) \
779 ::mozilla::detail::ProxyDeleteVoid( \
780 "ProxyDelete " #_class, _target, this, \
781 [](void* self) { delete static_cast<_class*>(self); })
784 * Use this macro to declare and implement the AddRef & Release methods for a
785 * given non-XPCOM <i>_class</i> in a threadsafe manner, ensuring the
786 * destructor runs on a specific nsISerialEventTarget.
788 * DOES NOT DO REFCOUNT STABILIZATION!
790 * @param _class The name of the class implementing the method
791 * @param _target nsISerialEventTarget to run the class's destructor on
792 * @param optional override Mark the AddRef & Release methods as overrides
794 # define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET( \
795 _class, _target, ...) \
796 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY( \
797 _class, NS_PROXY_DELETE_TO_EVENT_TARGET(_class, _target), __VA_ARGS__)
800 * Use this macro to declare and implement the AddRef & Release methods for a
801 * given non-XPCOM <i>_class</i> in a threadsafe manner, ensuring the
802 * destructor runs on the main thread.
804 * DOES NOT DO REFCOUNT STABILIZATION!
806 * @param _class The name of the class implementing the method
807 * @param optional override Mark the AddRef & Release methods as overrides
809 # define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD( \
811 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET( \
812 _class, ::mozilla::GetMainThreadSerialEventTarget(), __VA_ARGS__)
816 * Use this macro in interface classes that you want to be able to reference
817 * using RefPtr, but don't want to provide a refcounting implemenation. The
818 * refcounting implementation can be provided by concrete subclasses that
819 * implement the interface.
821 #define NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING \
823 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; \
824 NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; \
829 * Use this macro to implement the AddRef method for a given <i>_class</i>
830 * @param _class The name of the class implementing the method
831 * @param _name The class name to be passed to XPCOM leak checking
833 #define NS_IMPL_NAMED_ADDREF(_class, _name) \
834 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
835 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
836 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
837 MOZ_ASSERT(_name != nullptr, "Must specify a name"); \
838 if (!mRefCnt.isThreadSafe) NS_ASSERT_OWNINGTHREAD(_class); \
839 nsrefcnt count = ++mRefCnt; \
840 NS_LOG_ADDREF(this, count, _name, sizeof(*this)); \
845 * Use this macro to implement the AddRef method for a given <i>_class</i>
846 * @param _class The name of the class implementing the method
848 #define NS_IMPL_ADDREF(_class) NS_IMPL_NAMED_ADDREF(_class, #_class)
851 * Use this macro to implement the AddRef method for a given <i>_class</i>
852 * implemented as a wholly owned aggregated object intended to implement
853 * interface(s) for its owner
854 * @param _class The name of the class implementing the method
855 * @param _aggregator the owning/containing object
857 #define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \
858 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
859 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
860 MOZ_ASSERT(_aggregator, "null aggregator"); \
861 return (_aggregator)->AddRef(); \
864 // We decrement the refcnt before logging the actual release, but when logging
865 // named things, accessing the name may not be valid after the refcnt
866 // decrement, because the object may have been destroyed on a different thread.
867 // Use this macro to ensure that we have a local copy of the name prior to
868 // the refcnt decrement. (We use a macro to make absolutely sure the name
869 // isn't loaded in builds where it wouldn't be used.)
870 #ifdef NS_BUILD_REFCNT_LOGGING
871 # define NS_LOAD_NAME_BEFORE_RELEASE(localname, _name) \
872 const char* const localname = _name
874 # define NS_LOAD_NAME_BEFORE_RELEASE(localname, _name)
878 * Use this macro to implement the Release method for a given
880 * @param _class The name of the class implementing the method
881 * @param _name The class name to be passed to XPCOM leak checking
882 * @param _destroy A statement that is executed when the object's
883 * refcount drops to zero.
887 * NS_IMPL_RELEASE_WITH_DESTROY(Foo, "Foo", Destroy(this))
893 * to be invoked when the object's refcount drops to zero. This
894 * allows for arbitrary teardown activity to occur (e.g., deallocation
895 * of object allocated with placement new).
897 #define NS_IMPL_NAMED_RELEASE_WITH_DESTROY(_class, _name, _destroy) \
898 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
899 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
900 MOZ_ASSERT(_name != nullptr, "Must specify a name"); \
901 if (!mRefCnt.isThreadSafe) NS_ASSERT_OWNINGTHREAD(_class); \
902 NS_LOAD_NAME_BEFORE_RELEASE(nametmp, _name); \
903 nsrefcnt count = --mRefCnt; \
904 NS_LOG_RELEASE(this, count, nametmp); \
906 mRefCnt = 1; /* stabilize */ \
913 #define NS_IMPL_RELEASE_WITH_DESTROY(_class, _destroy) \
914 NS_IMPL_NAMED_RELEASE_WITH_DESTROY(_class, #_class, _destroy)
917 * Use this macro to implement the Release method for a given <i>_class</i>
918 * @param _class The name of the class implementing the method
920 * A note on the 'stabilization' of the refcnt to one. At that point,
921 * the object's refcount will have gone to zero. The object's
922 * destructor may trigger code that attempts to QueryInterface() and
923 * Release() 'this' again. Doing so will temporarily increment and
924 * decrement the refcount. (Only a logic error would make one try to
925 * keep a permanent hold on 'this'.) To prevent re-entering the
926 * destructor, we make sure that no balanced refcounting can return
927 * the refcount to |0|.
929 #define NS_IMPL_RELEASE(_class) \
930 NS_IMPL_RELEASE_WITH_DESTROY(_class, delete (this))
932 #define NS_IMPL_NAMED_RELEASE(_class, _name) \
933 NS_IMPL_NAMED_RELEASE_WITH_DESTROY(_class, _name, delete (this))
936 * Use this macro to implement the Release method for a given <i>_class</i>
937 * implemented as a wholly owned aggregated object intended to implement
938 * interface(s) for its owner
939 * @param _class The name of the class implementing the method
940 * @param _aggregator the owning/containing object
942 #define NS_IMPL_RELEASE_USING_AGGREGATOR(_class, _aggregator) \
943 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
944 MOZ_ASSERT(_aggregator, "null aggregator"); \
945 return (_aggregator)->Release(); \
948 #define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class) \
949 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
950 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
951 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
952 NS_ASSERT_OWNINGTHREAD(_class); \
953 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
954 nsrefcnt count = mRefCnt.incr(base); \
955 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
959 #define NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(_class) \
960 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
961 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
962 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
963 NS_ASSERT_OWNINGTHREAD(_class); \
964 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
965 nsrefcnt count = mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>(base); \
966 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
970 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy) \
971 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
972 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
973 NS_ASSERT_OWNINGTHREAD(_class); \
974 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
975 nsrefcnt count = mRefCnt.decr(base); \
976 NS_LOG_RELEASE(this, count, #_class); \
979 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { _destroy; }
981 #define NS_IMPL_CYCLE_COLLECTING_RELEASE(_class) \
982 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, delete (this))
984 // _LAST_RELEASE can be useful when certain resources should be released
985 // as soon as we know the object will be deleted.
986 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(_class, _last) \
987 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
988 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
989 NS_ASSERT_OWNINGTHREAD(_class); \
990 bool shouldDelete = false; \
991 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
992 nsrefcnt count = mRefCnt.decr(base, &shouldDelete); \
993 NS_LOG_RELEASE(this, count, #_class); \
995 mRefCnt.incr(base); \
997 mRefCnt.decr(base); \
998 if (shouldDelete) { \
999 mRefCnt.stabilizeForDeletion(); \
1000 DeleteCycleCollectable(); \
1005 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { delete this; }
1007 // This macro is same as NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE
1008 // except it doesn't have DeleteCycleCollectable.
1009 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE_AND_DESTROY( \
1010 _class, _last, _destroy) \
1011 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
1012 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
1013 NS_ASSERT_OWNINGTHREAD(_class); \
1014 bool shouldDelete = false; \
1015 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
1016 nsrefcnt count = mRefCnt.decr(base, &shouldDelete); \
1017 NS_LOG_RELEASE(this, count, #_class); \
1019 mRefCnt.incr(base); \
1021 mRefCnt.decr(base); \
1022 if (shouldDelete) { \
1023 mRefCnt.stabilizeForDeletion(); \
1024 DeleteCycleCollectable(); \
1029 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { _destroy; }
1031 #define NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE(_class) \
1032 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
1033 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
1034 NS_ASSERT_OWNINGTHREAD(_class); \
1035 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
1036 nsrefcnt count = mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>(base); \
1037 NS_LOG_RELEASE(this, count, #_class); \
1040 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { delete this; }
1042 // _LAST_RELEASE can be useful when certain resources should be released
1043 // as soon as we know the object will be deleted.
1044 #define NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE( \
1046 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
1047 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
1048 NS_ASSERT_OWNINGTHREAD(_class); \
1049 bool shouldDelete = false; \
1050 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
1051 nsrefcnt count = mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>( \
1052 base, &shouldDelete); \
1053 NS_LOG_RELEASE(this, count, #_class); \
1055 mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>(base); \
1057 mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>(base); \
1058 if (shouldDelete) { \
1059 mRefCnt.stabilizeForDeletion(); \
1060 DeleteCycleCollectable(); \
1065 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { delete this; }
1067 // _WITH_INTERRUPTABLE_LAST_RELEASE can be useful when certain resources
1068 // should be released as soon as we know the object will be deleted and the
1069 // instance may be cached for reuse.
1070 // _last is performed for cleaning up its resources. Then, _maybeInterrupt is
1071 // tested and when it returns true, this stops deleting the instance.
1072 // (Note that it's not allowed to grab the instance with nsCOMPtr or RefPtr
1073 // during _last is performed.)
1074 // Therefore, when _maybeInterrupt returns true, the instance has to be grabbed
1075 // by nsCOMPtr or RefPtr.
1076 #define NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_INTERRUPTABLE_LAST_RELEASE( \
1077 _class, _last, _maybeInterrupt) \
1078 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
1079 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
1080 NS_ASSERT_OWNINGTHREAD(_class); \
1081 bool shouldDelete = false; \
1082 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
1083 nsrefcnt count = mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>( \
1084 base, &shouldDelete); \
1085 NS_LOG_RELEASE(this, count, #_class); \
1087 mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>(base); \
1089 mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>(base); \
1090 if (_maybeInterrupt) { \
1091 MOZ_ASSERT(mRefCnt.get() > 0); \
1092 return mRefCnt.get(); \
1094 if (shouldDelete) { \
1095 mRefCnt.stabilizeForDeletion(); \
1096 DeleteCycleCollectable(); \
1101 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { delete this; }
1103 // _LAST_RELEASE can be useful when certain resources should be released
1104 // as soon as we know the object will be deleted.
1105 #define NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE_AND_DESTROY( \
1106 _class, _last, _destroy) \
1107 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
1108 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
1109 NS_ASSERT_OWNINGTHREAD(_class); \
1110 bool shouldDelete = false; \
1111 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
1112 nsrefcnt count = mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>( \
1113 base, &shouldDelete); \
1114 NS_LOG_RELEASE(this, count, #_class); \
1116 mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>(base); \
1118 mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>(base); \
1119 if (shouldDelete) { \
1120 mRefCnt.stabilizeForDeletion(); \
1121 DeleteCycleCollectable(); \
1126 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { _destroy; }
1128 ///////////////////////////////////////////////////////////////////////////////
1130 namespace mozilla::detail
{
1132 // Helper which is roughly equivalent to NS_GET_IID, which also performs static
1133 // assertions that `Class` is allowed to implement the given XPCOM interface.
1135 // These assertions are done like this to allow them to be used within the
1136 // `NS_INTERFACE_TABLE_ENTRY` macro, though they are also used in
1137 // `NS_IMPL_QUERY_BODY`.
1138 template <typename Class
, typename Interface
>
1139 constexpr const nsIID
& GetImplementedIID() {
1140 if constexpr (mozilla::detail::InterfaceNeedsThreadSafeRefCnt
<
1141 Interface
>::value
) {
1142 static_assert(Class::HasThreadSafeRefCnt::value
,
1143 "Cannot implement a threadsafe interface with "
1144 "non-threadsafe refcounting!");
1146 return NS_GET_TEMPLATE_IID(Interface
);
1149 template <typename Class
, typename Interface
>
1150 constexpr const nsIID
& kImplementedIID
= GetImplementedIID
<Class
, Interface
>();
1155 * There are two ways of implementing QueryInterface, and we use both:
1157 * Table-driven QueryInterface uses a static table of IID->offset mappings
1158 * and a shared helper function. Using it tends to reduce codesize and improve
1159 * runtime performance (due to processor cache hits).
1161 * Macro-driven QueryInterface generates a QueryInterface function directly
1162 * using common macros. This is necessary if special QueryInterface features
1163 * are being used (such as tearoffs and conditional interfaces).
1165 * These methods can be combined into a table-driven function call followed
1166 * by custom code for tearoffs and conditionals.
1169 struct QITableEntry
{
1170 const nsIID
* iid
; // null indicates end of the QITableEntry array
1174 nsresult NS_FASTCALL
NS_TableDrivenQI(void* aThis
, REFNSIID aIID
,
1175 void** aInstancePtr
,
1176 const QITableEntry
* aEntries
);
1179 * Implement table-driven queryinterface
1182 #define NS_INTERFACE_TABLE_HEAD(_class) \
1183 NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) { \
1184 NS_ASSERTION(aInstancePtr, \
1185 "QueryInterface requires a non-NULL destination!"); \
1186 nsresult rv = NS_ERROR_FAILURE;
1188 #define NS_INTERFACE_TABLE_BEGIN static const QITableEntry table[] = {
1189 #define NS_INTERFACE_TABLE_ENTRY(_class, _interface) \
1190 {&mozilla::detail::kImplementedIID<_class, _interface>, \
1192 reinterpret_cast<char*>(static_cast<_interface*>((_class*)0x1000)) - \
1193 reinterpret_cast<char*>((_class*)0x1000))},
1195 #define NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, _interface, _implClass) \
1196 {&mozilla::detail::kImplementedIID<_class, _interface>, \
1197 int32_t(reinterpret_cast<char*>(static_cast<_interface*>( \
1198 static_cast<_implClass*>((_class*)0x1000))) - \
1199 reinterpret_cast<char*>((_class*)0x1000))},
1202 * XXX: we want to use mozilla::ArrayLength (or equivalent,
1203 * MOZ_ARRAY_LENGTH) in this condition, but some versions of GCC don't
1204 * see that the static_assert condition is actually constant in those
1205 * cases, even with constexpr support (?).
1207 #define NS_INTERFACE_TABLE_END_WITH_PTR(_ptr) \
1211 static_assert((sizeof(table) / sizeof(table[0])) > 1, \
1212 "need at least 1 interface"); \
1213 rv = NS_TableDrivenQI(static_cast<void*>(_ptr), aIID, aInstancePtr, table);
1215 #define NS_INTERFACE_TABLE_END \
1216 NS_INTERFACE_TABLE_END_WITH_PTR \
1219 #define NS_INTERFACE_TABLE_TAIL \
1223 #define NS_INTERFACE_TABLE_TAIL_INHERITING(_baseclass) \
1224 if (NS_SUCCEEDED(rv)) return rv; \
1225 return _baseclass::QueryInterface(aIID, aInstancePtr); \
1228 #define NS_INTERFACE_TABLE_TAIL_USING_AGGREGATOR(_aggregator) \
1229 if (NS_SUCCEEDED(rv)) return rv; \
1230 NS_ASSERTION(_aggregator, "null aggregator"); \
1231 return _aggregator->QueryInterface(aIID, aInstancePtr) \
1235 * This implements query interface with two assumptions: First, the
1236 * class in question implements nsISupports and its own interface and
1237 * nothing else. Second, the implementation of the class's primary
1238 * inheritance chain leads to its own interface.
1240 * @param _class The name of the class implementing the method
1241 * @param _classiiddef The name of the #define symbol that defines the IID
1242 * for the class (e.g. NS_ISUPPORTS_IID)
1245 #define NS_IMPL_QUERY_HEAD(_class) \
1246 NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) { \
1247 NS_ASSERTION(aInstancePtr, \
1248 "QueryInterface requires a non-NULL destination!"); \
1249 nsISupports* foundInterface;
1251 #define NS_IMPL_QUERY_BODY_IID(_interface) \
1252 mozilla::detail::kImplementedIID<std::remove_reference_t<decltype(*this)>, \
1255 #define NS_IMPL_QUERY_BODY(_interface) \
1256 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1257 foundInterface = static_cast<_interface*>(this); \
1260 #define NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) \
1261 if ((condition) && aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1262 foundInterface = static_cast<_interface*>(this); \
1265 #define NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) \
1266 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1267 foundInterface = static_cast<_interface*>(static_cast<_implClass*>(this)); \
1270 // Use this for querying to concrete class types which cannot be unambiguously
1271 // cast to nsISupports. See also nsQueryObject.h.
1272 #define NS_IMPL_QUERY_BODY_CONCRETE(_class) \
1273 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_class))) { \
1274 *aInstancePtr = do_AddRef(static_cast<_class*>(this)).take(); \
1278 #define NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate) \
1279 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1280 foundInterface = static_cast<_interface*>(_aggregate); \
1283 #define NS_IMPL_QUERY_TAIL_GUTS \
1284 foundInterface = 0; \
1286 if (!foundInterface) { \
1287 /* nsISupports should be handled by this point. If not, fail. */ \
1288 MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsISupports))); \
1289 status = NS_NOINTERFACE; \
1291 NS_ADDREF(foundInterface); \
1294 *aInstancePtr = foundInterface; \
1298 #define NS_IMPL_QUERY_TAIL_INHERITING(_baseclass) \
1299 foundInterface = 0; \
1301 if (!foundInterface) \
1302 status = _baseclass::QueryInterface(aIID, (void**)&foundInterface); \
1304 NS_ADDREF(foundInterface); \
1307 *aInstancePtr = foundInterface; \
1311 #define NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) \
1312 foundInterface = 0; \
1314 if (!foundInterface) { \
1315 NS_ASSERTION(_aggregator, "null aggregator"); \
1316 status = _aggregator->QueryInterface(aIID, (void**)&foundInterface); \
1318 NS_ADDREF(foundInterface); \
1321 *aInstancePtr = foundInterface; \
1325 #define NS_IMPL_QUERY_TAIL(_supports_interface) \
1326 NS_IMPL_QUERY_BODY_AMBIGUOUS(nsISupports, _supports_interface) \
1327 NS_IMPL_QUERY_TAIL_GUTS
1330 This is the new scheme. Using this notation now will allow us to switch to
1331 a table driven mechanism when it's ready. Note the difference between this
1332 and the (currently) underlying NS_IMPL_QUERY_INTERFACE mechanism. You must
1333 explicitly mention |nsISupports| when using the interface maps.
1335 #define NS_INTERFACE_MAP_BEGIN(_implClass) NS_IMPL_QUERY_HEAD(_implClass)
1336 #define NS_INTERFACE_MAP_ENTRY(_interface) NS_IMPL_QUERY_BODY(_interface)
1337 #define NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, condition) \
1338 NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition)
1339 #define NS_INTERFACE_MAP_ENTRY_AGGREGATED(_interface, _aggregate) \
1340 NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate)
1342 #define NS_INTERFACE_MAP_END NS_IMPL_QUERY_TAIL_GUTS
1343 #define NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(_interface, _implClass) \
1344 NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass)
1345 #define NS_INTERFACE_MAP_ENTRY_CONCRETE(_class) \
1346 NS_IMPL_QUERY_BODY_CONCRETE(_class)
1347 #define NS_INTERFACE_MAP_END_INHERITING(_baseClass) \
1348 NS_IMPL_QUERY_TAIL_INHERITING(_baseClass)
1349 #define NS_INTERFACE_MAP_END_AGGREGATED(_aggregator) \
1350 NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator)
1352 #define NS_INTERFACE_TABLE0(_class) \
1353 NS_INTERFACE_TABLE_BEGIN \
1354 NS_INTERFACE_TABLE_ENTRY(_class, nsISupports) \
1355 NS_INTERFACE_TABLE_END
1357 #define NS_INTERFACE_TABLE(aClass, ...) \
1358 static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
1359 "Need more arguments to NS_INTERFACE_TABLE"); \
1360 NS_INTERFACE_TABLE_BEGIN \
1361 MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass, ), (__VA_ARGS__)) \
1362 NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(aClass, nsISupports, \
1363 MOZ_ARG_1(__VA_ARGS__)) \
1364 NS_INTERFACE_TABLE_END
1366 #define NS_IMPL_QUERY_INTERFACE0(_class) \
1367 NS_INTERFACE_TABLE_HEAD(_class) \
1368 NS_INTERFACE_TABLE0(_class) \
1369 NS_INTERFACE_TABLE_TAIL
1371 #define NS_IMPL_QUERY_INTERFACE(aClass, ...) \
1372 NS_INTERFACE_TABLE_HEAD(aClass) \
1373 NS_INTERFACE_TABLE(aClass, __VA_ARGS__) \
1374 NS_INTERFACE_TABLE_TAIL
1377 * Declare that you're going to inherit from something that already
1378 * implements nsISupports, but also implements an additional interface, thus
1379 * causing an ambiguity. In this case you don't need another mRefCnt, you
1380 * just need to forward the definitions to the appropriate superclass. E.g.
1382 * class Bar : public Foo, public nsIBar { // both provide nsISupports
1384 * NS_DECL_ISUPPORTS_INHERITED
1385 * ...other nsIBar and Bar methods...
1388 #define NS_DECL_ISUPPORTS_INHERITED \
1390 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
1391 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
1392 NS_IMETHOD_(MozExternalRefCountType) Release(void) override;
1395 * These macros can be used in conjunction with NS_DECL_ISUPPORTS_INHERITED
1396 * to implement the nsISupports methods, forwarding the invocations to a
1397 * superclass that already implements nsISupports. Don't do anything for
1398 * subclasses of Runnable because it deals with subclass logging in its own
1399 * way, using the mName field.
1401 * Note that I didn't make these inlined because they're virtual methods.
1407 class SupportsThreadSafeWeakPtrBase
;
1409 // Don't NS_LOG_{ADDREF,RELEASE} when inheriting from `Runnable*` or types with
1410 // thread safe weak references, as it will generate incorrect refcnt logs due to
1411 // the thread-safe `Upgrade()` call's refcount modifications not calling through
1412 // the derived class' `AddRef()` and `Release()` methods.
1413 template <typename T
>
1414 constexpr bool ShouldLogInheritedRefcnt
=
1415 !std::is_convertible_v
<T
*, Runnable
*> &&
1416 !std::is_base_of_v
<SupportsThreadSafeWeakPtrBase
, T
>;
1418 } // namespace mozilla
1420 #define NS_IMPL_ADDREF_INHERITED_GUTS(Class, Super) \
1421 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(Class) \
1422 nsrefcnt r = Super::AddRef(); \
1423 if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt<Class>) { \
1424 NS_LOG_ADDREF(this, r, #Class, sizeof(*this)); \
1426 return r /* Purposefully no trailing semicolon */
1428 #define NS_IMPL_ADDREF_INHERITED(Class, Super) \
1429 NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) { \
1430 NS_IMPL_ADDREF_INHERITED_GUTS(Class, Super); \
1433 #define NS_IMPL_RELEASE_INHERITED_GUTS(Class, Super) \
1434 nsrefcnt r = Super::Release(); \
1435 if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt<Class>) { \
1436 NS_LOG_RELEASE(this, r, #Class); \
1438 return r /* Purposefully no trailing semicolon */
1440 #define NS_IMPL_RELEASE_INHERITED(Class, Super) \
1441 NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) { \
1442 NS_IMPL_RELEASE_INHERITED_GUTS(Class, Super); \
1446 * As above but not logging the addref/release; needed if the base
1447 * class might be aggregated.
1449 #define NS_IMPL_NONLOGGING_ADDREF_INHERITED(Class, Super) \
1450 NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) { \
1451 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(Class) \
1452 return Super::AddRef(); \
1455 #define NS_IMPL_NONLOGGING_RELEASE_INHERITED(Class, Super) \
1456 NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) { \
1457 return Super::Release(); \
1460 #define NS_INTERFACE_TABLE_INHERITED0(Class) /* Nothing to do here */
1462 #define NS_INTERFACE_TABLE_INHERITED(aClass, ...) \
1463 static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
1464 "Need more arguments to NS_INTERFACE_TABLE_INHERITED"); \
1465 NS_INTERFACE_TABLE_BEGIN \
1466 MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass, ), (__VA_ARGS__)) \
1467 NS_INTERFACE_TABLE_END
1469 #define NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, ...) \
1470 NS_INTERFACE_TABLE_HEAD(aClass) \
1471 NS_INTERFACE_TABLE_INHERITED(aClass, __VA_ARGS__) \
1472 NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper)
1475 * Convenience macros for implementing all nsISupports methods for
1477 * @param _class The name of the class implementing the method
1478 * @param _classiiddef The name of the #define symbol that defines the IID
1479 * for the class (e.g. NS_ISUPPORTS_IID)
1482 #define NS_IMPL_ISUPPORTS0(_class) \
1483 NS_IMPL_ADDREF(_class) \
1484 NS_IMPL_RELEASE(_class) \
1485 NS_IMPL_QUERY_INTERFACE0(_class)
1487 #define NS_IMPL_ISUPPORTS(aClass, ...) \
1488 NS_IMPL_ADDREF(aClass) \
1489 NS_IMPL_RELEASE(aClass) \
1490 NS_IMPL_QUERY_INTERFACE(aClass, __VA_ARGS__)
1492 // When possible, prefer NS_INLINE_DECL_REFCOUNTING_INHERITED to
1493 // NS_IMPL_ISUPPORTS_INHERITED0.
1494 #define NS_IMPL_ISUPPORTS_INHERITED0(aClass, aSuper) \
1495 NS_INTERFACE_TABLE_HEAD(aClass) \
1496 NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper) \
1497 NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \
1498 NS_IMPL_RELEASE_INHERITED(aClass, aSuper)
1500 #define NS_IMPL_ISUPPORTS_INHERITED(aClass, aSuper, ...) \
1501 NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, __VA_ARGS__) \
1502 NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \
1503 NS_IMPL_RELEASE_INHERITED(aClass, aSuper)
1506 * A macro to declare and implement inherited addref/release for a class which
1507 * doesn't have or need to override QueryInterface from its base class.
1509 * Note: This macro always overrides the `AddRef` and `Release` methods,
1510 * including when refcount logging is disabled, meaning that it will implement
1511 * the `AddRef` or `Release` method from another virtual base class.
1513 #define NS_INLINE_DECL_REFCOUNTING_INHERITED(Class, Super) \
1514 NS_IMETHOD_(MozExternalRefCountType) AddRef() override { \
1515 NS_IMPL_ADDREF_INHERITED_GUTS(Class, Super); \
1517 NS_IMETHOD_(MozExternalRefCountType) Release() override { \
1518 NS_IMPL_RELEASE_INHERITED_GUTS(Class, Super); \
1522 * Macro to glue together a QI that starts with an interface table
1523 * and segues into an interface map (e.g. it uses singleton classinfo
1526 #define NS_INTERFACE_TABLE_TO_MAP_SEGUE \
1527 if (rv == NS_OK) return rv; \
1528 nsISupports* foundInterface;
1530 ///////////////////////////////////////////////////////////////////////////////
1533 * Macro to generate nsIClassInfo methods for classes which do not have
1534 * corresponding nsIFactory implementations.
1536 #define NS_IMPL_THREADSAFE_CI(_class) \
1538 _class::GetInterfaces(nsTArray<nsIID>& _array) { \
1539 return NS_CI_INTERFACE_GETTER_NAME(_class)(_array); \
1543 _class::GetScriptableHelper(nsIXPCScriptable** _retval) { \
1544 *_retval = nullptr; \
1549 _class::GetContractID(nsACString& _contractID) { \
1550 _contractID.SetIsVoid(true); \
1555 _class::GetClassDescription(nsACString& _classDescription) { \
1556 _classDescription.SetIsVoid(true); \
1561 _class::GetClassID(nsCID** _classID) { \
1562 *_classID = nullptr; \
1567 _class::GetFlags(uint32_t* _flags) { \
1568 *_flags = nsIClassInfo::THREADSAFE; \
1573 _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) { \
1574 return NS_ERROR_NOT_AVAILABLE; \