Backed out changeset bd51857879db (bug 1862957) for causing WakeLock related failures...
[gecko.git] / xpcom / base / nsISupportsImpl.h
blob27ff85b385c81b5b91f462f5d7ccebdd6d336983
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__
11 #include "nscore.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 */
17 #endif
19 #include "nsDebug.h"
20 #include "nsXPCOM.h"
21 #include <atomic>
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 {
49 public:
50 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.
57 template <int N>
58 void AssertOwnership(const char (&aMsg)[N]) const {
59 AssertCurrentThreadOwnsMe(aMsg);
62 bool IsCurrentThread() const;
64 private:
65 void AssertCurrentThreadOwnsMe(const char* aMsg) const;
67 void* mThread;
70 class nsISerialEventTarget;
71 class nsAutoOwningEventTarget {
72 public:
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.
81 template <int N>
82 void AssertOwnership(const char (&aMsg)[N]) const {
83 AssertCurrentThreadOwnsMe(aMsg);
86 bool IsCurrentThread() const;
88 private:
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 " \
122 "MOZ_COUNT_DTOR");
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) \
128 do { \
129 MOZ_ASSERT_CLASSNAME(_type); \
130 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
131 NS_LogCtor((void*)this, #_type, sizeof(*this)); \
132 } while (0)
134 # define MOZ_COUNT_CTOR_INHERITED(_type, _base) \
135 do { \
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)); \
140 } while (0)
142 # define MOZ_LOG_CTOR(_ptr, _name, _size) \
143 do { \
144 NS_LogCtor((void*)_ptr, _name, _size); \
145 } while (0)
147 # define MOZ_COUNT_DTOR(_type) \
148 do { \
149 MOZ_ASSERT_CLASSNAME(_type); \
150 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
151 NS_LogDtor((void*)this, #_type, sizeof(*this)); \
152 } while (0)
154 # define MOZ_COUNT_DTOR_INHERITED(_type, _base) \
155 do { \
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)); \
160 } while (0)
162 # define MOZ_LOG_DTOR(_ptr, _name, _size) \
163 do { \
164 NS_LogDtor((void*)_ptr, _name, _size); \
165 } while (0)
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 #ifdef HAVE_64BIT_BUILD
212 # define NS_NUMBER_OF_FLAGS_IN_REFCNT 3
213 # define NS_IS_ON_MAINTHREAD (1 << 2)
214 #else
215 # define NS_NUMBER_OF_FLAGS_IN_REFCNT 2
216 #endif
218 #define NS_IN_PURPLE_BUFFER (1 << 0)
219 #define NS_IS_PURPLE (1 << 1)
220 #define NS_REFCOUNT_CHANGE (1 << NS_NUMBER_OF_FLAGS_IN_REFCNT)
221 #define NS_REFCOUNT_VALUE(_val) (_val >> NS_NUMBER_OF_FLAGS_IN_REFCNT)
223 class nsCycleCollectingAutoRefCnt {
224 public:
225 typedef void (*Suspect)(void* aPtr, nsCycleCollectionParticipant* aCp,
226 nsCycleCollectingAutoRefCnt* aRefCnt,
227 bool* aShouldDelete);
229 nsCycleCollectingAutoRefCnt() : mRefCntAndFlags(0) {}
231 explicit nsCycleCollectingAutoRefCnt(uintptr_t aValue)
232 : mRefCntAndFlags(aValue << NS_NUMBER_OF_FLAGS_IN_REFCNT) {}
234 nsCycleCollectingAutoRefCnt(const nsCycleCollectingAutoRefCnt&) = delete;
235 void operator=(const nsCycleCollectingAutoRefCnt&) = delete;
237 MOZ_ALWAYS_INLINE uintptr_t incr(nsISupports* aOwner) {
238 return incr(aOwner, nullptr);
241 MOZ_ALWAYS_INLINE uintptr_t incr(void* aOwner,
242 nsCycleCollectionParticipant* aCp) {
243 mRefCntAndFlags += NS_REFCOUNT_CHANGE;
244 mRefCntAndFlags &= ~NS_IS_PURPLE;
245 // For incremental cycle collection, use the purple buffer to track objects
246 // that have been AddRef'd.
247 if (!IsInPurpleBuffer()) {
248 mRefCntAndFlags |= NS_IN_PURPLE_BUFFER;
249 // Refcount isn't zero, so Suspect won't delete anything.
250 MOZ_ASSERT(get() > 0);
251 NS_CycleCollectorSuspect3(aOwner, aCp, this, nullptr);
253 return NS_REFCOUNT_VALUE(mRefCntAndFlags);
256 MOZ_ALWAYS_INLINE void stabilizeForDeletion() {
257 // Set refcnt to 1 and mark us to be in the purple buffer.
258 // This way decr won't call suspect again.
259 mRefCntAndFlags = NS_REFCOUNT_CHANGE | NS_IN_PURPLE_BUFFER;
262 MOZ_ALWAYS_INLINE uintptr_t decr(nsISupports* aOwner,
263 bool* aShouldDelete = nullptr) {
264 return decr(aOwner, nullptr, aShouldDelete);
267 MOZ_ALWAYS_INLINE uintptr_t decr(void* aOwner,
268 nsCycleCollectionParticipant* aCp,
269 bool* aShouldDelete = nullptr) {
270 MOZ_ASSERT(get() > 0);
271 if (!IsInPurpleBuffer()) {
272 mRefCntAndFlags -= NS_REFCOUNT_CHANGE;
273 mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE);
274 uintptr_t retval = NS_REFCOUNT_VALUE(mRefCntAndFlags);
275 // Suspect may delete 'aOwner' and 'this'!
276 NS_CycleCollectorSuspect3(aOwner, aCp, this, aShouldDelete);
277 return retval;
279 mRefCntAndFlags -= NS_REFCOUNT_CHANGE;
280 mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE);
281 return NS_REFCOUNT_VALUE(mRefCntAndFlags);
284 MOZ_ALWAYS_INLINE void RemovePurple() {
285 MOZ_ASSERT(IsPurple(), "must be purple");
286 mRefCntAndFlags &= ~NS_IS_PURPLE;
289 MOZ_ALWAYS_INLINE void RemoveFromPurpleBuffer() {
290 MOZ_ASSERT(IsInPurpleBuffer());
291 mRefCntAndFlags &= ~(NS_IS_PURPLE | NS_IN_PURPLE_BUFFER);
294 MOZ_ALWAYS_INLINE bool IsPurple() const {
295 return !!(mRefCntAndFlags & NS_IS_PURPLE);
298 MOZ_ALWAYS_INLINE bool IsInPurpleBuffer() const {
299 return !!(mRefCntAndFlags & NS_IN_PURPLE_BUFFER);
302 // Cycle collected objects can only be used on a single thread, so if we ever
303 // see an object on the main thread, it will always be on the main thread.
304 // The cycle collector then uses this information to utilize faster nursery
305 // purple buffer on the main thread.
306 // The method works only on 64 bit systems.
307 MOZ_ALWAYS_INLINE void SetIsOnMainThread() {
308 #ifdef HAVE_64BIT_BUILD
309 mRefCntAndFlags |= NS_IS_ON_MAINTHREAD;
310 #endif
313 #ifdef HAVE_64BIT_BUILD
314 // The NS_IS_ON_MAINTHREAD flag only exists on 64-bit builds.
315 MOZ_ALWAYS_INLINE bool IsOnMainThread() {
316 return !!(mRefCntAndFlags & NS_IS_ON_MAINTHREAD);
318 #endif
320 MOZ_ALWAYS_INLINE nsrefcnt get() const {
321 return NS_REFCOUNT_VALUE(mRefCntAndFlags);
324 MOZ_ALWAYS_INLINE operator nsrefcnt() const { return get(); }
326 private:
327 uintptr_t mRefCntAndFlags;
330 class nsAutoRefCnt {
331 public:
332 nsAutoRefCnt() : mValue(0) {}
333 explicit nsAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {}
335 nsAutoRefCnt(const nsAutoRefCnt&) = delete;
336 void operator=(const nsAutoRefCnt&) = delete;
338 // only support prefix increment/decrement
339 nsrefcnt operator++() { return ++mValue; }
340 nsrefcnt operator--() { return --mValue; }
342 nsrefcnt operator=(nsrefcnt aValue) { return (mValue = aValue); }
343 operator nsrefcnt() const { return mValue; }
344 nsrefcnt get() const { return mValue; }
346 static const bool isThreadSafe = false;
348 private:
349 nsrefcnt operator++(int) = delete;
350 nsrefcnt operator--(int) = delete;
351 nsrefcnt mValue;
354 namespace mozilla {
355 class ThreadSafeAutoRefCnt {
356 public:
357 ThreadSafeAutoRefCnt() : mValue(0) {}
358 explicit ThreadSafeAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {}
360 ThreadSafeAutoRefCnt(const ThreadSafeAutoRefCnt&) = delete;
361 void operator=(const ThreadSafeAutoRefCnt&) = delete;
363 // only support prefix increment/decrement
364 MOZ_ALWAYS_INLINE nsrefcnt operator++() {
365 // Memory synchronization is not required when incrementing a
366 // reference count. The first increment of a reference count on a
367 // thread is not important, since the first use of the object on a
368 // thread can happen before it. What is important is the transfer
369 // of the pointer to that thread, which may happen prior to the
370 // first increment on that thread. The necessary memory
371 // synchronization is done by the mechanism that transfers the
372 // pointer between threads.
373 return mValue.fetch_add(1, std::memory_order_relaxed) + 1;
375 MOZ_ALWAYS_INLINE nsrefcnt operator--() {
376 // Since this may be the last release on this thread, we need
377 // release semantics so that prior writes on this thread are visible
378 // to the thread that destroys the object when it reads mValue with
379 // acquire semantics.
380 nsrefcnt result = mValue.fetch_sub(1, std::memory_order_release) - 1;
381 if (result == 0) {
382 // We're going to destroy the object on this thread, so we need
383 // acquire semantics to synchronize with the memory released by
384 // the last release on other threads, that is, to ensure that
385 // writes prior to that release are now visible on this thread.
386 #ifdef MOZ_TSAN
387 // TSan doesn't understand std::atomic_thread_fence, so in order
388 // to avoid a false positive for every time a refcounted object
389 // is deleted, we replace the fence with an atomic operation.
390 mValue.load(std::memory_order_acquire);
391 #else
392 std::atomic_thread_fence(std::memory_order_acquire);
393 #endif
395 return result;
398 MOZ_ALWAYS_INLINE nsrefcnt operator=(nsrefcnt aValue) {
399 // Use release semantics since we're not sure what the caller is
400 // doing.
401 mValue.store(aValue, std::memory_order_release);
402 return aValue;
404 MOZ_ALWAYS_INLINE operator nsrefcnt() const { return get(); }
405 MOZ_ALWAYS_INLINE nsrefcnt get() const {
406 // Use acquire semantics since we're not sure what the caller is
407 // doing.
408 return mValue.load(std::memory_order_acquire);
411 static const bool isThreadSafe = true;
413 private:
414 nsrefcnt operator++(int) = delete;
415 nsrefcnt operator--(int) = delete;
416 std::atomic<nsrefcnt> mValue;
419 namespace detail {
421 // Type trait indicating whether a given XPCOM interface class may only be
422 // implemented by types with threadsafe refcounts. This is specialized for
423 // classes with the `rust_sync` annotation within XPIDL-generated header files,
424 // and checked within macro-generated QueryInterface implementations.
425 template <typename T>
426 class InterfaceNeedsThreadSafeRefCnt : public std::false_type {};
429 } // namespace mozilla
431 ///////////////////////////////////////////////////////////////////////////////
434 * Declare the reference count variable and the implementations of the
435 * AddRef and QueryInterface methods.
438 #define NS_DECL_ISUPPORTS \
439 public: \
440 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
441 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
442 NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
443 using HasThreadSafeRefCnt = std::false_type; \
445 protected: \
446 nsAutoRefCnt mRefCnt; \
447 NS_DECL_OWNINGTHREAD \
448 public:
450 #define NS_DECL_ISUPPORTS_ONEVENTTARGET \
451 public: \
452 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
453 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
454 NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
455 using HasThreadSafeRefCnt = std::false_type; \
457 protected: \
458 nsAutoRefCnt mRefCnt; \
459 NS_DECL_OWNINGEVENTTARGET \
460 public:
462 #define NS_DECL_THREADSAFE_ISUPPORTS \
463 public: \
464 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
465 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
466 NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
467 using HasThreadSafeRefCnt = std::true_type; \
469 protected: \
470 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
471 NS_DECL_OWNINGTHREAD \
472 public:
474 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \
475 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(override) \
476 NS_IMETHOD_(void) DeleteCycleCollectable(void); \
478 public:
480 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL \
481 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(final) \
482 NS_IMETHOD_(void) DeleteCycleCollectable(void); \
484 public:
486 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(...) \
487 public: \
488 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) __VA_ARGS__; \
489 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) __VA_ARGS__; \
490 NS_IMETHOD_(MozExternalRefCountType) Release(void) __VA_ARGS__; \
491 using HasThreadSafeRefCnt = std::false_type; \
493 protected: \
494 nsCycleCollectingAutoRefCnt mRefCnt; \
495 NS_DECL_OWNINGTHREAD \
496 public:
498 ///////////////////////////////////////////////////////////////////////////////
501 * Implementation of AddRef and Release for non-nsISupports (ie "native")
502 * cycle-collected classes that use the purple buffer to avoid leaks.
505 #define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
506 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
507 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
508 NS_ASSERT_OWNINGTHREAD(_class); \
509 nsrefcnt count = \
510 mRefCnt.incr(static_cast<void*>(this), \
511 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
512 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
513 return count;
515 #define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
516 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
517 NS_ASSERT_OWNINGTHREAD(_class); \
518 nsrefcnt count = \
519 mRefCnt.decr(static_cast<void*>(this), \
520 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
521 NS_LOG_RELEASE(this, count, #_class); \
522 return count;
524 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(_class) \
525 NS_METHOD_(MozExternalRefCountType) _class::AddRef(void) { \
526 NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
529 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(_class, \
530 _last) \
531 NS_METHOD_(MozExternalRefCountType) _class::Release(void) { \
532 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
533 NS_ASSERT_OWNINGTHREAD(_class); \
534 bool shouldDelete = false; \
535 nsrefcnt count = \
536 mRefCnt.decr(static_cast<void*>(this), \
537 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant(), \
538 &shouldDelete); \
539 NS_LOG_RELEASE(this, count, #_class); \
540 if (count == 0) { \
541 mRefCnt.incr(static_cast<void*>(this), \
542 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
543 _last; \
544 mRefCnt.decr(static_cast<void*>(this), \
545 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
546 if (shouldDelete) { \
547 mRefCnt.stabilizeForDeletion(); \
548 DeleteCycleCollectable(); \
551 return count; \
554 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(_class) \
555 NS_METHOD_(MozExternalRefCountType) _class::Release(void) { \
556 NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
559 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(_class) \
560 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_METHOD_)
562 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_VIRTUAL(_class) \
563 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_IMETHOD_)
565 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_INHERITED(_class) \
566 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_METHOD_, \
567 override)
569 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, _decl, \
570 ...) \
571 public: \
572 _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__{ \
573 NS_IMPL_CC_NATIVE_ADDREF_BODY(_class)} _decl(MozExternalRefCountType) \
574 Release(void) __VA_ARGS__ { \
575 NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
577 using HasThreadSafeRefCnt = std::false_type; \
579 protected: \
580 nsCycleCollectingAutoRefCnt mRefCnt; \
581 NS_DECL_OWNINGTHREAD \
582 public:
584 ///////////////////////////////////////////////////////////////////////////////
587 * Use this macro to declare and implement the AddRef & Release methods for a
588 * given non-XPCOM <i>_class</i>.
590 * @param _class The name of the class implementing the method
591 * @param _destroy A statement that is executed when the object's
592 * refcount drops to zero.
593 * @param _decl Name of the macro to be used for the return type of the
594 * AddRef & Release methods (typically NS_IMETHOD_ or NS_METHOD_).
595 * @param optional override Mark the AddRef & Release methods as overrides.
597 #define NS_INLINE_DECL_REFCOUNTING_META(_class, _decl, _destroy, _owning, ...) \
598 public: \
599 _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
600 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
601 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
602 NS_ASSERT_OWNINGTHREAD(_class); \
603 ++mRefCnt; \
604 NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
605 return mRefCnt; \
607 _decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
608 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
609 NS_ASSERT_OWNINGTHREAD(_class); \
610 --mRefCnt; \
611 NS_LOG_RELEASE(this, mRefCnt, #_class); \
612 if (mRefCnt == 0) { \
613 mRefCnt = 1; /* stabilize */ \
614 _destroy; \
615 return 0; \
617 return mRefCnt; \
619 using HasThreadSafeRefCnt = std::false_type; \
621 protected: \
622 nsAutoRefCnt mRefCnt; \
623 _owning public:
626 * Use this macro to declare and implement the AddRef & Release methods for a
627 * given non-XPCOM <i>_class</i>.
629 * @param _class The name of the class implementing the method
630 * @param _destroy A statement that is executed when the object's
631 * refcount drops to zero.
632 * @param optional override Mark the AddRef & Release methods as overrides.
634 #define NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \
635 NS_INLINE_DECL_REFCOUNTING_META(_class, NS_METHOD_, _destroy, \
636 NS_DECL_OWNINGTHREAD, __VA_ARGS__)
639 * Like NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY with AddRef & Release declared
640 * virtual.
642 #define NS_INLINE_DECL_VIRTUAL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \
643 NS_INLINE_DECL_REFCOUNTING_META(_class, NS_IMETHOD_, _destroy, \
644 NS_DECL_OWNINGTHREAD, __VA_ARGS__)
647 * Use this macro to declare and implement the AddRef & Release methods for a
648 * given non-XPCOM <i>_class</i>.
650 * @param _class The name of the class implementing the method
651 * @param optional override Mark the AddRef & Release methods as overrides.
653 #define NS_INLINE_DECL_REFCOUNTING(_class, ...) \
654 NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, delete (this), __VA_ARGS__)
657 * Like NS_INLINE_DECL_REFCOUNTING, however the thread safety check will work
658 * with any nsISerialEventTarget. This is a workaround until bug 1648031 is
659 * properly resolved. Once this is done, it will be possible to use
660 * NS_INLINE_DECL_REFCOUNTING under all circumstances.
662 #define NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(_class, ...) \
663 NS_INLINE_DECL_REFCOUNTING_META(_class, NS_METHOD_, delete (this), \
664 NS_DECL_OWNINGEVENTTARGET, __VA_ARGS__)
666 #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, _decl, _destroy, \
667 ...) \
668 public: \
669 _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
670 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
671 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
672 nsrefcnt count = ++mRefCnt; \
673 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
674 return (nsrefcnt)count; \
676 _decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
677 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
678 nsrefcnt count = --mRefCnt; \
679 NS_LOG_RELEASE(this, count, #_class); \
680 if (count == 0) { \
681 _destroy; \
682 return 0; \
684 return count; \
686 using HasThreadSafeRefCnt = std::true_type; \
688 protected: \
689 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
691 public:
694 * Use this macro to declare and implement the AddRef & Release methods for a
695 * given non-XPCOM <i>_class</i> in a threadsafe manner.
697 * DOES NOT DO REFCOUNT STABILIZATION!
699 * @param _class The name of the class implementing the method
700 * @param _destroy A statement that is executed when the object's
701 * refcount drops to zero.
702 * @param optional override Mark the AddRef & Release methods as overrides.
704 #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(_class, _destroy, \
705 ...) \
706 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_METHOD_, _destroy, \
707 __VA_ARGS__)
710 * Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY with AddRef & Release
711 * declared virtual.
713 #define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING_WITH_DESTROY( \
714 _class, _destroy, ...) \
715 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_IMETHOD_, _destroy, \
716 __VA_ARGS__)
719 * Use this macro to declare and implement the AddRef & Release methods for a
720 * given non-XPCOM <i>_class</i> in a threadsafe manner.
722 * DOES NOT DO REFCOUNT STABILIZATION!
724 * @param _class The name of the class implementing the method
725 * @param optional override Mark the AddRef & Release methods as overrides.
727 #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING(_class, ...) \
728 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(_class, delete (this), \
729 __VA_ARGS__)
732 * Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING with AddRef & Release declared
733 * virtual.
735 #define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING(_class, ...) \
736 NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING_WITH_DESTROY( \
737 _class, delete (this), __VA_ARGS__)
739 #if !defined(XPCOM_GLUE_AVOID_NSPR)
740 class nsISerialEventTarget;
741 namespace mozilla {
742 // Forward-declare `GetMainThreadSerialEventTarget`, as `nsISupportsImpl.h`
743 // cannot include `nsThreadUtils.h`.
744 nsISerialEventTarget* GetMainThreadSerialEventTarget();
746 namespace detail {
747 using DeleteVoidFunction = void(void*);
748 void ProxyDeleteVoid(const char* aRunnableName,
749 nsISerialEventTarget* aEventTarget, void* aSelf,
750 DeleteVoidFunction* aDeleteFunc);
751 } // namespace detail
752 } // namespace mozilla
755 * Helper for _WITH_DELETE_ON_EVENT_TARGET threadsafe refcounting macros which
756 * provides an implementation of `_destroy`
758 # define NS_PROXY_DELETE_TO_EVENT_TARGET(_class, _target) \
759 ::mozilla::detail::ProxyDeleteVoid( \
760 "ProxyDelete " #_class, _target, this, \
761 [](void* self) { delete static_cast<_class*>(self); })
764 * Use this macro to declare and implement the AddRef & Release methods for a
765 * given non-XPCOM <i>_class</i> in a threadsafe manner, ensuring the
766 * destructor runs on a specific nsISerialEventTarget.
768 * DOES NOT DO REFCOUNT STABILIZATION!
770 * @param _class The name of the class implementing the method
771 * @param _target nsISerialEventTarget to run the class's destructor on
772 * @param optional override Mark the AddRef & Release methods as overrides
774 # define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET( \
775 _class, _target, ...) \
776 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY( \
777 _class, NS_PROXY_DELETE_TO_EVENT_TARGET(_class, _target), __VA_ARGS__)
780 * Use this macro to declare and implement the AddRef & Release methods for a
781 * given non-XPCOM <i>_class</i> in a threadsafe manner, ensuring the
782 * destructor runs on the main thread.
784 * DOES NOT DO REFCOUNT STABILIZATION!
786 * @param _class The name of the class implementing the method
787 * @param optional override Mark the AddRef & Release methods as overrides
789 # define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD( \
790 _class, ...) \
791 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET( \
792 _class, ::mozilla::GetMainThreadSerialEventTarget(), __VA_ARGS__)
793 #endif
796 * Use this macro in interface classes that you want to be able to reference
797 * using RefPtr, but don't want to provide a refcounting implemenation. The
798 * refcounting implementation can be provided by concrete subclasses that
799 * implement the interface.
801 #define NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING \
802 public: \
803 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; \
804 NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; \
806 public:
809 * Use this macro to implement the AddRef method for a given <i>_class</i>
810 * @param _class The name of the class implementing the method
811 * @param _name The class name to be passed to XPCOM leak checking
813 #define NS_IMPL_NAMED_ADDREF(_class, _name) \
814 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
815 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
816 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
817 MOZ_ASSERT(_name != nullptr, "Must specify a name"); \
818 if (!mRefCnt.isThreadSafe) NS_ASSERT_OWNINGTHREAD(_class); \
819 nsrefcnt count = ++mRefCnt; \
820 NS_LOG_ADDREF(this, count, _name, sizeof(*this)); \
821 return count; \
825 * Use this macro to implement the AddRef method for a given <i>_class</i>
826 * @param _class The name of the class implementing the method
828 #define NS_IMPL_ADDREF(_class) NS_IMPL_NAMED_ADDREF(_class, #_class)
831 * Use this macro to implement the AddRef method for a given <i>_class</i>
832 * implemented as a wholly owned aggregated object intended to implement
833 * interface(s) for its owner
834 * @param _class The name of the class implementing the method
835 * @param _aggregator the owning/containing object
837 #define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \
838 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
839 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
840 MOZ_ASSERT(_aggregator, "null aggregator"); \
841 return (_aggregator)->AddRef(); \
844 // We decrement the refcnt before logging the actual release, but when logging
845 // named things, accessing the name may not be valid after the refcnt
846 // decrement, because the object may have been destroyed on a different thread.
847 // Use this macro to ensure that we have a local copy of the name prior to
848 // the refcnt decrement. (We use a macro to make absolutely sure the name
849 // isn't loaded in builds where it wouldn't be used.)
850 #ifdef NS_BUILD_REFCNT_LOGGING
851 # define NS_LOAD_NAME_BEFORE_RELEASE(localname, _name) \
852 const char* const localname = _name
853 #else
854 # define NS_LOAD_NAME_BEFORE_RELEASE(localname, _name)
855 #endif
858 * Use this macro to implement the Release method for a given
859 * <i>_class</i>.
860 * @param _class The name of the class implementing the method
861 * @param _name The class name to be passed to XPCOM leak checking
862 * @param _destroy A statement that is executed when the object's
863 * refcount drops to zero.
865 * For example,
867 * NS_IMPL_RELEASE_WITH_DESTROY(Foo, "Foo", Destroy(this))
869 * will cause
871 * Destroy(this);
873 * to be invoked when the object's refcount drops to zero. This
874 * allows for arbitrary teardown activity to occur (e.g., deallocation
875 * of object allocated with placement new).
877 #define NS_IMPL_NAMED_RELEASE_WITH_DESTROY(_class, _name, _destroy) \
878 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
879 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
880 MOZ_ASSERT(_name != nullptr, "Must specify a name"); \
881 if (!mRefCnt.isThreadSafe) NS_ASSERT_OWNINGTHREAD(_class); \
882 NS_LOAD_NAME_BEFORE_RELEASE(nametmp, _name); \
883 nsrefcnt count = --mRefCnt; \
884 NS_LOG_RELEASE(this, count, nametmp); \
885 if (count == 0) { \
886 mRefCnt = 1; /* stabilize */ \
887 _destroy; \
888 return 0; \
890 return count; \
893 #define NS_IMPL_RELEASE_WITH_DESTROY(_class, _destroy) \
894 NS_IMPL_NAMED_RELEASE_WITH_DESTROY(_class, #_class, _destroy)
897 * Use this macro to implement the Release method for a given <i>_class</i>
898 * @param _class The name of the class implementing the method
900 * A note on the 'stabilization' of the refcnt to one. At that point,
901 * the object's refcount will have gone to zero. The object's
902 * destructor may trigger code that attempts to QueryInterface() and
903 * Release() 'this' again. Doing so will temporarily increment and
904 * decrement the refcount. (Only a logic error would make one try to
905 * keep a permanent hold on 'this'.) To prevent re-entering the
906 * destructor, we make sure that no balanced refcounting can return
907 * the refcount to |0|.
909 #define NS_IMPL_RELEASE(_class) \
910 NS_IMPL_RELEASE_WITH_DESTROY(_class, delete (this))
912 #define NS_IMPL_NAMED_RELEASE(_class, _name) \
913 NS_IMPL_NAMED_RELEASE_WITH_DESTROY(_class, _name, delete (this))
916 * Use this macro to implement the Release method for a given <i>_class</i>
917 * implemented as a wholly owned aggregated object intended to implement
918 * interface(s) for its owner
919 * @param _class The name of the class implementing the method
920 * @param _aggregator the owning/containing object
922 #define NS_IMPL_RELEASE_USING_AGGREGATOR(_class, _aggregator) \
923 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
924 MOZ_ASSERT(_aggregator, "null aggregator"); \
925 return (_aggregator)->Release(); \
928 #define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class) \
929 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
930 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
931 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
932 NS_ASSERT_OWNINGTHREAD(_class); \
933 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
934 nsrefcnt count = mRefCnt.incr(base); \
935 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
936 return count; \
939 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy) \
940 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
941 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
942 NS_ASSERT_OWNINGTHREAD(_class); \
943 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
944 nsrefcnt count = mRefCnt.decr(base); \
945 NS_LOG_RELEASE(this, count, #_class); \
946 return count; \
948 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { _destroy; }
950 #define NS_IMPL_CYCLE_COLLECTING_RELEASE(_class) \
951 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, delete (this))
953 // _LAST_RELEASE can be useful when certain resources should be released
954 // as soon as we know the object will be deleted.
955 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(_class, _last) \
956 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
957 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
958 NS_ASSERT_OWNINGTHREAD(_class); \
959 bool shouldDelete = false; \
960 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
961 nsrefcnt count = mRefCnt.decr(base, &shouldDelete); \
962 NS_LOG_RELEASE(this, count, #_class); \
963 if (count == 0) { \
964 mRefCnt.incr(base); \
965 _last; \
966 mRefCnt.decr(base); \
967 if (shouldDelete) { \
968 mRefCnt.stabilizeForDeletion(); \
969 DeleteCycleCollectable(); \
972 return count; \
974 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { delete this; }
976 // This macro is same as NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE
977 // except it doesn't have DeleteCycleCollectable.
978 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE_AND_DESTROY( \
979 _class, _last, _destroy) \
980 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
981 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
982 NS_ASSERT_OWNINGTHREAD(_class); \
983 bool shouldDelete = false; \
984 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
985 nsrefcnt count = mRefCnt.decr(base, &shouldDelete); \
986 NS_LOG_RELEASE(this, count, #_class); \
987 if (count == 0) { \
988 mRefCnt.incr(base); \
989 _last; \
990 mRefCnt.decr(base); \
991 if (shouldDelete) { \
992 mRefCnt.stabilizeForDeletion(); \
993 DeleteCycleCollectable(); \
996 return count; \
998 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { _destroy; }
1000 // _WITH_INTERRUPTABLE_LAST_RELEASE can be useful when certain resources
1001 // should be released as soon as we know the object will be deleted and the
1002 // instance may be cached for reuse.
1003 // _last is performed for cleaning up its resources. Then, _maybeInterrupt is
1004 // tested and when it returns true, this stops deleting the instance.
1005 // (Note that it's not allowed to grab the instance with nsCOMPtr or RefPtr
1006 // during _last is performed.)
1007 // Therefore, when _maybeInterrupt returns true, the instance has to be grabbed
1008 // by nsCOMPtr or RefPtr.
1009 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_INTERRUPTABLE_LAST_RELEASE( \
1010 _class, _last, _maybeInterrupt) \
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); \
1018 if (count == 0) { \
1019 mRefCnt.incr(base); \
1020 _last; \
1021 mRefCnt.decr(base); \
1022 if (_maybeInterrupt) { \
1023 MOZ_ASSERT(mRefCnt.get() > 0); \
1024 return mRefCnt.get(); \
1026 if (shouldDelete) { \
1027 mRefCnt.stabilizeForDeletion(); \
1028 DeleteCycleCollectable(); \
1031 return count; \
1033 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { delete this; }
1035 ///////////////////////////////////////////////////////////////////////////////
1037 namespace mozilla::detail {
1039 // Helper which is roughly equivalent to NS_GET_IID, which also performs static
1040 // assertions that `Class` is allowed to implement the given XPCOM interface.
1042 // These assertions are done like this to allow them to be used within the
1043 // `NS_INTERFACE_TABLE_ENTRY` macro, though they are also used in
1044 // `NS_IMPL_QUERY_BODY`.
1045 template <typename Class, typename Interface>
1046 constexpr const nsIID& GetImplementedIID() {
1047 if constexpr (mozilla::detail::InterfaceNeedsThreadSafeRefCnt<
1048 Interface>::value) {
1049 static_assert(Class::HasThreadSafeRefCnt::value,
1050 "Cannot implement a threadsafe interface with "
1051 "non-threadsafe refcounting!");
1053 return NS_GET_TEMPLATE_IID(Interface);
1056 template <typename Class, typename Interface>
1057 constexpr const nsIID& kImplementedIID = GetImplementedIID<Class, Interface>();
1062 * There are two ways of implementing QueryInterface, and we use both:
1064 * Table-driven QueryInterface uses a static table of IID->offset mappings
1065 * and a shared helper function. Using it tends to reduce codesize and improve
1066 * runtime performance (due to processor cache hits).
1068 * Macro-driven QueryInterface generates a QueryInterface function directly
1069 * using common macros. This is necessary if special QueryInterface features
1070 * are being used (such as tearoffs and conditional interfaces).
1072 * These methods can be combined into a table-driven function call followed
1073 * by custom code for tearoffs and conditionals.
1076 struct QITableEntry {
1077 const nsIID* iid; // null indicates end of the QITableEntry array
1078 int32_t offset;
1081 nsresult NS_FASTCALL NS_TableDrivenQI(void* aThis, REFNSIID aIID,
1082 void** aInstancePtr,
1083 const QITableEntry* aEntries);
1086 * Implement table-driven queryinterface
1089 #define NS_INTERFACE_TABLE_HEAD(_class) \
1090 NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) { \
1091 NS_ASSERTION(aInstancePtr, \
1092 "QueryInterface requires a non-NULL destination!"); \
1093 nsresult rv = NS_ERROR_FAILURE;
1095 #define NS_INTERFACE_TABLE_BEGIN static const QITableEntry table[] = {
1096 #define NS_INTERFACE_TABLE_ENTRY(_class, _interface) \
1097 {&mozilla::detail::kImplementedIID<_class, _interface>, \
1098 int32_t( \
1099 reinterpret_cast<char*>(static_cast<_interface*>((_class*)0x1000)) - \
1100 reinterpret_cast<char*>((_class*)0x1000))},
1102 #define NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, _interface, _implClass) \
1103 {&mozilla::detail::kImplementedIID<_class, _interface>, \
1104 int32_t(reinterpret_cast<char*>(static_cast<_interface*>( \
1105 static_cast<_implClass*>((_class*)0x1000))) - \
1106 reinterpret_cast<char*>((_class*)0x1000))},
1109 * XXX: we want to use mozilla::ArrayLength (or equivalent,
1110 * MOZ_ARRAY_LENGTH) in this condition, but some versions of GCC don't
1111 * see that the static_assert condition is actually constant in those
1112 * cases, even with constexpr support (?).
1114 #define NS_INTERFACE_TABLE_END_WITH_PTR(_ptr) \
1115 { nullptr, 0 } \
1118 static_assert((sizeof(table) / sizeof(table[0])) > 1, \
1119 "need at least 1 interface"); \
1120 rv = NS_TableDrivenQI(static_cast<void*>(_ptr), aIID, aInstancePtr, table);
1122 #define NS_INTERFACE_TABLE_END \
1123 NS_INTERFACE_TABLE_END_WITH_PTR \
1124 (this)
1126 #define NS_INTERFACE_TABLE_TAIL \
1127 return rv; \
1130 #define NS_INTERFACE_TABLE_TAIL_INHERITING(_baseclass) \
1131 if (NS_SUCCEEDED(rv)) return rv; \
1132 return _baseclass::QueryInterface(aIID, aInstancePtr); \
1135 #define NS_INTERFACE_TABLE_TAIL_USING_AGGREGATOR(_aggregator) \
1136 if (NS_SUCCEEDED(rv)) return rv; \
1137 NS_ASSERTION(_aggregator, "null aggregator"); \
1138 return _aggregator->QueryInterface(aIID, aInstancePtr) \
1142 * This implements query interface with two assumptions: First, the
1143 * class in question implements nsISupports and its own interface and
1144 * nothing else. Second, the implementation of the class's primary
1145 * inheritance chain leads to its own interface.
1147 * @param _class The name of the class implementing the method
1148 * @param _classiiddef The name of the #define symbol that defines the IID
1149 * for the class (e.g. NS_ISUPPORTS_IID)
1152 #define NS_IMPL_QUERY_HEAD(_class) \
1153 NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) { \
1154 NS_ASSERTION(aInstancePtr, \
1155 "QueryInterface requires a non-NULL destination!"); \
1156 nsISupports* foundInterface;
1158 #define NS_IMPL_QUERY_BODY_IID(_interface) \
1159 mozilla::detail::kImplementedIID<std::remove_reference_t<decltype(*this)>, \
1160 _interface>
1162 #define NS_IMPL_QUERY_BODY(_interface) \
1163 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1164 foundInterface = static_cast<_interface*>(this); \
1165 else
1167 #define NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) \
1168 if ((condition) && aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1169 foundInterface = static_cast<_interface*>(this); \
1170 else
1172 #define NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) \
1173 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1174 foundInterface = static_cast<_interface*>(static_cast<_implClass*>(this)); \
1175 else
1177 // Use this for querying to concrete class types which cannot be unambiguously
1178 // cast to nsISupports. See also nsQueryObject.h.
1179 #define NS_IMPL_QUERY_BODY_CONCRETE(_class) \
1180 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_class))) { \
1181 *aInstancePtr = do_AddRef(static_cast<_class*>(this)).take(); \
1182 return NS_OK; \
1183 } else
1185 #define NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate) \
1186 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1187 foundInterface = static_cast<_interface*>(_aggregate); \
1188 else
1190 #define NS_IMPL_QUERY_TAIL_GUTS \
1191 foundInterface = 0; \
1192 nsresult status; \
1193 if (!foundInterface) { \
1194 /* nsISupports should be handled by this point. If not, fail. */ \
1195 MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsISupports))); \
1196 status = NS_NOINTERFACE; \
1197 } else { \
1198 NS_ADDREF(foundInterface); \
1199 status = NS_OK; \
1201 *aInstancePtr = foundInterface; \
1202 return status; \
1205 #define NS_IMPL_QUERY_TAIL_INHERITING(_baseclass) \
1206 foundInterface = 0; \
1207 nsresult status; \
1208 if (!foundInterface) \
1209 status = _baseclass::QueryInterface(aIID, (void**)&foundInterface); \
1210 else { \
1211 NS_ADDREF(foundInterface); \
1212 status = NS_OK; \
1214 *aInstancePtr = foundInterface; \
1215 return status; \
1218 #define NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) \
1219 foundInterface = 0; \
1220 nsresult status; \
1221 if (!foundInterface) { \
1222 NS_ASSERTION(_aggregator, "null aggregator"); \
1223 status = _aggregator->QueryInterface(aIID, (void**)&foundInterface); \
1224 } else { \
1225 NS_ADDREF(foundInterface); \
1226 status = NS_OK; \
1228 *aInstancePtr = foundInterface; \
1229 return status; \
1232 #define NS_IMPL_QUERY_TAIL(_supports_interface) \
1233 NS_IMPL_QUERY_BODY_AMBIGUOUS(nsISupports, _supports_interface) \
1234 NS_IMPL_QUERY_TAIL_GUTS
1237 This is the new scheme. Using this notation now will allow us to switch to
1238 a table driven mechanism when it's ready. Note the difference between this
1239 and the (currently) underlying NS_IMPL_QUERY_INTERFACE mechanism. You must
1240 explicitly mention |nsISupports| when using the interface maps.
1242 #define NS_INTERFACE_MAP_BEGIN(_implClass) NS_IMPL_QUERY_HEAD(_implClass)
1243 #define NS_INTERFACE_MAP_ENTRY(_interface) NS_IMPL_QUERY_BODY(_interface)
1244 #define NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, condition) \
1245 NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition)
1246 #define NS_INTERFACE_MAP_ENTRY_AGGREGATED(_interface, _aggregate) \
1247 NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate)
1249 #define NS_INTERFACE_MAP_END NS_IMPL_QUERY_TAIL_GUTS
1250 #define NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(_interface, _implClass) \
1251 NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass)
1252 #define NS_INTERFACE_MAP_ENTRY_CONCRETE(_class) \
1253 NS_IMPL_QUERY_BODY_CONCRETE(_class)
1254 #define NS_INTERFACE_MAP_END_INHERITING(_baseClass) \
1255 NS_IMPL_QUERY_TAIL_INHERITING(_baseClass)
1256 #define NS_INTERFACE_MAP_END_AGGREGATED(_aggregator) \
1257 NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator)
1259 #define NS_INTERFACE_TABLE0(_class) \
1260 NS_INTERFACE_TABLE_BEGIN \
1261 NS_INTERFACE_TABLE_ENTRY(_class, nsISupports) \
1262 NS_INTERFACE_TABLE_END
1264 #define NS_INTERFACE_TABLE(aClass, ...) \
1265 static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
1266 "Need more arguments to NS_INTERFACE_TABLE"); \
1267 NS_INTERFACE_TABLE_BEGIN \
1268 MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass, ), (__VA_ARGS__)) \
1269 NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(aClass, nsISupports, \
1270 MOZ_ARG_1(__VA_ARGS__)) \
1271 NS_INTERFACE_TABLE_END
1273 #define NS_IMPL_QUERY_INTERFACE0(_class) \
1274 NS_INTERFACE_TABLE_HEAD(_class) \
1275 NS_INTERFACE_TABLE0(_class) \
1276 NS_INTERFACE_TABLE_TAIL
1278 #define NS_IMPL_QUERY_INTERFACE(aClass, ...) \
1279 NS_INTERFACE_TABLE_HEAD(aClass) \
1280 NS_INTERFACE_TABLE(aClass, __VA_ARGS__) \
1281 NS_INTERFACE_TABLE_TAIL
1284 * Declare that you're going to inherit from something that already
1285 * implements nsISupports, but also implements an additional interface, thus
1286 * causing an ambiguity. In this case you don't need another mRefCnt, you
1287 * just need to forward the definitions to the appropriate superclass. E.g.
1289 * class Bar : public Foo, public nsIBar { // both provide nsISupports
1290 * public:
1291 * NS_DECL_ISUPPORTS_INHERITED
1292 * ...other nsIBar and Bar methods...
1293 * };
1295 #define NS_DECL_ISUPPORTS_INHERITED \
1296 public: \
1297 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
1298 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
1299 NS_IMETHOD_(MozExternalRefCountType) Release(void) override;
1302 * These macros can be used in conjunction with NS_DECL_ISUPPORTS_INHERITED
1303 * to implement the nsISupports methods, forwarding the invocations to a
1304 * superclass that already implements nsISupports. Don't do anything for
1305 * subclasses of Runnable because it deals with subclass logging in its own
1306 * way, using the mName field.
1308 * Note that I didn't make these inlined because they're virtual methods.
1311 namespace mozilla {
1312 class Runnable;
1313 namespace detail {
1314 class SupportsThreadSafeWeakPtrBase;
1316 // Don't NS_LOG_{ADDREF,RELEASE} when inheriting from `Runnable*` or types with
1317 // thread safe weak references, as it will generate incorrect refcnt logs due to
1318 // the thread-safe `Upgrade()` call's refcount modifications not calling through
1319 // the derived class' `AddRef()` and `Release()` methods.
1320 template <typename T>
1321 constexpr bool ShouldLogInheritedRefcnt =
1322 !std::is_convertible_v<T*, Runnable*> &&
1323 !std::is_base_of_v<SupportsThreadSafeWeakPtrBase, T>;
1325 } // namespace mozilla
1327 #define NS_IMPL_ADDREF_INHERITED_GUTS(Class, Super) \
1328 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(Class) \
1329 nsrefcnt r = Super::AddRef(); \
1330 if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt<Class>) { \
1331 NS_LOG_ADDREF(this, r, #Class, sizeof(*this)); \
1333 return r /* Purposefully no trailing semicolon */
1335 #define NS_IMPL_ADDREF_INHERITED(Class, Super) \
1336 NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) { \
1337 NS_IMPL_ADDREF_INHERITED_GUTS(Class, Super); \
1340 #define NS_IMPL_RELEASE_INHERITED_GUTS(Class, Super) \
1341 nsrefcnt r = Super::Release(); \
1342 if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt<Class>) { \
1343 NS_LOG_RELEASE(this, r, #Class); \
1345 return r /* Purposefully no trailing semicolon */
1347 #define NS_IMPL_RELEASE_INHERITED(Class, Super) \
1348 NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) { \
1349 NS_IMPL_RELEASE_INHERITED_GUTS(Class, Super); \
1353 * As above but not logging the addref/release; needed if the base
1354 * class might be aggregated.
1356 #define NS_IMPL_NONLOGGING_ADDREF_INHERITED(Class, Super) \
1357 NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) { \
1358 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(Class) \
1359 return Super::AddRef(); \
1362 #define NS_IMPL_NONLOGGING_RELEASE_INHERITED(Class, Super) \
1363 NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) { \
1364 return Super::Release(); \
1367 #define NS_INTERFACE_TABLE_INHERITED0(Class) /* Nothing to do here */
1369 #define NS_INTERFACE_TABLE_INHERITED(aClass, ...) \
1370 static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
1371 "Need more arguments to NS_INTERFACE_TABLE_INHERITED"); \
1372 NS_INTERFACE_TABLE_BEGIN \
1373 MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass, ), (__VA_ARGS__)) \
1374 NS_INTERFACE_TABLE_END
1376 #define NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, ...) \
1377 NS_INTERFACE_TABLE_HEAD(aClass) \
1378 NS_INTERFACE_TABLE_INHERITED(aClass, __VA_ARGS__) \
1379 NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper)
1382 * Convenience macros for implementing all nsISupports methods for
1383 * a simple class.
1384 * @param _class The name of the class implementing the method
1385 * @param _classiiddef The name of the #define symbol that defines the IID
1386 * for the class (e.g. NS_ISUPPORTS_IID)
1389 #define NS_IMPL_ISUPPORTS0(_class) \
1390 NS_IMPL_ADDREF(_class) \
1391 NS_IMPL_RELEASE(_class) \
1392 NS_IMPL_QUERY_INTERFACE0(_class)
1394 #define NS_IMPL_ISUPPORTS(aClass, ...) \
1395 NS_IMPL_ADDREF(aClass) \
1396 NS_IMPL_RELEASE(aClass) \
1397 NS_IMPL_QUERY_INTERFACE(aClass, __VA_ARGS__)
1399 // When possible, prefer NS_INLINE_DECL_REFCOUNTING_INHERITED to
1400 // NS_IMPL_ISUPPORTS_INHERITED0.
1401 #define NS_IMPL_ISUPPORTS_INHERITED0(aClass, aSuper) \
1402 NS_INTERFACE_TABLE_HEAD(aClass) \
1403 NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper) \
1404 NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \
1405 NS_IMPL_RELEASE_INHERITED(aClass, aSuper)
1407 #define NS_IMPL_ISUPPORTS_INHERITED(aClass, aSuper, ...) \
1408 NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, __VA_ARGS__) \
1409 NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \
1410 NS_IMPL_RELEASE_INHERITED(aClass, aSuper)
1413 * A macro to declare and implement inherited addref/release for a class which
1414 * doesn't have or need to override QueryInterface from its base class.
1416 * Note: This macro always overrides the `AddRef` and `Release` methods,
1417 * including when refcount logging is disabled, meaning that it will implement
1418 * the `AddRef` or `Release` method from another virtual base class.
1420 #define NS_INLINE_DECL_REFCOUNTING_INHERITED(Class, Super) \
1421 NS_IMETHOD_(MozExternalRefCountType) AddRef() override { \
1422 NS_IMPL_ADDREF_INHERITED_GUTS(Class, Super); \
1424 NS_IMETHOD_(MozExternalRefCountType) Release() override { \
1425 NS_IMPL_RELEASE_INHERITED_GUTS(Class, Super); \
1429 * Macro to glue together a QI that starts with an interface table
1430 * and segues into an interface map (e.g. it uses singleton classinfo
1431 * or tearoffs).
1433 #define NS_INTERFACE_TABLE_TO_MAP_SEGUE \
1434 if (rv == NS_OK) return rv; \
1435 nsISupports* foundInterface;
1437 ///////////////////////////////////////////////////////////////////////////////
1440 * Macro to generate nsIClassInfo methods for classes which do not have
1441 * corresponding nsIFactory implementations.
1443 #define NS_IMPL_THREADSAFE_CI(_class) \
1444 NS_IMETHODIMP \
1445 _class::GetInterfaces(nsTArray<nsIID>& _array) { \
1446 return NS_CI_INTERFACE_GETTER_NAME(_class)(_array); \
1449 NS_IMETHODIMP \
1450 _class::GetScriptableHelper(nsIXPCScriptable** _retval) { \
1451 *_retval = nullptr; \
1452 return NS_OK; \
1455 NS_IMETHODIMP \
1456 _class::GetContractID(nsACString& _contractID) { \
1457 _contractID.SetIsVoid(true); \
1458 return NS_OK; \
1461 NS_IMETHODIMP \
1462 _class::GetClassDescription(nsACString& _classDescription) { \
1463 _classDescription.SetIsVoid(true); \
1464 return NS_OK; \
1467 NS_IMETHODIMP \
1468 _class::GetClassID(nsCID** _classID) { \
1469 *_classID = nullptr; \
1470 return NS_OK; \
1473 NS_IMETHODIMP \
1474 _class::GetFlags(uint32_t* _flags) { \
1475 *_flags = nsIClassInfo::THREADSAFE; \
1476 return NS_OK; \
1479 NS_IMETHODIMP \
1480 _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) { \
1481 return NS_ERROR_NOT_AVAILABLE; \
1484 #endif