Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | // IWYU pragma: private, include "nsISupports.h" |
michael@0 | 6 | |
michael@0 | 7 | |
michael@0 | 8 | #ifndef nsISupportsImpl_h__ |
michael@0 | 9 | #define nsISupportsImpl_h__ |
michael@0 | 10 | |
michael@0 | 11 | #include "nscore.h" |
michael@0 | 12 | #include "nsISupportsBase.h" |
michael@0 | 13 | #include "nsISupportsUtils.h" |
michael@0 | 14 | |
michael@0 | 15 | |
michael@0 | 16 | #if !defined(XPCOM_GLUE_AVOID_NSPR) |
michael@0 | 17 | #include "prthread.h" /* needed for thread-safety checks */ |
michael@0 | 18 | #endif // !XPCOM_GLUE_AVOID_NSPR |
michael@0 | 19 | |
michael@0 | 20 | #include "nsDebug.h" |
michael@0 | 21 | #include "nsXPCOM.h" |
michael@0 | 22 | #ifndef XPCOM_GLUE |
michael@0 | 23 | #include "mozilla/Atomics.h" |
michael@0 | 24 | #endif |
michael@0 | 25 | #include "mozilla/Attributes.h" |
michael@0 | 26 | #include "mozilla/Assertions.h" |
michael@0 | 27 | #include "mozilla/Likely.h" |
michael@0 | 28 | #include "mozilla/MacroArgs.h" |
michael@0 | 29 | #include "mozilla/MacroForEach.h" |
michael@0 | 30 | |
michael@0 | 31 | inline nsISupports* |
michael@0 | 32 | ToSupports(nsISupports* p) |
michael@0 | 33 | { |
michael@0 | 34 | return p; |
michael@0 | 35 | } |
michael@0 | 36 | |
michael@0 | 37 | inline nsISupports* |
michael@0 | 38 | ToCanonicalSupports(nsISupports* p) |
michael@0 | 39 | { |
michael@0 | 40 | return nullptr; |
michael@0 | 41 | } |
michael@0 | 42 | |
michael@0 | 43 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 44 | // Macros to help detect thread-safety: |
michael@0 | 45 | |
michael@0 | 46 | #if (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING))) && !defined(XPCOM_GLUE_AVOID_NSPR) |
michael@0 | 47 | |
michael@0 | 48 | class nsAutoOwningThread { |
michael@0 | 49 | public: |
michael@0 | 50 | nsAutoOwningThread() { mThread = PR_GetCurrentThread(); } |
michael@0 | 51 | void *GetThread() const { return mThread; } |
michael@0 | 52 | |
michael@0 | 53 | private: |
michael@0 | 54 | void *mThread; |
michael@0 | 55 | }; |
michael@0 | 56 | |
michael@0 | 57 | #define NS_DECL_OWNINGTHREAD nsAutoOwningThread _mOwningThread; |
michael@0 | 58 | #define NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class) \ |
michael@0 | 59 | NS_CheckThreadSafe(agg->_mOwningThread.GetThread(), #_class " not thread-safe") |
michael@0 | 60 | #define NS_ASSERT_OWNINGTHREAD(_class) NS_ASSERT_OWNINGTHREAD_AGGREGATE(this, _class) |
michael@0 | 61 | #else // !DEBUG && !(NIGHTLY_BUILD && !MOZ_PROFILING) |
michael@0 | 62 | |
michael@0 | 63 | #define NS_DECL_OWNINGTHREAD /* nothing */ |
michael@0 | 64 | #define NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class) ((void)0) |
michael@0 | 65 | #define NS_ASSERT_OWNINGTHREAD(_class) ((void)0) |
michael@0 | 66 | |
michael@0 | 67 | #endif // DEBUG || (NIGHTLY_BUILD && !MOZ_PROFILING) |
michael@0 | 68 | |
michael@0 | 69 | |
michael@0 | 70 | // Macros for reference-count and constructor logging |
michael@0 | 71 | |
michael@0 | 72 | #ifdef NS_BUILD_REFCNT_LOGGING |
michael@0 | 73 | |
michael@0 | 74 | #define NS_LOG_ADDREF(_p, _rc, _type, _size) \ |
michael@0 | 75 | NS_LogAddRef((_p), (_rc), (_type), (uint32_t) (_size)) |
michael@0 | 76 | |
michael@0 | 77 | #define NS_LOG_RELEASE(_p, _rc, _type) \ |
michael@0 | 78 | NS_LogRelease((_p), (_rc), (_type)) |
michael@0 | 79 | |
michael@0 | 80 | // Note that the following constructor/destructor logging macros are redundant |
michael@0 | 81 | // for refcounted objects that log via the NS_LOG_ADDREF/NS_LOG_RELEASE macros. |
michael@0 | 82 | // Refcount logging is preferred. |
michael@0 | 83 | #define MOZ_COUNT_CTOR(_type) \ |
michael@0 | 84 | do { \ |
michael@0 | 85 | NS_LogCtor((void*)this, #_type, sizeof(*this)); \ |
michael@0 | 86 | } while (0) |
michael@0 | 87 | |
michael@0 | 88 | #define MOZ_COUNT_CTOR_INHERITED(_type, _base) \ |
michael@0 | 89 | do { \ |
michael@0 | 90 | NS_LogCtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \ |
michael@0 | 91 | } while (0) |
michael@0 | 92 | |
michael@0 | 93 | #define MOZ_COUNT_DTOR(_type) \ |
michael@0 | 94 | do { \ |
michael@0 | 95 | NS_LogDtor((void*)this, #_type, sizeof(*this)); \ |
michael@0 | 96 | } while (0) |
michael@0 | 97 | |
michael@0 | 98 | #define MOZ_COUNT_DTOR_INHERITED(_type, _base) \ |
michael@0 | 99 | do { \ |
michael@0 | 100 | NS_LogDtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \ |
michael@0 | 101 | } while (0) |
michael@0 | 102 | |
michael@0 | 103 | /* nsCOMPtr.h allows these macros to be defined by clients |
michael@0 | 104 | * These logging functions require dynamic_cast<void*>, so they don't |
michael@0 | 105 | * do anything useful if we don't have dynamic_cast<void*>. */ |
michael@0 | 106 | #define NSCAP_LOG_ASSIGNMENT(_c, _p) \ |
michael@0 | 107 | if (_p) \ |
michael@0 | 108 | NS_LogCOMPtrAddRef((_c),static_cast<nsISupports*>(_p)) |
michael@0 | 109 | |
michael@0 | 110 | #define NSCAP_LOG_RELEASE(_c, _p) \ |
michael@0 | 111 | if (_p) \ |
michael@0 | 112 | NS_LogCOMPtrRelease((_c), static_cast<nsISupports*>(_p)) |
michael@0 | 113 | |
michael@0 | 114 | #else /* !NS_BUILD_REFCNT_LOGGING */ |
michael@0 | 115 | |
michael@0 | 116 | #define NS_LOG_ADDREF(_p, _rc, _type, _size) |
michael@0 | 117 | #define NS_LOG_RELEASE(_p, _rc, _type) |
michael@0 | 118 | #define MOZ_COUNT_CTOR(_type) |
michael@0 | 119 | #define MOZ_COUNT_CTOR_INHERITED(_type, _base) |
michael@0 | 120 | #define MOZ_COUNT_DTOR(_type) |
michael@0 | 121 | #define MOZ_COUNT_DTOR_INHERITED(_type, _base) |
michael@0 | 122 | |
michael@0 | 123 | #endif /* NS_BUILD_REFCNT_LOGGING */ |
michael@0 | 124 | |
michael@0 | 125 | |
michael@0 | 126 | // Support for ISupports classes which interact with cycle collector. |
michael@0 | 127 | |
michael@0 | 128 | #define NS_NUMBER_OF_FLAGS_IN_REFCNT 2 |
michael@0 | 129 | #define NS_IN_PURPLE_BUFFER (1 << 0) |
michael@0 | 130 | #define NS_IS_PURPLE (1 << 1) |
michael@0 | 131 | #define NS_REFCOUNT_CHANGE (1 << NS_NUMBER_OF_FLAGS_IN_REFCNT) |
michael@0 | 132 | #define NS_REFCOUNT_VALUE(_val) (_val >> NS_NUMBER_OF_FLAGS_IN_REFCNT) |
michael@0 | 133 | |
michael@0 | 134 | class nsCycleCollectingAutoRefCnt { |
michael@0 | 135 | |
michael@0 | 136 | public: |
michael@0 | 137 | nsCycleCollectingAutoRefCnt() |
michael@0 | 138 | : mRefCntAndFlags(0) |
michael@0 | 139 | {} |
michael@0 | 140 | |
michael@0 | 141 | nsCycleCollectingAutoRefCnt(uintptr_t aValue) |
michael@0 | 142 | : mRefCntAndFlags(aValue << NS_NUMBER_OF_FLAGS_IN_REFCNT) |
michael@0 | 143 | { |
michael@0 | 144 | } |
michael@0 | 145 | |
michael@0 | 146 | MOZ_ALWAYS_INLINE uintptr_t incr(nsISupports *owner) |
michael@0 | 147 | { |
michael@0 | 148 | return incr(owner, nullptr); |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | MOZ_ALWAYS_INLINE uintptr_t incr(void *owner, nsCycleCollectionParticipant *p) |
michael@0 | 152 | { |
michael@0 | 153 | mRefCntAndFlags += NS_REFCOUNT_CHANGE; |
michael@0 | 154 | mRefCntAndFlags &= ~NS_IS_PURPLE; |
michael@0 | 155 | // For incremental cycle collection, use the purple buffer to track objects |
michael@0 | 156 | // that have been AddRef'd. |
michael@0 | 157 | if (!IsInPurpleBuffer()) { |
michael@0 | 158 | mRefCntAndFlags |= NS_IN_PURPLE_BUFFER; |
michael@0 | 159 | // Refcount isn't zero, so Suspect won't delete anything. |
michael@0 | 160 | MOZ_ASSERT(get() > 0); |
michael@0 | 161 | NS_CycleCollectorSuspect3(owner, p, this, nullptr); |
michael@0 | 162 | } |
michael@0 | 163 | return NS_REFCOUNT_VALUE(mRefCntAndFlags); |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | MOZ_ALWAYS_INLINE void stabilizeForDeletion() |
michael@0 | 167 | { |
michael@0 | 168 | // Set refcnt to 1 and mark us to be in the purple buffer. |
michael@0 | 169 | // This way decr won't call suspect again. |
michael@0 | 170 | mRefCntAndFlags = NS_REFCOUNT_CHANGE | NS_IN_PURPLE_BUFFER; |
michael@0 | 171 | } |
michael@0 | 172 | |
michael@0 | 173 | MOZ_ALWAYS_INLINE uintptr_t decr(nsISupports *owner, |
michael@0 | 174 | bool *shouldDelete = nullptr) |
michael@0 | 175 | { |
michael@0 | 176 | return decr(owner, nullptr, shouldDelete); |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | MOZ_ALWAYS_INLINE uintptr_t decr(void *owner, nsCycleCollectionParticipant *p, |
michael@0 | 180 | bool *shouldDelete = nullptr) |
michael@0 | 181 | { |
michael@0 | 182 | MOZ_ASSERT(get() > 0); |
michael@0 | 183 | if (!IsInPurpleBuffer()) { |
michael@0 | 184 | mRefCntAndFlags -= NS_REFCOUNT_CHANGE; |
michael@0 | 185 | mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE); |
michael@0 | 186 | uintptr_t retval = NS_REFCOUNT_VALUE(mRefCntAndFlags); |
michael@0 | 187 | // Suspect may delete 'owner' and 'this'! |
michael@0 | 188 | NS_CycleCollectorSuspect3(owner, p, this, shouldDelete); |
michael@0 | 189 | return retval; |
michael@0 | 190 | } |
michael@0 | 191 | mRefCntAndFlags -= NS_REFCOUNT_CHANGE; |
michael@0 | 192 | mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE); |
michael@0 | 193 | return NS_REFCOUNT_VALUE(mRefCntAndFlags); |
michael@0 | 194 | } |
michael@0 | 195 | |
michael@0 | 196 | MOZ_ALWAYS_INLINE void RemovePurple() |
michael@0 | 197 | { |
michael@0 | 198 | MOZ_ASSERT(IsPurple(), "must be purple"); |
michael@0 | 199 | mRefCntAndFlags &= ~NS_IS_PURPLE; |
michael@0 | 200 | } |
michael@0 | 201 | |
michael@0 | 202 | MOZ_ALWAYS_INLINE void RemoveFromPurpleBuffer() |
michael@0 | 203 | { |
michael@0 | 204 | MOZ_ASSERT(IsInPurpleBuffer()); |
michael@0 | 205 | mRefCntAndFlags &= ~(NS_IS_PURPLE | NS_IN_PURPLE_BUFFER); |
michael@0 | 206 | } |
michael@0 | 207 | |
michael@0 | 208 | MOZ_ALWAYS_INLINE bool IsPurple() const |
michael@0 | 209 | { |
michael@0 | 210 | return !!(mRefCntAndFlags & NS_IS_PURPLE); |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | MOZ_ALWAYS_INLINE bool IsInPurpleBuffer() const |
michael@0 | 214 | { |
michael@0 | 215 | return !!(mRefCntAndFlags & NS_IN_PURPLE_BUFFER); |
michael@0 | 216 | } |
michael@0 | 217 | |
michael@0 | 218 | MOZ_ALWAYS_INLINE nsrefcnt get() const |
michael@0 | 219 | { |
michael@0 | 220 | return NS_REFCOUNT_VALUE(mRefCntAndFlags); |
michael@0 | 221 | } |
michael@0 | 222 | |
michael@0 | 223 | MOZ_ALWAYS_INLINE operator nsrefcnt() const |
michael@0 | 224 | { |
michael@0 | 225 | return get(); |
michael@0 | 226 | } |
michael@0 | 227 | |
michael@0 | 228 | private: |
michael@0 | 229 | uintptr_t mRefCntAndFlags; |
michael@0 | 230 | }; |
michael@0 | 231 | |
michael@0 | 232 | class nsAutoRefCnt { |
michael@0 | 233 | |
michael@0 | 234 | public: |
michael@0 | 235 | nsAutoRefCnt() : mValue(0) {} |
michael@0 | 236 | nsAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {} |
michael@0 | 237 | |
michael@0 | 238 | // only support prefix increment/decrement |
michael@0 | 239 | nsrefcnt operator++() { return ++mValue; } |
michael@0 | 240 | nsrefcnt operator--() { return --mValue; } |
michael@0 | 241 | |
michael@0 | 242 | nsrefcnt operator=(nsrefcnt aValue) { return (mValue = aValue); } |
michael@0 | 243 | operator nsrefcnt() const { return mValue; } |
michael@0 | 244 | nsrefcnt get() const { return mValue; } |
michael@0 | 245 | |
michael@0 | 246 | static const bool isThreadSafe = false; |
michael@0 | 247 | private: |
michael@0 | 248 | nsrefcnt operator++(int) MOZ_DELETE; |
michael@0 | 249 | nsrefcnt operator--(int) MOZ_DELETE; |
michael@0 | 250 | nsrefcnt mValue; |
michael@0 | 251 | }; |
michael@0 | 252 | |
michael@0 | 253 | #ifndef XPCOM_GLUE |
michael@0 | 254 | namespace mozilla { |
michael@0 | 255 | class ThreadSafeAutoRefCnt { |
michael@0 | 256 | public: |
michael@0 | 257 | ThreadSafeAutoRefCnt() : mValue(0) {} |
michael@0 | 258 | ThreadSafeAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {} |
michael@0 | 259 | |
michael@0 | 260 | // only support prefix increment/decrement |
michael@0 | 261 | MOZ_ALWAYS_INLINE nsrefcnt operator++() { return ++mValue; } |
michael@0 | 262 | MOZ_ALWAYS_INLINE nsrefcnt operator--() { return --mValue; } |
michael@0 | 263 | |
michael@0 | 264 | MOZ_ALWAYS_INLINE nsrefcnt operator=(nsrefcnt aValue) { return (mValue = aValue); } |
michael@0 | 265 | MOZ_ALWAYS_INLINE operator nsrefcnt() const { return mValue; } |
michael@0 | 266 | MOZ_ALWAYS_INLINE nsrefcnt get() const { return mValue; } |
michael@0 | 267 | |
michael@0 | 268 | static const bool isThreadSafe = true; |
michael@0 | 269 | private: |
michael@0 | 270 | nsrefcnt operator++(int) MOZ_DELETE; |
michael@0 | 271 | nsrefcnt operator--(int) MOZ_DELETE; |
michael@0 | 272 | // In theory, RelaseAcquire consistency (but no weaker) is sufficient for |
michael@0 | 273 | // the counter. Making it weaker could speed up builds on ARM (but not x86), |
michael@0 | 274 | // but could break pre-existing code that assumes sequential consistency. |
michael@0 | 275 | Atomic<nsrefcnt> mValue; |
michael@0 | 276 | }; |
michael@0 | 277 | } |
michael@0 | 278 | #endif |
michael@0 | 279 | |
michael@0 | 280 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 281 | |
michael@0 | 282 | /** |
michael@0 | 283 | * Declare the reference count variable and the implementations of the |
michael@0 | 284 | * AddRef and QueryInterface methods. |
michael@0 | 285 | */ |
michael@0 | 286 | |
michael@0 | 287 | #define NS_DECL_ISUPPORTS \ |
michael@0 | 288 | public: \ |
michael@0 | 289 | NS_IMETHOD QueryInterface(REFNSIID aIID, \ |
michael@0 | 290 | void** aInstancePtr); \ |
michael@0 | 291 | NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ |
michael@0 | 292 | NS_IMETHOD_(MozExternalRefCountType) Release(void); \ |
michael@0 | 293 | protected: \ |
michael@0 | 294 | nsAutoRefCnt mRefCnt; \ |
michael@0 | 295 | NS_DECL_OWNINGTHREAD \ |
michael@0 | 296 | public: |
michael@0 | 297 | |
michael@0 | 298 | #define NS_DECL_THREADSAFE_ISUPPORTS \ |
michael@0 | 299 | public: \ |
michael@0 | 300 | NS_IMETHOD QueryInterface(REFNSIID aIID, \ |
michael@0 | 301 | void** aInstancePtr); \ |
michael@0 | 302 | NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ |
michael@0 | 303 | NS_IMETHOD_(MozExternalRefCountType) Release(void); \ |
michael@0 | 304 | protected: \ |
michael@0 | 305 | ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \ |
michael@0 | 306 | NS_DECL_OWNINGTHREAD \ |
michael@0 | 307 | public: |
michael@0 | 308 | |
michael@0 | 309 | #define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \ |
michael@0 | 310 | public: \ |
michael@0 | 311 | NS_IMETHOD QueryInterface(REFNSIID aIID, \ |
michael@0 | 312 | void** aInstancePtr); \ |
michael@0 | 313 | NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ |
michael@0 | 314 | NS_IMETHOD_(MozExternalRefCountType) Release(void); \ |
michael@0 | 315 | NS_IMETHOD_(void) DeleteCycleCollectable(void); \ |
michael@0 | 316 | protected: \ |
michael@0 | 317 | nsCycleCollectingAutoRefCnt mRefCnt; \ |
michael@0 | 318 | NS_DECL_OWNINGTHREAD \ |
michael@0 | 319 | public: |
michael@0 | 320 | |
michael@0 | 321 | |
michael@0 | 322 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 323 | |
michael@0 | 324 | /* |
michael@0 | 325 | * Implementation of AddRef and Release for non-nsISupports (ie "native") |
michael@0 | 326 | * cycle-collected classes that use the purple buffer to avoid leaks. |
michael@0 | 327 | */ |
michael@0 | 328 | |
michael@0 | 329 | #define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \ |
michael@0 | 330 | MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ |
michael@0 | 331 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 332 | nsrefcnt count = \ |
michael@0 | 333 | mRefCnt.incr(static_cast<void*>(this), \ |
michael@0 | 334 | _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \ |
michael@0 | 335 | NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ |
michael@0 | 336 | return count; |
michael@0 | 337 | |
michael@0 | 338 | #define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \ |
michael@0 | 339 | MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ |
michael@0 | 340 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 341 | nsrefcnt count = \ |
michael@0 | 342 | mRefCnt.decr(static_cast<void*>(this), \ |
michael@0 | 343 | _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \ |
michael@0 | 344 | NS_LOG_RELEASE(this, count, #_class); \ |
michael@0 | 345 | return count; |
michael@0 | 346 | |
michael@0 | 347 | #define NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(_class) \ |
michael@0 | 348 | NS_METHOD_(MozExternalRefCountType) _class::AddRef(void) \ |
michael@0 | 349 | { \ |
michael@0 | 350 | NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \ |
michael@0 | 351 | } |
michael@0 | 352 | |
michael@0 | 353 | #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(_class, _last) \ |
michael@0 | 354 | NS_METHOD_(MozExternalRefCountType) _class::Release(void) \ |
michael@0 | 355 | { \ |
michael@0 | 356 | MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ |
michael@0 | 357 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 358 | bool shouldDelete = false; \ |
michael@0 | 359 | nsrefcnt count = \ |
michael@0 | 360 | mRefCnt.decr(static_cast<void*>(this), \ |
michael@0 | 361 | _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant(), \ |
michael@0 | 362 | &shouldDelete); \ |
michael@0 | 363 | NS_LOG_RELEASE(this, count, #_class); \ |
michael@0 | 364 | if (count == 0) { \ |
michael@0 | 365 | mRefCnt.incr(static_cast<void*>(this), \ |
michael@0 | 366 | _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \ |
michael@0 | 367 | _last; \ |
michael@0 | 368 | mRefCnt.decr(static_cast<void*>(this), \ |
michael@0 | 369 | _class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \ |
michael@0 | 370 | if (shouldDelete) { \ |
michael@0 | 371 | mRefCnt.stabilizeForDeletion(); \ |
michael@0 | 372 | DeleteCycleCollectable(); \ |
michael@0 | 373 | } \ |
michael@0 | 374 | } \ |
michael@0 | 375 | return count; \ |
michael@0 | 376 | } |
michael@0 | 377 | |
michael@0 | 378 | #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(_class) \ |
michael@0 | 379 | NS_METHOD_(MozExternalRefCountType) _class::Release(void) \ |
michael@0 | 380 | { \ |
michael@0 | 381 | NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \ |
michael@0 | 382 | } |
michael@0 | 383 | |
michael@0 | 384 | #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(_class) \ |
michael@0 | 385 | public: \ |
michael@0 | 386 | NS_METHOD_(MozExternalRefCountType) AddRef(void) { \ |
michael@0 | 387 | NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \ |
michael@0 | 388 | } \ |
michael@0 | 389 | NS_METHOD_(MozExternalRefCountType) Release(void) { \ |
michael@0 | 390 | NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \ |
michael@0 | 391 | } \ |
michael@0 | 392 | protected: \ |
michael@0 | 393 | nsCycleCollectingAutoRefCnt mRefCnt; \ |
michael@0 | 394 | NS_DECL_OWNINGTHREAD \ |
michael@0 | 395 | public: |
michael@0 | 396 | |
michael@0 | 397 | |
michael@0 | 398 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 399 | |
michael@0 | 400 | /** |
michael@0 | 401 | * Previously used to initialize the reference count, but no longer needed. |
michael@0 | 402 | * |
michael@0 | 403 | * DEPRECATED. |
michael@0 | 404 | */ |
michael@0 | 405 | #define NS_INIT_ISUPPORTS() ((void)0) |
michael@0 | 406 | |
michael@0 | 407 | /** |
michael@0 | 408 | * Use this macro to declare and implement the AddRef & Release methods for a |
michael@0 | 409 | * given non-XPCOM <i>_class</i>. |
michael@0 | 410 | * |
michael@0 | 411 | * @param _class The name of the class implementing the method |
michael@0 | 412 | */ |
michael@0 | 413 | #define NS_INLINE_DECL_REFCOUNTING(_class) \ |
michael@0 | 414 | public: \ |
michael@0 | 415 | NS_METHOD_(MozExternalRefCountType) AddRef(void) { \ |
michael@0 | 416 | MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ |
michael@0 | 417 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 418 | ++mRefCnt; \ |
michael@0 | 419 | NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \ |
michael@0 | 420 | return mRefCnt; \ |
michael@0 | 421 | } \ |
michael@0 | 422 | NS_METHOD_(MozExternalRefCountType) Release(void) { \ |
michael@0 | 423 | MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ |
michael@0 | 424 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 425 | --mRefCnt; \ |
michael@0 | 426 | NS_LOG_RELEASE(this, mRefCnt, #_class); \ |
michael@0 | 427 | if (mRefCnt == 0) { \ |
michael@0 | 428 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 429 | mRefCnt = 1; /* stabilize */ \ |
michael@0 | 430 | delete this; \ |
michael@0 | 431 | return 0; \ |
michael@0 | 432 | } \ |
michael@0 | 433 | return mRefCnt; \ |
michael@0 | 434 | } \ |
michael@0 | 435 | protected: \ |
michael@0 | 436 | nsAutoRefCnt mRefCnt; \ |
michael@0 | 437 | NS_DECL_OWNINGTHREAD \ |
michael@0 | 438 | public: |
michael@0 | 439 | |
michael@0 | 440 | /** |
michael@0 | 441 | * Use this macro to declare and implement the AddRef & Release methods for a |
michael@0 | 442 | * given non-XPCOM <i>_class</i> in a threadsafe manner. |
michael@0 | 443 | * |
michael@0 | 444 | * DOES NOT DO REFCOUNT STABILIZATION! |
michael@0 | 445 | * |
michael@0 | 446 | * @param _class The name of the class implementing the method |
michael@0 | 447 | */ |
michael@0 | 448 | #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING(_class) \ |
michael@0 | 449 | public: \ |
michael@0 | 450 | NS_METHOD_(MozExternalRefCountType) AddRef(void) { \ |
michael@0 | 451 | MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ |
michael@0 | 452 | nsrefcnt count = ++mRefCnt; \ |
michael@0 | 453 | NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ |
michael@0 | 454 | return (nsrefcnt) count; \ |
michael@0 | 455 | } \ |
michael@0 | 456 | NS_METHOD_(MozExternalRefCountType) Release(void) { \ |
michael@0 | 457 | MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ |
michael@0 | 458 | nsrefcnt count = --mRefCnt; \ |
michael@0 | 459 | NS_LOG_RELEASE(this, count, #_class); \ |
michael@0 | 460 | if (count == 0) { \ |
michael@0 | 461 | delete (this); \ |
michael@0 | 462 | return 0; \ |
michael@0 | 463 | } \ |
michael@0 | 464 | return count; \ |
michael@0 | 465 | } \ |
michael@0 | 466 | protected: \ |
michael@0 | 467 | ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \ |
michael@0 | 468 | public: |
michael@0 | 469 | |
michael@0 | 470 | /** |
michael@0 | 471 | * Use this macro to implement the AddRef method for a given <i>_class</i> |
michael@0 | 472 | * @param _class The name of the class implementing the method |
michael@0 | 473 | */ |
michael@0 | 474 | #define NS_IMPL_ADDREF(_class) \ |
michael@0 | 475 | NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \ |
michael@0 | 476 | { \ |
michael@0 | 477 | MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ |
michael@0 | 478 | if (!mRefCnt.isThreadSafe) \ |
michael@0 | 479 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 480 | nsrefcnt count = ++mRefCnt; \ |
michael@0 | 481 | NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ |
michael@0 | 482 | return count; \ |
michael@0 | 483 | } |
michael@0 | 484 | |
michael@0 | 485 | /** |
michael@0 | 486 | * Use this macro to implement the AddRef method for a given <i>_class</i> |
michael@0 | 487 | * implemented as a wholly owned aggregated object intended to implement |
michael@0 | 488 | * interface(s) for its owner |
michael@0 | 489 | * @param _class The name of the class implementing the method |
michael@0 | 490 | * @param _aggregator the owning/containing object |
michael@0 | 491 | */ |
michael@0 | 492 | #define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \ |
michael@0 | 493 | NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \ |
michael@0 | 494 | { \ |
michael@0 | 495 | NS_PRECONDITION(_aggregator, "null aggregator"); \ |
michael@0 | 496 | return (_aggregator)->AddRef(); \ |
michael@0 | 497 | } |
michael@0 | 498 | |
michael@0 | 499 | /** |
michael@0 | 500 | * Use this macro to implement the Release method for a given |
michael@0 | 501 | * <i>_class</i>. |
michael@0 | 502 | * @param _class The name of the class implementing the method |
michael@0 | 503 | * @param _destroy A statement that is executed when the object's |
michael@0 | 504 | * refcount drops to zero. |
michael@0 | 505 | * |
michael@0 | 506 | * For example, |
michael@0 | 507 | * |
michael@0 | 508 | * NS_IMPL_RELEASE_WITH_DESTROY(Foo, Destroy(this)) |
michael@0 | 509 | * |
michael@0 | 510 | * will cause |
michael@0 | 511 | * |
michael@0 | 512 | * Destroy(this); |
michael@0 | 513 | * |
michael@0 | 514 | * to be invoked when the object's refcount drops to zero. This |
michael@0 | 515 | * allows for arbitrary teardown activity to occur (e.g., deallocation |
michael@0 | 516 | * of object allocated with placement new). |
michael@0 | 517 | */ |
michael@0 | 518 | #define NS_IMPL_RELEASE_WITH_DESTROY(_class, _destroy) \ |
michael@0 | 519 | NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ |
michael@0 | 520 | { \ |
michael@0 | 521 | MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ |
michael@0 | 522 | if (!mRefCnt.isThreadSafe) \ |
michael@0 | 523 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 524 | nsrefcnt count = --mRefCnt; \ |
michael@0 | 525 | NS_LOG_RELEASE(this, count, #_class); \ |
michael@0 | 526 | if (count == 0) { \ |
michael@0 | 527 | if (!mRefCnt.isThreadSafe) \ |
michael@0 | 528 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 529 | mRefCnt = 1; /* stabilize */ \ |
michael@0 | 530 | _destroy; \ |
michael@0 | 531 | return 0; \ |
michael@0 | 532 | } \ |
michael@0 | 533 | return count; \ |
michael@0 | 534 | } |
michael@0 | 535 | |
michael@0 | 536 | /** |
michael@0 | 537 | * Use this macro to implement the Release method for a given <i>_class</i> |
michael@0 | 538 | * @param _class The name of the class implementing the method |
michael@0 | 539 | * |
michael@0 | 540 | * A note on the 'stabilization' of the refcnt to one. At that point, |
michael@0 | 541 | * the object's refcount will have gone to zero. The object's |
michael@0 | 542 | * destructor may trigger code that attempts to QueryInterface() and |
michael@0 | 543 | * Release() 'this' again. Doing so will temporarily increment and |
michael@0 | 544 | * decrement the refcount. (Only a logic error would make one try to |
michael@0 | 545 | * keep a permanent hold on 'this'.) To prevent re-entering the |
michael@0 | 546 | * destructor, we make sure that no balanced refcounting can return |
michael@0 | 547 | * the refcount to |0|. |
michael@0 | 548 | */ |
michael@0 | 549 | #define NS_IMPL_RELEASE(_class) \ |
michael@0 | 550 | NS_IMPL_RELEASE_WITH_DESTROY(_class, delete (this)) |
michael@0 | 551 | |
michael@0 | 552 | /** |
michael@0 | 553 | * Use this macro to implement the Release method for a given <i>_class</i> |
michael@0 | 554 | * implemented as a wholly owned aggregated object intended to implement |
michael@0 | 555 | * interface(s) for its owner |
michael@0 | 556 | * @param _class The name of the class implementing the method |
michael@0 | 557 | * @param _aggregator the owning/containing object |
michael@0 | 558 | */ |
michael@0 | 559 | #define NS_IMPL_RELEASE_USING_AGGREGATOR(_class, _aggregator) \ |
michael@0 | 560 | NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ |
michael@0 | 561 | { \ |
michael@0 | 562 | NS_PRECONDITION(_aggregator, "null aggregator"); \ |
michael@0 | 563 | return (_aggregator)->Release(); \ |
michael@0 | 564 | } |
michael@0 | 565 | |
michael@0 | 566 | |
michael@0 | 567 | #define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class) \ |
michael@0 | 568 | NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \ |
michael@0 | 569 | { \ |
michael@0 | 570 | MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ |
michael@0 | 571 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 572 | nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \ |
michael@0 | 573 | nsrefcnt count = mRefCnt.incr(base); \ |
michael@0 | 574 | NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ |
michael@0 | 575 | return count; \ |
michael@0 | 576 | } |
michael@0 | 577 | |
michael@0 | 578 | #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy) \ |
michael@0 | 579 | NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ |
michael@0 | 580 | { \ |
michael@0 | 581 | MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ |
michael@0 | 582 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 583 | nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \ |
michael@0 | 584 | nsrefcnt count = mRefCnt.decr(base); \ |
michael@0 | 585 | NS_LOG_RELEASE(this, count, #_class); \ |
michael@0 | 586 | return count; \ |
michael@0 | 587 | } \ |
michael@0 | 588 | NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \ |
michael@0 | 589 | { \ |
michael@0 | 590 | _destroy; \ |
michael@0 | 591 | } |
michael@0 | 592 | |
michael@0 | 593 | #define NS_IMPL_CYCLE_COLLECTING_RELEASE(_class) \ |
michael@0 | 594 | NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, delete (this)) |
michael@0 | 595 | |
michael@0 | 596 | // _LAST_RELEASE can be useful when certain resources should be released |
michael@0 | 597 | // as soon as we know the object will be deleted. |
michael@0 | 598 | #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(_class, _last) \ |
michael@0 | 599 | NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ |
michael@0 | 600 | { \ |
michael@0 | 601 | MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ |
michael@0 | 602 | NS_ASSERT_OWNINGTHREAD(_class); \ |
michael@0 | 603 | bool shouldDelete = false; \ |
michael@0 | 604 | nsISupports *base = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \ |
michael@0 | 605 | nsrefcnt count = mRefCnt.decr(base, &shouldDelete); \ |
michael@0 | 606 | NS_LOG_RELEASE(this, count, #_class); \ |
michael@0 | 607 | if (count == 0) { \ |
michael@0 | 608 | mRefCnt.incr(base); \ |
michael@0 | 609 | _last; \ |
michael@0 | 610 | mRefCnt.decr(base); \ |
michael@0 | 611 | if (shouldDelete) { \ |
michael@0 | 612 | mRefCnt.stabilizeForDeletion(); \ |
michael@0 | 613 | DeleteCycleCollectable(); \ |
michael@0 | 614 | } \ |
michael@0 | 615 | } \ |
michael@0 | 616 | return count; \ |
michael@0 | 617 | } \ |
michael@0 | 618 | NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \ |
michael@0 | 619 | { \ |
michael@0 | 620 | delete this; \ |
michael@0 | 621 | } |
michael@0 | 622 | |
michael@0 | 623 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 624 | |
michael@0 | 625 | /** |
michael@0 | 626 | * There are two ways of implementing QueryInterface, and we use both: |
michael@0 | 627 | * |
michael@0 | 628 | * Table-driven QueryInterface uses a static table of IID->offset mappings |
michael@0 | 629 | * and a shared helper function. Using it tends to reduce codesize and improve |
michael@0 | 630 | * runtime performance (due to processor cache hits). |
michael@0 | 631 | * |
michael@0 | 632 | * Macro-driven QueryInterface generates a QueryInterface function directly |
michael@0 | 633 | * using common macros. This is necessary if special QueryInterface features |
michael@0 | 634 | * are being used (such as tearoffs and conditional interfaces). |
michael@0 | 635 | * |
michael@0 | 636 | * These methods can be combined into a table-driven function call followed |
michael@0 | 637 | * by custom code for tearoffs and conditionals. |
michael@0 | 638 | */ |
michael@0 | 639 | |
michael@0 | 640 | struct QITableEntry |
michael@0 | 641 | { |
michael@0 | 642 | const nsIID *iid; // null indicates end of the QITableEntry array |
michael@0 | 643 | int32_t offset; |
michael@0 | 644 | }; |
michael@0 | 645 | |
michael@0 | 646 | NS_COM_GLUE nsresult NS_FASTCALL |
michael@0 | 647 | NS_TableDrivenQI(void* aThis, REFNSIID aIID, |
michael@0 | 648 | void **aInstancePtr, const QITableEntry* entries); |
michael@0 | 649 | |
michael@0 | 650 | /** |
michael@0 | 651 | * Implement table-driven queryinterface |
michael@0 | 652 | */ |
michael@0 | 653 | |
michael@0 | 654 | #define NS_INTERFACE_TABLE_HEAD(_class) \ |
michael@0 | 655 | NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \ |
michael@0 | 656 | { \ |
michael@0 | 657 | NS_ASSERTION(aInstancePtr, \ |
michael@0 | 658 | "QueryInterface requires a non-NULL destination!"); \ |
michael@0 | 659 | nsresult rv = NS_ERROR_FAILURE; |
michael@0 | 660 | |
michael@0 | 661 | #define NS_INTERFACE_TABLE_BEGIN \ |
michael@0 | 662 | static const QITableEntry table[] = { |
michael@0 | 663 | |
michael@0 | 664 | #define NS_INTERFACE_TABLE_ENTRY(_class, _interface) \ |
michael@0 | 665 | { &_interface::COMTypeInfo<int>::kIID, \ |
michael@0 | 666 | int32_t(reinterpret_cast<char*>( \ |
michael@0 | 667 | static_cast<_interface*>((_class*) 0x1000)) - \ |
michael@0 | 668 | reinterpret_cast<char*>((_class*) 0x1000)) \ |
michael@0 | 669 | }, |
michael@0 | 670 | |
michael@0 | 671 | #define NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, _interface, _implClass) \ |
michael@0 | 672 | { &_interface::COMTypeInfo<int>::kIID, \ |
michael@0 | 673 | int32_t(reinterpret_cast<char*>( \ |
michael@0 | 674 | static_cast<_interface*>( \ |
michael@0 | 675 | static_cast<_implClass*>( \ |
michael@0 | 676 | (_class*) 0x1000))) - \ |
michael@0 | 677 | reinterpret_cast<char*>((_class*) 0x1000)) \ |
michael@0 | 678 | }, |
michael@0 | 679 | |
michael@0 | 680 | /* |
michael@0 | 681 | * XXX: we want to use mozilla::ArrayLength (or equivalent, |
michael@0 | 682 | * MOZ_ARRAY_LENGTH) in this condition, but some versions of GCC don't |
michael@0 | 683 | * see that the static_assert condition is actually constant in those |
michael@0 | 684 | * cases, even with constexpr support (?). |
michael@0 | 685 | */ |
michael@0 | 686 | #define NS_INTERFACE_TABLE_END_WITH_PTR(_ptr) \ |
michael@0 | 687 | { nullptr, 0 } }; \ |
michael@0 | 688 | static_assert((sizeof(table)/sizeof(table[0])) > 1, "need at least 1 interface"); \ |
michael@0 | 689 | rv = NS_TableDrivenQI(static_cast<void*>(_ptr), \ |
michael@0 | 690 | aIID, aInstancePtr, table); |
michael@0 | 691 | |
michael@0 | 692 | #define NS_INTERFACE_TABLE_END \ |
michael@0 | 693 | NS_INTERFACE_TABLE_END_WITH_PTR(this) |
michael@0 | 694 | |
michael@0 | 695 | #define NS_INTERFACE_TABLE_TAIL \ |
michael@0 | 696 | return rv; \ |
michael@0 | 697 | } |
michael@0 | 698 | |
michael@0 | 699 | #define NS_INTERFACE_TABLE_TAIL_INHERITING(_baseclass) \ |
michael@0 | 700 | if (NS_SUCCEEDED(rv)) \ |
michael@0 | 701 | return rv; \ |
michael@0 | 702 | return _baseclass::QueryInterface(aIID, aInstancePtr); \ |
michael@0 | 703 | } |
michael@0 | 704 | |
michael@0 | 705 | #define NS_INTERFACE_TABLE_TAIL_USING_AGGREGATOR(_aggregator) \ |
michael@0 | 706 | if (NS_SUCCEEDED(rv)) \ |
michael@0 | 707 | return rv; \ |
michael@0 | 708 | NS_ASSERTION(_aggregator, "null aggregator"); \ |
michael@0 | 709 | return _aggregator->QueryInterface(aIID, aInstancePtr) \ |
michael@0 | 710 | } |
michael@0 | 711 | |
michael@0 | 712 | /** |
michael@0 | 713 | * This implements query interface with two assumptions: First, the |
michael@0 | 714 | * class in question implements nsISupports and its own interface and |
michael@0 | 715 | * nothing else. Second, the implementation of the class's primary |
michael@0 | 716 | * inheritance chain leads to its own interface. |
michael@0 | 717 | * |
michael@0 | 718 | * @param _class The name of the class implementing the method |
michael@0 | 719 | * @param _classiiddef The name of the #define symbol that defines the IID |
michael@0 | 720 | * for the class (e.g. NS_ISUPPORTS_IID) |
michael@0 | 721 | */ |
michael@0 | 722 | |
michael@0 | 723 | #define NS_IMPL_QUERY_HEAD(_class) \ |
michael@0 | 724 | NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \ |
michael@0 | 725 | { \ |
michael@0 | 726 | NS_ASSERTION(aInstancePtr, \ |
michael@0 | 727 | "QueryInterface requires a non-NULL destination!"); \ |
michael@0 | 728 | nsISupports* foundInterface; |
michael@0 | 729 | |
michael@0 | 730 | #define NS_IMPL_QUERY_BODY(_interface) \ |
michael@0 | 731 | if ( aIID.Equals(NS_GET_IID(_interface)) ) \ |
michael@0 | 732 | foundInterface = static_cast<_interface*>(this); \ |
michael@0 | 733 | else |
michael@0 | 734 | |
michael@0 | 735 | #define NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) \ |
michael@0 | 736 | if ( (condition) && aIID.Equals(NS_GET_IID(_interface))) \ |
michael@0 | 737 | foundInterface = static_cast<_interface*>(this); \ |
michael@0 | 738 | else |
michael@0 | 739 | |
michael@0 | 740 | #define NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) \ |
michael@0 | 741 | if ( aIID.Equals(NS_GET_IID(_interface)) ) \ |
michael@0 | 742 | foundInterface = static_cast<_interface*>( \ |
michael@0 | 743 | static_cast<_implClass*>(this)); \ |
michael@0 | 744 | else |
michael@0 | 745 | |
michael@0 | 746 | #define NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate) \ |
michael@0 | 747 | if ( aIID.Equals(NS_GET_IID(_interface)) ) \ |
michael@0 | 748 | foundInterface = static_cast<_interface*>(_aggregate); \ |
michael@0 | 749 | else |
michael@0 | 750 | |
michael@0 | 751 | #define NS_IMPL_QUERY_TAIL_GUTS \ |
michael@0 | 752 | foundInterface = 0; \ |
michael@0 | 753 | nsresult status; \ |
michael@0 | 754 | if ( !foundInterface ) \ |
michael@0 | 755 | { \ |
michael@0 | 756 | /* nsISupports should be handled by this point. If not, fail. */ \ |
michael@0 | 757 | MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsISupports))); \ |
michael@0 | 758 | status = NS_NOINTERFACE; \ |
michael@0 | 759 | } \ |
michael@0 | 760 | else \ |
michael@0 | 761 | { \ |
michael@0 | 762 | NS_ADDREF(foundInterface); \ |
michael@0 | 763 | status = NS_OK; \ |
michael@0 | 764 | } \ |
michael@0 | 765 | *aInstancePtr = foundInterface; \ |
michael@0 | 766 | return status; \ |
michael@0 | 767 | } |
michael@0 | 768 | |
michael@0 | 769 | #define NS_IMPL_QUERY_TAIL_INHERITING(_baseclass) \ |
michael@0 | 770 | foundInterface = 0; \ |
michael@0 | 771 | nsresult status; \ |
michael@0 | 772 | if ( !foundInterface ) \ |
michael@0 | 773 | status = _baseclass::QueryInterface(aIID, (void**)&foundInterface); \ |
michael@0 | 774 | else \ |
michael@0 | 775 | { \ |
michael@0 | 776 | NS_ADDREF(foundInterface); \ |
michael@0 | 777 | status = NS_OK; \ |
michael@0 | 778 | } \ |
michael@0 | 779 | *aInstancePtr = foundInterface; \ |
michael@0 | 780 | return status; \ |
michael@0 | 781 | } |
michael@0 | 782 | |
michael@0 | 783 | #define NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) \ |
michael@0 | 784 | foundInterface = 0; \ |
michael@0 | 785 | nsresult status; \ |
michael@0 | 786 | if ( !foundInterface ) { \ |
michael@0 | 787 | NS_ASSERTION(_aggregator, "null aggregator"); \ |
michael@0 | 788 | status = _aggregator->QueryInterface(aIID, (void**)&foundInterface); \ |
michael@0 | 789 | } else \ |
michael@0 | 790 | { \ |
michael@0 | 791 | NS_ADDREF(foundInterface); \ |
michael@0 | 792 | status = NS_OK; \ |
michael@0 | 793 | } \ |
michael@0 | 794 | *aInstancePtr = foundInterface; \ |
michael@0 | 795 | return status; \ |
michael@0 | 796 | } |
michael@0 | 797 | |
michael@0 | 798 | #define NS_IMPL_QUERY_TAIL(_supports_interface) \ |
michael@0 | 799 | NS_IMPL_QUERY_BODY_AMBIGUOUS(nsISupports, _supports_interface) \ |
michael@0 | 800 | NS_IMPL_QUERY_TAIL_GUTS |
michael@0 | 801 | |
michael@0 | 802 | |
michael@0 | 803 | /* |
michael@0 | 804 | This is the new scheme. Using this notation now will allow us to switch to |
michael@0 | 805 | a table driven mechanism when it's ready. Note the difference between this |
michael@0 | 806 | and the (currently) underlying NS_IMPL_QUERY_INTERFACE mechanism. You must |
michael@0 | 807 | explicitly mention |nsISupports| when using the interface maps. |
michael@0 | 808 | */ |
michael@0 | 809 | #define NS_INTERFACE_MAP_BEGIN(_implClass) NS_IMPL_QUERY_HEAD(_implClass) |
michael@0 | 810 | #define NS_INTERFACE_MAP_ENTRY(_interface) NS_IMPL_QUERY_BODY(_interface) |
michael@0 | 811 | #define NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, condition) \ |
michael@0 | 812 | NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) |
michael@0 | 813 | #define NS_INTERFACE_MAP_ENTRY_AGGREGATED(_interface,_aggregate) \ |
michael@0 | 814 | NS_IMPL_QUERY_BODY_AGGREGATED(_interface,_aggregate) |
michael@0 | 815 | |
michael@0 | 816 | #define NS_INTERFACE_MAP_END NS_IMPL_QUERY_TAIL_GUTS |
michael@0 | 817 | #define NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(_interface, _implClass) \ |
michael@0 | 818 | NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) |
michael@0 | 819 | #define NS_INTERFACE_MAP_END_INHERITING(_baseClass) \ |
michael@0 | 820 | NS_IMPL_QUERY_TAIL_INHERITING(_baseClass) |
michael@0 | 821 | #define NS_INTERFACE_MAP_END_AGGREGATED(_aggregator) \ |
michael@0 | 822 | NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) |
michael@0 | 823 | |
michael@0 | 824 | #define NS_INTERFACE_TABLE0(_class) \ |
michael@0 | 825 | NS_INTERFACE_TABLE_BEGIN \ |
michael@0 | 826 | NS_INTERFACE_TABLE_ENTRY(_class, nsISupports) \ |
michael@0 | 827 | NS_INTERFACE_TABLE_END |
michael@0 | 828 | |
michael@0 | 829 | #define NS_INTERFACE_TABLE(aClass, ...) \ |
michael@0 | 830 | MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ |
michael@0 | 831 | NS_INTERFACE_TABLE_BEGIN \ |
michael@0 | 832 | MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass,), (__VA_ARGS__)) \ |
michael@0 | 833 | NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(aClass, nsISupports, \ |
michael@0 | 834 | MOZ_ARG_1(__VA_ARGS__)) \ |
michael@0 | 835 | NS_INTERFACE_TABLE_END |
michael@0 | 836 | |
michael@0 | 837 | #define NS_IMPL_QUERY_INTERFACE0(_class) \ |
michael@0 | 838 | NS_INTERFACE_TABLE_HEAD(_class) \ |
michael@0 | 839 | NS_INTERFACE_TABLE0(_class) \ |
michael@0 | 840 | NS_INTERFACE_TABLE_TAIL |
michael@0 | 841 | |
michael@0 | 842 | #define NS_IMPL_QUERY_INTERFACE(aClass, ...) \ |
michael@0 | 843 | NS_INTERFACE_TABLE_HEAD(aClass) \ |
michael@0 | 844 | NS_INTERFACE_TABLE(aClass, __VA_ARGS__) \ |
michael@0 | 845 | NS_INTERFACE_TABLE_TAIL |
michael@0 | 846 | |
michael@0 | 847 | /** |
michael@0 | 848 | * Declare that you're going to inherit from something that already |
michael@0 | 849 | * implements nsISupports, but also implements an additional interface, thus |
michael@0 | 850 | * causing an ambiguity. In this case you don't need another mRefCnt, you |
michael@0 | 851 | * just need to forward the definitions to the appropriate superclass. E.g. |
michael@0 | 852 | * |
michael@0 | 853 | * class Bar : public Foo, public nsIBar { // both provide nsISupports |
michael@0 | 854 | * public: |
michael@0 | 855 | * NS_DECL_ISUPPORTS_INHERITED |
michael@0 | 856 | * ...other nsIBar and Bar methods... |
michael@0 | 857 | * }; |
michael@0 | 858 | */ |
michael@0 | 859 | #define NS_DECL_ISUPPORTS_INHERITED \ |
michael@0 | 860 | public: \ |
michael@0 | 861 | NS_IMETHOD QueryInterface(REFNSIID aIID, \ |
michael@0 | 862 | void** aInstancePtr); \ |
michael@0 | 863 | NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ |
michael@0 | 864 | NS_IMETHOD_(MozExternalRefCountType) Release(void); \ |
michael@0 | 865 | |
michael@0 | 866 | /** |
michael@0 | 867 | * These macros can be used in conjunction with NS_DECL_ISUPPORTS_INHERITED |
michael@0 | 868 | * to implement the nsISupports methods, forwarding the invocations to a |
michael@0 | 869 | * superclass that already implements nsISupports. |
michael@0 | 870 | * |
michael@0 | 871 | * Note that I didn't make these inlined because they're virtual methods. |
michael@0 | 872 | */ |
michael@0 | 873 | |
michael@0 | 874 | #define NS_IMPL_ADDREF_INHERITED(Class, Super) \ |
michael@0 | 875 | NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) \ |
michael@0 | 876 | { \ |
michael@0 | 877 | nsrefcnt r = Super::AddRef(); \ |
michael@0 | 878 | NS_LOG_ADDREF(this, r, #Class, sizeof(*this)); \ |
michael@0 | 879 | return r; \ |
michael@0 | 880 | } |
michael@0 | 881 | |
michael@0 | 882 | #define NS_IMPL_RELEASE_INHERITED(Class, Super) \ |
michael@0 | 883 | NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \ |
michael@0 | 884 | { \ |
michael@0 | 885 | nsrefcnt r = Super::Release(); \ |
michael@0 | 886 | NS_LOG_RELEASE(this, r, #Class); \ |
michael@0 | 887 | return r; \ |
michael@0 | 888 | } |
michael@0 | 889 | |
michael@0 | 890 | /** |
michael@0 | 891 | * As above but not logging the addref/release; needed if the base |
michael@0 | 892 | * class might be aggregated. |
michael@0 | 893 | */ |
michael@0 | 894 | #define NS_IMPL_NONLOGGING_ADDREF_INHERITED(Class, Super) \ |
michael@0 | 895 | NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) \ |
michael@0 | 896 | { \ |
michael@0 | 897 | return Super::AddRef(); \ |
michael@0 | 898 | } |
michael@0 | 899 | |
michael@0 | 900 | #define NS_IMPL_NONLOGGING_RELEASE_INHERITED(Class, Super) \ |
michael@0 | 901 | NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \ |
michael@0 | 902 | { \ |
michael@0 | 903 | return Super::Release(); \ |
michael@0 | 904 | } |
michael@0 | 905 | |
michael@0 | 906 | #define NS_INTERFACE_TABLE_INHERITED0(Class) /* Nothing to do here */ |
michael@0 | 907 | |
michael@0 | 908 | #define NS_INTERFACE_TABLE_INHERITED(aClass, ...) \ |
michael@0 | 909 | MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ |
michael@0 | 910 | NS_INTERFACE_TABLE_BEGIN \ |
michael@0 | 911 | MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass,), (__VA_ARGS__)) \ |
michael@0 | 912 | NS_INTERFACE_TABLE_END |
michael@0 | 913 | |
michael@0 | 914 | #define NS_IMPL_QUERY_INTERFACE_INHERITED0(aClass, aSuper) \ |
michael@0 | 915 | NS_INTERFACE_TABLE_HEAD(aClass) \ |
michael@0 | 916 | NS_INTERFACE_TABLE_INHERITED0(aClass) \ |
michael@0 | 917 | NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper) |
michael@0 | 918 | |
michael@0 | 919 | #define NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, ...) \ |
michael@0 | 920 | NS_INTERFACE_TABLE_HEAD(aClass) \ |
michael@0 | 921 | NS_INTERFACE_TABLE_INHERITED(aClass, __VA_ARGS__) \ |
michael@0 | 922 | NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper) |
michael@0 | 923 | |
michael@0 | 924 | /** |
michael@0 | 925 | * Convenience macros for implementing all nsISupports methods for |
michael@0 | 926 | * a simple class. |
michael@0 | 927 | * @param _class The name of the class implementing the method |
michael@0 | 928 | * @param _classiiddef The name of the #define symbol that defines the IID |
michael@0 | 929 | * for the class (e.g. NS_ISUPPORTS_IID) |
michael@0 | 930 | */ |
michael@0 | 931 | |
michael@0 | 932 | #define NS_IMPL_ISUPPORTS0(_class) \ |
michael@0 | 933 | NS_IMPL_ADDREF(_class) \ |
michael@0 | 934 | NS_IMPL_RELEASE(_class) \ |
michael@0 | 935 | NS_IMPL_QUERY_INTERFACE0(_class) |
michael@0 | 936 | |
michael@0 | 937 | #define NS_IMPL_ISUPPORTS(aClass, ...) \ |
michael@0 | 938 | NS_IMPL_ADDREF(aClass) \ |
michael@0 | 939 | NS_IMPL_RELEASE(aClass) \ |
michael@0 | 940 | NS_IMPL_QUERY_INTERFACE(aClass, __VA_ARGS__) |
michael@0 | 941 | |
michael@0 | 942 | #define NS_IMPL_ISUPPORTS_INHERITED0(aClass, aSuper) \ |
michael@0 | 943 | NS_IMPL_QUERY_INTERFACE_INHERITED0(aClass, aSuper) \ |
michael@0 | 944 | NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \ |
michael@0 | 945 | NS_IMPL_RELEASE_INHERITED(aClass, aSuper) \ |
michael@0 | 946 | |
michael@0 | 947 | #define NS_IMPL_ISUPPORTS_INHERITED(aClass, aSuper, ...) \ |
michael@0 | 948 | NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, __VA_ARGS__) \ |
michael@0 | 949 | NS_IMPL_ADDREF_INHERITED(aClass, aSuper) \ |
michael@0 | 950 | NS_IMPL_RELEASE_INHERITED(aClass, aSuper) |
michael@0 | 951 | |
michael@0 | 952 | /* |
michael@0 | 953 | * Macro to glue together a QI that starts with an interface table |
michael@0 | 954 | * and segues into an interface map (e.g. it uses singleton classinfo |
michael@0 | 955 | * or tearoffs). |
michael@0 | 956 | */ |
michael@0 | 957 | #define NS_INTERFACE_TABLE_TO_MAP_SEGUE \ |
michael@0 | 958 | if (rv == NS_OK) return rv; \ |
michael@0 | 959 | nsISupports* foundInterface; |
michael@0 | 960 | |
michael@0 | 961 | |
michael@0 | 962 | /////////////////////////////////////////////////////////////////////////////// |
michael@0 | 963 | /** |
michael@0 | 964 | * |
michael@0 | 965 | * Threadsafe implementations of the ISupports convenience macros. |
michael@0 | 966 | * |
michael@0 | 967 | * @note These are not available when linking against the standalone glue, |
michael@0 | 968 | * because the implementation requires PR_ symbols. |
michael@0 | 969 | */ |
michael@0 | 970 | #define NS_INTERFACE_MAP_END_THREADSAFE NS_IMPL_QUERY_TAIL_GUTS |
michael@0 | 971 | |
michael@0 | 972 | /** |
michael@0 | 973 | * Macro to generate nsIClassInfo methods for classes which do not have |
michael@0 | 974 | * corresponding nsIFactory implementations. |
michael@0 | 975 | */ |
michael@0 | 976 | #define NS_IMPL_THREADSAFE_CI(_class) \ |
michael@0 | 977 | NS_IMETHODIMP \ |
michael@0 | 978 | _class::GetInterfaces(uint32_t* _count, nsIID*** _array) \ |
michael@0 | 979 | { \ |
michael@0 | 980 | return NS_CI_INTERFACE_GETTER_NAME(_class)(_count, _array); \ |
michael@0 | 981 | } \ |
michael@0 | 982 | \ |
michael@0 | 983 | NS_IMETHODIMP \ |
michael@0 | 984 | _class::GetHelperForLanguage(uint32_t _language, nsISupports** _retval) \ |
michael@0 | 985 | { \ |
michael@0 | 986 | *_retval = nullptr; \ |
michael@0 | 987 | return NS_OK; \ |
michael@0 | 988 | } \ |
michael@0 | 989 | \ |
michael@0 | 990 | NS_IMETHODIMP \ |
michael@0 | 991 | _class::GetContractID(char** _contractID) \ |
michael@0 | 992 | { \ |
michael@0 | 993 | *_contractID = nullptr; \ |
michael@0 | 994 | return NS_OK; \ |
michael@0 | 995 | } \ |
michael@0 | 996 | \ |
michael@0 | 997 | NS_IMETHODIMP \ |
michael@0 | 998 | _class::GetClassDescription(char** _classDescription) \ |
michael@0 | 999 | { \ |
michael@0 | 1000 | *_classDescription = nullptr; \ |
michael@0 | 1001 | return NS_OK; \ |
michael@0 | 1002 | } \ |
michael@0 | 1003 | \ |
michael@0 | 1004 | NS_IMETHODIMP \ |
michael@0 | 1005 | _class::GetClassID(nsCID** _classID) \ |
michael@0 | 1006 | { \ |
michael@0 | 1007 | *_classID = nullptr; \ |
michael@0 | 1008 | return NS_OK; \ |
michael@0 | 1009 | } \ |
michael@0 | 1010 | \ |
michael@0 | 1011 | NS_IMETHODIMP \ |
michael@0 | 1012 | _class::GetImplementationLanguage(uint32_t* _language) \ |
michael@0 | 1013 | { \ |
michael@0 | 1014 | *_language = nsIProgrammingLanguage::CPLUSPLUS; \ |
michael@0 | 1015 | return NS_OK; \ |
michael@0 | 1016 | } \ |
michael@0 | 1017 | \ |
michael@0 | 1018 | NS_IMETHODIMP \ |
michael@0 | 1019 | _class::GetFlags(uint32_t* _flags) \ |
michael@0 | 1020 | { \ |
michael@0 | 1021 | *_flags = nsIClassInfo::THREADSAFE; \ |
michael@0 | 1022 | return NS_OK; \ |
michael@0 | 1023 | } \ |
michael@0 | 1024 | \ |
michael@0 | 1025 | NS_IMETHODIMP \ |
michael@0 | 1026 | _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) \ |
michael@0 | 1027 | { \ |
michael@0 | 1028 | return NS_ERROR_NOT_AVAILABLE; \ |
michael@0 | 1029 | } |
michael@0 | 1030 | |
michael@0 | 1031 | #endif |