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
7 #ifndef nsCycleCollectionParticipant_h__
8 #define nsCycleCollectionParticipant_h__
9
10 #include "mozilla/MacroArgs.h"
11 #include "mozilla/MacroForEach.h"
12 #include "nsCycleCollectionNoteChild.h"
13 #include "js/RootingAPI.h"
14
15 #define NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID \
16 { \
17 0x9674489b, \
18 0x1f6f, \
19 0x4550, \
20 { 0xa7, 0x30, 0xcc, 0xae, 0xdd, 0x10, 0x4c, 0xf9 } \
21 }
22
23 /**
24 * Special IID to get at the base nsISupports for a class. Usually this is the
25 * canonical nsISupports pointer, but in the case of tearoffs for example it is
26 * the base nsISupports pointer of the tearoff. This allow the cycle collector
27 * to have separate nsCycleCollectionParticipant's for tearoffs or aggregated
28 * classes.
29 */
30 #define NS_CYCLECOLLECTIONISUPPORTS_IID \
31 { \
32 0xc61eac14, \
33 0x5f7a, \
34 0x4481, \
35 { 0x96, 0x5e, 0x7e, 0xaa, 0x6e, 0xff, 0xa8, 0x5f } \
36 }
37
38 /**
39 * Just holds the IID so NS_GET_IID works.
40 */
41 class nsCycleCollectionISupports
42 {
43 public:
44 NS_DECLARE_STATIC_IID_ACCESSOR(NS_CYCLECOLLECTIONISUPPORTS_IID)
45 };
46
NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionISupports,NS_CYCLECOLLECTIONISUPPORTS_IID)47 NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionISupports,
48 NS_CYCLECOLLECTIONISUPPORTS_IID)
49
50 namespace JS {
51 template<class T> class Heap;
52 } /* namespace JS */
53
54 /*
55 * A struct defining pure virtual methods which are called when tracing cycle
56 * collection paticipants. The appropriate method is called depending on the
57 * type of JS GC thing.
58 */
59 struct TraceCallbacks
60 {
61 virtual void Trace(JS::Heap<JS::Value>* aPtr, const char* aName,
62 void* aClosure) const = 0;
63 virtual void Trace(JS::Heap<jsid>* aPtr, const char* aName,
64 void* aClosure) const = 0;
65 virtual void Trace(JS::Heap<JSObject*>* aPtr, const char* aName,
66 void* aClosure) const = 0;
67 virtual void Trace(JSObject** aPtr, const char* aName,
68 void* aClosure) const = 0;
69 virtual void Trace(JS::TenuredHeap<JSObject*>* aPtr, const char* aName,
70 void* aClosure) const = 0;
71 virtual void Trace(JS::Heap<JSString*>* aPtr, const char* aName,
72 void* aClosure) const = 0;
73 virtual void Trace(JS::Heap<JSScript*>* aPtr, const char* aName,
74 void* aClosure) const = 0;
75 virtual void Trace(JS::Heap<JSFunction*>* aPtr, const char* aName,
76 void* aClosure) const = 0;
77 };
78
79 /*
80 * An implementation of TraceCallbacks that calls a single function for all JS
81 * GC thing types encountered. Implemented in nsCycleCollectorTraceJSHelpers.cpp.
82 */
83 struct TraceCallbackFunc : public TraceCallbacks
84 {
85 typedef void (*Func)(JS::GCCellPtr aPtr, const char* aName, void* aClosure);
86
TraceCallbackFuncTraceCallbackFunc87 explicit TraceCallbackFunc(Func aCb) : mCallback(aCb) {}
88
89 virtual void Trace(JS::Heap<JS::Value>* aPtr, const char* aName,
90 void* aClosure) const override;
91 virtual void Trace(JS::Heap<jsid>* aPtr, const char* aName,
92 void* aClosure) const override;
93 virtual void Trace(JS::Heap<JSObject*>* aPtr, const char* aName,
94 void* aClosure) const override;
95 virtual void Trace(JSObject** aPtr, const char* aName,
96 void* aClosure) const override;
97 virtual void Trace(JS::TenuredHeap<JSObject*>* aPtr, const char* aName,
98 void* aClosure) const override;
99 virtual void Trace(JS::Heap<JSString*>* aPtr, const char* aName,
100 void* aClosure) const override;
101 virtual void Trace(JS::Heap<JSScript*>* aPtr, const char* aName,
102 void* aClosure) const override;
103 virtual void Trace(JS::Heap<JSFunction*>* aPtr, const char* aName,
104 void* aClosure) const override;
105
106 private:
107 Func mCallback;
108 };
109
110 /**
111 * Participant implementation classes
112 */
113 class NS_NO_VTABLE nsCycleCollectionParticipant
114 {
115 public:
nsCycleCollectionParticipant()116 constexpr nsCycleCollectionParticipant() : mMightSkip(false) {}
nsCycleCollectionParticipant(bool aSkip)117 constexpr explicit nsCycleCollectionParticipant(bool aSkip) : mMightSkip(aSkip) {}
118
119 NS_IMETHOD Traverse(void* aPtr, nsCycleCollectionTraversalCallback& aCb) = 0;
120
121 NS_IMETHOD_(void) Root(void* aPtr) = 0;
122 NS_IMETHOD_(void) Unlink(void* aPtr) = 0;
123 NS_IMETHOD_(void) Unroot(void* aPtr) = 0;
124 NS_IMETHOD_(const char*) ClassName() = 0;
125
Trace(void * aPtr,const TraceCallbacks & aCb,void * aClosure)126 NS_IMETHOD_(void) Trace(void* aPtr, const TraceCallbacks& aCb,
127 void* aClosure) {}
128
129 // If CanSkip returns true, p is removed from the purple buffer during
130 // a call to nsCycleCollector_forgetSkippable().
131 // Note, calling CanSkip may remove objects from the purple buffer!
132 // If aRemovingAllowed is true, p can be removed from the purple buffer.
CanSkip(void * aPtr,bool aRemovingAllowed)133 bool CanSkip(void* aPtr, bool aRemovingAllowed)
134 {
135 return mMightSkip ? CanSkipReal(aPtr, aRemovingAllowed) : false;
136 }
137
138 // If CanSkipInCC returns true, p is skipped when selecting roots for the
139 // cycle collector graph.
140 // Note, calling CanSkipInCC may remove other objects from the purple buffer!
CanSkipInCC(void * aPtr)141 bool CanSkipInCC(void* aPtr)
142 {
143 return mMightSkip ? CanSkipInCCReal(aPtr) : false;
144 }
145
146 // If CanSkipThis returns true, p is not added to the graph.
147 // This method is called during cycle collection, so don't
148 // change the state of any objects!
CanSkipThis(void * aPtr)149 bool CanSkipThis(void* aPtr)
150 {
151 return mMightSkip ? CanSkipThisReal(aPtr) : false;
152 }
153
154 NS_IMETHOD_(void) DeleteCycleCollectable(void* aPtr) = 0;
155
156 protected:
NS_IMETHOD_(bool)157 NS_IMETHOD_(bool) CanSkipReal(void* aPtr, bool aRemovingAllowed)
158 {
159 NS_ASSERTION(false, "Forgot to implement CanSkipReal?");
160 return false;
161 }
CanSkipInCCReal(void * aPtr)162 NS_IMETHOD_(bool) CanSkipInCCReal(void* aPtr)
163 {
164 NS_ASSERTION(false, "Forgot to implement CanSkipInCCReal?");
165 return false;
166 }
CanSkipThisReal(void * aPtr)167 NS_IMETHOD_(bool) CanSkipThisReal(void* aPtr)
168 {
169 NS_ASSERTION(false, "Forgot to implement CanSkipThisReal?");
170 return false;
171 }
172
173 private:
174 const bool mMightSkip;
175 };
176
177 class NS_NO_VTABLE nsScriptObjectTracer : public nsCycleCollectionParticipant
178 {
179 public:
nsScriptObjectTracer()180 constexpr nsScriptObjectTracer()
181 : nsCycleCollectionParticipant(false)
182 {
183 }
nsScriptObjectTracer(bool aSkip)184 constexpr explicit nsScriptObjectTracer(bool aSkip)
185 : nsCycleCollectionParticipant(aSkip)
186 {
187 }
188
189 NS_IMETHOD_(void) Trace(void* aPtr, const TraceCallbacks& aCb,
190 void* aClosure) override = 0;
191
192 // Implemented in nsCycleCollectorTraceJSHelpers.cpp.
193 static void NoteJSChild(JS::GCCellPtr aGCThing, const char* aName,
194 void* aClosure);
195 };
196
197 class NS_NO_VTABLE nsXPCOMCycleCollectionParticipant : public nsScriptObjectTracer
198 {
199 public:
nsXPCOMCycleCollectionParticipant()200 constexpr nsXPCOMCycleCollectionParticipant()
201 : nsScriptObjectTracer(false)
202 {
203 }
nsXPCOMCycleCollectionParticipant(bool aSkip)204 constexpr explicit nsXPCOMCycleCollectionParticipant(bool aSkip)
205 : nsScriptObjectTracer(aSkip)
206 {
207 }
208
209 NS_DECLARE_STATIC_IID_ACCESSOR(NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID)
210
211 NS_IMETHOD_(void) Root(void* aPtr) override;
212 NS_IMETHOD_(void) Unroot(void* aPtr) override;
213
214 NS_IMETHOD_(void) Trace(void* aPtr, const TraceCallbacks& aCb,
215 void* aClosure) override;
216
217 static bool CheckForRightISupports(nsISupports* aSupports);
218 };
219
220 NS_DEFINE_STATIC_IID_ACCESSOR(nsXPCOMCycleCollectionParticipant,
221 NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID)
222
223 ///////////////////////////////////////////////////////////////////////////////
224 // Helpers for implementing a QI to nsXPCOMCycleCollectionParticipant
225 ///////////////////////////////////////////////////////////////////////////////
226
227 #define NS_CYCLE_COLLECTION_CLASSNAME(_class) \
228 _class::NS_CYCLE_COLLECTION_INNERCLASS
229
230 #define NS_IMPL_QUERY_CYCLE_COLLECTION(_class) \
231 if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) { \
232 *aInstancePtr = NS_CYCLE_COLLECTION_PARTICIPANT(_class); \
233 return NS_OK; \
234 } else
235
236 #define NS_IMPL_QUERY_CYCLE_COLLECTION_ISUPPORTS(_class) \
237 if ( aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) ) { \
238 *aInstancePtr = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Upcast(this); \
239 return NS_OK; \
240 } else
241
242 #define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(_class) \
243 NS_IMPL_QUERY_CYCLE_COLLECTION(_class)
244
245 #define NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class) \
246 NS_IMPL_QUERY_CYCLE_COLLECTION_ISUPPORTS(_class)
247
248 #define NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(_class) \
249 NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(_class) \
250 NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION_ISUPPORTS(_class)
251
252 #define NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(_class) \
253 NS_INTERFACE_MAP_BEGIN(_class) \
254 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(_class)
255
256 #define NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(_class) \
257 NS_INTERFACE_MAP_BEGIN(_class) \
258 NS_INTERFACE_MAP_ENTRY_CYCLE_COLLECTION(_class)
259
260 #define NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(_class) \
261 if (rv == NS_OK) return rv; \
262 nsISupports* foundInterface; \
263 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(_class)
264
265 #define NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(_class) \
266 NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \
267 { \
268 NS_PRECONDITION(aInstancePtr, "null out param"); \
269 \
270 if ( aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant)) ) { \
271 *aInstancePtr = NS_CYCLE_COLLECTION_PARTICIPANT(_class); \
272 return NS_OK; \
273 } \
274 nsresult rv;
275
276 #define NS_CYCLE_COLLECTION_UPCAST(obj, clazz) \
277 NS_CYCLE_COLLECTION_CLASSNAME(clazz)::Upcast(obj)
278
279 #ifdef DEBUG
280 #define NS_CHECK_FOR_RIGHT_PARTICIPANT(_ptr) _ptr->CheckForRightParticipant()
281 #else
282 #define NS_CHECK_FOR_RIGHT_PARTICIPANT(_ptr)
283 #endif
284
285 // The default implementation of this class template is empty, because it
286 // should never be used: see the partial specializations below.
287 template<typename T,
288 bool IsXPCOM = mozilla::IsBaseOf<nsISupports, T>::value>
289 struct DowncastCCParticipantImpl
290 {
291 };
292
293 // Specialization for XPCOM CC participants
294 template<typename T>
295 struct DowncastCCParticipantImpl<T, true>
296 {
297 static T* Run(void* aPtr)
298 {
299 nsISupports* s = static_cast<nsISupports*>(aPtr);
300 MOZ_ASSERT(NS_CYCLE_COLLECTION_CLASSNAME(T)::CheckForRightISupports(s),
301 "not the nsISupports pointer we expect");
302 T* rval = NS_CYCLE_COLLECTION_CLASSNAME(T)::Downcast(s);
303 NS_CHECK_FOR_RIGHT_PARTICIPANT(rval);
304 return rval;
305 }
306 };
307
308 // Specialization for native CC participants
309 template<typename T>
310 struct DowncastCCParticipantImpl<T, false>
311 {
312 static T* Run(void* aPtr) { return static_cast<T*>(aPtr); }
313 };
314
315 template<typename T>
316 T*
317 DowncastCCParticipant(void* aPtr)
318 {
319 return DowncastCCParticipantImpl<T>::Run(aPtr);
320 }
321
322 ///////////////////////////////////////////////////////////////////////////////
323 // Helpers for implementing CanSkip methods
324 ///////////////////////////////////////////////////////////////////////////////
325
326 #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(_class) \
327 NS_IMETHODIMP_(bool) \
328 NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipReal(void *p, \
329 bool aRemovingAllowed) \
330 { \
331 _class *tmp = DowncastCCParticipant<_class >(p);
332
333 #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END \
334 (void)tmp; \
335 return false; \
336 }
337
338 #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(_class) \
339 NS_IMETHODIMP_(bool) \
340 NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipInCCReal(void *p) \
341 { \
342 _class *tmp = DowncastCCParticipant<_class >(p);
343
344 #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END \
345 (void)tmp; \
346 return false; \
347 }
348
349 #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(_class) \
350 NS_IMETHODIMP_(bool) \
351 NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipThisReal(void *p) \
352 { \
353 _class *tmp = DowncastCCParticipant<_class >(p);
354
355 #define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END \
356 (void)tmp; \
357 return false; \
358 }
359
360 ///////////////////////////////////////////////////////////////////////////////
361 // Helpers for implementing nsCycleCollectionParticipant::Unlink
362 //
363 // You need to use NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED if you want
364 // the base class Unlink version to be called before your own implementation.
365 // You can use NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED if you want the
366 // base class Unlink to get called after your own implementation. You should
367 // never use them together.
368 ///////////////////////////////////////////////////////////////////////////////
369
370 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \
371 NS_IMETHODIMP_(void) \
372 NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unlink(void *p) \
373 { \
374 _class *tmp = DowncastCCParticipant<_class >(p);
375
376 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base_class) \
377 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \
378 nsISupports *s = static_cast<nsISupports*>(p); \
379 NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Unlink(s);
380
381 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_HELPER(_field) \
382 ImplCycleCollectionUnlink(tmp->_field);
383
384 #define NS_IMPL_CYCLE_COLLECTION_UNLINK(...) \
385 MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \
386 MOZ_FOR_EACH(NS_IMPL_CYCLE_COLLECTION_UNLINK_HELPER, (), (__VA_ARGS__))
387
388 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
389 (void)tmp; \
390 }
391
392 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(_base_class) \
393 nsISupports *s = static_cast<nsISupports*>(p); \
394 NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Unlink(s); \
395 (void)tmp; \
396 }
397
398 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_0(_class) \
399 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \
400 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
401
402
403 ///////////////////////////////////////////////////////////////////////////////
404 // Helpers for implementing nsCycleCollectionParticipant::Traverse
405 ///////////////////////////////////////////////////////////////////////////////
406
407 #define NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, _refcnt) \
408 cb.DescribeRefCountedNode(_refcnt, #_class);
409
410 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(_class) \
411 NS_IMETHODIMP \
412 NS_CYCLE_COLLECTION_CLASSNAME(_class)::Traverse \
413 (void *p, nsCycleCollectionTraversalCallback &cb) \
414 { \
415 _class *tmp = DowncastCCParticipant<_class >(p);
416
417 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \
418 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(_class) \
419 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, tmp->mRefCnt.get())
420
421 // Base class' CC participant should return NS_SUCCESS_INTERRUPTED_TRAVERSE
422 // from Traverse if it wants derived classes to not traverse anything from
423 // their CC participant.
424
425 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base_class) \
426 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(_class) \
427 nsISupports *s = static_cast<nsISupports*>(p); \
428 if (NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Traverse(s, cb) \
429 == NS_SUCCESS_INTERRUPTED_TRAVERSE) { \
430 return NS_SUCCESS_INTERRUPTED_TRAVERSE; \
431 }
432
433 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_HELPER(_field) \
434 ImplCycleCollectionTraverse(cb, tmp->_field, #_field, 0);
435
436 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE(...) \
437 MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \
438 MOZ_FOR_EACH(NS_IMPL_CYCLE_COLLECTION_TRAVERSE_HELPER, (), (__VA_ARGS__))
439
440 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(_field) \
441 CycleCollectionNoteChild(cb, tmp->_field, #_field);
442
443 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \
444 { \
445 TraceCallbackFunc noteJsChild(&nsScriptObjectTracer::NoteJSChild); \
446 Trace(p, noteJsChild, &cb); \
447 }
448
449 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \
450 (void)tmp; \
451 return NS_OK; \
452 }
453
454 ///////////////////////////////////////////////////////////////////////////////
455 // Helpers for implementing nsScriptObjectTracer::Trace
456 ///////////////////////////////////////////////////////////////////////////////
457
458 #define NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(_class) \
459 void \
460 NS_CYCLE_COLLECTION_CLASSNAME(_class)::Trace(void *p, \
461 const TraceCallbacks &aCallbacks, \
462 void *aClosure) \
463 { \
464 _class *tmp = DowncastCCParticipant<_class >(p);
465
466 #define NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(_class, _base_class) \
467 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(_class) \
468 nsISupports *s = static_cast<nsISupports*>(p); \
469 NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Trace(s, aCallbacks, aClosure);
470
471 #define NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(_field) \
472 aCallbacks.Trace(&tmp->_field, #_field, aClosure);
473
474 // NB: The (void)tmp; hack in the TRACE_END macro exists to support
475 // implementations that don't need to do anything in their Trace method.
476 // Without this hack, some compilers warn about the unused tmp local.
477 #define NS_IMPL_CYCLE_COLLECTION_TRACE_END \
478 (void)tmp; \
479 }
480
481 ///////////////////////////////////////////////////////////////////////////////
482 // Helpers for implementing a concrete nsCycleCollectionParticipant
483 ///////////////////////////////////////////////////////////////////////////////
484
485 // If a class defines a participant, then QIing an instance of that class to
486 // nsXPCOMCycleCollectionParticipant should produce that participant.
487 #ifdef DEBUG
488 #define NS_CHECK_FOR_RIGHT_PARTICIPANT_BASE \
489 virtual void CheckForRightParticipant()
490 #define NS_CHECK_FOR_RIGHT_PARTICIPANT_DERIVED \
491 virtual void CheckForRightParticipant() override
492 #define NS_CHECK_FOR_RIGHT_PARTICIPANT_BODY(_class) \
493 { \
494 nsXPCOMCycleCollectionParticipant *p; \
495 CallQueryInterface(this, &p); \
496 MOZ_ASSERT(p == &NS_CYCLE_COLLECTION_INNERNAME, \
497 #_class " should QI to its own CC participant"); \
498 }
499 #define NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \
500 NS_CHECK_FOR_RIGHT_PARTICIPANT_BASE \
501 NS_CHECK_FOR_RIGHT_PARTICIPANT_BODY(_class)
502 #define NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL_INHERITED(_class) \
503 NS_CHECK_FOR_RIGHT_PARTICIPANT_DERIVED \
504 NS_CHECK_FOR_RIGHT_PARTICIPANT_BODY(_class)
505 #else
506 #define NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class)
507 #define NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL_INHERITED(_class)
508 #endif
509
510 #define NS_DECL_CYCLE_COLLECTION_CLASS_NAME_METHOD(_class) \
511 NS_IMETHOD_(const char*) ClassName() override { return #_class; };
512
513
514 #define NS_DECL_CYCLE_COLLECTION_CLASS_BODY_NO_UNLINK(_class, _base) \
515 public: \
516 NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb) \
517 override; \
518 NS_DECL_CYCLE_COLLECTION_CLASS_NAME_METHOD(_class) \
519 NS_IMETHOD_(void) DeleteCycleCollectable(void *p) override \
520 { \
521 DowncastCCParticipant<_class>(p)->DeleteCycleCollectable(); \
522 } \
523 static _class* Downcast(nsISupports* s) \
524 { \
525 return static_cast<_class*>(static_cast<_base*>(s)); \
526 } \
527 static nsISupports* Upcast(_class *p) \
528 { \
529 return NS_ISUPPORTS_CAST(_base*, p); \
530 } \
531 template<typename T> \
532 friend nsISupports* \
533 ToSupports(T* p, NS_CYCLE_COLLECTION_INNERCLASS* dummy);
534
535 #define NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \
536 NS_DECL_CYCLE_COLLECTION_CLASS_BODY_NO_UNLINK(_class, _base) \
537 NS_IMETHOD_(void) Unlink(void *p) override;
538
539 #define NS_PARTICIPANT_AS(type, participant) \
540 const_cast<type*>(reinterpret_cast<const type*>(participant))
541
542 #define NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \
543 static constexpr nsXPCOMCycleCollectionParticipant* GetParticipant() \
544 { \
545 return &_class::NS_CYCLE_COLLECTION_INNERNAME; \
546 }
547
548 /**
549 * We use this macro to force that classes that inherit from a ccable class and
550 * declare their own participant declare themselves as inherited cc classes.
551 * To avoid possibly unnecessary vtables we only do this checking in debug
552 * builds.
553 */
554 #ifdef DEBUG
555 #define NOT_INHERITED_CANT_OVERRIDE virtual void BaseCycleCollectable() final {}
556 #else
557 #define NOT_INHERITED_CANT_OVERRIDE
558 #endif
559
560 #define NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _base) \
561 class NS_CYCLE_COLLECTION_INNERCLASS \
562 : public nsXPCOMCycleCollectionParticipant \
563 { \
564 NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \
565 NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \
566 }; \
567 NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \
568 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; \
569 NOT_INHERITED_CANT_OVERRIDE
570
571 #define NS_DECL_CYCLE_COLLECTION_CLASS(_class) \
572 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(_class, _class)
573
574 // Cycle collector helper for ambiguous classes that can sometimes be skipped.
575 #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS_AMBIGUOUS(_class, _base) \
576 class NS_CYCLE_COLLECTION_INNERCLASS \
577 : public nsXPCOMCycleCollectionParticipant \
578 { \
579 public: \
580 constexpr NS_CYCLE_COLLECTION_INNERCLASS () \
581 : nsXPCOMCycleCollectionParticipant(true) {} \
582 private: \
583 NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \
584 NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed) override; \
585 NS_IMETHOD_(bool) CanSkipInCCReal(void *p) override; \
586 NS_IMETHOD_(bool) CanSkipThisReal(void *p) override; \
587 NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \
588 }; \
589 NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \
590 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; \
591 NOT_INHERITED_CANT_OVERRIDE
592
593 #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS(_class) \
594 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_CLASS_AMBIGUOUS(_class, _class)
595
596 #define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _base) \
597 class NS_CYCLE_COLLECTION_INNERCLASS \
598 : public nsXPCOMCycleCollectionParticipant \
599 { \
600 NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \
601 NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure) override; \
602 NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \
603 }; \
604 NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \
605 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; \
606 NOT_INHERITED_CANT_OVERRIDE
607
608 #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _base) \
609 class NS_CYCLE_COLLECTION_INNERCLASS \
610 : public nsXPCOMCycleCollectionParticipant \
611 { \
612 public: \
613 constexpr NS_CYCLE_COLLECTION_INNERCLASS () \
614 : nsXPCOMCycleCollectionParticipant(true) {} \
615 private: \
616 NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \
617 NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure) override; \
618 NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed) override; \
619 NS_IMETHOD_(bool) CanSkipInCCReal(void *p) override; \
620 NS_IMETHOD_(bool) CanSkipThisReal(void *p) override; \
621 NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \
622 }; \
623 NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL(_class) \
624 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; \
625 NOT_INHERITED_CANT_OVERRIDE
626
627 #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(_class) \
628 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _class)
629
630 #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(_class, \
631 _base_class) \
632 class NS_CYCLE_COLLECTION_INNERCLASS \
633 : public NS_CYCLE_COLLECTION_CLASSNAME(_base_class) \
634 { \
635 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY(_class, _base_class) \
636 NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure) override; \
637 NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed) override; \
638 NS_IMETHOD_(bool) CanSkipInCCReal(void *p) override; \
639 NS_IMETHOD_(bool) CanSkipThisReal(void *p) override; \
640 NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \
641 }; \
642 NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL_INHERITED(_class) \
643 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME;
644
645 #define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(_class) \
646 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _class)
647
648 #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY_NO_UNLINK(_class, \
649 _base_class) \
650 public: \
651 NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb) \
652 override; \
653 NS_DECL_CYCLE_COLLECTION_CLASS_NAME_METHOD(_class) \
654 static _class* Downcast(nsISupports* s) \
655 { \
656 return static_cast<_class*>(static_cast<_base_class*>( \
657 NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Downcast(s))); \
658 }
659
660 #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY(_class, _base_class) \
661 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY_NO_UNLINK(_class, _base_class) \
662 NS_IMETHOD_(void) Unlink(void *p) override;
663
664 #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(_class, _base_class) \
665 class NS_CYCLE_COLLECTION_INNERCLASS \
666 : public NS_CYCLE_COLLECTION_CLASSNAME(_base_class) \
667 { \
668 public: \
669 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY(_class, _base_class) \
670 NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \
671 }; \
672 NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL_INHERITED(_class) \
673 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME;
674
675 #define NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(_class, \
676 _base_class) \
677 class NS_CYCLE_COLLECTION_INNERCLASS \
678 : public NS_CYCLE_COLLECTION_CLASSNAME(_base_class) \
679 { \
680 public: \
681 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY_NO_UNLINK(_class, _base_class) \
682 NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \
683 }; \
684 NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL_INHERITED(_class) \
685 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME;
686
687 #define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(_class, \
688 _base_class) \
689 class NS_CYCLE_COLLECTION_INNERCLASS \
690 : public NS_CYCLE_COLLECTION_CLASSNAME(_base_class) \
691 { \
692 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_BODY(_class, _base_class) \
693 NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure) \
694 override; \
695 NS_IMPL_GET_XPCOM_CYCLE_COLLECTION_PARTICIPANT(_class) \
696 }; \
697 NS_CHECK_FOR_RIGHT_PARTICIPANT_IMPL_INHERITED(_class) \
698 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME;
699
700 // Cycle collector participant declarations.
701
702 #define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class) \
703 public: \
704 NS_IMETHOD_(void) Root(void *n) override; \
705 NS_IMETHOD_(void) Unlink(void *n) override; \
706 NS_IMETHOD_(void) Unroot(void *n) override; \
707 NS_IMETHOD Traverse(void *n, nsCycleCollectionTraversalCallback &cb) \
708 override; \
709 NS_DECL_CYCLE_COLLECTION_CLASS_NAME_METHOD(_class) \
710 NS_IMETHOD_(void) DeleteCycleCollectable(void *n) override \
711 { \
712 DowncastCCParticipant<_class>(n)->DeleteCycleCollectable(); \
713 } \
714 static _class* Downcast(void* s) \
715 { \
716 return DowncastCCParticipant<_class>(s); \
717 } \
718 static void* Upcast(_class *p) \
719 { \
720 return static_cast<void*>(p); \
721 }
722
723 #define NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(_class) \
724 void DeleteCycleCollectable(void) \
725 { \
726 delete this; \
727 } \
728 class NS_CYCLE_COLLECTION_INNERCLASS \
729 : public nsCycleCollectionParticipant \
730 { \
731 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class) \
732 static constexpr nsCycleCollectionParticipant* GetParticipant() \
733 { \
734 return &_class::NS_CYCLE_COLLECTION_INNERNAME; \
735 } \
736 }; \
737 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME;
738
739 #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_NATIVE_CLASS(_class) \
740 void DeleteCycleCollectable(void) \
741 { \
742 delete this; \
743 } \
744 class NS_CYCLE_COLLECTION_INNERCLASS \
745 : public nsCycleCollectionParticipant \
746 { \
747 public: \
748 constexpr NS_CYCLE_COLLECTION_INNERCLASS () \
749 : nsCycleCollectionParticipant(true) {} \
750 private: \
751 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class) \
752 NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed) override; \
753 NS_IMETHOD_(bool) CanSkipInCCReal(void *p) override; \
754 NS_IMETHOD_(bool) CanSkipThisReal(void *p) override; \
755 static nsCycleCollectionParticipant* GetParticipant() \
756 { \
757 return &_class::NS_CYCLE_COLLECTION_INNERNAME; \
758 } \
759 }; \
760 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME;
761
762 #define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_NATIVE_CLASS_WITH_CUSTOM_DELETE(_class) \
763 class NS_CYCLE_COLLECTION_INNERCLASS \
764 : public nsCycleCollectionParticipant \
765 { \
766 public: \
767 constexpr NS_CYCLE_COLLECTION_INNERCLASS () \
768 : nsCycleCollectionParticipant(true) {} \
769 private: \
770 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class) \
771 NS_IMETHOD_(bool) CanSkipReal(void *p, bool aRemovingAllowed) override; \
772 NS_IMETHOD_(bool) CanSkipInCCReal(void *p) override; \
773 NS_IMETHOD_(bool) CanSkipThisReal(void *p) override; \
774 static nsCycleCollectionParticipant* GetParticipant() \
775 { \
776 return &_class::NS_CYCLE_COLLECTION_INNERNAME; \
777 } \
778 }; \
779 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME;
780
781 #define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(_class) \
782 void DeleteCycleCollectable(void) \
783 { \
784 delete this; \
785 } \
786 class NS_CYCLE_COLLECTION_INNERCLASS \
787 : public nsScriptObjectTracer \
788 { \
789 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS_BODY(_class) \
790 NS_IMETHOD_(void) Trace(void *p, const TraceCallbacks &cb, void *closure) \
791 override; \
792 static constexpr nsScriptObjectTracer* GetParticipant() \
793 { \
794 return &_class::NS_CYCLE_COLLECTION_INNERNAME; \
795 } \
796 }; \
797 static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME;
798
799 #define NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(_class, _root_function) \
800 NS_IMETHODIMP_(void) \
801 NS_CYCLE_COLLECTION_CLASSNAME(_class)::Root(void *p) \
802 { \
803 _class *tmp = static_cast<_class*>(p); \
804 tmp->_root_function(); \
805 }
806
807 #define NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(_class, _unroot_function) \
808 NS_IMETHODIMP_(void) \
809 NS_CYCLE_COLLECTION_CLASSNAME(_class)::Unroot(void *p) \
810 { \
811 _class *tmp = static_cast<_class*>(p); \
812 tmp->_unroot_function(); \
813 }
814
815 #define NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
816 _class::NS_CYCLE_COLLECTION_INNERCLASS _class::NS_CYCLE_COLLECTION_INNERNAME;
817
818 // NB: This is not something you usually want to use. It is here to allow
819 // adding things to the CC graph to help debugging via CC logs, but it does not
820 // traverse or unlink anything, so it is useless for anything else.
821 #define NS_IMPL_CYCLE_COLLECTION_0(_class) \
822 NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
823 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \
824 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
825 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \
826 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
827
828 #define NS_IMPL_CYCLE_COLLECTION(_class, ...) \
829 NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
830 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \
831 NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \
832 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
833 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \
834 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \
835 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
836
837 // If you are looking for NS_IMPL_CYCLE_COLLECTION_INHERITED_0(_class, _base)
838 // you should instead not declare any cycle collected stuff in _class, so it
839 // will just inherit the CC declarations from _base.
840
841 #define NS_IMPL_CYCLE_COLLECTION_INHERITED(_class, _base, ...) \
842 NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
843 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base) \
844 NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \
845 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
846 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base) \
847 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \
848 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
849
850 #define NS_CYCLE_COLLECTION_NOTE_EDGE_NAME CycleCollectionNoteEdgeName
851
852 #endif // nsCycleCollectionParticipant_h__
853