Commit 6befba52 authored by Alexei Filippov's avatar Alexei Filippov Committed by Commit Bot

DevTools: Assign proper distances to non user reachable objects.

Do not assign zero distance to all GC root objects.
Instead assign zero to the global root and follow strong roots only
from there.

BUG=906847

Change-Id: Iee22162ac11a6700e019276daee1357ef33e61b9
Reviewed-on: https://chromium-review.googlesource.com/c/1353995
Commit-Queue: Alexei Filippov <alph@chromium.org>
Reviewed-by: default avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612438}
parent d897fb13
......@@ -1281,18 +1281,6 @@ HeapSnapshotWorker.HeapSnapshot = class {
return true;
}
/**
* @param {function(!HeapSnapshotWorker.HeapSnapshotNode)} action
* @param {boolean=} userRootsOnly
*/
forEachRoot(action, userRootsOnly) {
for (let iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
const node = iter.edge.node();
if (!userRootsOnly || this.isUserRoot(node))
action(node);
}
}
/**
* @param {function(!HeapSnapshotWorker.HeapSnapshotNode,!HeapSnapshotWorker.HeapSnapshotEdge):boolean=} filter
*/
......@@ -1306,24 +1294,20 @@ HeapSnapshotWorker.HeapSnapshot = class {
const nodesToVisit = new Uint32Array(this.nodeCount);
let nodesToVisitLength = 0;
/**
* @param {number} distance
* @param {!HeapSnapshotWorker.HeapSnapshotNode} node
*/
function enqueueNode(distance, node) {
const ordinal = node.ordinal();
if (distances[ordinal] !== noDistance)
return;
distances[ordinal] = distance;
nodesToVisit[nodesToVisitLength++] = node.nodeIndex;
// BFS for user root objects.
for (let iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
const node = iter.edge.node();
if (this.isUserRoot(node)) {
distances[node.ordinal()] = 1;
nodesToVisit[nodesToVisitLength++] = node.nodeIndex;
}
}
this.forEachRoot(enqueueNode.bind(null, 1), true);
this._bfs(nodesToVisit, nodesToVisitLength, distances, filter);
// bfs for the rest of objects
nodesToVisitLength = 0;
this.forEachRoot(enqueueNode.bind(null, HeapSnapshotModel.baseSystemDistance), false);
// BFS for objects not reached from user roots.
distances[this.rootNode().ordinal()] = HeapSnapshotModel.baseSystemDistance;
nodesToVisit[0] = this.rootNode().nodeIndex;
nodesToVisitLength = 1;
this._bfs(nodesToVisit, nodesToVisitLength, distances, filter);
}
......@@ -2581,60 +2565,6 @@ HeapSnapshotWorker.JSHeapSnapshot = class extends HeapSnapshotWorker.HeapSnapsho
return node.isUserRoot() || node.isDocumentDOMTreesRoot();
}
/**
* @override
* @param {function(!HeapSnapshotWorker.HeapSnapshotNode)} action
* @param {boolean=} userRootsOnly
*/
forEachRoot(action, userRootsOnly) {
/**
* @param {!HeapSnapshotWorker.HeapSnapshotNode} node
* @param {string} name
* @return {?HeapSnapshotWorker.HeapSnapshotNode}
*/
function getChildNodeByName(node, name) {
for (let iter = node.edges(); iter.hasNext(); iter.next()) {
const child = iter.edge.node();
if (child.name() === name)
return child;
}
return null;
}
const visitedNodes = {};
/**
* @param {!HeapSnapshotWorker.HeapSnapshotNode} node
*/
function doAction(node) {
const ordinal = node.ordinal();
if (!visitedNodes[ordinal]) {
action(node);
visitedNodes[ordinal] = true;
}
}
const gcRoots = getChildNodeByName(this.rootNode(), '(GC roots)');
if (!gcRoots)
return;
if (userRootsOnly) {
for (let iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
const node = iter.edge.node();
if (this.isUserRoot(node))
doAction(node);
}
} else {
for (let iter = gcRoots.edges(); iter.hasNext(); iter.next()) {
const subRoot = iter.edge.node();
for (let iter2 = subRoot.edges(); iter2.hasNext(); iter2.next())
doAction(iter2.edge.node());
doAction(subRoot);
}
for (let iter = this.rootNode().edges(); iter.hasNext(); iter.next())
doAction(iter.edge.node());
}
}
/**
* @override
* @return {?{map: !Uint32Array, flag: number}}
......
......@@ -2,5 +2,5 @@ Test that DOM node and its JS wrapper appear as a single node.
Took heap snapshot
Parsed snapshot
SUCCESS: found leaking
SUCCESS: retaining path = [Detached V8EventListener, Detached EventListener, Detached InternalNode, Detached InternalNode, Detached HTMLDivElement, Window / file://, ]
SUCCESS: retaining path = [Detached V8EventListener, Detached EventListener, Detached InternalNode, Detached InternalNode, Detached HTMLDivElement, Window / file://]
......@@ -2,5 +2,5 @@ Test retaining path for an event listener.
Took heap snapshot
Parsed snapshot
SUCCESS: found myEventListener
SUCCESS: retaining path = [V8EventListener, EventListener, InternalNode, InternalNode, HTMLBodyElement, HTMLHtmlElement, HTMLDocument, Window / file://, ]
SUCCESS: retaining path = [V8EventListener, EventListener, InternalNode, InternalNode, HTMLBodyElement, HTMLHtmlElement, HTMLDocument, Window / file://]
......@@ -6,6 +6,6 @@ SUCCESS: immediate retainer is V8EventListener.
SUCCESS: immediate retainer is EventListener.
SUCCESS: found single retaining path for v8EventListener.
SUCCESS: found multiple retaining paths.
SUCCESS: path1 = [InternalNode, HTMLBodyElement, HTMLHtmlElement, HTMLDocument, Window / file://, ]
SUCCESS: path2 = [InternalNode, HTMLDivElement, HTMLBodyElement, HTMLHtmlElement, HTMLDocument, Window / file://, ]
SUCCESS: path1 = [InternalNode, HTMLBodyElement, HTMLHtmlElement, HTMLDocument, Window / file://]
SUCCESS: path2 = [InternalNode, HTMLDivElement, HTMLBodyElement, HTMLHtmlElement, HTMLDocument, Window / file://]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment