summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/devtools/front_end/profiler/heap_snapshot_worker/JSHeapSnapshot.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/profiler/heap_snapshot_worker/JSHeapSnapshot.js')
-rw-r--r--chromium/third_party/WebKit/Source/devtools/front_end/profiler/heap_snapshot_worker/JSHeapSnapshot.js824
1 files changed, 824 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/profiler/heap_snapshot_worker/JSHeapSnapshot.js b/chromium/third_party/WebKit/Source/devtools/front_end/profiler/heap_snapshot_worker/JSHeapSnapshot.js
new file mode 100644
index 00000000000..f1c592ab7e6
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/devtools/front_end/profiler/heap_snapshot_worker/JSHeapSnapshot.js
@@ -0,0 +1,824 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.HeapSnapshot}
+ * @param {!Object} profile
+ * @param {!WebInspector.HeapSnapshotProgress} progress
+ * @param {boolean} showHiddenData
+ */
+WebInspector.JSHeapSnapshot = function(profile, progress, showHiddenData)
+{
+ this._nodeFlags = { // bit flags
+ canBeQueried: 1,
+ detachedDOMTreeNode: 2,
+ pageObject: 4, // The idea is to track separately the objects owned by the page and the objects owned by debugger.
+
+ visitedMarkerMask: 0x0ffff, // bits: 0,1111,1111,1111,1111
+ visitedMarker: 0x10000 // bits: 1,0000,0000,0000,0000
+ };
+ this._lazyStringCache = { };
+ WebInspector.HeapSnapshot.call(this, profile, progress, showHiddenData);
+}
+
+WebInspector.JSHeapSnapshot.prototype = {
+ /**
+ * @param {number} nodeIndex
+ * @return {!WebInspector.JSHeapSnapshotNode}
+ */
+ createNode: function(nodeIndex)
+ {
+ return new WebInspector.JSHeapSnapshotNode(this, nodeIndex);
+ },
+
+ /**
+ * @override
+ * @param {number} edgeIndex
+ * @return {!WebInspector.JSHeapSnapshotEdge}
+ */
+ createEdge: function(edgeIndex)
+ {
+ return new WebInspector.JSHeapSnapshotEdge(this, edgeIndex);
+ },
+
+ /**
+ * @override
+ * @param {number} retainerIndex
+ * @return {!WebInspector.JSHeapSnapshotRetainerEdge}
+ */
+ createRetainingEdge: function(retainerIndex)
+ {
+ return new WebInspector.JSHeapSnapshotRetainerEdge(this, retainerIndex);
+ },
+
+ /**
+ * @override
+ * @return {?function(!WebInspector.JSHeapSnapshotNode):boolean}
+ */
+ classNodesFilter: function()
+ {
+ /**
+ * @param {!WebInspector.JSHeapSnapshotNode} node
+ * @return {boolean}
+ */
+ function filter(node)
+ {
+ return node.isUserObject();
+ }
+ return this._showHiddenData ? null : filter;
+ },
+
+ /**
+ * @return {function(!WebInspector.HeapSnapshotEdge):boolean}
+ */
+ containmentEdgesFilter: function()
+ {
+ var showHiddenData = this._showHiddenData;
+ function filter(edge) {
+ if (edge.isInvisible())
+ return false;
+ if (showHiddenData)
+ return true;
+ return !edge.isHidden() && !edge.node().isHidden();
+ }
+ return filter;
+ },
+
+ /**
+ * @return {function(!WebInspector.HeapSnapshotEdge):boolean}
+ */
+ retainingEdgesFilter: function()
+ {
+ var containmentEdgesFilter = this.containmentEdgesFilter();
+ function filter(edge)
+ {
+ return containmentEdgesFilter(edge) && !edge.node().isRoot() && !edge.isWeak();
+ }
+ return filter;
+ },
+
+ dispose: function()
+ {
+ WebInspector.HeapSnapshot.prototype.dispose.call(this);
+ delete this._flags;
+ },
+
+ _calculateFlags: function()
+ {
+ this._flags = new Uint32Array(this.nodeCount);
+ this._markDetachedDOMTreeNodes();
+ this._markQueriableHeapObjects();
+ this._markPageOwnedNodes();
+ },
+
+ /**
+ * @param {!WebInspector.HeapSnapshotNode} node
+ * @return {!boolean}
+ */
+ _isUserRoot: function(node)
+ {
+ return node.isUserRoot() || node.isDocumentDOMTreesRoot();
+ },
+
+ /**
+ * @param {function(!WebInspector.HeapSnapshotNode)} action
+ * @param {boolean=} userRootsOnly
+ */
+ forEachRoot: function(action, userRootsOnly)
+ {
+ /**
+ * @param {!WebInspector.HeapSnapshotNode} node
+ * @param {string} name
+ * @return {?WebInspector.HeapSnapshotNode}
+ */
+ function getChildNodeByName(node, name)
+ {
+ for (var iter = node.edges(); iter.hasNext(); iter.next()) {
+ var child = iter.edge.node();
+ if (child.name() === name)
+ return child;
+ }
+ return null;
+ }
+
+ var visitedNodes = {};
+ /**
+ * @param {!WebInspector.HeapSnapshotNode} node
+ */
+ function doAction(node)
+ {
+ var ordinal = node._ordinal();
+ if (!visitedNodes[ordinal]) {
+ action(node);
+ visitedNodes[ordinal] = true;
+ }
+ }
+
+ var gcRoots = getChildNodeByName(this.rootNode(), "(GC roots)");
+ if (!gcRoots)
+ return;
+
+ if (userRootsOnly) {
+ for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
+ var node = iter.edge.node();
+ if (this._isUserRoot(node))
+ doAction(node);
+ }
+ } else {
+ for (var iter = gcRoots.edges(); iter.hasNext(); iter.next()) {
+ var subRoot = iter.edge.node();
+ for (var iter2 = subRoot.edges(); iter2.hasNext(); iter2.next())
+ doAction(iter2.edge.node());
+ doAction(subRoot);
+ }
+ for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next())
+ doAction(iter.edge.node())
+ }
+ },
+
+ /**
+ * @return {?{map: !Uint32Array, flag: number}}
+ */
+ userObjectsMapAndFlag: function()
+ {
+ return this._showHiddenData ? null : {
+ map: this._flags,
+ flag: this._nodeFlags.pageObject
+ };
+ },
+
+ _flagsOfNode: function(node)
+ {
+ return this._flags[node.nodeIndex / this._nodeFieldCount];
+ },
+
+ _markDetachedDOMTreeNodes: function()
+ {
+ var flag = this._nodeFlags.detachedDOMTreeNode;
+ var detachedDOMTreesRoot;
+ for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
+ var node = iter.edge.node();
+ if (node.name() === "(Detached DOM trees)") {
+ detachedDOMTreesRoot = node;
+ break;
+ }
+ }
+
+ if (!detachedDOMTreesRoot)
+ return;
+
+ var detachedDOMTreeRE = /^Detached DOM tree/;
+ for (var iter = detachedDOMTreesRoot.edges(); iter.hasNext(); iter.next()) {
+ var node = iter.edge.node();
+ if (detachedDOMTreeRE.test(node.className())) {
+ for (var edgesIter = node.edges(); edgesIter.hasNext(); edgesIter.next())
+ this._flags[edgesIter.edge.node().nodeIndex / this._nodeFieldCount] |= flag;
+ }
+ }
+ },
+
+ _markQueriableHeapObjects: function()
+ {
+ // Allow runtime properties query for objects accessible from Window objects
+ // via regular properties, and for DOM wrappers. Trying to access random objects
+ // can cause a crash due to insonsistent state of internal properties of wrappers.
+ var flag = this._nodeFlags.canBeQueried;
+ var hiddenEdgeType = this._edgeHiddenType;
+ var internalEdgeType = this._edgeInternalType;
+ var invisibleEdgeType = this._edgeInvisibleType;
+ var weakEdgeType = this._edgeWeakType;
+ var edgeToNodeOffset = this._edgeToNodeOffset;
+ var edgeTypeOffset = this._edgeTypeOffset;
+ var edgeFieldsCount = this._edgeFieldsCount;
+ var containmentEdges = this._containmentEdges;
+ var nodes = this._nodes;
+ var nodeCount = this.nodeCount;
+ var nodeFieldCount = this._nodeFieldCount;
+ var firstEdgeIndexes = this._firstEdgeIndexes;
+
+ var flags = this._flags;
+ var list = [];
+
+ for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) {
+ if (iter.edge.node().isUserRoot())
+ list.push(iter.edge.node().nodeIndex / nodeFieldCount);
+ }
+
+ while (list.length) {
+ var nodeOrdinal = list.pop();
+ if (flags[nodeOrdinal] & flag)
+ continue;
+ flags[nodeOrdinal] |= flag;
+ 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;
+ if (flags[childNodeOrdinal] & flag)
+ continue;
+ var type = containmentEdges[edgeIndex + edgeTypeOffset];
+ if (type === hiddenEdgeType || type === invisibleEdgeType || type === internalEdgeType || type === weakEdgeType)
+ continue;
+ list.push(childNodeOrdinal);
+ }
+ }
+ },
+
+ _markPageOwnedNodes: function()
+ {
+ var edgeShortcutType = this._edgeShortcutType;
+ var edgeElementType = this._edgeElementType;
+ var edgeToNodeOffset = this._edgeToNodeOffset;
+ var edgeTypeOffset = this._edgeTypeOffset;
+ var edgeFieldsCount = this._edgeFieldsCount;
+ var edgeWeakType = this._edgeWeakType;
+ var firstEdgeIndexes = this._firstEdgeIndexes;
+ var containmentEdges = this._containmentEdges;
+ var containmentEdgesLength = containmentEdges.length;
+ var nodes = this._nodes;
+ var nodeFieldCount = this._nodeFieldCount;
+ var nodesCount = this.nodeCount;
+
+ var flags = this._flags;
+ var flag = this._nodeFlags.pageObject;
+ var visitedMarker = this._nodeFlags.visitedMarker;
+ var visitedMarkerMask = this._nodeFlags.visitedMarkerMask;
+ var markerAndFlag = visitedMarker | flag;
+
+ var nodesToVisit = new Uint32Array(nodesCount);
+ var nodesToVisitLength = 0;
+
+ var rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
+ var node = this.rootNode();
+ for (var edgeIndex = firstEdgeIndexes[rootNodeOrdinal], endEdgeIndex = firstEdgeIndexes[rootNodeOrdinal + 1];
+ edgeIndex < endEdgeIndex;
+ edgeIndex += edgeFieldsCount) {
+ var edgeType = containmentEdges[edgeIndex + edgeTypeOffset];
+ var nodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
+ if (edgeType === edgeElementType) {
+ node.nodeIndex = nodeIndex;
+ if (!node.isDocumentDOMTreesRoot())
+ continue;
+ } else if (edgeType !== edgeShortcutType)
+ continue;
+ var nodeOrdinal = nodeIndex / nodeFieldCount;
+ nodesToVisit[nodesToVisitLength++] = nodeOrdinal;
+ flags[nodeOrdinal] |= visitedMarker;
+ }
+
+ while (nodesToVisitLength) {
+ var nodeOrdinal = nodesToVisit[--nodesToVisitLength];
+ flags[nodeOrdinal] |= flag;
+ flags[nodeOrdinal] &= visitedMarkerMask;
+ 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;
+ if (flags[childNodeOrdinal] & markerAndFlag)
+ continue;
+ var type = containmentEdges[edgeIndex + edgeTypeOffset];
+ if (type === edgeWeakType)
+ continue;
+ nodesToVisit[nodesToVisitLength++] = childNodeOrdinal;
+ flags[childNodeOrdinal] |= visitedMarker;
+ }
+ }
+ },
+
+ _calculateStatistics: function()
+ {
+ var nodeFieldCount = this._nodeFieldCount;
+ var nodes = this._nodes;
+ var nodesLength = nodes.length;
+ var nodeTypeOffset = this._nodeTypeOffset;
+ var nodeSizeOffset = this._nodeSelfSizeOffset;;
+ var nodeNativeType = this._nodeNativeType;
+ var nodeCodeType = this._nodeCodeType;
+ var nodeConsStringType = this._nodeConsStringType;
+ var nodeSlicedStringType = this._nodeSlicedStringType;
+ var sizeNative = 0;
+ var sizeCode = 0;
+ var sizeStrings = 0;
+ var sizeJSArrays = 0;
+ var node = this.rootNode();
+ for (var nodeIndex = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
+ node.nodeIndex = nodeIndex;
+ var nodeType = nodes[nodeIndex + nodeTypeOffset];
+ var nodeSize = nodes[nodeIndex + nodeSizeOffset];
+ if (nodeType === nodeNativeType)
+ sizeNative += nodeSize;
+ else if (nodeType === nodeCodeType)
+ sizeCode += nodeSize;
+ else if (nodeType === nodeConsStringType || nodeType === nodeSlicedStringType || node.type() === "string")
+ sizeStrings += nodeSize;
+ else if (node.name() === "Array")
+ sizeJSArrays += this._calculateArraySize(node);
+ }
+ this._statistics = new WebInspector.HeapSnapshotCommon.Statistics();
+ this._statistics.total = this.totalSize;
+ this._statistics.v8heap = this.totalSize - sizeNative;
+ this._statistics.native = sizeNative;
+ this._statistics.code = sizeCode;
+ this._statistics.jsArrays = sizeJSArrays;
+ this._statistics.strings = sizeStrings;
+ },
+
+ /**
+ * @param {!WebInspector.HeapSnapshotNode} node
+ * @return {number}
+ */
+ _calculateArraySize: function(node)
+ {
+ var size = node.selfSize();
+ var beginEdgeIndex = node._edgeIndexesStart();
+ var endEdgeIndex = node._edgeIndexesEnd();
+ var containmentEdges = this._containmentEdges;
+ var strings = this._strings;
+ var edgeToNodeOffset = this._edgeToNodeOffset;
+ var edgeTypeOffset = this._edgeTypeOffset;
+ var edgeNameOffset = this._edgeNameOffset;
+ var edgeFieldsCount = this._edgeFieldsCount;
+ var edgeInternalType = this._edgeInternalType;
+ for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) {
+ var edgeType = containmentEdges[edgeIndex + edgeTypeOffset];
+ if (edgeType !== edgeInternalType)
+ continue;
+ var edgeName = strings[containmentEdges[edgeIndex + edgeNameOffset]];
+ if (edgeName !== "elements")
+ continue;
+ var elementsNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset];
+ node.nodeIndex = elementsNodeIndex;
+ if (node.retainersCount() === 1)
+ size += node.selfSize();
+ break;
+ }
+ return size;
+ },
+
+ /**
+ * @return {!WebInspector.HeapSnapshotCommon.Statistics}
+ */
+ getStatistics: function()
+ {
+ return this._statistics;
+ },
+
+ __proto__: WebInspector.HeapSnapshot.prototype
+};
+
+/**
+ * @constructor
+ * @extends {WebInspector.HeapSnapshotNode}
+ * @param {!WebInspector.JSHeapSnapshot} snapshot
+ * @param {number=} nodeIndex
+ */
+WebInspector.JSHeapSnapshotNode = function(snapshot, nodeIndex)
+{
+ WebInspector.HeapSnapshotNode.call(this, snapshot, nodeIndex)
+}
+
+WebInspector.JSHeapSnapshotNode.prototype = {
+ /**
+ * @return {boolean}
+ */
+ canBeQueried: function()
+ {
+ var flags = this._snapshot._flagsOfNode(this);
+ return !!(flags & this._snapshot._nodeFlags.canBeQueried);
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isUserObject: function()
+ {
+ var flags = this._snapshot._flagsOfNode(this);
+ return !!(flags & this._snapshot._nodeFlags.pageObject);
+ },
+
+
+ /**
+ * @return {string}
+ */
+ name: function() {
+ var snapshot = this._snapshot;
+ if (this._type() === snapshot._nodeConsStringType) {
+ var string = snapshot._lazyStringCache[this.nodeIndex];
+ if (typeof string === "undefined") {
+ string = this._consStringName();
+ snapshot._lazyStringCache[this.nodeIndex] = string;
+ }
+ return string;
+ }
+ return WebInspector.HeapSnapshotNode.prototype.name.call(this);
+ },
+
+ _consStringName: function()
+ {
+ var snapshot = this._snapshot;
+ var consStringType = snapshot._nodeConsStringType;
+ var edgeInternalType = snapshot._edgeInternalType;
+ var edgeFieldsCount = snapshot._edgeFieldsCount;
+ var edgeToNodeOffset = snapshot._edgeToNodeOffset;
+ var edgeTypeOffset = snapshot._edgeTypeOffset;
+ var edgeNameOffset = snapshot._edgeNameOffset;
+ var strings = snapshot._strings;
+ var edges = snapshot._containmentEdges;
+ var firstEdgeIndexes = snapshot._firstEdgeIndexes;
+ var nodeFieldCount = snapshot._nodeFieldCount;
+ var nodeTypeOffset = snapshot._nodeTypeOffset;
+ var nodeNameOffset = snapshot._nodeNameOffset;
+ var nodes = snapshot._nodes;
+ var nodesStack = [];
+ nodesStack.push(this.nodeIndex);
+ var name = "";
+
+ while (nodesStack.length && name.length < 1024) {
+ var nodeIndex = nodesStack.pop();
+ if (nodes[nodeIndex + nodeTypeOffset] !== consStringType) {
+ name += strings[nodes[nodeIndex + nodeNameOffset]];
+ continue;
+ }
+ var nodeOrdinal = nodeIndex / nodeFieldCount;
+ var beginEdgeIndex = firstEdgeIndexes[nodeOrdinal];
+ var endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1];
+ var firstNodeIndex = 0;
+ var secondNodeIndex = 0;
+ for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex && (!firstNodeIndex || !secondNodeIndex); edgeIndex += edgeFieldsCount) {
+ var edgeType = edges[edgeIndex + edgeTypeOffset];
+ if (edgeType === edgeInternalType) {
+ var edgeName = strings[edges[edgeIndex + edgeNameOffset]];
+ if (edgeName === "first")
+ firstNodeIndex = edges[edgeIndex + edgeToNodeOffset];
+ else if (edgeName === "second")
+ secondNodeIndex = edges[edgeIndex + edgeToNodeOffset];
+ }
+ }
+ nodesStack.push(secondNodeIndex);
+ nodesStack.push(firstNodeIndex);
+ }
+ return name;
+ },
+
+ /**
+ * @return {string}
+ */
+ className: function()
+ {
+ var type = this.type();
+ switch (type) {
+ case "hidden":
+ return "(system)";
+ case "object":
+ case "native":
+ return this.name();
+ case "code":
+ return "(compiled code)";
+ default:
+ return "(" + type + ")";
+ }
+ },
+
+ /**
+ * @return {number}
+ */
+ classIndex: function()
+ {
+ var snapshot = this._snapshot;
+ var nodes = snapshot._nodes;
+ var type = nodes[this.nodeIndex + snapshot._nodeTypeOffset];;
+ if (type === snapshot._nodeObjectType || type === snapshot._nodeNativeType)
+ return nodes[this.nodeIndex + snapshot._nodeNameOffset];
+ return -1 - type;
+ },
+
+ /**
+ * @return {number}
+ */
+ id: function()
+ {
+ var snapshot = this._snapshot;
+ return snapshot._nodes[this.nodeIndex + snapshot._nodeIdOffset];
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isHidden: function()
+ {
+ return this._type() === this._snapshot._nodeHiddenType;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isSynthetic: function()
+ {
+ return this._type() === this._snapshot._nodeSyntheticType;
+ },
+
+ /**
+ * @return {!boolean}
+ */
+ isUserRoot: function()
+ {
+ return !this.isSynthetic();
+ },
+
+ /**
+ * @return {!boolean}
+ */
+ isDocumentDOMTreesRoot: function()
+ {
+ return this.isSynthetic() && this.name() === "(Document DOM trees)";
+ },
+
+ /**
+ * @return {!WebInspector.HeapSnapshotCommon.Node}
+ */
+ serialize: function()
+ {
+ var result = WebInspector.HeapSnapshotNode.prototype.serialize.call(this);
+ var flags = this._snapshot._flagsOfNode(this);
+ if (flags & this._snapshot._nodeFlags.canBeQueried)
+ result.canBeQueried = true;
+ if (flags & this._snapshot._nodeFlags.detachedDOMTreeNode)
+ result.detachedDOMTreeNode = true;
+ return result;
+ },
+
+ __proto__: WebInspector.HeapSnapshotNode.prototype
+};
+
+/**
+ * @constructor
+ * @extends {WebInspector.HeapSnapshotEdge}
+ * @param {!WebInspector.JSHeapSnapshot} snapshot
+ * @param {number=} edgeIndex
+ */
+WebInspector.JSHeapSnapshotEdge = function(snapshot, edgeIndex)
+{
+ WebInspector.HeapSnapshotEdge.call(this, snapshot, edgeIndex);
+}
+
+WebInspector.JSHeapSnapshotEdge.prototype = {
+ /**
+ * @return {!WebInspector.JSHeapSnapshotEdge}
+ */
+ clone: function()
+ {
+ var snapshot = /** @type {!WebInspector.JSHeapSnapshot} */ (this._snapshot);
+ return new WebInspector.JSHeapSnapshotEdge(snapshot, this.edgeIndex);
+ },
+
+ /**
+ * @return {boolean}
+ */
+ hasStringName: function()
+ {
+ if (!this.isShortcut())
+ return this._hasStringName();
+ return isNaN(parseInt(this._name(), 10));
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isElement: function()
+ {
+ return this._type() === this._snapshot._edgeElementType;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isHidden: function()
+ {
+ return this._type() === this._snapshot._edgeHiddenType;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isWeak: function()
+ {
+ return this._type() === this._snapshot._edgeWeakType;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isInternal: function()
+ {
+ return this._type() === this._snapshot._edgeInternalType;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isInvisible: function()
+ {
+ return this._type() === this._snapshot._edgeInvisibleType;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isShortcut: function()
+ {
+ return this._type() === this._snapshot._edgeShortcutType;
+ },
+
+ /**
+ * @return {string}
+ */
+ name: function()
+ {
+ if (!this.isShortcut())
+ return this._name();
+ var numName = parseInt(this._name(), 10);
+ return isNaN(numName) ? this._name() : numName;
+ },
+
+ /**
+ * @return {string}
+ */
+ toString: function()
+ {
+ var name = this.name();
+ switch (this.type()) {
+ case "context": return "->" + name;
+ case "element": return "[" + name + "]";
+ case "weak": return "[[" + name + "]]";
+ case "property":
+ return name.indexOf(" ") === -1 ? "." + name : "[\"" + name + "\"]";
+ case "shortcut":
+ if (typeof name === "string")
+ return name.indexOf(" ") === -1 ? "." + name : "[\"" + name + "\"]";
+ else
+ return "[" + name + "]";
+ case "internal":
+ case "hidden":
+ case "invisible":
+ return "{" + name + "}";
+ };
+ return "?" + name + "?";
+ },
+
+ _hasStringName: function()
+ {
+ return !this.isElement() && !this.isHidden();
+ },
+
+ _name: function()
+ {
+ return this._hasStringName() ? this._snapshot._strings[this._nameOrIndex()] : this._nameOrIndex();
+ },
+
+ _nameOrIndex: function()
+ {
+ return this._edges[this.edgeIndex + this._snapshot._edgeNameOffset];
+ },
+
+ _type: function()
+ {
+ return this._edges[this.edgeIndex + this._snapshot._edgeTypeOffset];
+ },
+
+ __proto__: WebInspector.HeapSnapshotEdge.prototype
+};
+
+
+/**
+ * @constructor
+ * @extends {WebInspector.HeapSnapshotRetainerEdge}
+ * @param {!WebInspector.JSHeapSnapshot} snapshot
+ * @param {number} retainerIndex
+ */
+WebInspector.JSHeapSnapshotRetainerEdge = function(snapshot, retainerIndex)
+{
+ WebInspector.HeapSnapshotRetainerEdge.call(this, snapshot, retainerIndex);
+}
+
+WebInspector.JSHeapSnapshotRetainerEdge.prototype = {
+ /**
+ * @return {!WebInspector.JSHeapSnapshotRetainerEdge}
+ */
+ clone: function()
+ {
+ var snapshot = /** @type {!WebInspector.JSHeapSnapshot} */ (this._snapshot);
+ return new WebInspector.JSHeapSnapshotRetainerEdge(snapshot, this.retainerIndex());
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isHidden: function()
+ {
+ return this._edge().isHidden();
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isInternal: function()
+ {
+ return this._edge().isInternal();
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isInvisible: function()
+ {
+ return this._edge().isInvisible();
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isShortcut: function()
+ {
+ return this._edge().isShortcut();
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isWeak: function()
+ {
+ return this._edge().isWeak();
+ },
+
+ __proto__: WebInspector.HeapSnapshotRetainerEdge.prototype
+}
+