DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (d1ed7de67f5a)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "nsISupports.idl"

%{C++
#include <stdio.h>
%}

[ptr] native FILE(FILE);
interface nsIFile;

/**
 * Interfaces for observing the cycle collector's work, both from C++ and
 * from JavaScript.
 *
 * If given an object implementing nsICycleCollectorListener, the cycle
 * collector calls that object's methods as it works, describing the
 * objects it visits, the edges it finds, and the conclusions it reaches
 * about which objects are live.
 *
 * Analyzing cycle collection from JS is harder: an nsICycleCollectorListener
 * mustn't mess with the object graph while the cycle collector is trying to
 * figure it out, which means it can't be implemented by JS code: JS can't do
 * much of anything useful within those constraints. Instead, JS code can
 * instantiate @mozilla.org/cycle-collector-logger;1, a C++ class implementing
 * nsICycleCollectorListener that logs the cycle collector's mumblings and then
 * replays them later to an nsICycleCollectorHandler --- which *can* be
 * implemented in JS.
 */

/**
 * The interface JS code should implement to receive annotations logged by an
 * @mozilla.org/cycle-collector-logger;1 instance. Pass an instance of this to
 * the logger's 'processNext' method.
 *
 * The methods are a subset of those in nsICycleCollectorListener; see the
 * descriptions there.
 */
[scriptable, uuid(39a8f80e-7eee-4141-b9ef-6e2a7d6e466d)]
interface nsICycleCollectorHandler : nsISupports
{
    void noteRefCountedObject(in ACString aAddress,
                              in unsigned long aRefCount,
                              in ACString aObjectDescription);
    void noteGCedObject(in ACString aAddress,
                        in boolean aMarked,
                        in ACString aObjectDescription,
                        in ACString aCompartmentAddress);
    void noteEdge(in ACString aFromAddress,
                  in ACString aToAddress,
                  in ACString aEdgeName);
    void describeRoot(in ACString aAddress,
                      in unsigned long aKnownEdges);
    void describeGarbage(in ACString aAddress);
};


/**
 * This interface allows replacing the log-writing backend for an
 * nsICycleCollectorListener.  As this interface is also called while
 * the cycle collector is running, it cannot be implemented in JS.
 */
[scriptable, builtinclass, uuid(3ad9875f-d0e4-4ac2-87e3-f127f6c02ce1)]
interface nsICycleCollectorLogSink : nsISupports
{
  [noscript] void open(out FILE aGCLog, out FILE aCCLog);
  void closeGCLog();
  void closeCCLog();

  // This string will appear somewhere in the log's filename.
  attribute AString filenameIdentifier;

  // This is the process ID; it can be changed if logging is on behalf
  // of another process.
  attribute int32_t processIdentifier;

  // The GC log file, if logging to files.
  readonly attribute nsIFile gcLog;

  // The CC log file, if logging to files.
  readonly attribute nsIFile ccLog;
};


