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 { ...@@ -1281,18 +1281,6 @@ HeapSnapshotWorker.HeapSnapshot = class {
return true; 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 * @param {function(!HeapSnapshotWorker.HeapSnapshotNode,!HeapSnapshotWorker.HeapSnapshotEdge):boolean=} filter
*/ */
...@@ -1306,24 +1294,20 @@ HeapSnapshotWorker.HeapSnapshot = class { ...@@ -1306,24 +1294,20 @@ HeapSnapshotWorker.HeapSnapshot = class {
const nodesToVisit = new Uint32Array(this.nodeCount); const nodesToVisit = new Uint32Array(this.nodeCount);
let nodesToVisitLength = 0; let nodesToVisitLength = 0;
/** // BFS for user root objects.
* @param {number} distance for (let iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
* @param {!HeapSnapshotWorker.HeapSnapshotNode} node const node = iter.edge.node();
*/ if (this.isUserRoot(node)) {
function enqueueNode(distance, node) { distances[node.ordinal()] = 1;
const ordinal = node.ordinal();
if (distances[ordinal] !== noDistance)
return;
distances[ordinal] = distance;
nodesToVisit[nodesToVisitLength++] = node.nodeIndex; nodesToVisit[nodesToVisitLength++] = node.nodeIndex;
} }
}
this.forEachRoot(enqueueNode.bind(null, 1), true);
this._bfs(nodesToVisit, nodesToVisitLength, distances, filter); this._bfs(nodesToVisit, nodesToVisitLength, distances, filter);
// bfs for the rest of objects // BFS for objects not reached from user roots.
nodesToVisitLength = 0; distances[this.rootNode().ordinal()] = HeapSnapshotModel.baseSystemDistance;
this.forEachRoot(enqueueNode.bind(null, HeapSnapshotModel.baseSystemDistance), false); nodesToVisit[0] = this.rootNode().nodeIndex;
nodesToVisitLength = 1;
this._bfs(nodesToVisit, nodesToVisitLength, distances, filter); this._bfs(nodesToVisit, nodesToVisitLength, distances, filter);
} }
...@@ -2581,60 +2565,6 @@ HeapSnapshotWorker.JSHeapSnapshot = class extends HeapSnapshotWorker.HeapSnapsho ...@@ -2581,60 +2565,6 @@ HeapSnapshotWorker.JSHeapSnapshot = class extends HeapSnapshotWorker.HeapSnapsho
return node.isUserRoot() || node.isDocumentDOMTreesRoot(); 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 * @override
* @return {?{map: !Uint32Array, flag: number}} * @return {?{map: !Uint32Array, flag: number}}
......
...@@ -2,5 +2,5 @@ Test that DOM node and its JS wrapper appear as a single node. ...@@ -2,5 +2,5 @@ Test that DOM node and its JS wrapper appear as a single node.
Took heap snapshot Took heap snapshot
Parsed snapshot Parsed snapshot
SUCCESS: found leaking 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. ...@@ -2,5 +2,5 @@ Test retaining path for an event listener.
Took heap snapshot Took heap snapshot
Parsed snapshot Parsed snapshot
SUCCESS: found myEventListener 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. ...@@ -6,6 +6,6 @@ SUCCESS: immediate retainer is V8EventListener.
SUCCESS: immediate retainer is EventListener. SUCCESS: immediate retainer is EventListener.
SUCCESS: found single retaining path for v8EventListener. SUCCESS: found single retaining path for v8EventListener.
SUCCESS: found multiple retaining paths. SUCCESS: found multiple retaining paths.
SUCCESS: path1 = [InternalNode, HTMLBodyElement, HTMLHtmlElement, HTMLDocument, Window / file://, ] SUCCESS: path1 = [InternalNode, HTMLBodyElement, HTMLHtmlElement, HTMLDocument, Window / file://]
SUCCESS: path2 = [InternalNode, HTMLDivElement, 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