Bug 1919083 - [ci] Enable os-integration variant for more suites, r=jmaher
[gecko.git] / xpcom / base / nsISupportsImpl.h
blob8a4ef05181f5d8ff2133c6717d515f62ccfde88c
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();
75 nsAutoOwningEventTarget(const nsAutoOwningEventTarget& aOther);
77 // Per https://en.cppreference.com/w/cpp/language/move_constructor
78 // there's no implicitly-declared move constructor if there are user-declared
79 // copy constructors, and we have one, immediately above.
81 nsAutoOwningEventTarget& operator=(const nsAutoOwningEventTarget& aRhs);
83 // Per https://en.cppreference.com/w/cpp/language/move_assignment
84 // there's no implicitly-declared move assignment operator if there are
85 // user-declared copy assignment operators, and we have one, immediately
86 // above.
88 ~nsAutoOwningEventTarget();
90 // We move the actual assertion checks out-of-line to minimize code bloat,
91 // but that means we have to pass a non-literal string to MOZ_CRASH_UNSAFE.
92 // To make that more safe, the public interface requires a literal string
93 // and passes that to the private interface; we can then be assured that we
94 // effectively are passing a literal string to MOZ_CRASH_UNSAFE.
95 template <int N>
96 void AssertOwnership(const char (&aMsg)[N]) const {
97 AssertCurrentThreadOwnsMe(aMsg);
100 bool IsCurrentThread() const;
102 private:
103 void AssertCurrentThreadOwnsMe(const char* aMsg) const;
105 // A raw pointer to avoid nsCOMPtr.h dependency.
106 nsISerialEventTarget* mTarget;
109 # define NS_DECL_OWNINGTHREAD nsAutoOwningThread _mOwningThread;
110 # define NS_DECL_OWNINGEVENTTARGET nsAutoOwningEventTarget _mOwningThread;
111 # define NS_ASSERT_OWNINGTHREAD(_class) \
112 _mOwningThread.AssertOwnership(#_class " not thread-safe")
113 #else // !MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
115 # define NS_DECL_OWNINGTHREAD /* nothing */
116 # define NS_DECL_OWNINGEVENTTARGET /* nothing */
117 # define NS_ASSERT_OWNINGTHREAD(_class) ((void)0)
119 #endif // MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
121 // Macros for reference-count and constructor logging
123 #if defined(NS_BUILD_REFCNT_LOGGING)
125 # define NS_LOG_ADDREF(_p, _rc, _type, _size) \
126 NS_LogAddRef((_p), (_rc), (_type), (uint32_t)(_size))
128 # define NS_LOG_RELEASE(_p, _rc, _type) NS_LogRelease((_p), (_rc), (_type))
130 # define MOZ_ASSERT_CLASSNAME(_type) \
131 static_assert(std::is_class_v<_type>, \
132 "Token '" #_type "' is not a class type.")
134 # define MOZ_ASSERT_NOT_ISUPPORTS(_type) \
135 static_assert(!std::is_base_of<nsISupports, _type>::value, \
136 "nsISupports classes don't need to call MOZ_COUNT_CTOR or " \
137 "MOZ_COUNT_DTOR");
139 // Note that the following constructor/destructor logging macros are redundant
140 // for refcounted objects that log via the NS_LOG_ADDREF/NS_LOG_RELEASE macros.
141 // Refcount logging is preferred.
142 # define MOZ_COUNT_CTOR(_type) \
143 do { \
144 MOZ_ASSERT_CLASSNAME(_type); \
145 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
146 NS_LogCtor((void*)this, #_type, sizeof(*this)); \
147 } while (0)
149 # define MOZ_COUNT_CTOR_INHERITED(_type, _base) \
150 do { \
151 MOZ_ASSERT_CLASSNAME(_type); \
152 MOZ_ASSERT_CLASSNAME(_base); \
153 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
154 NS_LogCtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
155 } while (0)
157 # define MOZ_LOG_CTOR(_ptr, _name, _size) \
158 do { \
159 NS_LogCtor((void*)_ptr, _name, _size); \
160 } while (0)
162 # define MOZ_COUNT_DTOR(_type) \
163 do { \
164 MOZ_ASSERT_CLASSNAME(_type); \
165 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
166 NS_LogDtor((void*)this, #_type, sizeof(*this)); \
167 } while (0)
169 # define MOZ_COUNT_DTOR_INHERITED(_type, _base) \
170 do { \
171 MOZ_ASSERT_CLASSNAME(_type); \
172 MOZ_ASSERT_CLASSNAME(_base); \
173 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
174 NS_LogDtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
175 } while (0)
177 # define MOZ_LOG_DTOR(_ptr, _name, _size) \
178 do { \
179 NS_LogDtor((void*)_ptr, _name, _size); \
180 } while (0)
182 # define MOZ_COUNTED_DEFAULT_CTOR(_type) \
183 _type() { MOZ_COUNT_CTOR(_type); }
185 # define MOZ_COUNTED_DTOR_META(_type, _prefix, _postfix) \
186 _prefix ~_type() _postfix { MOZ_COUNT_DTOR(_type); }
187 # define MOZ_COUNTED_DTOR_NESTED(_type, _nestedName) \
188 ~_type() { MOZ_COUNT_DTOR(_nestedName); }
190 /* nsCOMPtr.h allows these macros to be defined by clients
191 * These logging functions require dynamic_cast<void*>, so they don't
192 * do anything useful if we don't have dynamic_cast<void*>.
193 * Note: The explicit comparison to nullptr is needed to avoid warnings
194 * when _p is a nullptr itself. */
195 # define NSCAP_LOG_ASSIGNMENT(_c, _p) \
196 if (_p != nullptr) NS_LogCOMPtrAddRef((_c), ToSupports(_p))
198 # define NSCAP_LOG_RELEASE(_c, _p) \
199 if (_p) NS_LogCOMPtrRelease((_c), ToSupports(_p))
201 #else /* !NS_BUILD_REFCNT_LOGGING */
203 # define NS_LOG_ADDREF(_p, _rc, _type, _size)
204 # define NS_LOG_RELEASE(_p, _rc, _type)
205 # define MOZ_COUNT_CTOR(_type)
206 # define MOZ_COUNT_CTOR_INHERITED(_type, _base)
207 # define MOZ_LOG_CTOR(_ptr, _name, _size)
208 # define MOZ_COUNT_DTOR(_type)
209 # define MOZ_COUNT_DTOR_INHERITED(_type, _base)
210 # define MOZ_LOG_DTOR(_ptr, _name, _size)
211 # define MOZ_COUNTED_DEFAULT_CTOR(_type) _type() = default;
212 # define MOZ_COUNTED_DTOR_META(_type, _prefix, _postfix) \
213 _prefix ~_type() _postfix = default;
214 # define MOZ_COUNTED_DTOR_NESTED(_type, _nestedName) ~_type() = default;
216 #endif /* NS_BUILD_REFCNT_LOGGING */
218 #define MOZ_COUNTED_DTOR(_type) MOZ_COUNTED_DTOR_META(_type, , )
219 #define MOZ_COUNTED_DTOR_OVERRIDE(_type) \
220 MOZ_COUNTED_DTOR_META(_type, , override)
221 #define MOZ_COUNTED_DTOR_FINAL(_type) MOZ_COUNTED_DTOR_META(_type, , final)
222 #define MOZ_COUNTED_DTOR_VIRTUAL(_type) MOZ_COUNTED_DTOR_META(_type, virtual, )
224 // Support for ISupports classes which interact with cycle collector.
226 #ifdef HAVE_64BIT_BUILD
227 # define NS_NUMBER_OF_FLAGS_IN_REFCNT 3
228 # define NS_IS_ON_MAINTHREAD (1 << 2)
229 #else
230 # define NS_NUMBER_OF_FLAGS_IN_REFCNT 2
231 #endif
233 #define NS_IN_PURPLE_BUFFER (1 << 0)
234 #define NS_IS_PURPLE (1 << 1)
235 #define NS_REFCOUNT_CHANGE (1 << NS_NUMBER_OF_FLAGS_IN_REFCNT)
236 #define NS_REFCOUNT_VALUE(_val) (_val >> NS_NUMBER_OF_FLAGS_IN_REFCNT)
238 class nsCycleCollectingAutoRefCnt {
239 public:
240 typedef void (*Suspect)(void* aPtr, nsCycleCollectionParticipant* aCp,
241 nsCycleCollectingAutoRefCnt* aRefCnt,
242 bool* aShouldDelete);
244 nsCycleCollectingAutoRefCnt() : mRefCntAndFlags(0) {}
246 explicit nsCycleCollectingAutoRefCnt(uintptr_t aValue)
247 : mRefCntAndFlags(aValue << NS_NUMBER_OF_FLAGS_IN_REFCNT) {}
249 nsCycleCollectingAutoRefCnt(const nsCycleCollectingAutoRefCnt&) = delete;
250 void operator=(const nsCycleCollectingAutoRefCnt&) = delete;
252 MOZ_ALWAYS_INLINE uintptr_t incr(nsISupports* aOwner) {
253 return incr(aOwner, nullptr);
256 MOZ_ALWAYS_INLINE uintptr_t incr(void* aOwner,
257 nsCycleCollectionParticipant* aCp) {
258 mRefCntAndFlags += NS_REFCOUNT_CHANGE;
259 mRefCntAndFlags &= ~NS_IS_PURPLE;
260 // For incremental cycle collection, use the purple buffer to track objects
261 // that have been AddRef'd.
262 if (!IsInPurpleBuffer()) {
263 mRefCntAndFlags |= NS_IN_PURPLE_BUFFER;
264 // Refcount isn't zero, so Suspect won't delete anything.
265 MOZ_ASSERT(get() > 0);
266 NS_CycleCollectorSuspect3(aOwner, aCp, this, nullptr);
268 return NS_REFCOUNT_VALUE(mRefCntAndFlags);
271 MOZ_ALWAYS_INLINE void stabilizeForDeletion() {
272 // Set refcnt to 1 and mark us to be in the purple buffer.
273 // This way decr won't call suspect again.
274 mRefCntAndFlags = NS_REFCOUNT_CHANGE | NS_IN_PURPLE_BUFFER;
277 MOZ_ALWAYS_INLINE uintptr_t decr(nsISupports* aOwner,
278 bool* aShouldDelete = nullptr) {
279 return decr(aOwner, nullptr, aShouldDelete);
282 MOZ_ALWAYS_INLINE uintptr_t decr(void* aOwner,
283 nsCycleCollectionParticipant* aCp,
284 bool* aShouldDelete = nullptr) {
285 MOZ_ASSERT(get() > 0);
286 if (!IsInPurpleBuffer()) {
287 mRefCntAndFlags -= NS_REFCOUNT_CHANGE;
288 mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE);
289 uintptr_t retval = NS_REFCOUNT_VALUE(mRefCntAndFlags);
290 // Suspect may delete 'aOwner' and 'this'!
291 NS_CycleCollectorSuspect3(aOwner, aCp, this, aShouldDelete);
292 return retval;
294 mRefCntAndFlags -= NS_REFCOUNT_CHANGE;
295 mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE);
296 return NS_REFCOUNT_VALUE(mRefCntAndFlags);
299 MOZ_ALWAYS_INLINE void RemovePurple() {
300 MOZ_ASSERT(IsPurple(), "must be purple");
301 mRefCntAndFlags &= ~NS_IS_PURPLE;
304 MOZ_ALWAYS_INLINE void RemoveFromPurpleBuffer() {
305 MOZ_ASSERT(IsInPurpleBuffer());
306 mRefCntAndFlags &= ~(NS_IS_PURPLE | NS_IN_PURPLE_BUFFER);
309 MOZ_ALWAYS_INLINE bool IsPurple() const {
310 return !!(mRefCntAndFlags & NS_IS_PURPLE);
313 MOZ_ALWAYS_INLINE bool IsInPurpleBuffer() const {
314 return !!(mRefCntAndFlags & NS_IN_PURPLE_BUFFER);
317 // Cycle collected objects can only be used on a single thread, so if we ever
318 // see an object on the main thread, it will always be on the main thread.
319 // The cycle collector then uses this information to utilize faster nursery
320 // purple buffer on the main thread.
321 // The method works only on 64 bit systems.
322 MOZ_ALWAYS_INLINE void SetIsOnMainThread() {
323 #ifdef HAVE_64BIT_BUILD
324 mRefCntAndFlags |= NS_IS_ON_MAINTHREAD;
325 #endif
328 #ifdef HAVE_64BIT_BUILD
329 // The NS_IS_ON_MAINTHREAD flag only exists on 64-bit builds.
330 MOZ_ALWAYS_INLINE bool IsOnMainThread() {
331 return !!(mRefCntAndFlags & NS_IS_ON_MAINTHREAD);
333 #endif
335 MOZ_ALWAYS_INLINE nsrefcnt get() const {
336 return NS_REFCOUNT_VALUE(mRefCntAndFlags);
339 MOZ_ALWAYS_INLINE operator nsrefcnt() const { return get(); }
341 private:
342 uintptr_t mRefCntAndFlags;
345 class nsAutoRefCnt {
346 public:
347 nsAutoRefCnt() : mValue(0) {}
348 explicit nsAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {}
350 nsAutoRefCnt(const nsAutoRefCnt&) = delete;
351 void operator=(const nsAutoRefCnt&) = delete;
353 // only support prefix increment/decrement
354 nsrefcnt operator++() { return ++mValue; }
355 nsrefcnt operator--() { return --mValue; }
357 nsrefcnt operator=(nsrefcnt aValue) { return (mValue = aValue); }
358 operator nsrefcnt() const { return mValue; }
359 nsrefcnt get() const { return mValue; }
361 static const bool isThreadSafe = false;
363 private:
364 nsrefcnt operator++(int) = delete;
365 nsrefcnt operator--(int) = delete;
366 nsrefcnt mValue;
369 namespace mozilla {
370 class ThreadSafeAutoRefCnt {
371 public:
372 ThreadSafeAutoRefCnt() : mValue(0) {}
373 explicit ThreadSafeAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {}
375 ThreadSafeAutoRefCnt(const ThreadSafeAutoRefCnt&) = delete;
376 void operator=(const ThreadSafeAutoRefCnt&) = delete;
378 // only support prefix increment/decrement
379 MOZ_ALWAYS_INLINE nsrefcnt operator++() {
380 // Memory synchronization is not required when incrementing a
381 // reference count. The first increment of a reference count on a
382 // thread is not important, since the first use of the object on a
383 // thread can happen before it. What is important is the transfer
384 // of the pointer to that thread, which may happen prior to the
385 // first increment on that thread. The necessary memory
386 // synchronization is done by the mechanism that transfers the
387 // pointer between threads.
388 return mValue.fetch_add(1, std::memory_order_relaxed) + 1;
390 MOZ_ALWAYS_INLINE nsrefcnt operator--() {
391 // Since this may be the last release on this thread, we need
392 // release semantics so that prior writes on this thread are visible
393 // to the thread that destroys the object when it reads mValue with
394 // acquire semantics.
395 nsrefcnt result = mValue.fetch_sub(1, std::memory_order_release) - 1;
396 if (result == 0) {
397 // We're going to destroy the object on this thread, so we need
398 // acquire semantics to synchronize with the memory released by
399 // the last release on other threads, that is, to ensure that
400 // writes prior to that release are now visible on this thread.
401 #ifdef MOZ_TSAN
402 // TSan doesn't understand std::atomic_thread_fence, so in order
403 // to avoid a false positive for every time a refcounted object
404 // is deleted, we replace the fence with an atomic operation.
405 mValue.load(std::memory_order_acquire);
406 #else
407 std::atomic_thread_fence(std::memory_order_acquire);
408 #endif
410 return result;
413 MOZ_ALWAYS_INLINE nsrefcnt operator=(nsrefcnt aValue) {
414 // Use release semantics since we're not sure what the caller is
415 // doing.
416 mValue.store(aValue, std::memory_order_release);
417 return aValue;
419 MOZ_ALWAYS_INLINE operator nsrefcnt() const { return get(); }
420 MOZ_ALWAYS_INLINE nsrefcnt get() const {
421 // Use acquire semantics since we're not sure what the caller is
422 // doing.
423 return mValue.load(std::memory_order_acquire);
426 static const bool isThreadSafe = true;
428 private:
429 nsrefcnt operator++(int) = delete;
430 nsrefcnt operator--(int) = delete;
431 std::atomic<nsrefcnt> mValue;
434 namespace detail {
436 // Type trait indicating whether a given XPCOM interface class may only be
437 // implemented by types with threadsafe refcounts. This is specialized for
438 // classes with the `rust_sync` annotation within XPIDL-generated header files,
439 // and checked within macro-generated QueryInterface implementations.
440 template <typename T>
441 class InterfaceNeedsThreadSafeRefCnt : public std::false_type {};
444 } // namespace mozilla
446 ///////////////////////////////////////////////////////////////////////////////
449 * Declare the reference count variable and the implementations of the
450 * AddRef and QueryInterface methods.
453 #define NS_DECL_ISUPPORTS \
454 public: \
455 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
456 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
457 NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
458 using HasThreadSafeRefCnt = std::false_type; \
460 protected: \
461 nsAutoRefCnt mRefCnt; \
462 NS_DECL_OWNINGTHREAD \
463 public:
465 #define NS_DECL_ISUPPORTS_ONEVENTTARGET \
466 public: \
467 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
468 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
469 NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
470 using HasThreadSafeRefCnt = std::false_type; \
472 protected: \
473 nsAutoRefCnt mRefCnt; \
474 NS_DECL_OWNINGEVENTTARGET \
475 public:
477 #define NS_DECL_THREADSAFE_ISUPPORTS \
478 public: \
479 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
480 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
481 NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
482 using HasThreadSafeRefCnt = std::true_type; \
484 protected: \
485 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
486 NS_DECL_OWNINGTHREAD \
487 public:
489 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \
490 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(override) \
491 NS_IMETHOD_(void) DeleteCycleCollectable(void); \
493 public:
495 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL \
496 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(final) \
497 NS_IMETHOD_(void) DeleteCycleCollectable(void); \
499 public:
501 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(...) \
502 public: \
503 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) __VA_ARGS__; \
504 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) __VA_ARGS__; \
505 NS_IMETHOD_(MozExternalRefCountType) Release(void) __VA_ARGS__; \
506 using HasThreadSafeRefCnt = std::false_type; \
508 protected: \
509 nsCycleCollectingAutoRefCnt mRefCnt; \
510 NS_DECL_OWNINGTHREAD \
511 public:
513 ///////////////////////////////////////////////////////////////////////////////
516 * Implementation of AddRef and Release for non-nsISupports (ie "native")
517 * cycle-collected classes that use the purple buffer to avoid leaks.
520 #define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
521 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
522 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
523 NS_ASSERT_OWNINGTHREAD(_class); \
524 nsrefcnt count = \
525 mRefCnt.incr(static_cast<void*>(this), \
526 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
527 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
528 return count;
530 #define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
531 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
532 NS_ASSERT_OWNINGTHREAD(_class); \
533 nsrefcnt count = \
534 mRefCnt.decr(static_cast<void*>(this), \
535 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
536 NS_LOG_RELEASE(this, count, #_class); \
537 return count;
539 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(_class) \
540 NS_METHOD_(MozExternalRefCountType) _class::AddRef(void) { \
541 NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
544 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(_class, \
545 _last) \
546 NS_METHOD_(MozExternalRefCountType) _class::Release(void) { \
547 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
548 NS_ASSERT_OWNINGTHREAD(_class); \
549 bool shouldDelete = false; \
550 nsrefcnt count = \
551 mRefCnt.decr(static_cast<void*>(this), \
552 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant(), \
553 &shouldDelete); \
554 NS_LOG_RELEASE(this, count, #_class); \
555 if (count == 0) { \
556 mRefCnt.incr(static_cast<void*>(this), \
557 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
558 _last; \
559 mRefCnt.decr(static_cast<void*>(this), \
560 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
561 if (shouldDelete) { \
562 mRefCnt.stabilizeForDeletion(); \
563 DeleteCycleCollectable(); \
566 return count; \
569 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(_class) \
570 NS_METHOD_(MozExternalRefCountType) _class::Release(void) { \
571 NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
574 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(_class) \
575 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_METHOD_)
577 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_VIRTUAL(_class) \
578 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_IMETHOD_)
580 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_INHERITED(_class) \
581 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, NS_METHOD_, \
582 override)
584 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, _decl, \
585 ...) \
586 public: \
587 _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__{ \
588 NS_IMPL_CC_NATIVE_ADDREF_BODY(_class)} _decl(MozExternalRefCountType) \
589 Release(void) __VA_ARGS__ { \
590 NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
592 using HasThreadSafeRefCnt = std::false_type; \
594 protected: \
595 nsCycleCollectingAutoRefCnt mRefCnt; \
596 NS_DECL_OWNINGTHREAD \
597 public:
599 ///////////////////////////////////////////////////////////////////////////////
602 * Use this macro to declare and implement the AddRef & Release methods for a
603 * given non-XPCOM <i>_class</i>.
605 * @param _class The name of the class implementing the method
606 * @param _destroy A statement that is executed when the object's
607 * refcount drops to zero.
608 * @param _decl Name of the macro to be used for the return type of the
609 * AddRef & Release methods (typically NS_IMETHOD_ or NS_METHOD_).
610 * @param optional override Mark the AddRef & Release methods as overrides.
612 #define NS_INLINE_DECL_REFCOUNTING_META(_class, _decl, _destroy, _owning, ...) \
613 public: \
614 _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
615 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
616 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
617 NS_ASSERT_OWNINGTHREAD(_class); \
618 ++mRefCnt; \
619 NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
620 return mRefCnt; \
622 _decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
623 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
624 NS_ASSERT_OWNINGTHREAD(_class); \
625 --mRefCnt; \
626 NS_LOG_RELEASE(this, mRefCnt, #_class); \
627 if (mRefCnt == 0) { \
628 mRefCnt = 1; /* stabilize */ \
629 _destroy; \
630 return 0; \
632 return mRefCnt; \
634 using HasThreadSafeRefCnt = std::false_type; \
636 protected: \
637 nsAutoRefCnt mRefCnt; \
638 _owning public:
641 * Use this macro to declare and implement the AddRef & Release methods for a
642 * given non-XPCOM <i>_class</i>.
644 * @param _class The name of the class implementing the method
645 * @param _destroy A statement that is executed when the object's
646 * refcount drops to zero.
647 * @param optional override Mark the AddRef & Release methods as overrides.
649 #define NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \
650 NS_INLINE_DECL_REFCOUNTING_META(_class, NS_METHOD_, _destroy, \
651 NS_DECL_OWNINGTHREAD, __VA_ARGS__)
654 * Like NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY with AddRef & Release declared
655 * virtual.
657 #define NS_INLINE_DECL_VIRTUAL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \
658 NS_INLINE_DECL_REFCOUNTING_META(_class, NS_IMETHOD_, _destroy, \
659 NS_DECL_OWNINGTHREAD, __VA_ARGS__)
662 * Use this macro to declare and implement the AddRef & Release methods for a
663 * given non-XPCOM <i>_class</i>.
665 * @param _class The name of the class implementing the method
666 * @param optional override Mark the AddRef & Release methods as overrides.
668 #define NS_INLINE_DECL_REFCOUNTING(_class, ...) \
669 NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, delete (this), __VA_ARGS__)
672 * Like NS_INLINE_DECL_REFCOUNTING, however the thread safety check will work
673 * with any nsISerialEventTarget. This is a workaround until bug 1648031 is
674 * properly resolved. Once this is done, it will be possible to use
675 * NS_INLINE_DECL_REFCOUNTING under all circumstances.
677 #define NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(_class, ...) \
678 NS_INLINE_DECL_REFCOUNTING_META(_class, NS_METHOD_, delete (this), \
679 NS_DECL_OWNINGEVENTTARGET, __VA_ARGS__)
681 #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, _decl, _destroy, \
682 ...) \
683 public: \
684 _decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
685 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
686 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
687 nsrefcnt count = ++mRefCnt; \
688 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
689 return (nsrefcnt)count; \
691 _decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
692 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
693 nsrefcnt count = --mRefCnt; \
694 NS_LOG_RELEASE(this, count, #_class); \
695 if (count == 0) { \
696 _destroy; \
697 return 0; \
699 return count; \
701 using HasThreadSafeRefCnt = std::true_type; \
703 protected: \
704 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
706 public:
709 * Use this macro to declare and implement the AddRef & Release methods for a
710 * given non-XPCOM <i>_class</i> in a threadsafe manner.
712 * DOES NOT DO REFCOUNT STABILIZATION!
714 * @param _class The name of the class implementing the method
715 * @param _destroy A statement that is executed when the object's
716 * refcount drops to zero.
717 * @param optional override Mark the AddRef & Release methods as overrides.
719 #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(_class, _destroy, \
720 ...) \
721 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_METHOD_, _destroy, \
722 __VA_ARGS__)
725 * Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY with AddRef & Release
726 * declared virtual.
728 #define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING_WITH_DESTROY( \
729 _class, _destroy, ...) \
730 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_IMETHOD_, _destroy, \
731 __VA_ARGS__)
734 * Use this macro to declare and implement the AddRef & Release methods for a
735 * given non-XPCOM <i>_class</i> in a threadsafe manner.
737 * DOES NOT DO REFCOUNT STABILIZATION!
739 * @param _class The name of the class implementing the method
740 * @param optional override Mark the AddRef & Release methods as overrides.
742 #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING(_class, ...) \
743 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(_class, delete (this), \
744 __VA_ARGS__)
747 * Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING with AddRef & Release declared
748 * virtual.
750 #define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING(_class, ...) \
751 NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING_WITH_DESTROY( \
752 _class, delete (this), __VA_ARGS__)
754 #if !defined(XPCOM_GLUE_AVOID_NSPR)
755 class nsISerialEventTarget;
756 namespace mozilla {
757 // Forward-declare `GetMainThreadSerialEventTarget`, as `nsISupportsImpl.h`
758 // cannot include `nsThreadUtils.h`.
759 nsISerialEventTarget* GetMainThreadSerialEventTarget();
761 namespace detail {
762 using DeleteVoidFunction = void(void*);
763 void ProxyDeleteVoid(const char* aRunnableName,
764 nsISerialEventTarget* aEventTarget, void* aSelf,
765 DeleteVoidFunction* aDeleteFunc);
766 } // namespace detail
767 } // namespace mozilla
770 * Helper for _WITH_DELETE_ON_EVENT_TARGET threadsafe refcounting macros which
771 * provides an implementation of `_destroy`
773 # define NS_PROXY_DELETE_TO_EVENT_TARGET(_class, _target) \
774 ::mozilla::detail::ProxyDeleteVoid( \
775 "ProxyDelete " #_class, _target, this, \
776 [](void* self) { delete static_cast<_class*>(self); })
779 * Use this macro to declare and implement the AddRef & Release methods for a
780 * given non-XPCOM <i>_class</i> in a threadsafe manner, ensuring the
781 * destructor runs on a specific nsISerialEventTarget.
783 * DOES NOT DO REFCOUNT STABILIZATION!
785 * @param _class The name of the class implementing the method
786 * @param _target nsISerialEventTarget to run the class's destructor on
787 * @param optional override Mark the AddRef & Release methods as overrides
789 # define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET( \
790 _class, _target, ...) \
791 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY( \
792 _class, NS_PROXY_DELETE_TO_EVENT_TARGET(_class, _target), __VA_ARGS__)
795 * Use this macro to declare and implement the AddRef & Release methods for a
796 * given non-XPCOM <i>_class</i> in a threadsafe manner, ensuring the
797 * destructor runs on the main thread.
799 * DOES NOT DO REFCOUNT STABILIZATION!
801 * @param _class The name of the class implementing the method
802 * @param optional override Mark the AddRef & Release methods as overrides
804 # define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD( \
805 _class, ...) \
806 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET( \
807 _class, ::mozilla::GetMainThreadSerialEventTarget(), __VA_ARGS__)
808 #endif
811 * Use this macro in interface classes that you want to be able to reference
812 * using RefPtr, but don't want to provide a refcounting implemenation. The
813 * refcounting implementation can be provided by concrete subclasses that
814 * implement the interface.
816 #define NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING \
817 public: \
818 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; \
819 NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; \
821 public:
824 * Use this macro to implement the AddRef method for a given <i>_class</i>
825 * @param _class The name of the class implementing the method
826 * @param _name The class name to be passed to XPCOM leak checking
828 #define NS_IMPL_NAMED_ADDREF(_class, _name) \
829 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
830 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
831 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
832 MOZ_ASSERT(_name != nullptr, "Must specify a name"); \
833 if (!mRefCnt.isThreadSafe) NS_ASSERT_OWNINGTHREAD(_class); \
834 nsrefcnt count = ++mRefCnt; \
835 NS_LOG_ADDREF(this, count, _name, sizeof(*this)); \
836 return count; \
840 * Use this macro to implement the AddRef method for a given <i>_class</i>
841 * @param _class The name of the class implementing the method
843 #define NS_IMPL_ADDREF(_class) NS_IMPL_NAMED_ADDREF(_class, #_class)
846 * Use this macro to implement the AddRef method for a given <i>_class</i>
847 * implemented as a wholly owned aggregated object intended to implement
848 * interface(s) for its owner
849 * @param _class The name of the class implementing the method
850 * @param _aggregator the owning/containing object
852 #define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \
853 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
854 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
855 MOZ_ASSERT(_aggregator, "null aggregator"); \
856 return (_aggregator)->AddRef(); \
859 // We decrement the refcnt before logging the actual release, but when logging
860 // named things, accessing the name may not be valid after the refcnt
861 // decrement, because the object may have been destroyed on a different thread.
862 // Use this macro to ensure that we have a local copy of the name prior to
863 // the refcnt decrement. (We use a macro to make absolutely sure the name
864 // isn't loaded in builds where it wouldn't be used.)
865 #ifdef NS_BUILD_REFCNT_LOGGING
866 # define NS_LOAD_NAME_BEFORE_RELEASE(localname, _name) \
867 const char* const localname = _name
868 #else
869 # define NS_LOAD_NAME_BEFORE_RELEASE(localname, _name)
870 #endif
873 * Use this macro to implement the Release method for a given
874 * <i>_class</i>.
875 * @param _class The name of the class implementing the method
876 * @param _name The class name to be passed to XPCOM leak checking
877 * @param _destroy A statement that is executed when the object's
878 * refcount drops to zero.
880 * For example,
882 * NS_IMPL_RELEASE_WITH_DESTROY(Foo, "Foo", Destroy(this))
884 * will cause
886 * Destroy(this);
888 * to be invoked when the object's refcount drops to zero. This
889 * allows for arbitrary teardown activity to occur (e.g., deallocation
890 * of object allocated with placement new).
892 #define NS_IMPL_NAMED_RELEASE_WITH_DESTROY(_class, _name, _destroy) \
893 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
894 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
895 MOZ_ASSERT(_name != nullptr, "Must specify a name"); \
896 if (!mRefCnt.isThreadSafe) NS_ASSERT_OWNINGTHREAD(_class); \
897 NS_LOAD_NAME_BEFORE_RELEASE(nametmp, _name); \
898 nsrefcnt count = --mRefCnt; \
899 NS_LOG_RELEASE(this, count, nametmp); \
900 if (count == 0) { \
901 mRefCnt = 1; /* stabilize */ \
902 _destroy; \
903 return 0; \
905 return count; \
908 #define NS_IMPL_RELEASE_WITH_DESTROY(_class, _destroy) \
909 NS_IMPL_NAMED_RELEASE_WITH_DESTROY(_class, #_class, _destroy)
912 * Use this macro to implement the Release method for a given <i>_class</i>
913 * @param _class The name of the class implementing the method
915 * A note on the 'stabilization' of the refcnt to one. At that point,
916 * the object's refcount will have gone to zero. The object's
917 * destructor may trigger code that attempts to QueryInterface() and
918 * Release() 'this' again. Doing so will temporarily increment and
919 * decrement the refcount. (Only a logic error would make one try to
920 * keep a permanent hold on 'this'.) To prevent re-entering the
921 * destructor, we make sure that no balanced refcounting can return
922 * the refcount to |0|.
924 #define NS_IMPL_RELEASE(_class) \
925 NS_IMPL_RELEASE_WITH_DESTROY(_class, delete (this))
927 #define NS_IMPL_NAMED_RELEASE(_class, _name) \
928 NS_IMPL_NAMED_RELEASE_WITH_DESTROY(_class, _name, delete (this))
931 * Use this macro to implement the Release method for a given <i>_class</i>
932 * implemented as a wholly owned aggregated object intended to implement
933 * interface(s) for its owner
934 * @param _class The name of the class implementing the method
935 * @param _aggregator the owning/containing object
937 #define NS_IMPL_RELEASE_USING_AGGREGATOR(_class, _aggregator) \
938 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
939 MOZ_ASSERT(_aggregator, "null aggregator"); \
940 return (_aggregator)->Release(); \
943 #define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class) \
944 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
945 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
946 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
947 NS_ASSERT_OWNINGTHREAD(_class); \
948 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
949 nsrefcnt count = mRefCnt.incr(base); \
950 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
951 return count; \
954 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy) \
955 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
956 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
957 NS_ASSERT_OWNINGTHREAD(_class); \
958 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
959 nsrefcnt count = mRefCnt.decr(base); \
960 NS_LOG_RELEASE(this, count, #_class); \
961 return count; \
963 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { _destroy; }
965 #define NS_IMPL_CYCLE_COLLECTING_RELEASE(_class) \
966 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, delete (this))
968 // _LAST_RELEASE can be useful when certain resources should be released
969 // as soon as we know the object will be deleted.
970 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(_class, _last) \
971 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
972 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
973 NS_ASSERT_OWNINGTHREAD(_class); \
974 bool shouldDelete = false; \
975 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
976 nsrefcnt count = mRefCnt.decr(base, &shouldDelete); \
977 NS_LOG_RELEASE(this, count, #_class); \
978 if (count == 0) { \
979 mRefCnt.incr(base); \
980 _last; \
981 mRefCnt.decr(base); \
982 if (shouldDelete) { \
983 mRefCnt.stabilizeForDeletion(); \
984 DeleteCycleCollectable(); \
987 return count; \
989 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { delete this; }
991 // This macro is same as NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE
992 // except it doesn't have DeleteCycleCollectable.
993 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE_AND_DESTROY( \
994 _class, _last, _destroy) \
995 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
996 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
997 NS_ASSERT_OWNINGTHREAD(_class); \
998 bool shouldDelete = false; \
999 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
1000 nsrefcnt count = mRefCnt.decr(base, &shouldDelete); \
1001 NS_LOG_RELEASE(this, count, #_class); \
1002 if (count == 0) { \
1003 mRefCnt.incr(base); \
1004 _last; \
1005 mRefCnt.decr(base); \
1006 if (shouldDelete) { \
1007 mRefCnt.stabilizeForDeletion(); \
1008 DeleteCycleCollectable(); \
1011 return count; \
1013 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { _destroy; }
1015 // _WITH_INTERRUPTABLE_LAST_RELEASE can be useful when certain resources
1016 // should be released as soon as we know the object will be deleted and the
1017 // instance may be cached for reuse.
1018 // _last is performed for cleaning up its resources. Then, _maybeInterrupt is
1019 // tested and when it returns true, this stops deleting the instance.
1020 // (Note that it's not allowed to grab the instance with nsCOMPtr or RefPtr
1021 // during _last is performed.)
1022 // Therefore, when _maybeInterrupt returns true, the instance has to be grabbed
1023 // by nsCOMPtr or RefPtr.
1024 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_INTERRUPTABLE_LAST_RELEASE( \
1025 _class, _last, _maybeInterrupt) \
1026 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
1027 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
1028 NS_ASSERT_OWNINGTHREAD(_class); \
1029 bool shouldDelete = false; \
1030 nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
1031 nsrefcnt count = mRefCnt.decr(base, &shouldDelete); \
1032 NS_LOG_RELEASE(this, count, #_class); \
1033 if (count == 0) { \
1034 mRefCnt.incr(base); \
1035 _last; \
1036 mRefCnt.decr(base); \
1037 if (_maybeInterrupt) { \
1038 MOZ_ASSERT(mRefCnt.get() > 0); \
1039 return mRefCnt.get(); \
1041 if (shouldDelete) { \
1042 mRefCnt.stabilizeForDeletion(); \
1043 DeleteCycleCollectable(); \
1046 return count; \
1048 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) { delete this; }
1050 ///////////////////////////////////////////////////////////////////////////////
1052 namespace mozilla::detail {
1054 // Helper which is roughly equivalent to NS_GET_IID, which also performs static
1055 // assertions that `Class` is allowed to implement the given XPCOM interface.
1057 // These assertions are done like this to allow them to be used within the
1058 // `NS_INTERFACE_TABLE_ENTRY` macro, though they are also used in
1059 // `NS_IMPL_QUERY_BODY`.
1060 template <typename Class, typename Interface>
1061 constexpr const nsIID& GetImplementedIID() {
1062 if constexpr (mozilla::detail::InterfaceNeedsThreadSafeRefCnt<
1063 Interface>::value) {
1064 static_assert(Class::HasThreadSafeRefCnt::value,
1065 "Cannot implement a threadsafe interface with "
1066 "non-threadsafe refcounting!");
1068 return NS_GET_TEMPLATE_IID(Interface);
1071 template <typename Class, typename Interface>
1072 constexpr const nsIID& kImplementedIID = GetImplementedIID<Class, Interface>();
1077 * There are two ways of implementing QueryInterface, and we use both:
1079 * Table-driven QueryInterface uses a static table of IID->offset mappings
1080 * and a shared helper function. Using it tends to reduce codesize and improve
1081 * runtime performance (due to processor cache hits).
1083 * Macro-driven QueryInterface generates a QueryInterface function directly
1084 * using common macros. This is necessary if special QueryInterface features
1085 * are being used (such as tearoffs and conditional interfaces).
1087 * These methods can be combined into a table-driven function call followed
1088 * by custom code for tearoffs and conditionals.
1091 struct QITableEntry {
1092 const nsIID* iid; // null indicates end of the QITableEntry array
1093 int32_t offset;
1096 nsresult NS_FASTCALL NS_TableDrivenQI(void* aThis, REFNSIID aIID,
1097 void** aInstancePtr,
1098 const QITableEntry* aEntries);
1101 * Implement table-driven queryinterface
1104 #define NS_INTERFACE_TABLE_HEAD(_class) \
1105 NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) { \
1106 NS_ASSERTION(aInstancePtr, \
1107 "QueryInterface requires a non-NULL destination!"); \
1108 nsresult rv = NS_ERROR_FAILURE;
1110 #define NS_INTERFACE_TABLE_BEGIN static const QITableEntry table[] = {
1111 #define NS_INTERFACE_TABLE_ENTRY(_class, _interface) \
1112 {&mozilla::detail::kImplementedIID<_class, _interface>, \
1113 int32_t( \
1114 reinterpret_cast<char*>(static_cast<_interface*>((_class*)0x1000)) - \
1115 reinterpret_cast<char*>((_class*)0x1000))},
1117 #define NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, _interface, _implClass) \
1118 {&mozilla::detail::kImplementedIID<_class, _interface>, \
1119 int32_t(reinterpret_cast<char*>(static_cast<_interface*>( \
1120 static_cast<_implClass*>((_class*)0x1000))) - \
1121 reinterpret_cast<char*>((_class*)0x1000))},
1123 #define NS_INTERFACE_TABLE_END_WITH_PTR(_ptr) \
1124 { nullptr, 0 } \
1127 static_assert(std::size(table) > 1, "need at least 1 interface"); \
1128 rv = NS_TableDrivenQI(static_cast<void*>(_ptr), aIID, aInstancePtr, table);
1130 #define NS_INTERFACE_TABLE_END \
1131 NS_INTERFACE_TABLE_END_WITH_PTR \
1132 (this)
1134 #define NS_INTERFACE_TABLE_TAIL \
1135 return rv; \
1138 #define NS_INTERFACE_TABLE_TAIL_INHERITING(_baseclass) \
1139 if (NS_SUCCEEDED(rv)) return rv; \
1140 return _baseclass::QueryInterface(aIID, aInstancePtr); \
1143 #define NS_INTERFACE_TABLE_TAIL_USING_AGGREGATOR(_aggregator) \
1144 if (NS_SUCCEEDED(rv)) return rv; \
1145 NS_ASSERTION(_aggregator, "null aggregator"); \
1146 return _aggregator->QueryInterface(aIID, aInstancePtr) \
1150 * This implements query interface with two assumptions: First, the
1151 * class in question implements nsISupports and its own interface and
1152 * nothing else. Second, the implementation of the class's primary
1153 * inheritance chain leads to its own interface.
1155 * @param _class The name of the class implementing the method
1156 * @param _classiiddef The name of the #define symbol that defines the IID
1157 * for the class (e.g. NS_ISUPPORTS_IID)
1160 #define NS_IMPL_QUERY_HEAD(_class) \
1161 NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) { \
1162 NS_ASSERTION(aInstancePtr, \
1163 "QueryInterface requires a non-NULL destination!"); \
1164 nsISupports* foundInterface;
1166 #define NS_IMPL_QUERY_BODY_IID(_interface) \
1167 mozilla::detail::kImplementedIID<std::remove_reference_t<decltype(*this)>, \
1168 _interface>
1170 #define NS_IMPL_QUERY_BODY(_interface) \
1171 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1172 foundInterface = static_cast<_interface*>(this); \
1173 else
1175 #define NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) \
1176 if ((condition) && aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1177 foundInterface = static_cast<_interface*>(this); \
1178 else
1180 #define NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) \
1181 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1182 foundInterface = static_cast<_interface*>(static_cast<_implClass*>(this)); \
1183 else
1185 // Use this for querying to concrete class types which cannot be unambiguously
1186 // cast to nsISupports. See also nsQueryObject.h.
1187 #define NS_IMPL_QUERY_BODY_CONCRETE(_class) \
1188 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_class))) { \
1189 *aInstancePtr = do_AddRef(static_cast<_class*>(this)).take(); \
1190 return NS_OK; \
1191 } else
1193 #define NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate) \
1194 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1195 foundInterface = static_cast<_interface*>(_aggregate); \
1196 else
1198 #define NS_IMPL_QUERY_TAIL_GUTS \
1199 foundInterface = 0; \
1200 nsresult status; \
1201 if (!foundInterface) { \
1202 /* nsISupports should be handled by this point. If not, fail. */ \
1203 MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsISupports))); \
1204 status = NS_NOINTERFACE; \
1205 } else { \
1206 NS_ADDREF(foundInterface); \
1207 status = NS_OK; \
1209 *aInstancePtr = foundInterface; \
1210 return status; \
1213 #define NS_IMPL_QUERY_TAIL_INHERITING(_baseclass) \
1214 foundInterface = 0; \
1215 nsresult status; \
1216 if (!foundInterface) \
1217 status = _baseclass::QueryInterface(aIID, (void**)&foundInterface); \
1218 else { \
1219 NS_ADDREF(foundInterface); \
1220 status = NS_OK; \
1222 *aInstancePtr = foundInterface; \
1223 return status; \
1226 #define NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) \
1227 foundInterface = 0; \
1228 nsresult status; \
1229 if (!foundInterface) { \
1230 NS_ASSERTION(_aggregator, "null aggregator"); \
1231 status = _aggregator->QueryInterface(aIID, (void**)&foundInterface); \
1232 } else { \
1233 NS_ADDREF(foundInterface); \
1234 status = NS_OK; \
1236 *aInstancePtr = foundInterface; \
1237 return status; \
1240 #define NS_IMPL_QUERY_TAIL(_supports_interface) \
1241 NS_IMPL_QUERY_BODY_AMBIGUOUS(nsISupports, _supports_interface) \
1242 NS_IMPL_QUERY_TAIL_GUTS
1245 This is the new scheme. Using this notation now will allow us to switch to
1246 a table driven mechanism when it's ready. Note the difference between this
1247 and the (currently) underlying NS_IMPL_QUERY_INTERFACE mechanism. You must
1248 explicitly mention |nsISupports| when using the interface maps.
1250 #define NS_INTERFACE_MAP_BEGIN(_implClass) NS_IMPL_QUERY_HEAD(_implClass)
1251 #define NS_INTERFACE_MAP_ENTRY(_interface) NS_IMPL_QUERY_BODY(_interface)
1252 #define NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, condition) \
1253 NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition)
1254 #define NS_INTERFACE_MAP_ENTRY_AGGREGATED(_interface, _aggregate) \
1255 NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate)
1257 #define NS_INTERFACE_MAP_END NS_IMPL_QUERY_TAIL_GUTS
1258 #define NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(_interface, _implClass) \
1259 NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass)
1260 #define NS_INTERFACE_MAP_ENTRY_CONCRETE(_class) \
1261 NS_IMPL_QUERY_BODY_CONCRETE(_class)
1262 #define NS_INTERFACE_MAP_END_INHERITING(_baseClass) \
1263 NS_IMPL_QUERY_TAIL_INHERITING(_baseClass)
1264 #define NS_INTERFACE_MAP_END_AGGREGATED(_aggregator) \
1265 NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator)
1267 #define NS_INTERFACE_TABLE0(_class) \
1268 NS_INTERFACE_TABLE_BEGIN \
1269 NS_INTERFACE_TABLE_ENTRY(_class, nsISupports) \
1270 NS_INTERFACE_TABLE_END
1272 #define NS_INTERFACE_TABLE(aClass, ...) \
1273 static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
1274 "Need more arguments to NS_INTERFACE_TABLE"); \
1275 NS_INTERFACE_TABLE_BEGIN \
1276 MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass, ), (__VA_ARGS__)) \
1277 NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(aClass, nsISupports, \
1278 MOZ_ARG_1(__VA_ARGS__)) \
1279 NS_INTERFACE_TABLE_END
1281 #define NS_IMPL_QUERY_INTERFACE0(_class) \
1282 NS_INTERFACE_TABLE_HEAD(_class) \
1283 NS_INTERFACE_TABLE0(_class) \
1284 NS_INTERFACE_TABLE_TAIL
1286 #define NS_IMPL_QUERY_INTERFACE(aClass, ...) \
1287 NS_INTERFACE_TABLE_HEAD(aClass) \
1288 NS_INTERFACE_TABLE(aClass, __VA_ARGS__) \
1289 NS_INTERFACE_TABLE_TAIL
1292 * Declare that you're going to inherit from something that already
1293 * implements nsISupports, but also implements an additional interface, thus
1294 * causing an ambiguity. In this case you don't need another mRefCnt, you
1295 * just need to forward the definitions to the appropriate superclass. E.g.
1297 * class Bar : public Foo, public nsIBar { // both provide nsISupports
1298 * public:
1299 * NS_DECL_ISUPPORTS_INHERITED
1300 * ...other nsIBar and Bar methods...
1301 * };
1303 #define NS_DECL_ISUPPORTS_INHERITED \
1304 public: \
1305 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
1306 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
1307 NS_IMETHOD_(MozExternalRefCountType) Release(void) override;
1310 * These macros can be used in conjunction with NS_DECL_ISUPPORTS_INHERITED
1311 * to implement the nsISupports methods, forwarding the invocations to a
1312 * superclass that already implements nsISupports. Don't do anything for
1313 * subclasses of Runnable because it deals with subclass logging in its own
1314 * way, using the mName field.
1316 * Note that I didn't make these inlined because they're virtual methods.
1319 namespace mozilla {
1320 class Runnable;
1321 namespace detail {
1322 class SupportsThreadSafeWeakPtrBase;
1324 // Don't NS_LOG_{ADDREF,RELEASE} when inheriting from `Runnable*` or types with
1325 // thread safe weak references, as it will generate incorrect refcnt logs due to
1326 // the thread-safe `Upgrade()` call's refcount modifications not calling through
1327 // the derived class' `AddRef()` and `Release()` methods.
1328 template <typename T>
1329 constexpr bool ShouldLogInheritedRefcnt =
1330 !std::is_convertible_v<T*, Runnable*> &&
1331 !std::is_base_of_v<SupportsThreadSafeWeakPtrBase, T>;
1333 } // namespace mozilla
1335 #define NS_IMPL_ADDREF_INHERITED_GUTS(Class, Super) \
1336 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(Class) \
1337 nsrefcnt r = Super::AddRef(); \
1338 if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt<Class>) { \
1339 NS_LOG_ADDREF(this, r, #Class, sizeof(*this)); \
1341 return r /* Purposefully no trailing semicolon */
1343 #define NS_IMPL_ADDREF_INHERITED(Class, Super) \
1344 NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) { \
1345 NS_IMPL_ADDREF_INHERITED_GUTS(Class, Super); \
1348 #define NS_IMPL_RELEASE_INHERITED_GUTS(Class, Super) \
1349 nsrefcnt r = Super::Release(); \
1350 if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt<Class>) { \
1351 NS_LOG_RELEASE(this, r, #Class); \
1353 return r /* Purposefully no trailing semicolon */
1355 #define NS_IMPL_RELEASE_INHERITED(Class, Super) \
1356 NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) { \
1357 NS_IMPL_RELEASE_INHERITED_GUTS(Class, Super); \
1361 * As above but not logging the addref/release; needed if the base
1362 * class might be aggregated.
1364 #define NS_IMPL_NONLOGGING_ADDREF_INHERITED(Class, Super) \
1365 NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) { \
1366 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(Class) \
1367 return Super::AddRef(); \
1370 #define NS_IMPL_NONLOGGING_RELEASE_INHERITED(Class, Super) \
1371 NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) { \
1372 return Super::Release(); \
1375 #define NS_INTERFACE_TABLE_INHERITED0(Class) /* Nothing to do here */
1377 #define NS_INTERFACE_TABLE_INHERITED(aClass, ...) \
1378 static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
1379 "Need more arguments to NS_INTERFACE_TABLE_INHERITED"); \
1380 NS_INTERFACE_TABLE_BEGIN \
1381 MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass, ), (__VA_ARGS__)) \
1382 NS_INTERFACE_TABLE_END
1384 #define NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, ...) \
1385 NS_INTERFACE_TABLE_HEAD(aClass) \
1386 NS_INTERFACE_TABLE_INHERITED(aClass, __VA_ARGS__) \
1387 NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper)
1390 * Convenience macros for implementing all nsISupports methods for
1391 * a simple class.
1392 * @param _class The name of the class implementing the method
1393 * @param _classiiddef The name of the #define symbol that defines the IID
1394 * for the class (e.g. NS_ISUPPORTS_IID)
1397 #define NS_IMPL_ISUPPORTS0(_class) \
1398 NS_IMPL_ADDREF(_class) \
1399 NS_IMPL_RELEASE(_class) \
1400 NS_IMPL_QUERY_INTERFACE0(_class)
1402 #define NS_IMPL_ISUPPORTS(aClass, ...) \
1403 NS_IMPL_ADDREF(aClass) \
1404 NS_IMPL_RELEASE(aClass) \
1405 NS_IMPL_QUERY_INTERFACE(aClass, __VA_ARGS__)
1407 // When possible, prefer NS_INLINE_DECL_REFCOUNTING_INHERITED to
1408 // NS_IMPL_ISUPPORTS_INHERITED0.
1409 #define NS_IMPL_ISUPPORTS_INHERITED0(aClass, aSuper) \
1410 NS_INTERFACE_TABLE_HEAD(aClass) \
1411 NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper) \
1412 NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \
1413 NS_IMPL_RELEASE_INHERITED(aClass, aSuper)
1415 #define NS_IMPL_ISUPPORTS_INHERITED(aClass, aSuper, ...) \
1416 NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, __VA_ARGS__) \
1417 NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \
1418 NS_IMPL_RELEASE_INHERITED(aClass, aSuper)
1421 * A macro to declare and implement inherited addref/release for a class which
1422 * doesn't have or need to override QueryInterface from its base class.
1424 * Note: This macro always overrides the `AddRef` and `Release` methods,
1425 * including when refcount logging is disabled, meaning that it will implement
1426 * the `AddRef` or `Release` method from another virtual base class.
1428 #define NS_INLINE_DECL_REFCOUNTING_INHERITED(Class, Super) \
1429 NS_IMETHOD_(MozExternalRefCountType) AddRef() override { \
1430 NS_IMPL_ADDREF_INHERITED_GUTS(Class, Super); \
1432 NS_IMETHOD_(MozExternalRefCountType) Release() override { \
1433 NS_IMPL_RELEASE_INHERITED_GUTS(Class, Super); \
1437 * Macro to glue together a QI that starts with an interface table
1438 * and segues into an interface map (e.g. it uses singleton classinfo
1439 * or tearoffs).
1441 #define NS_INTERFACE_TABLE_TO_MAP_SEGUE \
1442 if (rv == NS_OK) return rv; \
1443 nsISupports* foundInterface;
1445 ///////////////////////////////////////////////////////////////////////////////
1448 * Macro to generate nsIClassInfo methods for classes which do not have
1449 * corresponding nsIFactory implementations.
1451 #define NS_IMPL_THREADSAFE_CI(_class) \
1452 NS_IMETHODIMP \
1453 _class::GetInterfaces(nsTArray<nsIID>& _array) { \
1454 return NS_CI_INTERFACE_GETTER_NAME(_class)(_array); \
1457 NS_IMETHODIMP \
1458 _class::GetScriptableHelper(nsIXPCScriptable** _retval) { \
1459 *_retval = nullptr; \
1460 return NS_OK; \
1463 NS_IMETHODIMP \
1464 _class::GetContractID(nsACString& _contractID) { \
1465 _contractID.SetIsVoid(true); \
1466 return NS_OK; \
1469 NS_IMETHODIMP \
1470 _class::GetClassDescription(nsACString& _classDescription) { \
1471 _classDescription.SetIsVoid(true); \
1472 return NS_OK; \
1475 NS_IMETHODIMP \
1476 _class::GetClassID(nsCID** _classID) { \
1477 *_classID = nullptr; \
1478 return NS_OK; \
1481 NS_IMETHODIMP \
1482 _class::GetFlags(uint32_t* _flags) { \
1483 *_flags = nsIClassInfo::THREADSAFE; \
1484 return NS_OK; \
1487 NS_IMETHODIMP \
1488 _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) { \
1489 return NS_ERROR_NOT_AVAILABLE; \
1492 #endif