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