/**
 * Given an instance of this interface, the cycle collector calls the instance's
 * methods to report the objects it visits, the edges between them, and its
 * conclusions about which objects are roots and which are garbage.
 *
 * For a single cycle collection pass, the cycle collector calls this
 * interface's methods in the following order:
 *
 * - First, |begin|. If |begin| returns an error, none of the listener's other
 *   methods will be called.
 *
 * - Then, for each node in the graph:
 *   - a call to either |noteRefCountedObject| or |noteGCedObject|, to describe
 *     the node itself; and
 *   - for each edge starting at that node, a call to |noteEdge|.
 *
 * - Then, zero or more calls to |noteIncrementalRoot|; an "incremental
 *   root" is an object that may have had a new reference to it created
 *   during an incremental collection, and must therefore be treated as
 *   live for safety.
 *
 * - After all the nodes have been described, a call to |beginResults|.
 *
 * - A series of calls to:
 *   - |describeRoot|, for reference-counted nodes that the CC has identified as
 *     roots of collection. (The cycle collector didn't find enough incoming
 *     edges to account for these nodes' reference counts, so there must be code
 *     holding on to them that the cycle collector doesn't know about.)
 *   - |describeGarbage|, for nodes the cycle collector has identified as garbage.
 *
 *   Any node not mentioned in a call to |describeRoot| or |describeGarbage| is
 *   neither a root nor garbage. (The cycle collector was able to find all the
 *   edges implied by the node's reference count.)
 *
 * - Finally, a call to |end|.
 *
 *
 * This interface cannot be implemented by JavaScript code, as it is called
 * while the cycle collector is running. To analyze cycle collection data in JS:
 *
 * - Create an instance of @mozilla.org/cycle-collector-logger;1, which
 *   implements this interface.
 *
 * - Set its |disableLog| property to true. This prevents the logger from
 *   printing messages about each method call to a temporary log file.
 *
 * - Set its |wantAfterProcessing| property to true. This tells the logger
 *   to record calls to its methods in memory. The |processNext| method
 *   returns events from this record.
 *
 * - Perform a collection using the logger. For example, call
 *   |nsIDOMWindowUtils|'s |garbageCollect| method, passing the logger as
 *   the |aListener| argument.
 *
 * - When the collection is complete, loop calling the logger's
 *   |processNext| method, passing a JavaScript object that implements
 *   nsICycleCollectorHandler. This JS code is free to allocate and operate
 *   on objects however it pleases: the cycle collector has finished its
 *   work, and the JS code is simply consuming recorded data.
 */
[scriptable, builtinclass, uuid(c7d55656-e0d8-4986-88bb-cb28cb55b993)]
interface nsICycleCollectorListener : nsISupports
{
    // Return a listener that directs the cycle collector to traverse
    // objects that it knows won't be collectable.
    //
    // Note that even this listener will not visit every node in the heap;
    // the cycle collector can't see the entire heap. But while this
    // listener is in use, the collector disables some optimizations it
    // normally uses to avoid certain classes of objects that are certainly
    // alive. So, if your purpose is to get a view of the portion of the
    // heap that is of interest to the cycle collector, and not simply find
    // garbage, then you should use the listener this returns.
    //
    // Note that this does not necessarily return a new listener; rather, it may
    // simply set a flag on this listener (a side effect!) and return it.
    nsICycleCollectorListener allTraces();

    // True if this listener will behave like one returned by allTraces().
    readonly attribute boolean wantAllTraces;

    // If true, do not log each method call to a temporary file.
    // Initially false.
    attribute boolean disableLog;

    // If |disableLog| is false, this object will be sent the log text.
    attribute nsICycleCollectorLogSink logSink;

    // If true, record all method calls in memory, to be retrieved later
    // using |processNext|. Initially false.
    attribute boolean wantAfterProcessing;

    void begin();
    void noteRefCountedObject (in unsigned long long aAddress,
			       in unsigned long aRefCount,
			       in string aObjectDescription);
    void noteGCedObject (in unsigned long long aAddress,
			 in boolean aMarked,
			 in string aObjectDescription,
			 in unsigned long long aCompartmentAddress);
    void noteEdge(in unsigned long long aToAddress,
                  in string aEdgeName);
    void noteWeakMapEntry(in unsigned long long aMap,
                          in unsigned long long aKey,
                          in unsigned long long aKeyDelegate,
                          in unsigned long long aValue);
    void noteIncrementalRoot(in unsigned long long aAddress);

    void beginResults();
    void describeRoot(in unsigned long long aAddress,
		      in unsigned long aKnownEdges);
    void describeGarbage(in unsigned long long aAddress);
    void end();

    // Report the next recorded event to |aHandler|, and remove it from the
    // record. Return false if there isn't anything more to process.
    //
    // Note that we only record events to report here if our
    // |wantAfterProcessing| property is true.
    boolean processNext(in nsICycleCollectorHandler aHandler);
};