michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: function CCAnalyzer() { michael@0: } michael@0: michael@0: CCAnalyzer.prototype = { michael@0: clear: function () { michael@0: this.callback = null; michael@0: this.processingCount = 0; michael@0: this.graph = {}; michael@0: this.roots = []; michael@0: this.garbage = []; michael@0: this.edges = []; michael@0: this.listener = null; michael@0: }, michael@0: michael@0: run: function (aCallback) { michael@0: this.clear(); michael@0: this.callback = aCallback; michael@0: michael@0: this.listener = Cc["@mozilla.org/cycle-collector-logger;1"]. michael@0: createInstance(Ci.nsICycleCollectorListener); michael@0: michael@0: this.listener.disableLog = true; michael@0: this.listener.wantAfterProcessing = true; michael@0: michael@0: this.runCC(3); michael@0: }, michael@0: michael@0: runCC: function (aCounter) { michael@0: let utils = window.QueryInterface(Ci.nsIInterfaceRequestor). michael@0: getInterface(Ci.nsIDOMWindowUtils); michael@0: michael@0: if (aCounter > 1) { michael@0: utils.garbageCollect(); michael@0: setTimeout(this.runCC.bind(this, aCounter - 1), 0); michael@0: } else { michael@0: utils.garbageCollect(this.listener); michael@0: this.processLog(); michael@0: } michael@0: }, michael@0: michael@0: processLog: function () { michael@0: // Process entire heap step by step in 5K chunks michael@0: for (let i = 0; i < 5000; i++) { michael@0: if (!this.listener.processNext(this)) { michael@0: this.callback(); michael@0: this.clear(); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: // Next chunk on timeout. michael@0: setTimeout(this.processLog.bind(this), 0); michael@0: }, michael@0: michael@0: noteRefCountedObject: function (aAddress, aRefCount, aObjectDescription) { michael@0: let o = this.ensureObject(aAddress); michael@0: o.address = aAddress; michael@0: o.refcount = aRefCount; michael@0: o.name = aObjectDescription; michael@0: }, michael@0: michael@0: noteGCedObject: function (aAddress, aMarked, aObjectDescription) { michael@0: let o = this.ensureObject(aAddress); michael@0: o.address = aAddress; michael@0: o.gcmarked = aMarked; michael@0: o.name = aObjectDescription; michael@0: }, michael@0: michael@0: noteEdge: function (aFromAddress, aToAddress, aEdgeName) { michael@0: let fromObject = this.ensureObject(aFromAddress); michael@0: let toObject = this.ensureObject(aToAddress); michael@0: fromObject.edges.push({name: aEdgeName, to: toObject}); michael@0: toObject.owners.push({name: aEdgeName, from: fromObject}); michael@0: michael@0: this.edges.push({ michael@0: name: aEdgeName, michael@0: from: fromObject, michael@0: to: toObject michael@0: }); michael@0: }, michael@0: michael@0: describeRoot: function (aAddress, aKnownEdges) { michael@0: let o = this.ensureObject(aAddress); michael@0: o.root = true; michael@0: o.knownEdges = aKnownEdges; michael@0: this.roots.push(o); michael@0: }, michael@0: michael@0: describeGarbage: function (aAddress) { michael@0: let o = this.ensureObject(aAddress); michael@0: o.garbage = true; michael@0: this.garbage.push(o); michael@0: }, michael@0: michael@0: ensureObject: function (aAddress) { michael@0: if (!this.graph[aAddress]) michael@0: this.graph[aAddress] = new CCObject(); michael@0: michael@0: return this.graph[aAddress]; michael@0: }, michael@0: michael@0: find: function (aText) { michael@0: let result = []; michael@0: for each (let o in this.graph) { michael@0: if (!o.garbage && o.name.indexOf(aText) >= 0) michael@0: result.push(o); michael@0: } michael@0: return result; michael@0: } michael@0: }; michael@0: michael@0: function CCObject() { michael@0: this.name = ""; michael@0: this.address = null; michael@0: this.refcount = 0; michael@0: this.gcmarked = false; michael@0: this.root = false; michael@0: this.garbage = false; michael@0: this.knownEdges = 0; michael@0: this.edges = []; michael@0: this.owners = []; michael@0: }