tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

cc-analyzer.sys.mjs (3813B)


      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 file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 import { setTimeout } from "resource://gre/modules/Timer.sys.mjs";
      6 
      7 /**
      8 * Helper class to retrieve CC/GC Logs via nsICycleCollectorListener interface.
      9 */
     10 export class CCAnalyzer {
     11  clear() {
     12    this.processingCount = 0;
     13    this.graph = {};
     14    this.roots = [];
     15    this.garbage = [];
     16    this.edges = [];
     17    this.listener = null;
     18    this.count = 0;
     19  }
     20 
     21  /**
     22   * Run the analyzer by running the CC/GC, which would allow use
     23   * to call nsICycleCollectorListener.processNext()
     24   * which would call nsICycleCollectorListener.{noteRefCountedObject,noteGCedObject,noteEdge}.
     25   *
     26   * @param {boolean} wantAllTraces
     27   *        See nsICycleCollectorListener.allTraces() jsdoc.
     28   */
     29  async run(wantAllTraces = false) {
     30    this.clear();
     31 
     32    // Instantiate and configure the CC logger
     33    this.listener = Cu.createCCLogger();
     34    if (wantAllTraces) {
     35      dump("CC Analyzer >> all traces!\n");
     36      this.listener = this.listener.allTraces();
     37    }
     38 
     39    this.listener.disableLog = true;
     40    this.listener.wantAfterProcessing = true;
     41 
     42    // Register the CC logger
     43    Cu.forceCC(this.listener);
     44 
     45    // Process the entire heap step by step in 10K chunks
     46    let done = false;
     47    while (!done) {
     48      for (let i = 0; i < 10000; i++) {
     49        if (!this.listener.processNext(this)) {
     50          done = true;
     51          break;
     52        }
     53      }
     54      dump("Process CC/GC logs " + this.count + "\n");
     55      // Process next chunk after an event loop to avoid freezing the process
     56      await new Promise(resolve => setTimeout(resolve, 0));
     57    }
     58    await new Promise(resolve => setTimeout(resolve, 0));
     59    dump("Done!\n");
     60  }
     61 
     62  noteRefCountedObject(address, refCount, objectDescription) {
     63    const o = this.ensureObject(address);
     64    o.address = address;
     65    o.refcount = refCount;
     66    o.name = objectDescription;
     67  }
     68 
     69  noteGCedObject(address, marked, objectDescription, compartmentAddr) {
     70    const o = this.ensureObject(address);
     71    o.address = address;
     72    o.gcmarked = marked;
     73    o.name = objectDescription;
     74    o.compartment = compartmentAddr;
     75  }
     76 
     77  noteEdge(fromAddress, toAddress, edgeName) {
     78    const fromObject = this.ensureObject(fromAddress);
     79    const toObject = this.ensureObject(toAddress);
     80    fromObject.edges.push({ name: edgeName, to: toObject });
     81    toObject.owners.push({ name: edgeName, from: fromObject });
     82 
     83    this.edges.push({
     84      name: edgeName,
     85      from: fromObject,
     86      to: toObject,
     87    });
     88  }
     89 
     90  describeRoot(address, knownEdges) {
     91    const o = this.ensureObject(address);
     92    o.root = true;
     93    o.knownEdges = knownEdges;
     94    this.roots.push(o);
     95  }
     96 
     97  describeGarbage(address) {
     98    const o = this.ensureObject(address);
     99    o.garbage = true;
    100    this.garbage.push(o);
    101  }
    102 
    103  ensureObject(address) {
    104    if (!this.graph[address]) {
    105      this.count++;
    106      this.graph[address] = new CCObject();
    107    }
    108 
    109    return this.graph[address];
    110  }
    111 
    112  find(text) {
    113    const result = [];
    114    for (const address in this.graph) {
    115      const o = this.graph[address];
    116      if (!o.garbage && o.name.includes(text)) {
    117        result.push(o);
    118      }
    119    }
    120    return result;
    121  }
    122 
    123  findNotJS() {
    124    const result = [];
    125    for (const address in this.graph) {
    126      const o = this.graph[address];
    127      if (!o.garbage && o.name.indexOf("JS") != 0) {
    128        result.push(o);
    129      }
    130    }
    131    return result;
    132  }
    133 }
    134 
    135 class CCObject {
    136  constructor() {
    137    this.name = "";
    138    this.address = null;
    139    this.refcount = 0;
    140    this.gcmarked = false;
    141    this.root = false;
    142    this.garbage = false;
    143    this.knownEdges = 0;
    144    this.edges = [];
    145    this.owners = [];
    146  }
    147 }