Bumping manifests a=b2g-bump
[gecko.git] / xpcom / glue / nsISupportsImpl.h
blob75c5179c3fa4f4c9c72927b3b432290f951910a7
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__
12 #include "nscore.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
21 #include "nsDebug.h"
22 #include "nsXPCOM.h"
23 #ifndef XPCOM_GLUE
24 #include "mozilla/Atomics.h"
25 #endif
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"
33 namespace mozilla {
34 template <typename T>
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
55 # endif
56 #endif
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
62 namespace mozilla {
63 struct IsDestructibleFallbackImpl
65 template<typename T> static T&& Declval();
67 template<typename T, typename = decltype(Declval<T>().~T())>
68 static TrueType Test(int);
70 template<typename>
71 static FalseType Test(...);
73 template<typename T>
74 struct Selector
76 typedef decltype(Test<T>(0)) type;
80 template<typename T>
81 struct IsDestructibleFallback
82 : IsDestructibleFallbackImpl::Selector<T>::type
86 # define MOZ_IS_DESTRUCTIBLE(X) (mozilla::IsDestructibleFallback<X>::value)
87 #endif
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.");
101 #else
102 #define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X)
103 #endif
105 inline nsISupports*
106 ToSupports(nsISupports* aSupports)
108 return aSupports;
111 inline nsISupports*
112 ToCanonicalSupports(nsISupports* aSupports)
114 return nullptr;
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
124 public:
125 nsAutoOwningThread() { mThread = PR_GetCurrentThread(); }
126 void* GetThread() const { return mThread; }
128 private:
129 void* 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.
161 #if MOZ_IS_GCC
162 # if !MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
163 # undef MOZ_ASSERT_CLASSNAME
164 # define MOZ_ASSERT_CLASSNAME(_type)
165 # endif
166 #endif
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) \
172 do { \
173 MOZ_ASSERT_CLASSNAME(_type); \
174 NS_LogCtor((void*)this, #_type, sizeof(*this)); \
175 } while (0)
177 #define MOZ_COUNT_CTOR_INHERITED(_type, _base) \
178 do { \
179 MOZ_ASSERT_CLASSNAME(_type); \
180 MOZ_ASSERT_CLASSNAME(_base); \
181 NS_LogCtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
182 } while (0)
184 #define MOZ_COUNT_DTOR(_type) \
185 do { \
186 MOZ_ASSERT_CLASSNAME(_type); \
187 NS_LogDtor((void*)this, #_type, sizeof(*this)); \
188 } while (0)
190 #define MOZ_COUNT_DTOR_INHERITED(_type, _base) \
191 do { \
192 MOZ_ASSERT_CLASSNAME(_type); \
193 MOZ_ASSERT_CLASSNAME(_base); \
194 NS_LogDtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
195 } while (0)
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) \
201 if (_p) \
202 NS_LogCOMPtrAddRef((_c),static_cast<nsISupports*>(_p))
204 #define NSCAP_LOG_RELEASE(_c, _p) \
205 if (_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
230 public:
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);
283 return retval;
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
319 return get();
322 private:
323 uintptr_t mRefCntAndFlags;
326 class nsAutoRefCnt
328 public:
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;
341 private:
342 nsrefcnt operator++(int) = delete;
343 nsrefcnt operator--(int) = delete;
344 nsrefcnt mValue;
347 #ifndef XPCOM_GLUE
348 namespace mozilla {
349 class ThreadSafeAutoRefCnt
351 public:
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;
367 private:
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;
376 #endif
378 ///////////////////////////////////////////////////////////////////////////////
381 * Declare the reference count variable and the implementations of the
382 * AddRef and QueryInterface methods.
385 #define NS_DECL_ISUPPORTS \
386 public: \
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; \
391 protected: \
392 nsAutoRefCnt mRefCnt; \
393 NS_DECL_OWNINGTHREAD \
394 public:
396 #define NS_DECL_THREADSAFE_ISUPPORTS \
397 public: \
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; \
402 protected: \
403 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
404 NS_DECL_OWNINGTHREAD \
405 public:
407 #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \
408 public: \
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); \
414 protected: \
415 nsCycleCollectingAutoRefCnt mRefCnt; \
416 NS_DECL_OWNINGTHREAD \
417 public:
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); \
431 nsrefcnt count = \
432 mRefCnt.incr(static_cast<void*>(this), \
433 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
434 NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
435 return count;
437 #define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
438 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
439 NS_ASSERT_OWNINGTHREAD(_class); \
440 nsrefcnt count = \
441 mRefCnt.decr(static_cast<void*>(this), \
442 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
443 NS_LOG_RELEASE(this, count, #_class); \
444 return count;
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; \
458 nsrefcnt count = \
459 mRefCnt.decr(static_cast<void*>(this), \
460 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant(), \
461 &shouldDelete); \
462 NS_LOG_RELEASE(this, count, #_class); \
463 if (count == 0) { \
464 mRefCnt.incr(static_cast<void*>(this), \
465 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
466 _last; \
467 mRefCnt.decr(static_cast<void*>(this), \
468 _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
469 if (shouldDelete) { \
470 mRefCnt.stabilizeForDeletion(); \
471 DeleteCycleCollectable(); \
474 return count; \
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) \
484 public: \
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) \
491 protected: \
492 nsCycleCollectingAutoRefCnt mRefCnt; \
493 NS_DECL_OWNINGTHREAD \
494 public:
497 ///////////////////////////////////////////////////////////////////////////////
500 * Previously used to initialize the reference count, but no longer needed.
502 * DEPRECATED.
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, ...) \
514 public: \
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); \
519 ++mRefCnt; \
520 NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
521 return mRefCnt; \
523 NS_METHOD_(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
524 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
525 NS_ASSERT_OWNINGTHREAD(_class); \
526 --mRefCnt; \
527 NS_LOG_RELEASE(this, mRefCnt, #_class); \
528 if (mRefCnt == 0) { \
529 NS_ASSERT_OWNINGTHREAD(_class); \
530 mRefCnt = 1; /* stabilize */ \
531 delete this; \
532 return 0; \
534 return mRefCnt; \
536 protected: \
537 nsAutoRefCnt mRefCnt; \
538 NS_DECL_OWNINGTHREAD \
539 public:
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, ...) \
550 public: \
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); \
562 if (count == 0) { \
563 delete (this); \
564 return 0; \
566 return count; \
568 protected: \
569 ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
570 public:
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)); \
585 return count; \
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
605 * <i>_class</i>.
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.
610 * For example,
612 * NS_IMPL_RELEASE_WITH_DESTROY(Foo, Destroy(this))
614 * will cause
616 * 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); \
630 if (count == 0) { \
631 if (!mRefCnt.isThreadSafe) \
632 NS_ASSERT_OWNINGTHREAD(_class); \
633 mRefCnt = 1; /* stabilize */ \
634 _destroy; \
635 return 0; \
637 return count; \
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)); \
680 return count; \
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); \
691 return count; \
693 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \
695 _destroy; \
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); \
712 if (count == 0) { \
713 mRefCnt.incr(base); \
714 _last; \
715 mRefCnt.decr(base); \
716 if (shouldDelete) { \
717 mRefCnt.stabilizeForDeletion(); \
718 DeleteCycleCollectable(); \
721 return count; \
723 NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \
725 delete this; \
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.
745 struct QITableEntry
747 const nsIID* iid; // null indicates end of the QITableEntry array
748 int32_t offset;
751 nsresult NS_FASTCALL
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) \
792 { nullptr, 0 } }; \
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 \
801 return rv; \
804 #define NS_INTERFACE_TABLE_TAIL_INHERITING(_baseclass) \
805 if (NS_SUCCEEDED(rv)) \
806 return rv; \
807 return _baseclass::QueryInterface(aIID, aInstancePtr); \
810 #define NS_INTERFACE_TABLE_TAIL_USING_AGGREGATOR(_aggregator) \
811 if (NS_SUCCEEDED(rv)) \
812 return 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); \
838 else
840 #define NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) \
841 if ( (condition) && aIID.Equals(NS_GET_IID(_interface))) \
842 foundInterface = static_cast<_interface*>(this); \
843 else
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)); \
849 else
851 #define NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate) \
852 if ( aIID.Equals(NS_GET_IID(_interface)) ) \
853 foundInterface = static_cast<_interface*>(_aggregate); \
854 else
856 #define NS_IMPL_QUERY_TAIL_GUTS \
857 foundInterface = 0; \
858 nsresult status; \
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; \
865 else \
867 NS_ADDREF(foundInterface); \
868 status = NS_OK; \
870 *aInstancePtr = foundInterface; \
871 return status; \
874 #define NS_IMPL_QUERY_TAIL_INHERITING(_baseclass) \
875 foundInterface = 0; \
876 nsresult status; \
877 if ( !foundInterface ) \
878 status = _baseclass::QueryInterface(aIID, (void**)&foundInterface); \
879 else \
881 NS_ADDREF(foundInterface); \
882 status = NS_OK; \
884 *aInstancePtr = foundInterface; \
885 return status; \
888 #define NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) \
889 foundInterface = 0; \
890 nsresult status; \
891 if ( !foundInterface ) { \
892 NS_ASSERTION(_aggregator, "null aggregator"); \
893 status = _aggregator->QueryInterface(aIID, (void**)&foundInterface); \
894 } else \
896 NS_ADDREF(foundInterface); \
897 status = NS_OK; \
899 *aInstancePtr = foundInterface; \
900 return status; \
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
959 * public:
960 * NS_DECL_ISUPPORTS_INHERITED
961 * ...other nsIBar and Bar methods...
962 * };
964 #define NS_DECL_ISUPPORTS_INHERITED \
965 public: \
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)); \
985 return r; \
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); \
993 return r; \
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
1033 * a simple class.
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
1062 * or tearoffs).
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) \
1084 NS_IMETHODIMP \
1085 _class::GetInterfaces(uint32_t* _count, nsIID*** _array) \
1087 return NS_CI_INTERFACE_GETTER_NAME(_class)(_count, _array); \
1090 NS_IMETHODIMP \
1091 _class::GetHelperForLanguage(uint32_t _language, nsISupports** _retval) \
1093 *_retval = nullptr; \
1094 return NS_OK; \
1097 NS_IMETHODIMP \
1098 _class::GetContractID(char** _contractID) \
1100 *_contractID = nullptr; \
1101 return NS_OK; \
1104 NS_IMETHODIMP \
1105 _class::GetClassDescription(char** _classDescription) \
1107 *_classDescription = nullptr; \
1108 return NS_OK; \
1111 NS_IMETHODIMP \
1112 _class::GetClassID(nsCID** _classID) \
1114 *_classID = nullptr; \
1115 return NS_OK; \
1118 NS_IMETHODIMP \
1119 _class::GetImplementationLanguage(uint32_t* _language) \
1121 *_language = nsIProgrammingLanguage::CPLUSPLUS; \
1122 return NS_OK; \
1125 NS_IMETHODIMP \
1126 _class::GetFlags(uint32_t* _flags) \
1128 *_flags = nsIClassInfo::THREADSAFE; \
1129 return NS_OK; \
1132 NS_IMETHODIMP \
1133 _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) \
1135 return NS_ERROR_NOT_AVAILABLE; \
1138 #endif