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"
9 #ifndef nsISupportsImpl_h__
10 #define nsISupportsImpl_h__
13 #include "nsISupportsBase.h"
14 #include "nsISupportsUtils.h"
17 #if !defined(XPCOM_GLUE_AVOID_NSPR)
18 #include "prthread.h" /* needed for thread-safety checks */
19 #endif // !XPCOM_GLUE_AVOID_NSPR
24 #include "mozilla/Atomics.h"
26 #include "mozilla/Attributes.h"
27 #include "mozilla/Assertions.h"
28 #include "mozilla/Compiler.h"
29 #include "mozilla/Likely.h"
30 #include "mozilla/MacroArgs.h"
31 #include "mozilla/MacroForEach.h"
35 struct HasDangerousPublicDestructor
37 static const bool value
= false;
41 #if defined(__clang__)
42 // bug 1028428 shows that at least in FreeBSD 10.0 with Clang 3.4 and libc++ 3.4,
43 // std::is_destructible is buggy in that it returns false when it should return true
44 // on ipc::SharedMemory. On the other hand, all Clang versions currently in use
45 // seem to handle the fallback just fine.
46 # define MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
47 #elif defined(__GNUC__)
48 // GCC 4.7 is has buggy std::is_destructible
49 # if MOZ_USING_LIBSTDCXX && MOZ_GCC_VERSION_AT_LEAST(4, 8, 0)
50 # define MOZ_HAVE_STD_IS_DESTRUCTIBLE
51 // Some GCC versions have an ICE when using destructors in decltype().
52 // Works for me on GCC 4.8.2 on Fedora 20 x86-64.
53 # elif MOZ_GCC_VERSION_AT_LEAST(4, 8, 2)
54 # define MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
58 #ifdef MOZ_HAVE_STD_IS_DESTRUCTIBLE
59 # include <type_traits>
60 # define MOZ_IS_DESTRUCTIBLE(X) (std::is_destructible<X>::value)
61 #elif defined MOZ_CAN_USE_IS_DESTRUCTIBLE_FALLBACK
63 struct IsDestructibleFallbackImpl
65 template<typename T
> static T
&& Declval();
67 template<typename T
, typename
= decltype(Declval
<T
>().~T())>
68 static TrueType
Test(int);
71 static FalseType
Test(...);
76 typedef decltype(Test
<T
>(0)) type
;
81 struct IsDestructibleFallback
82 : IsDestructibleFallbackImpl::Selector
<T
>::type
86 # define MOZ_IS_DESTRUCTIBLE(X) (mozilla::IsDestructibleFallback<X>::value)
89 #ifdef MOZ_IS_DESTRUCTIBLE
90 #define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X) \
91 static_assert(!MOZ_IS_DESTRUCTIBLE(X) || \
92 mozilla::HasDangerousPublicDestructor<X>::value, \
93 "Reference-counted class " #X " should not have a public destructor. " \
94 "Try to make this class's destructor non-public. If that is really " \
95 "not possible, you can whitelist this class by providing a " \
96 "HasDangerousPublicDestructor specialization for it."); \
97 static_assert(!mozilla::HasDangerousPublicDestructor<X>::value || \
98 MOZ_IS_DESTRUCTIBLE(X), \
99 "Class " #X " has no public destructor. That's good! So please " \
100 "remove the HasDangerousPublicDestructor specialization for it.");
102 #define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X)
106 ToSupports(nsISupports
* aSupports
)
112 ToCanonicalSupports(nsISupports
* aSupports
)
117 ////////////////////////////////////////////////////////////////////////////////
118 // Macros to help detect thread-safety:
120 #if (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING))) && !defined(XPCOM_GLUE_AVOID_NSPR)
122 class nsAutoOwningThread
125 nsAutoOwningThread() { mThread
= PR_GetCurrentThread(); }
126 void* GetThread() const { return mThread
; }
132 #define NS_DECL_OWNINGTHREAD nsAutoOwningThread _mOwningThread;
133 #define NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class) \
134 NS_CheckThreadSafe(agg->_mOwningThread.GetThread(), #_class " not thread-safe")
135 #define NS_ASSERT_OWNINGTHREAD(_class) NS_ASSERT_OWNINGTHREAD_AGGREGATE(this, _class)
136 #else // !DEBUG && !(NIGHTLY_BUILD && !MOZ_PROFILING)
138 #define NS_DECL_OWNINGTHREAD /* nothing */
139 #define NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class) ((void)0)
140 #define NS_ASSERT_OWNINGTHREAD(_class) ((void)0)
142 #endif // DEBUG || (NIGHTLY_BUILD && !MOZ_PROFILING)
145 // Macros for reference-count and constructor logging
147 #ifdef NS_BUILD_REFCNT_LOGGING
149 #define NS_LOG_ADDREF(_p, _rc, _type, _size) \
150 NS_LogAddRef((_p), (_rc), (_type), (uint32_t) (_size))
152 #define NS_LOG_RELEASE(_p, _rc, _type) \
153 NS_LogRelease((_p), (_rc), (_type))
155 #include "mozilla/TypeTraits.h"
156 #define MOZ_ASSERT_CLASSNAME(_type) \
157 static_assert(mozilla::IsClass<_type>::value, \
158 "Token '" #_type "' is not a class type.")
159 // Older versions of gcc can't instantiate local classes in templates.
160 // GCC 4.7 doesn't have this problem.
162 # if !MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
163 # undef MOZ_ASSERT_CLASSNAME
164 # define MOZ_ASSERT_CLASSNAME(_type)
168 // Note that the following constructor/destructor logging macros are redundant
169 // for refcounted objects that log via the NS_LOG_ADDREF/NS_LOG_RELEASE macros.
170 // Refcount logging is preferred.
171 #define MOZ_COUNT_CTOR(_type) \
173 MOZ_ASSERT_CLASSNAME(_type); \
174 NS_LogCtor((void*)this, #_type, sizeof(*this)); \
177 #define MOZ_COUNT_CTOR_INHERITED(_type, _base) \
179 MOZ_ASSERT_CLASSNAME(_type); \
180 MOZ_ASSERT_CLASSNAME(_base); \
181 NS_LogCtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
184 #define MOZ_COUNT_DTOR(_type) \
186 MOZ_ASSERT_CLASSNAME(_type); \
187 NS_LogDtor((void*)this, #_type, sizeof(*this)); \
190 #define MOZ_COUNT_DTOR_INHERITED(_type, _base) \
192 MOZ_ASSERT_CLASSNAME(_type); \
193 MOZ_ASSERT_CLASSNAME(_base); \
194 NS_LogDtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
197 /* nsCOMPtr.h allows these macros to be defined by clients
198 * These logging functions require dynamic_cast<void*>, so they don't
199 * do anything useful if we don't have dynamic_cast<void*>. */
200 #define NSCAP_LOG_ASSIGNMENT(_c, _p) \
202 NS_LogCOMPtrAddRef((_c),static_cast<nsISupports*>(_p))
204 #define NSCAP_LOG_RELEASE(_c, _p) \
206 NS_LogCOMPtrRelease((_c), static_cast<nsISupports*>(_p))
208 #else /* !NS_BUILD_REFCNT_LOGGING */
210 #define NS_LOG_ADDREF(_p, _rc, _type, _size)
211 #define NS_LOG_RELEASE(_p, _rc, _type)
212 #define MOZ_COUNT_CTOR(_type)
213 #define MOZ_COUNT_CTOR_INHERITED(_type, _base)
214 #define MOZ_COUNT_DTOR(_type)
215 #define MOZ_COUNT_DTOR_INHERITED(_type, _base)
217 #endif /* NS_BUILD_REFCNT_LOGGING */
220 // Support for ISupports classes which interact with cycle collector.
222 #define NS_NUMBER_OF_FLAGS_IN_REFCNT 2
223 #define NS_IN_PURPLE_BUFFER (1 << 0)
224 #define NS_IS_PURPLE (1 << 1)
225 #define NS_REFCOUNT_CHANGE (1 << NS_NUMBER_OF_FLAGS_IN_REFCNT)
226 #define NS_REFCOUNT_VALUE(_val) (_val >> NS_NUMBER_OF_FLAGS_IN_REFCNT)
228 class nsCycleCollectingAutoRefCnt
231 nsCycleCollectingAutoRefCnt() : mRefCntAndFlags(0) {}
233 explicit nsCycleCollectingAutoRefCnt(uintptr_t aValue
)
234 : mRefCntAndFlags(aValue
<< NS_NUMBER_OF_FLAGS_IN_REFCNT
)
238 MOZ_ALWAYS_INLINE
uintptr_t incr(nsISupports
* aOwner
)
240 return incr(aOwner
, nullptr);
243 MOZ_ALWAYS_INLINE
uintptr_t incr(void* aOwner
,
244 nsCycleCollectionParticipant
* aCp
)
246 mRefCntAndFlags
+= NS_REFCOUNT_CHANGE
;
247 mRefCntAndFlags
&= ~NS_IS_PURPLE
;
248 // For incremental cycle collection, use the purple buffer to track objects
249 // that have been AddRef'd.
250 if (!IsInPurpleBuffer()) {
251 mRefCntAndFlags
|= NS_IN_PURPLE_BUFFER
;
252 // Refcount isn't zero, so Suspect won't delete anything.
253 MOZ_ASSERT(get() > 0);
254 NS_CycleCollectorSuspect3(aOwner
, aCp
, this, nullptr);
256 return NS_REFCOUNT_VALUE(mRefCntAndFlags
);
259 MOZ_ALWAYS_INLINE
void stabilizeForDeletion()
261 // Set refcnt to 1 and mark us to be in the purple buffer.
262 // This way decr won't call suspect again.
263 mRefCntAndFlags
= NS_REFCOUNT_CHANGE
| NS_IN_PURPLE_BUFFER
;
266 MOZ_ALWAYS_INLINE
uintptr_t decr(nsISupports
* aOwner
,
267 bool* aShouldDelete
= nullptr)
269 return decr(aOwner
, nullptr, aShouldDelete
);
272 MOZ_ALWAYS_INLINE
uintptr_t decr(void* aOwner
,
273 nsCycleCollectionParticipant
* aCp
,
274 bool* aShouldDelete
= nullptr)
276 MOZ_ASSERT(get() > 0);
277 if (!IsInPurpleBuffer()) {
278 mRefCntAndFlags
-= NS_REFCOUNT_CHANGE
;
279 mRefCntAndFlags
|= (NS_IN_PURPLE_BUFFER
| NS_IS_PURPLE
);
280 uintptr_t retval
= NS_REFCOUNT_VALUE(mRefCntAndFlags
);
281 // Suspect may delete 'aOwner' and 'this'!
282 NS_CycleCollectorSuspect3(aOwner
, aCp
, this, aShouldDelete
);
285 mRefCntAndFlags
-= NS_REFCOUNT_CHANGE
;
286 mRefCntAndFlags
|= (NS_IN_PURPLE_BUFFER
| NS_IS_PURPLE
);
287 return NS_REFCOUNT_VALUE(mRefCntAndFlags
);
290 MOZ_ALWAYS_INLINE
void RemovePurple()
292 MOZ_ASSERT(IsPurple(), "must be purple");
293 mRefCntAndFlags
&= ~NS_IS_PURPLE
;
296 MOZ_ALWAYS_INLINE
void RemoveFromPurpleBuffer()
298 MOZ_ASSERT(IsInPurpleBuffer());
299 mRefCntAndFlags
&= ~(NS_IS_PURPLE
| NS_IN_PURPLE_BUFFER
);
302 MOZ_ALWAYS_INLINE
bool IsPurple() const
304 return !!(mRefCntAndFlags
& NS_IS_PURPLE
);
307 MOZ_ALWAYS_INLINE
bool IsInPurpleBuffer() const
309 return !!(mRefCntAndFlags
& NS_IN_PURPLE_BUFFER
);
312 MOZ_ALWAYS_INLINE nsrefcnt
get() const
314 return NS_REFCOUNT_VALUE(mRefCntAndFlags
);
317 MOZ_ALWAYS_INLINE
operator nsrefcnt() const
323 uintptr_t mRefCntAndFlags
;
329 nsAutoRefCnt() : mValue(0) {}
330 explicit nsAutoRefCnt(nsrefcnt aValue
) : mValue(aValue
) {}
332 // only support prefix increment/decrement
333 nsrefcnt
operator++() { return ++mValue
; }
334 nsrefcnt
operator--() { return --mValue
; }
336 nsrefcnt
operator=(nsrefcnt aValue
) { return (mValue
= aValue
); }
337 operator nsrefcnt() const { return mValue
; }
338 nsrefcnt
get() const { return mValue
; }
340 static const bool isThreadSafe
= false;
342 nsrefcnt
operator++(int) = delete;
343 nsrefcnt
operator--(int) = delete;
349 class ThreadSafeAutoRefCnt
352 ThreadSafeAutoRefCnt() : mValue(0) {}
353 explicit ThreadSafeAutoRefCnt(nsrefcnt aValue
) : mValue(aValue
) {}
355 // only support prefix increment/decrement
356 MOZ_ALWAYS_INLINE nsrefcnt
operator++() { return ++mValue
; }
357 MOZ_ALWAYS_INLINE nsrefcnt
operator--() { return --mValue
; }
359 MOZ_ALWAYS_INLINE nsrefcnt
operator=(nsrefcnt aValue
)
361 return (mValue
= aValue
);
363 MOZ_ALWAYS_INLINE
operator nsrefcnt() const { return mValue
; }
364 MOZ_ALWAYS_INLINE nsrefcnt
get() const { return mValue
; }
366 static const bool isThreadSafe
= true;
368 nsrefcnt
operator++(int) = delete;
369 nsrefcnt
operator--(int) = delete;
370 // In theory, RelaseAcquire consistency (but no weaker) is sufficient for
371 // the counter. Making it weaker could speed up builds on ARM (but not x86),
372 // but could break pre-existing code that assumes sequential consistency.
373 Atomic
<nsrefcnt
> mValue
;
378 ///////////////////////////////////////////////////////////////////////////////
381 * Declare the reference count variable and the implementations of the
382 * AddRef and QueryInterface methods.
385 #define NS_DECL_ISUPPORTS \
387 NS_IMETHOD QueryInterface(REFNSIID aIID, \
388 void** aInstancePtr) MOZ_OVERRIDE; \
389 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) MOZ_OVERRIDE; \
390 NS_IMETHOD_(MozExternalRefCountType) Release(void) MOZ_OVERRIDE; \
392 nsAutoRefCnt mRefCnt; \
393 NS_DECL_OWNINGTHREAD \
396 #define NS_DECL_THREADSAFE_ISUPPORTS \
398 NS_IMETHOD QueryInterface(REFNSIID aIID, \
399 void** aInstancePtr) MOZ_OVERRIDE; \
400 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) MOZ_OVERRIDE; \
401 NS_IMETHOD_(MozExternalRefCountType) Release(void) MOZ_OVERRIDE; \
403 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
404 NS_DECL_OWNINGTHREAD \
407 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \
409 NS_IMETHOD QueryInterface(REFNSIID aIID, \
410 void** aInstancePtr) MOZ_OVERRIDE; \
411 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) MOZ_OVERRIDE; \
412 NS_IMETHOD_(MozExternalRefCountType) Release(void) MOZ_OVERRIDE; \
413 NS_IMETHOD_(void) DeleteCycleCollectable(void); \
415 nsCycleCollectingAutoRefCnt mRefCnt; \
416 NS_DECL_OWNINGTHREAD \
420 ///////////////////////////////////////////////////////////////////////////////
423 * Implementation of AddRef and Release for non-nsISupports (ie "native")
424 * cycle-collected classes that use the purple buffer to avoid leaks.
427 #define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
428 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
429 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
430 NS_ASSERT_OWNINGTHREAD(_class); \
432 mRefCnt.incr(static_cast<void*>(this), \
433 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
434 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
437 #define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
438 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
439 NS_ASSERT_OWNINGTHREAD(_class); \
441 mRefCnt.decr(static_cast<void*>(this), \
442 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
443 NS_LOG_RELEASE(this, count, #_class); \
446 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(_class) \
447 NS_METHOD_(MozExternalRefCountType) _class::AddRef(void) \
449 NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
452 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(_class, _last) \
453 NS_METHOD_(MozExternalRefCountType) _class::Release(void) \
455 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
456 NS_ASSERT_OWNINGTHREAD(_class); \
457 bool shouldDelete = false; \
459 mRefCnt.decr(static_cast<void*>(this), \
460 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant(), \
462 NS_LOG_RELEASE(this, count, #_class); \
464 mRefCnt.incr(static_cast<void*>(this), \
465 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
467 mRefCnt.decr(static_cast<void*>(this), \
468 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
469 if (shouldDelete) { \
470 mRefCnt.stabilizeForDeletion(); \
471 DeleteCycleCollectable(); \
477 #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(_class) \
478 NS_METHOD_(MozExternalRefCountType) _class::Release(void) \
480 NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
483 #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(_class) \
485 NS_METHOD_(MozExternalRefCountType) AddRef(void) { \
486 NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
488 NS_METHOD_(MozExternalRefCountType) Release(void) { \
489 NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
492 nsCycleCollectingAutoRefCnt mRefCnt; \
493 NS_DECL_OWNINGTHREAD \
497 ///////////////////////////////////////////////////////////////////////////////
500 * Previously used to initialize the reference count, but no longer needed.
504 #define NS_INIT_ISUPPORTS() ((void)0)
507 * Use this macro to declare and implement the AddRef & Release methods for a
508 * given non-XPCOM <i>_class</i>.
510 * @param _class The name of the class implementing the method
511 * @param optional MOZ_OVERRIDE Mark the AddRef & Release methods as overrides.
513 #define NS_INLINE_DECL_REFCOUNTING(_class, ...) \
515 NS_METHOD_(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
516 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
517 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
518 NS_ASSERT_OWNINGTHREAD(_class); \
520 NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
523 NS_METHOD_(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
524 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
525 NS_ASSERT_OWNINGTHREAD(_class); \
527 NS_LOG_RELEASE(this, mRefCnt, #_class); \
528 if (mRefCnt == 0) { \
529 NS_ASSERT_OWNINGTHREAD(_class); \
530 mRefCnt = 1; /* stabilize */ \
537 nsAutoRefCnt mRefCnt; \
538 NS_DECL_OWNINGTHREAD \
542 * Use this macro to declare and implement the AddRef & Release methods for a
543 * given non-XPCOM <i>_class</i> in a threadsafe manner.
545 * DOES NOT DO REFCOUNT STABILIZATION!
547 * @param _class The name of the class implementing the method
549 #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING(_class, ...) \
551 NS_METHOD_(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
552 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
553 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
554 nsrefcnt count = ++mRefCnt; \
555 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
556 return (nsrefcnt) count; \
558 NS_METHOD_(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
559 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
560 nsrefcnt count = --mRefCnt; \
561 NS_LOG_RELEASE(this, count, #_class); \
569 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
573 * Use this macro to implement the AddRef method for a given <i>_class</i>
574 * @param _class The name of the class implementing the method
576 #define NS_IMPL_ADDREF(_class) \
577 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
579 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
580 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
581 if (!mRefCnt.isThreadSafe) \
582 NS_ASSERT_OWNINGTHREAD(_class); \
583 nsrefcnt count = ++mRefCnt; \
584 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
589 * Use this macro to implement the AddRef method for a given <i>_class</i>
590 * implemented as a wholly owned aggregated object intended to implement
591 * interface(s) for its owner
592 * @param _class The name of the class implementing the method
593 * @param _aggregator the owning/containing object
595 #define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \
596 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
598 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
599 NS_PRECONDITION(_aggregator, "null aggregator"); \
600 return (_aggregator)->AddRef(); \
604 * Use this macro to implement the Release method for a given
606 * @param _class The name of the class implementing the method
607 * @param _destroy A statement that is executed when the object's
608 * refcount drops to zero.
612 * NS_IMPL_RELEASE_WITH_DESTROY(Foo, Destroy(this))
618 * to be invoked when the object's refcount drops to zero. This
619 * allows for arbitrary teardown activity to occur (e.g., deallocation
620 * of object allocated with placement new).
622 #define NS_IMPL_RELEASE_WITH_DESTROY(_class, _destroy) \
623 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \
625 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
626 if (!mRefCnt.isThreadSafe) \
627 NS_ASSERT_OWNINGTHREAD(_class); \
628 nsrefcnt count = --mRefCnt; \
629 NS_LOG_RELEASE(this, count, #_class); \
631 if (!mRefCnt.isThreadSafe) \
632 NS_ASSERT_OWNINGTHREAD(_class); \
633 mRefCnt = 1; /* stabilize */ \
641 * Use this macro to implement the Release method for a given <i>_class</i>
642 * @param _class The name of the class implementing the method
644 * A note on the 'stabilization' of the refcnt to one. At that point,
645 * the object's refcount will have gone to zero. The object's
646 * destructor may trigger code that attempts to QueryInterface() and
647 * Release() 'this' again. Doing so will temporarily increment and
648 * decrement the refcount. (Only a logic error would make one try to
649 * keep a permanent hold on 'this'.) To prevent re-entering the
650 * destructor, we make sure that no balanced refcounting can return
651 * the refcount to |0|.
653 #define NS_IMPL_RELEASE(_class) \
654 NS_IMPL_RELEASE_WITH_DESTROY(_class, delete (this))
657 * Use this macro to implement the Release method for a given <i>_class</i>
658 * implemented as a wholly owned aggregated object intended to implement
659 * interface(s) for its owner
660 * @param _class The name of the class implementing the method
661 * @param _aggregator the owning/containing object
663 #define NS_IMPL_RELEASE_USING_AGGREGATOR(_class, _aggregator) \
664 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \
666 NS_PRECONDITION(_aggregator, "null aggregator"); \
667 return (_aggregator)->Release(); \
671 #define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class) \
672 NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \
674 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
675 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
676 NS_ASSERT_OWNINGTHREAD(_class); \
677 nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
678 nsrefcnt count = mRefCnt.incr(base); \
679 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
683 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy) \
684 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \
686 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
687 NS_ASSERT_OWNINGTHREAD(_class); \
688 nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
689 nsrefcnt count = mRefCnt.decr(base); \
690 NS_LOG_RELEASE(this, count, #_class); \
693 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \
698 #define NS_IMPL_CYCLE_COLLECTING_RELEASE(_class) \
699 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, delete (this))
701 // _LAST_RELEASE can be useful when certain resources should be released
702 // as soon as we know the object will be deleted.
703 #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(_class, _last) \
704 NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \
706 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
707 NS_ASSERT_OWNINGTHREAD(_class); \
708 bool shouldDelete = false; \
709 nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
710 nsrefcnt count = mRefCnt.decr(base, &shouldDelete); \
711 NS_LOG_RELEASE(this, count, #_class); \
713 mRefCnt.incr(base); \
715 mRefCnt.decr(base); \
716 if (shouldDelete) { \
717 mRefCnt.stabilizeForDeletion(); \
718 DeleteCycleCollectable(); \
723 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \
728 ///////////////////////////////////////////////////////////////////////////////
731 * There are two ways of implementing QueryInterface, and we use both:
733 * Table-driven QueryInterface uses a static table of IID->offset mappings
734 * and a shared helper function. Using it tends to reduce codesize and improve
735 * runtime performance (due to processor cache hits).
737 * Macro-driven QueryInterface generates a QueryInterface function directly
738 * using common macros. This is necessary if special QueryInterface features
739 * are being used (such as tearoffs and conditional interfaces).
741 * These methods can be combined into a table-driven function call followed
742 * by custom code for tearoffs and conditionals.
747 const nsIID
* iid
; // null indicates end of the QITableEntry array
752 NS_TableDrivenQI(void* aThis
, REFNSIID aIID
,
753 void** aInstancePtr
, const QITableEntry
* aEntries
);
756 * Implement table-driven queryinterface
759 #define NS_INTERFACE_TABLE_HEAD(_class) \
760 NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \
762 NS_ASSERTION(aInstancePtr, \
763 "QueryInterface requires a non-NULL destination!"); \
764 nsresult rv = NS_ERROR_FAILURE;
766 #define NS_INTERFACE_TABLE_BEGIN \
767 static const QITableEntry table[] = {
769 #define NS_INTERFACE_TABLE_ENTRY(_class, _interface) \
770 { &NS_GET_IID(_interface), \
771 int32_t(reinterpret_cast<char*>( \
772 static_cast<_interface*>((_class*) 0x1000)) - \
773 reinterpret_cast<char*>((_class*) 0x1000)) \
776 #define NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, _interface, _implClass) \
777 { &NS_GET_IID(_interface), \
778 int32_t(reinterpret_cast<char*>( \
779 static_cast<_interface*>( \
780 static_cast<_implClass*>( \
781 (_class*) 0x1000))) - \
782 reinterpret_cast<char*>((_class*) 0x1000)) \
786 * XXX: we want to use mozilla::ArrayLength (or equivalent,
787 * MOZ_ARRAY_LENGTH) in this condition, but some versions of GCC don't
788 * see that the static_assert condition is actually constant in those
789 * cases, even with constexpr support (?).
791 #define NS_INTERFACE_TABLE_END_WITH_PTR(_ptr) \
793 static_assert((sizeof(table)/sizeof(table[0])) > 1, "need at least 1 interface"); \
794 rv = NS_TableDrivenQI(static_cast<void*>(_ptr), \
795 aIID, aInstancePtr, table);
797 #define NS_INTERFACE_TABLE_END \
798 NS_INTERFACE_TABLE_END_WITH_PTR(this)
800 #define NS_INTERFACE_TABLE_TAIL \
804 #define NS_INTERFACE_TABLE_TAIL_INHERITING(_baseclass) \
805 if (NS_SUCCEEDED(rv)) \
807 return _baseclass::QueryInterface(aIID, aInstancePtr); \
810 #define NS_INTERFACE_TABLE_TAIL_USING_AGGREGATOR(_aggregator) \
811 if (NS_SUCCEEDED(rv)) \
813 NS_ASSERTION(_aggregator, "null aggregator"); \
814 return _aggregator->QueryInterface(aIID, aInstancePtr) \
818 * This implements query interface with two assumptions: First, the
819 * class in question implements nsISupports and its own interface and
820 * nothing else. Second, the implementation of the class's primary
821 * inheritance chain leads to its own interface.
823 * @param _class The name of the class implementing the method
824 * @param _classiiddef The name of the #define symbol that defines the IID
825 * for the class (e.g. NS_ISUPPORTS_IID)
828 #define NS_IMPL_QUERY_HEAD(_class) \
829 NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \
831 NS_ASSERTION(aInstancePtr, \
832 "QueryInterface requires a non-NULL destination!"); \
833 nsISupports* foundInterface;
835 #define NS_IMPL_QUERY_BODY(_interface) \
836 if ( aIID.Equals(NS_GET_IID(_interface)) ) \
837 foundInterface = static_cast<_interface*>(this); \
840 #define NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) \
841 if ( (condition) && aIID.Equals(NS_GET_IID(_interface))) \
842 foundInterface = static_cast<_interface*>(this); \
845 #define NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) \
846 if ( aIID.Equals(NS_GET_IID(_interface)) ) \
847 foundInterface = static_cast<_interface*>( \
848 static_cast<_implClass*>(this)); \
851 #define NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate) \
852 if ( aIID.Equals(NS_GET_IID(_interface)) ) \
853 foundInterface = static_cast<_interface*>(_aggregate); \
856 #define NS_IMPL_QUERY_TAIL_GUTS \
857 foundInterface = 0; \
859 if ( !foundInterface ) \
861 /* nsISupports should be handled by this point. If not, fail. */ \
862 MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsISupports))); \
863 status = NS_NOINTERFACE; \
867 NS_ADDREF(foundInterface); \
870 *aInstancePtr = foundInterface; \
874 #define NS_IMPL_QUERY_TAIL_INHERITING(_baseclass) \
875 foundInterface = 0; \
877 if ( !foundInterface ) \
878 status = _baseclass::QueryInterface(aIID, (void**)&foundInterface); \
881 NS_ADDREF(foundInterface); \
884 *aInstancePtr = foundInterface; \
888 #define NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) \
889 foundInterface = 0; \
891 if ( !foundInterface ) { \
892 NS_ASSERTION(_aggregator, "null aggregator"); \
893 status = _aggregator->QueryInterface(aIID, (void**)&foundInterface); \
896 NS_ADDREF(foundInterface); \
899 *aInstancePtr = foundInterface; \
903 #define NS_IMPL_QUERY_TAIL(_supports_interface) \
904 NS_IMPL_QUERY_BODY_AMBIGUOUS(nsISupports, _supports_interface) \
905 NS_IMPL_QUERY_TAIL_GUTS
909 This is the new scheme. Using this notation now will allow us to switch to
910 a table driven mechanism when it's ready. Note the difference between this
911 and the (currently) underlying NS_IMPL_QUERY_INTERFACE mechanism. You must
912 explicitly mention |nsISupports| when using the interface maps.
914 #define NS_INTERFACE_MAP_BEGIN(_implClass) NS_IMPL_QUERY_HEAD(_implClass)
915 #define NS_INTERFACE_MAP_ENTRY(_interface) NS_IMPL_QUERY_BODY(_interface)
916 #define NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, condition) \
917 NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition)
918 #define NS_INTERFACE_MAP_ENTRY_AGGREGATED(_interface,_aggregate) \
919 NS_IMPL_QUERY_BODY_AGGREGATED(_interface,_aggregate)
921 #define NS_INTERFACE_MAP_END NS_IMPL_QUERY_TAIL_GUTS
922 #define NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(_interface, _implClass) \
923 NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass)
924 #define NS_INTERFACE_MAP_END_INHERITING(_baseClass) \
925 NS_IMPL_QUERY_TAIL_INHERITING(_baseClass)
926 #define NS_INTERFACE_MAP_END_AGGREGATED(_aggregator) \
927 NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator)
929 #define NS_INTERFACE_TABLE0(_class) \
930 NS_INTERFACE_TABLE_BEGIN \
931 NS_INTERFACE_TABLE_ENTRY(_class, nsISupports) \
932 NS_INTERFACE_TABLE_END
934 #define NS_INTERFACE_TABLE(aClass, ...) \
935 MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \
936 NS_INTERFACE_TABLE_BEGIN \
937 MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass,), (__VA_ARGS__)) \
938 NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(aClass, nsISupports, \
939 MOZ_ARG_1(__VA_ARGS__)) \
940 NS_INTERFACE_TABLE_END
942 #define NS_IMPL_QUERY_INTERFACE0(_class) \
943 NS_INTERFACE_TABLE_HEAD(_class) \
944 NS_INTERFACE_TABLE0(_class) \
945 NS_INTERFACE_TABLE_TAIL
947 #define NS_IMPL_QUERY_INTERFACE(aClass, ...) \
948 NS_INTERFACE_TABLE_HEAD(aClass) \
949 NS_INTERFACE_TABLE(aClass, __VA_ARGS__) \
950 NS_INTERFACE_TABLE_TAIL
953 * Declare that you're going to inherit from something that already
954 * implements nsISupports, but also implements an additional interface, thus
955 * causing an ambiguity. In this case you don't need another mRefCnt, you
956 * just need to forward the definitions to the appropriate superclass. E.g.
958 * class Bar : public Foo, public nsIBar { // both provide nsISupports
960 * NS_DECL_ISUPPORTS_INHERITED
961 * ...other nsIBar and Bar methods...
964 #define NS_DECL_ISUPPORTS_INHERITED \
966 NS_IMETHOD QueryInterface(REFNSIID aIID, \
967 void** aInstancePtr) MOZ_OVERRIDE; \
968 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) MOZ_OVERRIDE; \
969 NS_IMETHOD_(MozExternalRefCountType) Release(void) MOZ_OVERRIDE; \
972 * These macros can be used in conjunction with NS_DECL_ISUPPORTS_INHERITED
973 * to implement the nsISupports methods, forwarding the invocations to a
974 * superclass that already implements nsISupports.
976 * Note that I didn't make these inlined because they're virtual methods.
979 #define NS_IMPL_ADDREF_INHERITED(Class, Super) \
980 NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) \
982 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(Class) \
983 nsrefcnt r = Super::AddRef(); \
984 NS_LOG_ADDREF(this, r, #Class, sizeof(*this)); \
988 #define NS_IMPL_RELEASE_INHERITED(Class, Super) \
989 NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \
991 nsrefcnt r = Super::Release(); \
992 NS_LOG_RELEASE(this, r, #Class); \
997 * As above but not logging the addref/release; needed if the base
998 * class might be aggregated.
1000 #define NS_IMPL_NONLOGGING_ADDREF_INHERITED(Class, Super) \
1001 NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) \
1003 MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(Class) \
1004 return Super::AddRef(); \
1007 #define NS_IMPL_NONLOGGING_RELEASE_INHERITED(Class, Super) \
1008 NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \
1010 return Super::Release(); \
1013 #define NS_INTERFACE_TABLE_INHERITED0(Class) /* Nothing to do here */
1015 #define NS_INTERFACE_TABLE_INHERITED(aClass, ...) \
1016 MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \
1017 NS_INTERFACE_TABLE_BEGIN \
1018 MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass,), (__VA_ARGS__)) \
1019 NS_INTERFACE_TABLE_END
1021 #define NS_IMPL_QUERY_INTERFACE_INHERITED0(aClass, aSuper) \
1022 NS_INTERFACE_TABLE_HEAD(aClass) \
1023 NS_INTERFACE_TABLE_INHERITED0(aClass) \
1024 NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper)
1026 #define NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, ...) \
1027 NS_INTERFACE_TABLE_HEAD(aClass) \
1028 NS_INTERFACE_TABLE_INHERITED(aClass, __VA_ARGS__) \
1029 NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper)
1032 * Convenience macros for implementing all nsISupports methods for
1034 * @param _class The name of the class implementing the method
1035 * @param _classiiddef The name of the #define symbol that defines the IID
1036 * for the class (e.g. NS_ISUPPORTS_IID)
1039 #define NS_IMPL_ISUPPORTS0(_class) \
1040 NS_IMPL_ADDREF(_class) \
1041 NS_IMPL_RELEASE(_class) \
1042 NS_IMPL_QUERY_INTERFACE0(_class)
1044 #define NS_IMPL_ISUPPORTS(aClass, ...) \
1045 NS_IMPL_ADDREF(aClass) \
1046 NS_IMPL_RELEASE(aClass) \
1047 NS_IMPL_QUERY_INTERFACE(aClass, __VA_ARGS__)
1049 #define NS_IMPL_ISUPPORTS_INHERITED0(aClass, aSuper) \
1050 NS_IMPL_QUERY_INTERFACE_INHERITED0(aClass, aSuper) \
1051 NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \
1052 NS_IMPL_RELEASE_INHERITED(aClass, aSuper) \
1054 #define NS_IMPL_ISUPPORTS_INHERITED(aClass, aSuper, ...) \
1055 NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, __VA_ARGS__) \
1056 NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \
1057 NS_IMPL_RELEASE_INHERITED(aClass, aSuper)
1060 * Macro to glue together a QI that starts with an interface table
1061 * and segues into an interface map (e.g. it uses singleton classinfo
1064 #define NS_INTERFACE_TABLE_TO_MAP_SEGUE \
1065 if (rv == NS_OK) return rv; \
1066 nsISupports* foundInterface;
1069 ///////////////////////////////////////////////////////////////////////////////
1072 * Threadsafe implementations of the ISupports convenience macros.
1074 * @note These are not available when linking against the standalone glue,
1075 * because the implementation requires PR_ symbols.
1077 #define NS_INTERFACE_MAP_END_THREADSAFE NS_IMPL_QUERY_TAIL_GUTS
1080 * Macro to generate nsIClassInfo methods for classes which do not have
1081 * corresponding nsIFactory implementations.
1083 #define NS_IMPL_THREADSAFE_CI(_class) \
1085 _class::GetInterfaces(uint32_t* _count, nsIID*** _array) \
1087 return NS_CI_INTERFACE_GETTER_NAME(_class)(_count, _array); \
1091 _class::GetHelperForLanguage(uint32_t _language, nsISupports** _retval) \
1093 *_retval = nullptr; \
1098 _class::GetContractID(char** _contractID) \
1100 *_contractID = nullptr; \
1105 _class::GetClassDescription(char** _classDescription) \
1107 *_classDescription = nullptr; \
1112 _class::GetClassID(nsCID** _classID) \
1114 *_classID = nullptr; \
1119 _class::GetImplementationLanguage(uint32_t* _language) \
1121 *_language = nsIProgrammingLanguage::CPLUSPLUS; \
1126 _class::GetFlags(uint32_t* _flags) \
1128 *_flags = nsIClassInfo::THREADSAFE; \
1133 _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) \
1135 return NS_ERROR_NOT_AVAILABLE; \