|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "nsISupports.idl" |
|
6 |
|
7 /** |
|
8 * Interfaces for observing the cycle collector's work, both from C++ and |
|
9 * from JavaScript. |
|
10 * |
|
11 * If given an object implementing nsICycleCollectorListener, the cycle |
|
12 * collector calls that object's methods as it works, describing the |
|
13 * objects it visits, the edges it finds, and the conclusions it reaches |
|
14 * about which objects are live. |
|
15 * |
|
16 * Analyzing cycle collection from JS is harder: an nsICycleCollectorListener |
|
17 * mustn't mess with the object graph while the cycle collector is trying to |
|
18 * figure it out, which means it can't be implemented by JS code: JS can't do |
|
19 * much of anything useful within those constraints. Instead, JS code can |
|
20 * instantiate @mozilla.org/cycle-collector-logger;1, a C++ class implementing |
|
21 * nsICycleCollectorListener that logs the cycle collector's mumblings and then |
|
22 * replays them later to an nsICycleCollectorHandler --- which *can* be |
|
23 * implemented in JS. |
|
24 */ |
|
25 |
|
26 /** |
|
27 * The interface JS code should implement to receive annotations logged by an |
|
28 * @mozilla.org/cycle-collector-logger;1 instance. Pass an instance of this to |
|
29 * the logger's 'processNext' method. |
|
30 * |
|
31 * The methods are a subset of those in nsICycleCollectorListener; see the |
|
32 * descriptions there. |
|
33 */ |
|
34 [scriptable, uuid(39a8f80e-7eee-4141-b9ef-6e2a7d6e466d)] |
|
35 interface nsICycleCollectorHandler : nsISupports |
|
36 { |
|
37 void noteRefCountedObject(in ACString aAddress, |
|
38 in unsigned long aRefCount, |
|
39 in ACString aObjectDescription); |
|
40 void noteGCedObject(in ACString aAddress, |
|
41 in boolean aMarked, |
|
42 in ACString aObjectDescription, |
|
43 in ACString aCompartmentAddress); |
|
44 void noteEdge(in ACString aFromAddress, |
|
45 in ACString aToAddress, |
|
46 in ACString aEdgeName); |
|
47 void describeRoot(in ACString aAddress, |
|
48 in unsigned long aKnownEdges); |
|
49 void describeGarbage(in ACString aAddress); |
|
50 }; |
|
51 |
|
52 /** |
|
53 * Given an instance of this interface, the cycle collector calls the instance's |
|
54 * methods to report the objects it visits, the edges between them, and its |
|
55 * conclusions about which objects are roots and which are garbage. |
|
56 * |
|
57 * For a single cycle collection pass, the cycle collector calls this |
|
58 * interface's methods in the following order: |
|
59 * |
|
60 * - First, |begin|. If |begin| returns an error, none of the listener's other |
|
61 * methods will be called. |
|
62 * |
|
63 * - Then, for each node in the graph: |
|
64 * - a call to either |noteRefCountedObject| or |noteGCedObject|, to describe |
|
65 * the node itself; and |
|
66 * - for each edge starting at that node, a call to |noteEdge|. |
|
67 * |
|
68 * - Then, zero or more calls to |noteIncrementalRoot|; an "incremental |
|
69 * root" is an object that may have had a new reference to it created |
|
70 * during an incremental collection, and must therefore be treated as |
|
71 * live for safety. |
|
72 * |
|
73 * - After all the nodes have been described, a call to |beginResults|. |
|
74 * |
|
75 * - A series of calls to: |
|
76 * - |describeRoot|, for reference-counted nodes that the CC has identified as |
|
77 * roots of collection. (The cycle collector didn't find enough incoming |
|
78 * edges to account for these nodes' reference counts, so there must be code |
|
79 * holding on to them that the cycle collector doesn't know about.) |
|
80 * - |describeGarbage|, for nodes the cycle collector has identified as garbage. |
|
81 * |
|
82 * Any node not mentioned in a call to |describeRoot| or |describeGarbage| is |
|
83 * neither a root nor garbage. (The cycle collector was able to find all the |
|
84 * edges implied by the node's reference count.) |
|
85 * |
|
86 * - Finally, a call to |end|. |
|
87 * |
|
88 * |
|
89 * This interface cannot be implemented by JavaScript code, as it is called |
|
90 * while the cycle collector works. To analyze cycle collection data in JS: |
|
91 * |
|
92 * - Create an instance of @mozilla.org/cycle-collector-logger;1, which |
|
93 * implements this interface. |
|
94 * |
|
95 * - Set its |disableLog| property to true. This prevents the logger from |
|
96 * printing messages about each method call to a temporary log file. |
|
97 * |
|
98 * - Set its |wantAfterProcessing| property to true. This tells the logger |
|
99 * to record calls to its methods in memory. The |processNext| method |
|
100 * returns events from this record. |
|
101 * |
|
102 * - Perform a collection using the logger. For example, call |
|
103 * |nsIDOMWindowUtils|'s |garbageCollect| method, passing the logger as |
|
104 * the |aListener| argument. |
|
105 * |
|
106 * - When the collection is complete, loop calling the logger's |
|
107 * |processNext| method, passing a JavaScript object that implements |
|
108 * nsICycleCollectorHandler. This JS code is free to allocate and operate |
|
109 * on objects however it pleases: the cycle collector has finished its |
|
110 * work, and the JS code is simply consuming recorded data. |
|
111 */ |
|
112 [scriptable, builtinclass, uuid(c46e6947-9076-4a0e-bb27-d4aa3706c54d)] |
|
113 interface nsICycleCollectorListener : nsISupports |
|
114 { |
|
115 // Return a listener that directs the cycle collector to traverse |
|
116 // objects that it knows won't be collectable. |
|
117 // |
|
118 // Note that even this listener will not visit every node in the heap; |
|
119 // the cycle collector can't see the entire heap. But while this |
|
120 // listener is in use, the collector disables some optimizations it |
|
121 // normally uses to avoid certain classes of objects that are certainly |
|
122 // alive. So, if your purpose is to get a view of the portion of the |
|
123 // heap that is of interest to the cycle collector, and not simply find |
|
124 // garbage, then you should use the listener this returns. |
|
125 // |
|
126 // Note that this does not necessarily return a new listener; rather, it may |
|
127 // simply set a flag on this listener (a side effect!) and return it. |
|
128 nsICycleCollectorListener allTraces(); |
|
129 |
|
130 // True if this listener will behave like one returned by allTraces(). |
|
131 readonly attribute boolean wantAllTraces; |
|
132 |
|
133 // If true, do not log each method call to a temporary file. |
|
134 // Initially false. |
|
135 attribute boolean disableLog; |
|
136 |
|
137 // This string will appear somewhere in the log's filename. |
|
138 attribute AString filenameIdentifier; |
|
139 |
|
140 // If true, record all method calls in memory, to be retrieved later |
|
141 // using |processNext|. Initially false. |
|
142 attribute boolean wantAfterProcessing; |
|
143 |
|
144 // This string will indicate the full path of the GC log if enabled. |
|
145 readonly attribute AString gcLogPath; |
|
146 |
|
147 // This string will indicate the full path of the CC log if enabled. |
|
148 readonly attribute AString ccLogPath; |
|
149 |
|
150 void begin(); |
|
151 void noteRefCountedObject (in unsigned long long aAddress, |
|
152 in unsigned long aRefCount, |
|
153 in string aObjectDescription); |
|
154 void noteGCedObject (in unsigned long long aAddress, |
|
155 in boolean aMarked, |
|
156 in string aObjectDescription, |
|
157 in unsigned long long aCompartmentAddress); |
|
158 void noteEdge(in unsigned long long aToAddress, |
|
159 in string aEdgeName); |
|
160 void noteWeakMapEntry(in unsigned long long aMap, |
|
161 in unsigned long long aKey, |
|
162 in unsigned long long aKeyDelegate, |
|
163 in unsigned long long aValue); |
|
164 void noteIncrementalRoot(in unsigned long long aAddress); |
|
165 |
|
166 void beginResults(); |
|
167 void describeRoot(in unsigned long long aAddress, |
|
168 in unsigned long aKnownEdges); |
|
169 void describeGarbage(in unsigned long long aAddress); |
|
170 void end(); |
|
171 |
|
172 // Report the next recorded event to |aHandler|, and remove it from the |
|
173 // record. Return false if there isn't anything more to process. |
|
174 // |
|
175 // Note that we only record events to report here if our |
|
176 // |wantAfterProcessing| property is true. |
|
177 boolean processNext(in nsICycleCollectorHandler aHandler); |
|
178 }; |