Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
// IWYU pragma: private, include "nsISupports.h"
7
8
#ifndef nsISupportsImpl_h__
9
#define nsISupportsImpl_h__
10
11
#include "nscore.h"
12
#include "nsISupportsBase.h"
13
#include "nsISupportsUtils.h"
14
15
#if !defined(XPCOM_GLUE_AVOID_NSPR)
16
# include "prthread.h" /* needed for cargo-culting headers */
17
#endif
18
19
#include "nsDebug.h"
20
#include "nsXPCOM.h"
21
#include <atomic>
22
#include "mozilla/Attributes.h"
23
#include "mozilla/Assertions.h"
24
#include "mozilla/Atomics.h"
25
#include "mozilla/Compiler.h"
26
#include "mozilla/Likely.h"
27
#include "mozilla/MacroArgs.h"
28
#include "mozilla/MacroForEach.h"
29
#include "mozilla/TypeTraits.h"
30
31
#define MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(X) \
32
static_assert(!mozilla::IsDestructible<X>::value, \
33
"Reference-counted class " #X \
34
" should not have a public destructor. " \
35
"Make this class's destructor non-public");
36
37
inline nsISupports* ToSupports(decltype(nullptr)) { return nullptr; }
38
39
inline nsISupports* ToSupports(nsISupports* aSupports) { return aSupports; }
40
41
////////////////////////////////////////////////////////////////////////////////
42
// Macros to help detect thread-safety:
43
44
#ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
45
46
# include "prthread.h" /* needed for thread-safety checks */
47
48
class nsAutoOwningThread {
49
public:
50
nsAutoOwningThread();
51
52
// We move the actual assertion checks out-of-line to minimize code bloat,
53
// but that means we have to pass a non-literal string to MOZ_CRASH_UNSAFE.
54
// To make that more safe, the public interface requires a literal string
55
// and passes that to the private interface; we can then be assured that we
56
// effectively are passing a literal string to MOZ_CRASH_UNSAFE.
57
template <int N>
58
void AssertOwnership(const char (&aMsg)[N]) const {
59
AssertCurrentThreadOwnsMe(aMsg);
60
}
61
62
bool IsCurrentThread() const;
63
64
private:
65
void AssertCurrentThreadOwnsMe(const char* aMsg) const;
66
67
void* mThread;
68
};
69
70
# define NS_DECL_OWNINGTHREAD nsAutoOwningThread _mOwningThread;
71
# define NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class) \
72
agg->_mOwningThread.AssertOwnership(#_class " not thread-safe")
73
# define NS_ASSERT_OWNINGTHREAD(_class) \
74
NS_ASSERT_OWNINGTHREAD_AGGREGATE(this, _class)
75
#else // !MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
76
77
# define NS_DECL_OWNINGTHREAD /* nothing */
78
# define NS_ASSERT_OWNINGTHREAD_AGGREGATE(agg, _class) ((void)0)
79
# define NS_ASSERT_OWNINGTHREAD(_class) ((void)0)
80
81
#endif // MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
82
83
// Macros for reference-count and constructor logging
84
85
#if defined(NS_BUILD_REFCNT_LOGGING)
86
87
# define NS_LOG_ADDREF(_p, _rc, _type, _size) \
88
NS_LogAddRef((_p), (_rc), (_type), (uint32_t)(_size))
89
90
# define NS_LOG_RELEASE(_p, _rc, _type) NS_LogRelease((_p), (_rc), (_type))
91
92
# include "mozilla/TypeTraits.h"
93
# define MOZ_ASSERT_CLASSNAME(_type) \
94
static_assert(mozilla::IsClass<_type>::value, \
95
"Token '" #_type "' is not a class type.")
96
97
# define MOZ_ASSERT_NOT_ISUPPORTS(_type) \
98
static_assert(!mozilla::IsBaseOf<nsISupports, _type>::value, \
99
"nsISupports classes don't need to call MOZ_COUNT_CTOR or " \
100
"MOZ_COUNT_DTOR");
101
102
// Note that the following constructor/destructor logging macros are redundant
103
// for refcounted objects that log via the NS_LOG_ADDREF/NS_LOG_RELEASE macros.
104
// Refcount logging is preferred.
105
# define MOZ_COUNT_CTOR(_type) \
106
do { \
107
MOZ_ASSERT_CLASSNAME(_type); \
108
MOZ_ASSERT_NOT_ISUPPORTS(_type); \
109
NS_LogCtor((void*)this, #_type, sizeof(*this)); \
110
} while (0)
111
112
# define MOZ_COUNT_CTOR_INHERITED(_type, _base) \
113
do { \
114
MOZ_ASSERT_CLASSNAME(_type); \
115
MOZ_ASSERT_CLASSNAME(_base); \
116
MOZ_ASSERT_NOT_ISUPPORTS(_type); \
117
NS_LogCtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
118
} while (0)
119
120
# define MOZ_LOG_CTOR(_ptr, _name, _size) \
121
do { \
122
NS_LogCtor((void*)_ptr, _name, _size); \
123
} while (0)
124
125
# define MOZ_COUNT_DTOR(_type) \
126
do { \
127
MOZ_ASSERT_CLASSNAME(_type); \
128
MOZ_ASSERT_NOT_ISUPPORTS(_type); \
129
NS_LogDtor((void*)this, #_type, sizeof(*this)); \
130
} while (0)
131
132
# define MOZ_COUNT_DTOR_INHERITED(_type, _base) \
133
do { \
134
MOZ_ASSERT_CLASSNAME(_type); \
135
MOZ_ASSERT_CLASSNAME(_base); \
136
MOZ_ASSERT_NOT_ISUPPORTS(_type); \
137
NS_LogDtor((void*)this, #_type, sizeof(*this) - sizeof(_base)); \
138
} while (0)
139
140
# define MOZ_LOG_DTOR(_ptr, _name, _size) \
141
do { \
142
NS_LogDtor((void*)_ptr, _name, _size); \
143
} while (0)
144
145
/* nsCOMPtr.h allows these macros to be defined by clients
146
* These logging functions require dynamic_cast<void*>, so they don't
147
* do anything useful if we don't have dynamic_cast<void*>.
148
* Note: The explicit comparison to nullptr is needed to avoid warnings
149
* when _p is a nullptr itself. */
150
# define NSCAP_LOG_ASSIGNMENT(_c, _p) \
151
if (_p != nullptr) NS_LogCOMPtrAddRef((_c), ToSupports(_p))
152
153
# define NSCAP_LOG_RELEASE(_c, _p) \
154
if (_p) NS_LogCOMPtrRelease((_c), ToSupports(_p))
155
156
#else /* !NS_BUILD_REFCNT_LOGGING */
157
158
# define NS_LOG_ADDREF(_p, _rc, _type, _size)
159
# define NS_LOG_RELEASE(_p, _rc, _type)
160
# define MOZ_COUNT_CTOR(_type)
161
# define MOZ_COUNT_CTOR_INHERITED(_type, _base)
162
# define MOZ_LOG_CTOR(_ptr, _name, _size)
163
# define MOZ_COUNT_DTOR(_type)
164
# define MOZ_COUNT_DTOR_INHERITED(_type, _base)
165
# define MOZ_LOG_DTOR(_ptr, _name, _size)
166
167
#endif /* NS_BUILD_REFCNT_LOGGING */
168
169
// Support for ISupports classes which interact with cycle collector.
170
171
#define NS_NUMBER_OF_FLAGS_IN_REFCNT 2
172
#define NS_IN_PURPLE_BUFFER (1 << 0)
173
#define NS_IS_PURPLE (1 << 1)
174
#define NS_REFCOUNT_CHANGE (1 << NS_NUMBER_OF_FLAGS_IN_REFCNT)
175
#define NS_REFCOUNT_VALUE(_val) (_val >> NS_NUMBER_OF_FLAGS_IN_REFCNT)
176
177
class nsCycleCollectingAutoRefCnt {
178
public:
179
typedef void (*Suspect)(void* aPtr, nsCycleCollectionParticipant* aCp,
180
nsCycleCollectingAutoRefCnt* aRefCnt,
181
bool* aShouldDelete);
182
183
nsCycleCollectingAutoRefCnt() : mRefCntAndFlags(0) {}
184
185
explicit nsCycleCollectingAutoRefCnt(uintptr_t aValue)
186
: mRefCntAndFlags(aValue << NS_NUMBER_OF_FLAGS_IN_REFCNT) {}
187
188
nsCycleCollectingAutoRefCnt(const nsCycleCollectingAutoRefCnt&) = delete;
189
void operator=(const nsCycleCollectingAutoRefCnt&) = delete;
190
191
template <Suspect suspect = NS_CycleCollectorSuspect3>
192
MOZ_ALWAYS_INLINE uintptr_t incr(nsISupports* aOwner) {
193
return incr<suspect>(aOwner, nullptr);
194
}
195
196
template <Suspect suspect = NS_CycleCollectorSuspect3>
197
MOZ_ALWAYS_INLINE uintptr_t incr(void* aOwner,
198
nsCycleCollectionParticipant* aCp) {
199
mRefCntAndFlags += NS_REFCOUNT_CHANGE;
200
mRefCntAndFlags &= ~NS_IS_PURPLE;
201
// For incremental cycle collection, use the purple buffer to track objects
202
// that have been AddRef'd.
203
if (!IsInPurpleBuffer()) {
204
mRefCntAndFlags |= NS_IN_PURPLE_BUFFER;
205
// Refcount isn't zero, so Suspect won't delete anything.
206
MOZ_ASSERT(get() > 0);
207
suspect(aOwner, aCp, this, nullptr);
208
}
209
return NS_REFCOUNT_VALUE(mRefCntAndFlags);
210
}
211
212
MOZ_ALWAYS_INLINE void stabilizeForDeletion() {
213
// Set refcnt to 1 and mark us to be in the purple buffer.
214
// This way decr won't call suspect again.
215
mRefCntAndFlags = NS_REFCOUNT_CHANGE | NS_IN_PURPLE_BUFFER;
216
}
217
218
template <Suspect suspect = NS_CycleCollectorSuspect3>
219
MOZ_ALWAYS_INLINE uintptr_t decr(nsISupports* aOwner,
220
bool* aShouldDelete = nullptr) {
221
return decr<suspect>(aOwner, nullptr, aShouldDelete);
222
}
223
224
template <Suspect suspect = NS_CycleCollectorSuspect3>
225
MOZ_ALWAYS_INLINE uintptr_t decr(void* aOwner,
226
nsCycleCollectionParticipant* aCp,
227
bool* aShouldDelete = nullptr) {
228
MOZ_ASSERT(get() > 0);
229
if (!IsInPurpleBuffer()) {
230
mRefCntAndFlags -= NS_REFCOUNT_CHANGE;
231
mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE);
232
uintptr_t retval = NS_REFCOUNT_VALUE(mRefCntAndFlags);
233
// Suspect may delete 'aOwner' and 'this'!
234
suspect(aOwner, aCp, this, aShouldDelete);
235
return retval;
236
}
237
mRefCntAndFlags -= NS_REFCOUNT_CHANGE;
238
mRefCntAndFlags |= (NS_IN_PURPLE_BUFFER | NS_IS_PURPLE);
239
return NS_REFCOUNT_VALUE(mRefCntAndFlags);
240
}
241
242
MOZ_ALWAYS_INLINE void RemovePurple() {
243
MOZ_ASSERT(IsPurple(), "must be purple");
244
mRefCntAndFlags &= ~NS_IS_PURPLE;
245
}
246
247
MOZ_ALWAYS_INLINE void RemoveFromPurpleBuffer() {
248
MOZ_ASSERT(IsInPurpleBuffer());
249
mRefCntAndFlags &= ~(NS_IS_PURPLE | NS_IN_PURPLE_BUFFER);
250
}
251
252
MOZ_ALWAYS_INLINE bool IsPurple() const {
253
return !!(mRefCntAndFlags & NS_IS_PURPLE);
254
}
255
256
MOZ_ALWAYS_INLINE bool IsInPurpleBuffer() const {
257
return !!(mRefCntAndFlags & NS_IN_PURPLE_BUFFER);
258
}
259
260
MOZ_ALWAYS_INLINE nsrefcnt get() const {
261
return NS_REFCOUNT_VALUE(mRefCntAndFlags);
262
}
263
264
MOZ_ALWAYS_INLINE operator nsrefcnt() const { return get(); }
265
266
private:
267
uintptr_t mRefCntAndFlags;
268
};
269
270
class nsAutoRefCnt {
271
public:
272
nsAutoRefCnt() : mValue(0) {}
273
explicit nsAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {}
274
275
nsAutoRefCnt(const nsAutoRefCnt&) = delete;
276
void operator=(const nsAutoRefCnt&) = delete;
277
278
// only support prefix increment/decrement
279
nsrefcnt operator++() { return ++mValue; }
280
nsrefcnt operator--() { return --mValue; }
281
282
nsrefcnt operator=(nsrefcnt aValue) { return (mValue = aValue); }
283
operator nsrefcnt() const { return mValue; }
284
nsrefcnt get() const { return mValue; }
285
286
static const bool isThreadSafe = false;
287
288
private:
289
nsrefcnt operator++(int) = delete;
290
nsrefcnt operator--(int) = delete;
291
nsrefcnt mValue;
292
};
293
294
namespace mozilla {
295
template <recordreplay::Behavior Recording>
296
class ThreadSafeAutoRefCntWithRecording {
297
public:
298
ThreadSafeAutoRefCntWithRecording() : mValue(0) {}
299
explicit ThreadSafeAutoRefCntWithRecording(nsrefcnt aValue)
300
: mValue(aValue) {}
301
302
ThreadSafeAutoRefCntWithRecording(const ThreadSafeAutoRefCntWithRecording&) =
303
delete;
304
void operator=(const ThreadSafeAutoRefCntWithRecording&) = delete;
305
306
// only support prefix increment/decrement
307
MOZ_ALWAYS_INLINE nsrefcnt operator++() {
308
// Memory synchronization is not required when incrementing a
309
// reference count. The first increment of a reference count on a
310
// thread is not important, since the first use of the object on a
311
// thread can happen before it. What is important is the transfer
312
// of the pointer to that thread, which may happen prior to the
313
// first increment on that thread. The necessary memory
314
// synchronization is done by the mechanism that transfers the
315
// pointer between threads.
316
detail::AutoRecordAtomicAccess<Recording> record(this);
317
return mValue.fetch_add(1, std::memory_order_relaxed) + 1;
318
}
319
MOZ_ALWAYS_INLINE nsrefcnt operator--() {
320
// Since this may be the last release on this thread, we need
321
// release semantics so that prior writes on this thread are visible
322
// to the thread that destroys the object when it reads mValue with
323
// acquire semantics.
324
detail::AutoRecordAtomicAccess<Recording> record(this);
325
nsrefcnt result = mValue.fetch_sub(1, std::memory_order_release) - 1;
326
if (result == 0) {
327
// We're going to destroy the object on this thread, so we need
328
// acquire semantics to synchronize with the memory released by
329
// the last release on other threads, that is, to ensure that
330
// writes prior to that release are now visible on this thread.
331
#ifdef MOZ_TSAN
332
// TSan doesn't understand std::atomic_thread_fence, so in order
333
// to avoid a false positive for every time a refcounted object
334
// is deleted, we replace the fence with an atomic operation.
335
mValue.load(std::memory_order_acquire);
336
#else
337
std::atomic_thread_fence(std::memory_order_acquire);
338
#endif
339
}
340
return result;
341
}
342
343
MOZ_ALWAYS_INLINE nsrefcnt operator=(nsrefcnt aValue) {
344
// Use release semantics since we're not sure what the caller is
345
// doing.
346
detail::AutoRecordAtomicAccess<Recording> record(this);
347
mValue.store(aValue, std::memory_order_release);
348
return aValue;
349
}
350
MOZ_ALWAYS_INLINE operator nsrefcnt() const { return get(); }
351
MOZ_ALWAYS_INLINE nsrefcnt get() const {
352
// Use acquire semantics since we're not sure what the caller is
353
// doing.
354
detail::AutoRecordAtomicAccess<Recording> record(this);
355
return mValue.load(std::memory_order_acquire);
356
}
357
358
static const bool isThreadSafe = true;
359
360
private:
361
nsrefcnt operator++(int) = delete;
362
nsrefcnt operator--(int) = delete;
363
std::atomic<nsrefcnt> mValue;
364
};
365
366
typedef ThreadSafeAutoRefCntWithRecording<recordreplay::Behavior::DontPreserve>
367
ThreadSafeAutoRefCnt;
368
369
} // namespace mozilla
370
371
///////////////////////////////////////////////////////////////////////////////
372
373
/**
374
* Declare the reference count variable and the implementations of the
375
* AddRef and QueryInterface methods.
376
*/
377
378
#define NS_DECL_ISUPPORTS \
379
public: \
380
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
381
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
382
NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
383
typedef mozilla::FalseType HasThreadSafeRefCnt; \
384
\
385
protected: \
386
nsAutoRefCnt mRefCnt; \
387
NS_DECL_OWNINGTHREAD \
388
public:
389
390
#define NS_DECL_THREADSAFE_ISUPPORTS_WITH_RECORDING(_recording) \
391
public: \
392
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; \
393
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override; \
394
NS_IMETHOD_(MozExternalRefCountType) Release(void) override; \
395
typedef mozilla::TrueType HasThreadSafeRefCnt; \
396
\
397
protected: \
398
::mozilla::ThreadSafeAutoRefCntWithRecording<_recording> mRefCnt; \
399
NS_DECL_OWNINGTHREAD \
400
public:
401
402
#define NS_DECL_THREADSAFE_ISUPPORTS \
403
NS_DECL_THREADSAFE_ISUPPORTS_WITH_RECORDING( \
404
mozilla::recordreplay::Behavior::DontPreserve)
405
406
#define NS_DECL_CYCLE_COLLECTING_ISUPPORTS \
407
NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(override)
408
409
#define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL \
410
NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(final)
411
412
#define NS_DECL_CYCLE_COLLECTING_ISUPPORTS_META(...) \
413
public: \
414
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) __VA_ARGS__; \
415
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) __VA_ARGS__; \
416
NS_IMETHOD_(MozExternalRefCountType) Release(void) __VA_ARGS__; \
417
NS_IMETHOD_(void) DeleteCycleCollectable(void); \
418
typedef mozilla::FalseType HasThreadSafeRefCnt; \
419
\
420
protected: \
421
nsCycleCollectingAutoRefCnt mRefCnt; \
422
NS_DECL_OWNINGTHREAD \
423
public:
424
425
///////////////////////////////////////////////////////////////////////////////
426
427
/*
428
* Implementation of AddRef and Release for non-nsISupports (ie "native")
429
* cycle-collected classes that use the purple buffer to avoid leaks.
430
*/
431
432
#define NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
433
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
434
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
435
NS_ASSERT_OWNINGTHREAD(_class); \
436
nsrefcnt count = \
437
mRefCnt.incr(static_cast<void*>(this), \
438
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
439
NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
440
return count;
441
442
#define NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_ADDREF_BODY(_class) \
443
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
444
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
445
NS_ASSERT_OWNINGTHREAD(_class); \
446
nsrefcnt count = mRefCnt.incr<NS_CycleCollectorSuspectUsingNursery>( \
447
static_cast<void*>(this), \
448
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
449
NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
450
return count;
451
452
#define NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
453
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
454
NS_ASSERT_OWNINGTHREAD(_class); \
455
nsrefcnt count = \
456
mRefCnt.decr(static_cast<void*>(this), \
457
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
458
NS_LOG_RELEASE(this, count, #_class); \
459
return count;
460
461
#define NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_RELEASE_BODY(_class) \
462
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
463
NS_ASSERT_OWNINGTHREAD(_class); \
464
nsrefcnt count = mRefCnt.decr<NS_CycleCollectorSuspectUsingNursery>( \
465
static_cast<void*>(this), \
466
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
467
NS_LOG_RELEASE(this, count, #_class); \
468
return count;
469
470
#define NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(_class) \
471
NS_METHOD_(MozExternalRefCountType) _class::AddRef(void) { \
472
NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \
473
}
474
475
#define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(_class, \
476
_last) \
477
NS_METHOD_(MozExternalRefCountType) _class::Release(void) { \
478
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
479
NS_ASSERT_OWNINGTHREAD(_class); \
480
bool shouldDelete = false; \
481
nsrefcnt count = \
482
mRefCnt.decr(static_cast<void*>(this), \
483
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant(), \
484
&shouldDelete); \
485
NS_LOG_RELEASE(this, count, #_class); \
486
if (count == 0) { \
487
mRefCnt.incr(static_cast<void*>(this), \
488
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
489
_last; \
490
mRefCnt.decr(static_cast<void*>(this), \
491
_class::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant()); \
492
if (shouldDelete) { \
493
mRefCnt.stabilizeForDeletion(); \
494
DeleteCycleCollectable(); \
495
} \
496
} \
497
return count; \
498
}
499
500
#define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(_class) \
501
NS_METHOD_(MozExternalRefCountType) _class::Release(void) { \
502
NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
503
}
504
505
#define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(_class) \
506
public: \
507
NS_METHOD_(MozExternalRefCountType) \
508
AddRef(void){NS_IMPL_CC_NATIVE_ADDREF_BODY(_class)} NS_METHOD_( \
509
MozExternalRefCountType) Release(void) { \
510
NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \
511
} \
512
typedef mozilla::FalseType HasThreadSafeRefCnt; \
513
\
514
protected: \
515
nsCycleCollectingAutoRefCnt mRefCnt; \
516
NS_DECL_OWNINGTHREAD \
517
public:
518
519
#define NS_INLINE_DECL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_NATIVE_REFCOUNTING( \
520
_class) \
521
public: \
522
NS_METHOD_(MozExternalRefCountType) \
523
AddRef(void){NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_ADDREF_BODY( \
524
_class)} NS_METHOD_(MozExternalRefCountType) Release(void) { \
525
NS_IMPL_CC_MAIN_THREAD_ONLY_NATIVE_RELEASE_BODY(_class) \
526
} \
527
typedef mozilla::FalseType HasThreadSafeRefCnt; \
528
\
529
protected: \
530
nsCycleCollectingAutoRefCnt mRefCnt; \
531
NS_DECL_OWNINGTHREAD \
532
public:
533
534
///////////////////////////////////////////////////////////////////////////////
535
536
/**
537
* Use this macro to declare and implement the AddRef & Release methods for a
538
* given non-XPCOM <i>_class</i>.
539
*
540
* @param _class The name of the class implementing the method
541
* @param _destroy A statement that is executed when the object's
542
* refcount drops to zero.
543
* @param optional override Mark the AddRef & Release methods as overrides.
544
*/
545
#define NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, _destroy, ...) \
546
public: \
547
NS_METHOD_(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
548
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
549
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
550
NS_ASSERT_OWNINGTHREAD(_class); \
551
++mRefCnt; \
552
NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
553
return mRefCnt; \
554
} \
555
NS_METHOD_(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
556
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
557
NS_ASSERT_OWNINGTHREAD(_class); \
558
--mRefCnt; \
559
NS_LOG_RELEASE(this, mRefCnt, #_class); \
560
if (mRefCnt == 0) { \
561
mRefCnt = 1; /* stabilize */ \
562
_destroy; \
563
return 0; \
564
} \
565
return mRefCnt; \
566
} \
567
typedef mozilla::FalseType HasThreadSafeRefCnt; \
568
\
569
protected: \
570
nsAutoRefCnt mRefCnt; \
571
NS_DECL_OWNINGTHREAD \
572
public:
573
574
/**
575
* Use this macro to declare and implement the AddRef & Release methods for a
576
* given non-XPCOM <i>_class</i>.
577
*
578
* @param _class The name of the class implementing the method
579
* @param optional override Mark the AddRef & Release methods as overrides.
580
*/
581
#define NS_INLINE_DECL_REFCOUNTING(_class, ...) \
582
NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(_class, delete (this), __VA_ARGS__)
583
584
#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, _decl, _recording, \
585
...) \
586
public: \
587
_decl(MozExternalRefCountType) AddRef(void) __VA_ARGS__ { \
588
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
589
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
590
nsrefcnt count = ++mRefCnt; \
591
NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
592
return (nsrefcnt)count; \
593
} \
594
_decl(MozExternalRefCountType) Release(void) __VA_ARGS__ { \
595
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
596
nsrefcnt count = --mRefCnt; \
597
NS_LOG_RELEASE(this, count, #_class); \
598
if (count == 0) { \
599
delete (this); \
600
return 0; \
601
} \
602
return count; \
603
} \
604
typedef mozilla::TrueType HasThreadSafeRefCnt; \
605
\
606
protected: \
607
::mozilla::ThreadSafeAutoRefCntWithRecording<_recording> mRefCnt; \
608
\
609
public:
610
611
/**
612
* Use this macro to declare and implement the AddRef & Release methods for a
613
* given non-XPCOM <i>_class</i> in a threadsafe manner.
614
*
615
* DOES NOT DO REFCOUNT STABILIZATION!
616
*
617
* @param _class The name of the class implementing the method
618
*/
619
#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING(_class, ...) \
620
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META( \
621
_class, NS_METHOD_, mozilla::recordreplay::Behavior::DontPreserve, \
622
__VA_ARGS__)
623
624
/**
625
* Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING with AddRef & Release declared
626
* virtual.
627
*/
628
#define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING(_class, ...) \
629
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META( \
630
_class, NS_IMETHOD_, mozilla::recordreplay::Behavior::DontPreserve, \
631
__VA_ARGS__)
632
633
/**
634
* Like NS_INLINE_DECL_THREADSAFE_REFCOUNTING except that reference changes
635
* are recorded and replayed.
636
*/
637
#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_RECORDED(_class, ...) \
638
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META( \
639
_class, NS_METHOD_, mozilla::recordreplay::Behavior::Preserve, \
640
__VA_ARGS__)
641
642
/**
643
* Like NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING except that reference
644
* changes are recorded and replayed.
645
*/
646
#define NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING_RECORDED(_class, ...) \
647
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META( \
648
_class, NS_IMETHOD_, mozilla::recordreplay::Behavior::Preserve, \
649
__VA_ARGS__)
650
651
/**
652
* Use this macro in interface classes that you want to be able to reference
653
* using RefPtr, but don't want to provide a refcounting implemenation. The
654
* refcounting implementation can be provided by concrete subclasses that
655
* implement the interface.
656
*/
657
#define NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING \
658
public: \
659
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; \
660
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; \
661
\
662
public:
663
664
/**
665
* Use this macro to implement the AddRef method for a given <i>_class</i>
666
* @param _class The name of the class implementing the method
667
* @param _name The class name to be passed to XPCOM leak checking
668
*/
669
#define NS_IMPL_NAMED_ADDREF(_class, _name) \
670
NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
671
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
672
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
673
MOZ_ASSERT(_name != nullptr, "Must specify a name"); \
674
if (!mRefCnt.isThreadSafe) NS_ASSERT_OWNINGTHREAD(_class); \
675
nsrefcnt count = ++mRefCnt; \
676
NS_LOG_ADDREF(this, count, _name, sizeof(*this)); \
677
return count; \
678
}
679
680
/**
681
* Use this macro to implement the AddRef method for a given <i>_class</i>
682
* @param _class The name of the class implementing the method
683
*/
684
#define NS_IMPL_ADDREF(_class) NS_IMPL_NAMED_ADDREF(_class, #_class)
685
686
/**
687
* Use this macro to implement the AddRef method for a given <i>_class</i>
688
* implemented as a wholly owned aggregated object intended to implement
689
* interface(s) for its owner
690
* @param _class The name of the class implementing the method
691
* @param _aggregator the owning/containing object
692
*/
693
#define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \
694
NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) { \
695
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
696
MOZ_ASSERT(_aggregator, "null aggregator"); \
697
return (_aggregator)->AddRef(); \
698
}
699
700
// We decrement the refcnt before logging the actual release, but when logging
701
// named things, accessing the name may not be valid after the refcnt
702
// decrement, because the object may have been destroyed on a different thread.
703
// Use this macro to ensure that we have a local copy of the name prior to
704
// the refcnt decrement. (We use a macro to make absolutely sure the name
705
// isn't loaded in builds where it wouldn't be used.)
706
#ifdef NS_BUILD_REFCNT_LOGGING
707
# define NS_LOAD_NAME_BEFORE_RELEASE(localname, _name) \
708
const char* const localname = _name
709
#else
710
# define NS_LOAD_NAME_BEFORE_RELEASE(localname, _name)
711
#endif
712
713
/**
714
* Use this macro to implement the Release method for a given
715
* <i>_class</i>.
716
* @param _class The name of the class implementing the method
717
* @param _name The class name to be passed to XPCOM leak checking
718
* @param _destroy A statement that is executed when the object's
719
* refcount drops to zero.
720
*
721
* For example,
722
*
723
* NS_IMPL_RELEASE_WITH_DESTROY(Foo, "Foo", Destroy(this))
724
*
725
* will cause
726
*
727
* Destroy(this);
728
*
729
* to be invoked when the object's refcount drops to zero. This
730
* allows for arbitrary teardown activity to occur (e.g., deallocation
731
* of object allocated with placement new).
732
*/
733
#define NS_IMPL_NAMED_RELEASE_WITH_DESTROY(_class, _name, _destroy) \
734
NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) { \
735
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
736
MOZ_ASSERT(_name != nullptr, "Must specify a name"); \
737
if (!