xpcom/glue/nsISupportsImpl.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial