1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/base/nsICycleCollectorListener.idl Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,178 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "nsISupports.idl" 1.9 + 1.10 +/** 1.11 + * Interfaces for observing the cycle collector's work, both from C++ and 1.12 + * from JavaScript. 1.13 + * 1.14 + * If given an object implementing nsICycleCollectorListener, the cycle 1.15 + * collector calls that object's methods as it works, describing the 1.16 + * objects it visits, the edges it finds, and the conclusions it reaches 1.17 + * about which objects are live. 1.18 + * 1.19 + * Analyzing cycle collection from JS is harder: an nsICycleCollectorListener 1.20 + * mustn't mess with the object graph while the cycle collector is trying to 1.21 + * figure it out, which means it can't be implemented by JS code: JS can't do 1.22 + * much of anything useful within those constraints. Instead, JS code can 1.23 + * instantiate @mozilla.org/cycle-collector-logger;1, a C++ class implementing 1.24 + * nsICycleCollectorListener that logs the cycle collector's mumblings and then 1.25 + * replays them later to an nsICycleCollectorHandler --- which *can* be 1.26 + * implemented in JS. 1.27 + */ 1.28 + 1.29 +/** 1.30 + * The interface JS code should implement to receive annotations logged by an 1.31 + * @mozilla.org/cycle-collector-logger;1 instance. Pass an instance of this to 1.32 + * the logger's 'processNext' method. 1.33 + * 1.34 + * The methods are a subset of those in nsICycleCollectorListener; see the 1.35 + * descriptions there. 1.36 + */ 1.37 +[scriptable, uuid(39a8f80e-7eee-4141-b9ef-6e2a7d6e466d)] 1.38 +interface nsICycleCollectorHandler : nsISupports 1.39 +{ 1.40 + void noteRefCountedObject(in ACString aAddress, 1.41 + in unsigned long aRefCount, 1.42 + in ACString aObjectDescription); 1.43 + void noteGCedObject(in ACString aAddress, 1.44 + in boolean aMarked, 1.45 + in ACString aObjectDescription, 1.46 + in ACString aCompartmentAddress); 1.47 + void noteEdge(in ACString aFromAddress, 1.48 + in ACString aToAddress, 1.49 + in ACString aEdgeName); 1.50 + void describeRoot(in ACString aAddress, 1.51 + in unsigned long aKnownEdges); 1.52 + void describeGarbage(in ACString aAddress); 1.53 +}; 1.54 + 1.55 +/** 1.56 + * Given an instance of this interface, the cycle collector calls the instance's 1.57 + * methods to report the objects it visits, the edges between them, and its 1.58 + * conclusions about which objects are roots and which are garbage. 1.59 + * 1.60 + * For a single cycle collection pass, the cycle collector calls this 1.61 + * interface's methods in the following order: 1.62 + * 1.63 + * - First, |begin|. If |begin| returns an error, none of the listener's other 1.64 + * methods will be called. 1.65 + * 1.66 + * - Then, for each node in the graph: 1.67 + * - a call to either |noteRefCountedObject| or |noteGCedObject|, to describe 1.68 + * the node itself; and 1.69 + * - for each edge starting at that node, a call to |noteEdge|. 1.70 + * 1.71 + * - Then, zero or more calls to |noteIncrementalRoot|; an "incremental 1.72 + * root" is an object that may have had a new reference to it created 1.73 + * during an incremental collection, and must therefore be treated as 1.74 + * live for safety. 1.75 + * 1.76 + * - After all the nodes have been described, a call to |beginResults|. 1.77 + * 1.78 + * - A series of calls to: 1.79 + * - |describeRoot|, for reference-counted nodes that the CC has identified as 1.80 + * roots of collection. (The cycle collector didn't find enough incoming 1.81 + * edges to account for these nodes' reference counts, so there must be code 1.82 + * holding on to them that the cycle collector doesn't know about.) 1.83 + * - |describeGarbage|, for nodes the cycle collector has identified as garbage. 1.84 + * 1.85 + * Any node not mentioned in a call to |describeRoot| or |describeGarbage| is 1.86 + * neither a root nor garbage. (The cycle collector was able to find all the 1.87 + * edges implied by the node's reference count.) 1.88 + * 1.89 + * - Finally, a call to |end|. 1.90 + * 1.91 + * 1.92 + * This interface cannot be implemented by JavaScript code, as it is called 1.93 + * while the cycle collector works. To analyze cycle collection data in JS: 1.94 + * 1.95 + * - Create an instance of @mozilla.org/cycle-collector-logger;1, which 1.96 + * implements this interface. 1.97 + * 1.98 + * - Set its |disableLog| property to true. This prevents the logger from 1.99 + * printing messages about each method call to a temporary log file. 1.100 + * 1.101 + * - Set its |wantAfterProcessing| property to true. This tells the logger 1.102 + * to record calls to its methods in memory. The |processNext| method 1.103 + * returns events from this record. 1.104 + * 1.105 + * - Perform a collection using the logger. For example, call 1.106 + * |nsIDOMWindowUtils|'s |garbageCollect| method, passing the logger as 1.107 + * the |aListener| argument. 1.108 + * 1.109 + * - When the collection is complete, loop calling the logger's 1.110 + * |processNext| method, passing a JavaScript object that implements 1.111 + * nsICycleCollectorHandler. This JS code is free to allocate and operate 1.112 + * on objects however it pleases: the cycle collector has finished its 1.113 + * work, and the JS code is simply consuming recorded data. 1.114 + */ 1.115 +[scriptable, builtinclass, uuid(c46e6947-9076-4a0e-bb27-d4aa3706c54d)] 1.116 +interface nsICycleCollectorListener : nsISupports 1.117 +{ 1.118 + // Return a listener that directs the cycle collector to traverse 1.119 + // objects that it knows won't be collectable. 1.120 + // 1.121 + // Note that even this listener will not visit every node in the heap; 1.122 + // the cycle collector can't see the entire heap. But while this 1.123 + // listener is in use, the collector disables some optimizations it 1.124 + // normally uses to avoid certain classes of objects that are certainly 1.125 + // alive. So, if your purpose is to get a view of the portion of the 1.126 + // heap that is of interest to the cycle collector, and not simply find 1.127 + // garbage, then you should use the listener this returns. 1.128 + // 1.129 + // Note that this does not necessarily return a new listener; rather, it may 1.130 + // simply set a flag on this listener (a side effect!) and return it. 1.131 + nsICycleCollectorListener allTraces(); 1.132 + 1.133 + // True if this listener will behave like one returned by allTraces(). 1.134 + readonly attribute boolean wantAllTraces; 1.135 + 1.136 + // If true, do not log each method call to a temporary file. 1.137 + // Initially false. 1.138 + attribute boolean disableLog; 1.139 + 1.140 + // This string will appear somewhere in the log's filename. 1.141 + attribute AString filenameIdentifier; 1.142 + 1.143 + // If true, record all method calls in memory, to be retrieved later 1.144 + // using |processNext|. Initially false. 1.145 + attribute boolean wantAfterProcessing; 1.146 + 1.147 + // This string will indicate the full path of the GC log if enabled. 1.148 + readonly attribute AString gcLogPath; 1.149 + 1.150 + // This string will indicate the full path of the CC log if enabled. 1.151 + readonly attribute AString ccLogPath; 1.152 + 1.153 + void begin(); 1.154 + void noteRefCountedObject (in unsigned long long aAddress, 1.155 + in unsigned long aRefCount, 1.156 + in string aObjectDescription); 1.157 + void noteGCedObject (in unsigned long long aAddress, 1.158 + in boolean aMarked, 1.159 + in string aObjectDescription, 1.160 + in unsigned long long aCompartmentAddress); 1.161 + void noteEdge(in unsigned long long aToAddress, 1.162 + in string aEdgeName); 1.163 + void noteWeakMapEntry(in unsigned long long aMap, 1.164 + in unsigned long long aKey, 1.165 + in unsigned long long aKeyDelegate, 1.166 + in unsigned long long aValue); 1.167 + void noteIncrementalRoot(in unsigned long long aAddress); 1.168 + 1.169 + void beginResults(); 1.170 + void describeRoot(in unsigned long long aAddress, 1.171 + in unsigned long aKnownEdges); 1.172 + void describeGarbage(in unsigned long long aAddress); 1.173 + void end(); 1.174 + 1.175 + // Report the next recorded event to |aHandler|, and remove it from the 1.176 + // record. Return false if there isn't anything more to process. 1.177 + // 1.178 + // Note that we only record events to report here if our 1.179 + // |wantAfterProcessing| property is true. 1.180 + boolean processNext(in nsICycleCollectorHandler aHandler); 1.181 +};