_rootNodeIndex: 0,
_nodeTypeOffset: 0,
_nodeNameOffset: 1,
- _edgesCountOffset: 2,
- _firstEdgeIndexOffset: 2,
- _firstEdgeOffset: 3,
+ _nodeEdgeCountOffset: 2,
_nodeFieldCount: 3,
_edgeFieldsCount: 3,
_edgeTypeOffset: 0,
// -> B (6) -bd- D (12)
//
_nodes: [
- 0, 0, 0, // 0: root
- 1, 1, 6, // 3: A
- 1, 2, 12, // 6: B
- 1, 3, 18, // 9: C
- 1, 4, 21, // 12: D
- 1, 5, 21, // 15: E
- 0, 0, 21], // 18: (extra node)
+ 0, 0, 2, // 0: root
+ 1, 1, 2, // 3: A
+ 1, 2, 2, // 6: B
+ 1, 3, 1, // 9: C
+ 1, 4, 0, // 12: D
+ 1, 5, 0], // 15: E
_containmentEdges: [
2, 6, 3, // 0: shortcut 'a' to node 'A'
1, 7, 6, // 3: property 'b' to node 'B'
1, 9, 9, // 12: property 'bc' to node 'C'
1, 10, 12, // 15: property 'bd' to node 'D'
1, 11, 15], // 18: property 'ce' to node 'E'
- _strings: ["", "A", "B", "C", "D", "E", "a", "b", "ac", "bc", "bd", "ce"]
+ _strings: ["", "A", "B", "C", "D", "E", "a", "b", "ac", "bc", "bd", "ce"],
+ _firstEdgeIndexes: [0, 6, 12, 18, 21, 21, 21]
};
};
return {
snapshot: {
meta: {
- node_fields: ["type", "name", "id", "self_size", "retained_size", "dominator", "edges_index"],
+ node_fields: ["type", "name", "id", "self_size", "retained_size", "dominator", "edge_count"],
node_types: [["hidden", "object"], "", "", "", "", "", ""],
edge_fields: ["type", "name_or_index", "to_node"],
edge_types: [["element", "property", "shortcut"], "", ""]
node_count: 6,
edge_count: 7},
nodes: [
- 0, 0, 1, 0, 20, 0, 0, // root (0)
- 1, 1, 2, 2, 2, 0, 6, // A (7)
- 1, 2, 3, 3, 8, 0, 12, // B (14)
- 1, 3, 4, 4, 10, 0, 18, // C (21)
- 1, 4, 5, 5, 5, 14, 21, // D (28)
- 1, 5, 6, 6, 6, 21, 21],// E (35)
+ 0, 0, 1, 0, 20, 0, 2, // root (0)
+ 1, 1, 2, 2, 2, 0, 2, // A (7)
+ 1, 2, 3, 3, 8, 0, 2, // B (14)
+ 1, 3, 4, 4, 10, 0, 1, // C (21)
+ 1, 4, 5, 5, 5, 14, 0, // D (28)
+ 1, 5, 6, 6, 6, 21, 0], // E (35)
edges: [
// root node edges
2, 6, 7, // shortcut 'a' to node 'A'
return InspectorTest._postprocessHeapSnapshotMock({
snapshot: {
meta: {
- node_fields: ["type", "name", "id", "edges_index"],
+ node_fields: ["type", "name", "id", "edge_count"],
node_types: [["hidden", "object"], "", "", ""],
edge_fields: ["type", "name_or_index", "to_node"],
edge_types: [["element", "hidden", "internal"], "", ""]
// | v
// |----->F--->G M
//
- /* (root) */ 0, 0, 1, 0,
- /* Window */ 1, 11, 2, 12,
- /* Window */ 1, 11, 3, 18,
- /* E */ 1, 5, 4, 27,
- /* F */ 1, 6, 5, 27,
- /* A */ 1, 1, 6, 30,
- /* B */ 1, 2, 7, 30,
- /* D */ 1, 4, 8, 33,
- /* H */ 1, 8, 9, 39,
- /* G */ 1, 7, 10, 39,
- /* C */ 1, 3, 11, 39,
- /* N */ 1, 10, 12, 39,
- /* M */ 1, 9, 13, 39
+ /* (root) */ 0, 0, 1, 4,
+ /* Window */ 1, 11, 2, 2,
+ /* Window */ 1, 11, 3, 3,
+ /* E */ 1, 5, 4, 0,
+ /* F */ 1, 6, 5, 1,
+ /* A */ 1, 1, 6, 0,
+ /* B */ 1, 2, 7, 1,
+ /* D */ 1, 4, 8, 2,
+ /* H */ 1, 8, 9, 0,
+ /* G */ 1, 7, 10, 0,
+ /* C */ 1, 3, 11, 0,
+ /* N */ 1, 10, 12, 0,
+ /* M */ 1, 9, 13, 0
],
edges: [
/* from (root) */ 0, 1, 4, 0, 2, 8, 0, 3, 12, 0, 4, 16,
// and even ids based on a hash for native DOMObject groups.
rawSnapshot.nodes.push(this._id || this._ordinal * 2 + 1);
rawSnapshot.nodes.push(this._selfSize);
- rawSnapshot.nodes.push(0); // retained_size
- rawSnapshot.nodes.push(0); // dominator
- rawSnapshot.nodes.push(rawSnapshot.edges.length); // edges_index
+ rawSnapshot.nodes.push(0); // retained_size
+ rawSnapshot.nodes.push(0); // dominator
+ rawSnapshot.nodes.push(Object.keys(this._edges).length); // edge_count
for (var i in this._edges)
this._edges[i]._serialize(rawSnapshot);
var rawSnapshot = {
"snapshot": {
"meta": {
- "node_fields": ["type","name","id","self_size","retained_size","dominator","edges_index"],
+ "node_fields": ["type","name","id","self_size","retained_size","dominator","edge_count"],
"node_types": [
this._nodeTypesArray,
"string",
_edgeIndexesStart: function()
{
- var snapshot = this._snapshot;
- return snapshot._nodes[this.nodeIndex + snapshot._firstEdgeIndexOffset];
+ return this._snapshot._firstEdgeIndexes[this._ordinal()];
},
_edgeIndexesEnd: function()
{
- var snapshot = this._snapshot;
- return snapshot._nodes[this._nextNodeIndex() + snapshot._firstEdgeIndexOffset]
+ return this._snapshot._firstEdgeIndexes[this._ordinal() + 1];
+ },
+
+ _ordinal: function()
+ {
+ return this.nodeIndex / this._snapshot._nodeFieldCount;
},
_nextNodeIndex: function()
WebInspector.HeapSnapshotNodeIterator = function(node)
{
this.node = node;
- this._nodesLength = node._snapshot._realNodesLength;
+ this._nodesLength = node._snapshot._nodes.length;
}
WebInspector.HeapSnapshotNodeIterator.prototype = {
this._nodeNameOffset = meta.node_fields.indexOf("name");
this._nodeIdOffset = meta.node_fields.indexOf("id");
this._nodeSelfSizeOffset = meta.node_fields.indexOf("self_size");
- this._firstEdgeIndexOffset = meta.node_fields.indexOf("edges_index");
+ this._nodeEdgeCountOffset = meta.node_fields.indexOf("edge_count");
this._nodeFieldCount = meta.node_fields.length;
this._nodeTypes = meta.node_types[this._nodeTypeOffset];
visitedMarker: 0x10000 // bits: 1,0000,0000,0000,0000
};
- this._realNodesLength = this._nodes.length;
- this.nodeCount = this._realNodesLength / this._nodeFieldCount;
+ this.nodeCount = this._nodes.length / this._nodeFieldCount;
this._edgeCount = this._containmentEdges.length / this._edgeFieldsCount;
- // Add an extra node and make its first edge field point to the end of edges array.
- var nodes = this._nodes;
- this._nodes = new Uint32Array(this._realNodesLength + this._nodeFieldCount);
- this._nodes.set(nodes);
- this._nodes[this._realNodesLength + this._firstEdgeIndexOffset] = this._containmentEdges.length;
-
+ this._buildEdgeIndexes();
this._markInvisibleEdges();
this._buildRetainers();
this._calculateFlags();
this._buildDominatedNodes();
},
+ _buildEdgeIndexes: function()
+ {
+ // Support for old serialization.
+ if (this._nodeEdgeCountOffset === -1) {
+ var nodes = this._nodes;
+ var nodeCount = this.nodeCount;
+ var firstEdgeIndexes = this._firstEdgeIndexes = new Uint32Array(nodeCount + 1);
+ var nodeFieldCount = this._nodeFieldCount;
+ var nodeEdgesIndexOffset = this._metaNode.node_fields.indexOf("edges_index");
+ firstEdgeIndexes[nodeCount] = this._containmentEdges.length;
+ for (var nodeOrdinal = 0; nodeOrdinal < nodeCount; ++nodeOrdinal) {
+ firstEdgeIndexes[nodeOrdinal] = nodes[nodeOrdinal * nodeFieldCount + nodeEdgesIndexOffset];
+ }
+ return;
+ }
+
+ var nodes = this._nodes;
+ var nodeCount = this.nodeCount;
+ var firstEdgeIndexes = this._firstEdgeIndexes = new Uint32Array(nodeCount + 1);
+ var nodeFieldCount = this._nodeFieldCount;
+ var edgeFieldsCount = this._edgeFieldsCount;
+ var nodeEdgeCountOffset = this._nodeEdgeCountOffset;
+ firstEdgeIndexes[nodeCount] = this._containmentEdges.length;
+ for (var nodeOrdinal = 0, edgeIndex = 0; nodeOrdinal < nodeCount; ++nodeOrdinal) {
+ firstEdgeIndexes[nodeOrdinal] = edgeIndex;
+ edgeIndex += nodes[nodeOrdinal * nodeFieldCount + nodeEdgeCountOffset] * edgeFieldsCount;
+ }
+ },
+
_buildRetainers: function()
{
var retainingNodes = this._retainingNodes = new Uint32Array(this._edgeCount);
var nodeFieldCount = this._nodeFieldCount;
var edgeToNodeOffset = this._edgeToNodeOffset;
var nodes = this._nodes;
- var firstEdgeIndexOffset = this._firstEdgeIndexOffset;
+ var firstEdgeIndexes = this._firstEdgeIndexes;
+ var nodeCount = this.nodeCount;
for (var toNodeFieldIndex = edgeToNodeOffset, l = containmentEdges.length; toNodeFieldIndex < l; toNodeFieldIndex += edgeFieldsCount) {
var toNodeIndex = containmentEdges[toNodeFieldIndex];
throw new Error("Invalid toNodeIndex " + toNodeIndex);
++firstRetainerIndex[toNodeIndex / nodeFieldCount];
}
- for (var i = 0, firstUnusedRetainerSlot = 0, l = this.nodeCount; i < l; i++) {
+ for (var i = 0, firstUnusedRetainerSlot = 0; i < nodeCount; i++) {
var retainersCount = firstRetainerIndex[i];
firstRetainerIndex[i] = firstUnusedRetainerSlot;
retainingNodes[firstUnusedRetainerSlot] = retainersCount;
firstUnusedRetainerSlot += retainersCount;
}
- firstRetainerIndex[this.nodeCount] = retainingNodes.length;
+ firstRetainerIndex[nodeCount] = retainingNodes.length;
- var srcNodeIndex = 0;
- var nextNodeFirstEdgeIndex = nodes[firstEdgeIndexOffset];
- var nodesLength = this._realNodesLength;
- while (srcNodeIndex < nodesLength) {
+ var nextNodeFirstEdgeIndex = firstEdgeIndexes[0];
+ for (var srcNodeOrdinal = 0; srcNodeOrdinal < nodeCount; ++srcNodeOrdinal) {
var firstEdgeIndex = nextNodeFirstEdgeIndex;
- var nextNodeIndex = srcNodeIndex + nodeFieldCount;
- nextNodeFirstEdgeIndex = nodes[nextNodeIndex + firstEdgeIndexOffset];
+ nextNodeFirstEdgeIndex = firstEdgeIndexes[srcNodeOrdinal + 1];
+ var srcNodeIndex = srcNodeOrdinal * nodeFieldCount;
for (var edgeIndex = firstEdgeIndex; edgeIndex < nextNodeFirstEdgeIndex; edgeIndex += edgeFieldsCount) {
var toNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
if (toNodeIndex % nodeFieldCount)
retainingNodes[nextUnusedRetainerSlotIndex] = srcNodeIndex;
retainingEdges[nextUnusedRetainerSlotIndex] = edgeIndex;
}
- srcNodeIndex = nextNodeIndex;
}
},
{
// Peload fields into local variables for better performance.
var edgeFieldsCount = this._edgeFieldsCount;
- var containmentEdges = this._containmentEdges;
var nodeFieldCount = this._nodeFieldCount;
- var firstEdgeIndexOffset = this._firstEdgeIndexOffset;
+ var containmentEdges = this._containmentEdges;
+ var firstEdgeIndexes = this._firstEdgeIndexes;
var edgeToNodeOffset = this._edgeToNodeOffset;
var nodes = this._nodes;
var nodeCount = this.nodeCount;
var nodeIndex = nodesToVisit[index++]; // shift generates too much garbage.
var nodeOrdinal = nodeIndex / nodeFieldCount;
var distance = distances[nodeOrdinal] + 1;
- var firstEdgeIndex = nodes[nodeIndex + firstEdgeIndexOffset];
- var edgesEnd = nodes[nodeIndex + firstEdgeIndexOffset + nodeFieldCount];
+ var firstEdgeIndex = firstEdgeIndexes[nodeOrdinal];
+ var edgesEnd = firstEdgeIndexes[nodeOrdinal + 1];
for (var edgeToNodeIndex = firstEdgeIndex + edgeToNodeOffset; edgeToNodeIndex < edgesEnd; edgeToNodeIndex += edgeFieldsCount) {
var childNodeIndex = containmentEdges[edgeToNodeIndex];
var childNodeOrdinal = childNodeIndex / nodeFieldCount;
var classIndexes = [];
var nodes = this._nodes;
var flags = this._flags;
- var nodesLength = this._realNodesLength;
+ var nodesLength = nodes.length;
var nodeNativeType = this._nodeNativeType;
var nodeFieldCount = this._nodeFieldCount;
var selfSizeOffset = this._nodeSelfSizeOffset;
var nodeFieldCount = this._nodeFieldCount;
var nodes = this._nodes;
var nodeCount = this.nodeCount;
- var rootNodeIndex = this._rootNodeIndex;
+ var rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
var edgeFieldsCount = this._edgeFieldsCount;
- var edgeToNodeOffset = this._edgeToNodeOffset;
var edgeTypeOffset = this._edgeTypeOffset;
+ var edgeToNodeOffset = this._edgeToNodeOffset;
var edgeShortcutType = this._edgeShortcutType;
- var firstEdgeIndexOffset = this._firstEdgeIndexOffset;
+ var firstEdgeIndexes = this._firstEdgeIndexes;
var containmentEdges = this._containmentEdges;
var containmentEdgesLength = this._containmentEdges.length;
var grey = 1;
var black = 2;
- nodesToVisit[nodesToVisitLength++] = this._rootNodeIndex;
- painted[this._rootNodeIndex / nodeFieldCount] = grey;
+ nodesToVisit[nodesToVisitLength++] = rootNodeOrdinal;
+ painted[rootNodeOrdinal] = grey;
while (nodesToVisitLength) {
- var nodeIndex = nodesToVisit[nodesToVisitLength - 1];
- var nodeOrdinal = nodeIndex / nodeFieldCount;
+ var nodeOrdinal = nodesToVisit[nodesToVisitLength - 1];
if (painted[nodeOrdinal] === grey) {
painted[nodeOrdinal] = black;
var nodeFlag = flags[nodeOrdinal] & flag;
- var beginEdgeIndex = nodes[nodeIndex + firstEdgeIndexOffset];
- var endEdgeIndex = nodes[nodeIndex + firstEdgeIndexOffset + nodeFieldCount];
+ var beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
+ var endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
- if (nodeIndex !== rootNodeIndex && containmentEdges[edgeIndex + edgeTypeOffset] === edgeShortcutType)
+ if (nodeOrdinal !== rootNodeOrdinal && containmentEdges[edgeIndex + edgeTypeOffset] === edgeShortcutType)
continue;
var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
var childNodeOrdinal = childNodeIndex / nodeFieldCount;
var childNodeFlag = flags[childNodeOrdinal] & flag;
// We are skipping the edges from non-page-owned nodes to page-owned nodes.
// Otherwise the dominators for the objects that also were retained by debugger would be affected.
- if (nodeIndex !== rootNodeIndex && childNodeFlag && !nodeFlag)
+ if (nodeOrdinal !== rootNodeOrdinal && childNodeFlag && !nodeFlag)
continue;
if (!painted[childNodeOrdinal]) {
painted[childNodeOrdinal] = grey;
- nodesToVisit[nodesToVisitLength++] = childNodeIndex;
+ nodesToVisit[nodesToVisitLength++] = childNodeOrdinal;
}
}
} else {
var retainingNodes = this._retainingNodes;
var retainingEdges = this._retainingEdges;
var edgeFieldsCount = this._edgeFieldsCount;
- var edgeToNodeOffset = this._edgeToNodeOffset;
var edgeTypeOffset = this._edgeTypeOffset;
+ var edgeToNodeOffset = this._edgeToNodeOffset;
var edgeShortcutType = this._edgeShortcutType;
- var firstEdgeIndexOffset = this._firstEdgeIndexOffset;
+ var firstEdgeIndexes = this._firstEdgeIndexes;
var containmentEdges = this._containmentEdges;
var containmentEdgesLength = this._containmentEdges.length;
var rootNodeIndex = this._rootNodeIndex;
var affected = new Uint8Array(nodesCount);
{ // Mark the root direct children as affected.
- var nodeIndex = this._rootNodeIndex;
- var beginEdgeToNodeFieldIndex = nodes[nodeIndex + firstEdgeIndexOffset] + edgeToNodeOffset;
- var endEdgeToNodeFieldIndex = nodes[nodeIndex + nodeFieldCount + firstEdgeIndexOffset];
+ var nodeOrdinal = this._rootNodeIndex / nodeFieldCount;
+ var beginEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal] + edgeToNodeOffset;
+ var endEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal + 1];
for (var toNodeFieldIndex = beginEdgeToNodeFieldIndex;
toNodeFieldIndex < endEdgeToNodeFieldIndex;
toNodeFieldIndex += edgeFieldsCount) {
dominators[postOrderIndex] = newDominatorIndex;
changed = true;
nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex];
- nodeIndex = nodeOrdinal * nodeFieldCount;
- beginEdgeToNodeFieldIndex = nodes[nodeIndex + firstEdgeIndexOffset] + edgeToNodeOffset;
- endEdgeToNodeFieldIndex = nodes[nodeIndex + firstEdgeIndexOffset + nodeFieldCount];
+ beginEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal] + edgeToNodeOffset;
+ endEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal + 1];
for (var toNodeFieldIndex = beginEdgeToNodeFieldIndex;
toNodeFieldIndex < endEdgeToNodeFieldIndex;
toNodeFieldIndex += edgeFieldsCount) {
var edgeTypeOffset = this._edgeTypeOffset;
var edgeFieldsCount = this._edgeFieldsCount;
var edgeWeakType = this._edgeWeakType;
- var firstEdgeIndexOffset = this._firstEdgeIndexOffset;
+ var firstEdgeIndexes = this._firstEdgeIndexes;
var containmentEdges = this._containmentEdges;
var containmentEdgesLength = containmentEdges.length;
var nodes = this._nodes;
var nodesToVisit = new Uint32Array(nodesCount);
var nodesToVisitLength = 0;
- for (var edgeIndex = nodes[this._rootNodeIndex + firstEdgeIndexOffset], endEdgeIndex = nodes[this._rootNodeIndex + nodeFieldCount + firstEdgeIndexOffset];
+ var rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
+ for (var edgeIndex = firstEdgeIndexes[rootNodeOrdinal], endEdgeIndex = firstEdgeIndexes[rootNodeOrdinal + 1];
edgeIndex < endEdgeIndex;
edgeIndex += edgeFieldsCount) {
if (containmentEdges[edgeIndex + edgeTypeOffset] === edgeShortcutType) {
- var nodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
- nodesToVisit[nodesToVisitLength++] = nodeIndex;
- flags[nodeIndex / nodeFieldCount] |= visitedMarker;
+ var nodeOrdinal = containmentEdges[edgeIndex + edgeToNodeOffset] / nodeFieldCount;
+ nodesToVisit[nodesToVisitLength++] = nodeOrdinal;
+ flags[nodeOrdinal] |= visitedMarker;
}
}
while (nodesToVisitLength) {
- var nodeIndex = nodesToVisit[--nodesToVisitLength];
- var nodeOrdinal = nodeIndex / nodeFieldCount;
+ var nodeOrdinal = nodesToVisit[--nodesToVisitLength];
flags[nodeOrdinal] |= flag;
flags[nodeOrdinal] &= visitedMarkerMask;
- var beginEdgeIndex = nodes[nodeIndex + firstEdgeIndexOffset];
- var endEdgeIndex = nodeOrdinal < nodesCount - 1
- ? nodes[nodeIndex + firstEdgeIndexOffset + nodeFieldCount]
- : containmentEdgesLength;
+ var beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
+ var endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
var childNodeOrdinal = childNodeIndex / nodeFieldCount;
var type = containmentEdges[edgeIndex + edgeTypeOffset];
if (type === edgeWeakType)
continue;
- nodesToVisit[nodesToVisitLength++] = childNodeIndex;
+ nodesToVisit[nodesToVisitLength++] = childNodeOrdinal;
flags[childNodeOrdinal] |= visitedMarker;
}
}
var nodes = this._nodes;
var nodeCount = this.nodeCount;
var nodeFieldCount = this._nodeFieldCount;
- var firstEdgeIndexOffset = this._firstEdgeIndexOffset;
+ var firstEdgeIndexes = this._firstEdgeIndexes;
var flags = this._flags;
var list = [];
for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
if (iter.edge.node().isWindow())
- list.push(iter.edge.node().nodeIndex);
+ list.push(iter.edge.node().nodeIndex / nodeFieldCount);
}
while (list.length) {
- var nodeIndex = list.pop();
- var nodeOrdinal = nodeIndex / nodeFieldCount;
+ var nodeOrdinal = list.pop();
if (flags[nodeOrdinal] & flag)
continue;
flags[nodeOrdinal] |= flag;
- var beginEdgeIndex = nodes[nodeIndex + firstEdgeIndexOffset];
- var endEdgeIndex = nodes[nodeIndex + firstEdgeIndexOffset + nodeFieldCount];
+ var beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
+ var endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
- if (flags[childNodeIndex / nodeFieldCount] & flag)
+ var childNodeOrdinal = childNodeIndex / nodeFieldCount;
+ if (flags[childNodeOrdinal] & flag)
continue;
var type = containmentEdges[edgeIndex + edgeTypeOffset];
if (type === hiddenEdgeType || type === invisibleEdgeType || type === internalEdgeType)
continue;
- list.push(childNodeIndex);
+ list.push(childNodeOrdinal);
}
}
},