1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 // IWYU pragma: private, include "nsISupports.h"
8 #ifndef nsISupportsImpl_h__
9 #define nsISupportsImpl_h__
12 #include "nsISupports.h"
13 #include "nsISupportsUtils.h"
15 #if !defined(XPCOM_GLUE_AVOID_NSPR)
16 # include "prthread.h" /* needed for cargo-culting headers */
22 #include <type_traits>
23 #include "mozilla/Attributes.h"
24 #include "mozilla/Assertions.h"
25 #include "mozilla/Atomics.h"
26 #include "mozilla/Compiler.h"
27 #include "mozilla/Likely.h"
28 #include "mozilla/MacroArgs.h"
29 #include "mozilla/MacroForEach.h"
31 #define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X) \
32 static_assert(!std::is_destructible_v<X>, \
33 "Reference-counted class " #X \
34 " should not have a public destructor. " \
35 "Make this class's destructor non-public");
37 inline nsISupports
* ToSupports(decltype(nullptr)) { return nullptr; }
39 inline nsISupports
* ToSupports(nsISupports
* aSupports
) { return aSupports
; }
41 ////////////////////////////////////////////////////////////////////////////////
42 // Macros to help detect thread-safety:
44 #ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
46 # include "prthread.h" /* needed for thread-safety checks */
48 class nsAutoOwningThread
{
52 // We move the actual assertion checks out-of-line to minimize code bloat,
53 // but that means we have to pass a non-literal string to MOZ_CRASH_UNSAFE.
54 // To make that more safe, the public interface requires a literal string
55 // and passes that to the private interface; we can then be assured that we
56 // effectively are passing a literal string to MOZ_CRASH_UNSAFE.
58 void AssertOwnership(const char (&aMsg
)[N
]) const {
59 AssertCurrentThreadOwnsMe(aMsg
);
62 bool IsCurrentThread() const;
65 void AssertCurrentThreadOwnsMe(const char* aMsg
) const;
70 class nsISerialEventTarget
;
71 class nsAutoOwningEventTarget
{
73 nsAutoOwningEventTarget();
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
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.
96 void AssertOwnership(const char (&aMsg
)[N
]) const {
97 AssertCurrentThreadOwnsMe(aMsg
);
100 bool IsCurrentThread() const;
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 " \
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) \
144 MOZ_ASSERT_CLASSNAME(_type); \
145 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
146 NS_LogCtor((void*)this, #_type, sizeof(*this)); \
149 # define MOZ_COUNT_CTOR_INHERITED(_type, _base) \
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)); \
157 # define MOZ_LOG_CTOR(_ptr, _name, _size) \
159 NS_LogCtor((void*)_ptr, _name, _size); \
162 # define MOZ_COUNT_DTOR(_type) \
164 MOZ_ASSERT_CLASSNAME(_type); \
165 MOZ_ASSERT_NOT_ISUPPORTS(_type); \
166 NS_LogDtor((void*)this, #_type, sizeof(*this)); \
169 # define MOZ_COUNT_DTOR_INHERITED(_type, _base) \
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)); \
177 # define MOZ_LOG_DTOR(_ptr, _name, _size) \
179 NS_LogDtor((void*)_ptr, _name, _size); \
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)
230 # define NS_NUMBER_OF_FLAGS_IN_REFCNT 2
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
{
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
);
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
;
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
);
335 MOZ_ALWAYS_INLINE nsrefcnt
get() const {
336 return NS_REFCOUNT_VALUE(mRefCntAndFlags
);
339 MOZ_ALWAYS_INLINE
operator nsrefcnt() const { return get(); }
342 uintptr_t mRefCntAndFlags
;
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;
364 nsrefcnt
operator++(int) = delete;
365 nsrefcnt
operator--(int) = delete;
370 class ThreadSafeAutoRefCnt
{
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;
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.
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
);
407 std::atomic_thread_fence(std::memory_order_acquire
);
413 MOZ_ALWAYS_INLINE nsrefcnt
operator=(nsrefcnt aValue
) {
414 // Use release semantics since we're not sure what the caller is
416 mValue
.store(aValue
, std::memory_order_release
);
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
423 return mValue
.load(std::memory_order_acquire
);
426 static const bool isThreadSafe
= true;
429 nsrefcnt
operator++(int) = delete;
430 nsrefcnt
operator--(int) = delete;
431 std::atomic
<nsrefcnt
> mValue
;
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 \
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; \
461 nsAutoRefCnt mRefCnt; \
462 NS_DECL_OWNINGTHREAD \
465 #define NS_DECL_ISUPPORTS_ONEVENTTARGET \
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; \
473 nsAutoRefCnt mRefCnt; \
474 NS_DECL_OWNINGEVENTTARGET \
477 #define NS_DECL_THREADSAFE_ISUPPORTS \
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; \
485 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
486 NS_DECL_OWNINGTHREAD \
489 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \
490 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(override) \
491 NS_IMETHOD_(void) DeleteCycleCollectable(void); \
495 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL \
496 NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(final) \
497 NS_IMETHOD_(void) DeleteCycleCollectable(void); \
501 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(...) \
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; \
509 nsCycleCollectingAutoRefCnt mRefCnt; \
510 NS_DECL_OWNINGTHREAD \
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); \
525 mRefCnt.incr(static_cast<void*>(this), \
526 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
527 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
530 #define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
531 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
532 NS_ASSERT_OWNINGTHREAD(_class); \
534 mRefCnt.decr(static_cast<void*>(this), \
535 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
536 NS_LOG_RELEASE(this, count, #_class); \
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, \
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; \
551 mRefCnt.decr(static_cast<void*>(this), \
552 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant(), \
554 NS_LOG_RELEASE(this, count, #_class); \
556 mRefCnt.incr(static_cast<void*>(this), \
557 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
559 mRefCnt.decr(static_cast<void*>(this), \
560 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
561 if (shouldDelete) { \
562 mRefCnt.stabilizeForDeletion(); \
563 DeleteCycleCollectable(); \
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_, \
584 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING_META(_class, _decl, \
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; \
595 nsCycleCollectingAutoRefCnt mRefCnt; \
596 NS_DECL_OWNINGTHREAD \
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, ...) \
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); \
619 NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
622 _decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
623 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
624 NS_ASSERT_OWNINGTHREAD(_class); \
626 NS_LOG_RELEASE(this, mRefCnt, #_class); \
627 if (mRefCnt == 0) { \
628 mRefCnt = 1; /* stabilize */ \
634 using HasThreadSafeRefCnt = std::false_type; \
637 nsAutoRefCnt mRefCnt; \
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
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, \
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); \
701 using HasThreadSafeRefCnt = std::true_type; \
704 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
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, \
721 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_METHOD_, _destroy, \
725 * Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY with AddRef & Release
728 #define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING_WITH_DESTROY( \
729 _class, _destroy, ...) \
730 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_IMETHOD_, _destroy, \
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), \
747 * Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING with AddRef & Release declared
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
;
757 // Forward-declare `GetMainThreadSerialEventTarget`, as `nsISupportsImpl.h`
758 // cannot include `nsThreadUtils.h`.
759 nsISerialEventTarget
* GetMainThreadSerialEventTarget();
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( \
806 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET( \
807 _class, ::mozilla::GetMainThreadSerialEventTarget(), __VA_ARGS__)
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 \
818 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; \
819 NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; \
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)); \
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
869 # define NS_LOAD_NAME_BEFORE_RELEASE(localname, _name)
873 * Use this macro to implement the Release method for a given
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.
882 * NS_IMPL_RELEASE_WITH_DESTROY(Foo, "Foo", 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); \
901 mRefCnt = 1; /* stabilize */ \
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)); \
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); \
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); \
979 mRefCnt.incr(base); \
981 mRefCnt.decr(base); \
982 if (shouldDelete) { \
983 mRefCnt.stabilizeForDeletion(); \
984 DeleteCycleCollectable(); \
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); \
1003 mRefCnt.incr(base); \
1005 mRefCnt.decr(base); \
1006 if (shouldDelete) { \
1007 mRefCnt.stabilizeForDeletion(); \
1008 DeleteCycleCollectable(); \
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); \
1034 mRefCnt.incr(base); \
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(); \
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
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>, \
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) \
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 \
1134 #define NS_INTERFACE_TABLE_TAIL \
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)>, \
1170 #define NS_IMPL_QUERY_BODY(_interface) \
1171 if (aIID.Equals(NS_IMPL_QUERY_BODY_IID(_interface))) \
1172 foundInterface = static_cast<_interface*>(this); \
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); \
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)); \
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(); \
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); \
1198 #define NS_IMPL_QUERY_TAIL_GUTS \
1199 foundInterface = 0; \
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; \
1206 NS_ADDREF(foundInterface); \
1209 *aInstancePtr = foundInterface; \
1213 #define NS_IMPL_QUERY_TAIL_INHERITING(_baseclass) \
1214 foundInterface = 0; \
1216 if (!foundInterface) \
1217 status = _baseclass::QueryInterface(aIID, (void**)&foundInterface); \
1219 NS_ADDREF(foundInterface); \
1222 *aInstancePtr = foundInterface; \
1226 #define NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) \
1227 foundInterface = 0; \
1229 if (!foundInterface) { \
1230 NS_ASSERTION(_aggregator, "null aggregator"); \
1231 status = _aggregator->QueryInterface(aIID, (void**)&foundInterface); \
1233 NS_ADDREF(foundInterface); \
1236 *aInstancePtr = foundInterface; \
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
1299 * NS_DECL_ISUPPORTS_INHERITED
1300 * ...other nsIBar and Bar methods...
1303 #define NS_DECL_ISUPPORTS_INHERITED \
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.
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
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
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) \
1453 _class::GetInterfaces(nsTArray<nsIID>& _array) { \
1454 return NS_CI_INTERFACE_GETTER_NAME(_class)(_array); \
1458 _class::GetScriptableHelper(nsIXPCScriptable** _retval) { \
1459 *_retval = nullptr; \
1464 _class::GetContractID(nsACString& _contractID) { \
1465 _contractID.SetIsVoid(true); \
1470 _class::GetClassDescription(nsACString& _classDescription) { \
1471 _classDescription.SetIsVoid(true); \
1476 _class::GetClassID(nsCID** _classID) { \
1477 *_classID = nullptr; \
1482 _class::GetFlags(uint32_t* _flags) { \
1483 *_flags = nsIClassInfo::THREADSAFE; \
1488 _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) { \
1489 return NS_ERROR_NOT_AVAILABLE; \