| Index: third_party/WebKit/Source/devtools/front_end/heap_snapshot_worker/JSHeapSnapshot.js
|
| diff --git a/third_party/WebKit/Source/devtools/front_end/heap_snapshot_worker/JSHeapSnapshot.js b/third_party/WebKit/Source/devtools/front_end/heap_snapshot_worker/JSHeapSnapshot.js
|
| index a39ca70e3197893ff6a40d66221f89a661c62984..58ee226b584f8be67c58f236c1fa7863796083c1 100644
|
| --- a/third_party/WebKit/Source/devtools/front_end/heap_snapshot_worker/JSHeapSnapshot.js
|
| +++ b/third_party/WebKit/Source/devtools/front_end/heap_snapshot_worker/JSHeapSnapshot.js
|
| @@ -27,868 +27,813 @@
|
| * (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
|
| + * @unrestricted
|
| */
|
| -WebInspector.JSHeapSnapshot = function(profile, progress)
|
| -{
|
| - WebInspector.HeapSnapshot.call(this, profile, progress);
|
| - 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.
|
| +WebInspector.JSHeapSnapshot = class extends WebInspector.HeapSnapshot {
|
| + /**
|
| + * @param {!Object} profile
|
| + * @param {!WebInspector.HeapSnapshotProgress} progress
|
| + */
|
| + constructor(profile, progress) {
|
| + super(profile, progress);
|
| + 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.
|
| };
|
| this.initialize();
|
| this._lazyStringCache = {};
|
| -};
|
| -
|
| -WebInspector.JSHeapSnapshot.prototype = {
|
| - /**
|
| - * @override
|
| - * @param {number=} nodeIndex
|
| - * @return {!WebInspector.JSHeapSnapshotNode}
|
| - */
|
| - createNode: function(nodeIndex)
|
| - {
|
| - return new WebInspector.JSHeapSnapshotNode(this, nodeIndex === undefined ? -1 : 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.HeapSnapshotNode):boolean}
|
| - */
|
| - classNodesFilter: function()
|
| - {
|
| - var mapAndFlag = this.userObjectsMapAndFlag();
|
| - if (!mapAndFlag)
|
| - return null;
|
| - var map = mapAndFlag.map;
|
| - var flag = mapAndFlag.flag;
|
| - /**
|
| - * @param {!WebInspector.HeapSnapshotNode} node
|
| - * @return {boolean}
|
| - */
|
| - function filter(node)
|
| - {
|
| - return !!(map[node.ordinal()] & flag);
|
| - }
|
| - return filter;
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @return {function(!WebInspector.HeapSnapshotEdge):boolean}
|
| - */
|
| - containmentEdgesFilter: function()
|
| - {
|
| - return edge => !edge.isInvisible();
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @return {function(!WebInspector.HeapSnapshotEdge):boolean}
|
| - */
|
| - retainingEdgesFilter: function()
|
| - {
|
| - var containmentEdgesFilter = this.containmentEdgesFilter();
|
| - function filter(edge)
|
| - {
|
| - return containmentEdgesFilter(edge) && !edge.node().isRoot() && !edge.isWeak();
|
| - }
|
| - return filter;
|
| - },
|
| -
|
| - _calculateFlags: function()
|
| - {
|
| - this._flags = new Uint32Array(this.nodeCount);
|
| - this._markDetachedDOMTreeNodes();
|
| - this._markQueriableHeapObjects();
|
| - this._markPageOwnedNodes();
|
| - },
|
| -
|
| - calculateDistances: function()
|
| - {
|
| - /**
|
| - * @param {!WebInspector.HeapSnapshotNode} node
|
| - * @param {!WebInspector.HeapSnapshotEdge} edge
|
| - * @return {boolean}
|
| - */
|
| - function filter(node, edge)
|
| - {
|
| - if (node.isHidden())
|
| - return edge.name() !== "sloppy_function_map" || node.rawName() !== "system / NativeContext";
|
| - if (node.isArray()) {
|
| - // DescriptorArrays are fixed arrays used to hold instance descriptors.
|
| - // The format of the these objects is:
|
| - // [0]: Number of descriptors
|
| - // [1]: Either Smi(0) if uninitialized, or a pointer to small fixed array:
|
| - // [0]: pointer to fixed array with enum cache
|
| - // [1]: either Smi(0) or pointer to fixed array with indices
|
| - // [i*3+2]: i-th key
|
| - // [i*3+3]: i-th type
|
| - // [i*3+4]: i-th descriptor
|
| - // As long as maps may share descriptor arrays some of the descriptor
|
| - // links may not be valid for all the maps. We just skip
|
| - // all the descriptor links when calculating distances.
|
| - // For more details see http://crbug.com/413608
|
| - if (node.rawName() !== "(map descriptors)")
|
| - return true;
|
| - var index = edge.name();
|
| - return index < 2 || (index % 3) !== 1;
|
| - }
|
| - return true;
|
| - }
|
| - WebInspector.HeapSnapshot.prototype.calculateDistances.call(this, filter);
|
| - },
|
| -
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @param {number=} nodeIndex
|
| + * @return {!WebInspector.JSHeapSnapshotNode}
|
| + */
|
| + createNode(nodeIndex) {
|
| + return new WebInspector.JSHeapSnapshotNode(this, nodeIndex === undefined ? -1 : nodeIndex);
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @param {number} edgeIndex
|
| + * @return {!WebInspector.JSHeapSnapshotEdge}
|
| + */
|
| + createEdge(edgeIndex) {
|
| + return new WebInspector.JSHeapSnapshotEdge(this, edgeIndex);
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @param {number} retainerIndex
|
| + * @return {!WebInspector.JSHeapSnapshotRetainerEdge}
|
| + */
|
| + createRetainingEdge(retainerIndex) {
|
| + return new WebInspector.JSHeapSnapshotRetainerEdge(this, retainerIndex);
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {?function(!WebInspector.HeapSnapshotNode):boolean}
|
| + */
|
| + classNodesFilter() {
|
| + var mapAndFlag = this.userObjectsMapAndFlag();
|
| + if (!mapAndFlag)
|
| + return null;
|
| + var map = mapAndFlag.map;
|
| + var flag = mapAndFlag.flag;
|
| /**
|
| - * @override
|
| - * @protected
|
| * @param {!WebInspector.HeapSnapshotNode} node
|
| * @return {boolean}
|
| */
|
| - isUserRoot: function(node)
|
| - {
|
| - return node.isUserRoot() || node.isDocumentDOMTreesRoot();
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @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 {
|
| - map: this._flags,
|
| - flag: this._nodeFlags.pageObject
|
| - };
|
| - },
|
| -
|
| + function filter(node) {
|
| + return !!(map[node.ordinal()] & flag);
|
| + }
|
| + return filter;
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {function(!WebInspector.HeapSnapshotEdge):boolean}
|
| + */
|
| + containmentEdgesFilter() {
|
| + return edge => !edge.isInvisible();
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {function(!WebInspector.HeapSnapshotEdge):boolean}
|
| + */
|
| + retainingEdgesFilter() {
|
| + var containmentEdgesFilter = this.containmentEdgesFilter();
|
| + function filter(edge) {
|
| + return containmentEdgesFilter(edge) && !edge.node().isRoot() && !edge.isWeak();
|
| + }
|
| + return filter;
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + */
|
| + calculateFlags() {
|
| + this._flags = new Uint32Array(this.nodeCount);
|
| + this._markDetachedDOMTreeNodes();
|
| + this._markQueriableHeapObjects();
|
| + this._markPageOwnedNodes();
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + */
|
| + calculateDistances() {
|
| /**
|
| * @param {!WebInspector.HeapSnapshotNode} node
|
| - * @return {number}
|
| - */
|
| - _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 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 nodeFieldCount = this._nodeFieldCount;
|
| - var nodesCount = this.nodeCount;
|
| -
|
| - var flags = this._flags;
|
| - var pageObjectFlag = this._nodeFlags.pageObject;
|
| -
|
| - var nodesToVisit = new Uint32Array(nodesCount);
|
| - var nodesToVisitLength = 0;
|
| -
|
| - var rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
|
| - var node = this.rootNode();
|
| -
|
| - // Populate the entry points. They are Window objects and DOM Tree Roots.
|
| - 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] |= pageObjectFlag;
|
| - }
|
| -
|
| - // Mark everything reachable with the pageObject flag.
|
| - while (nodesToVisitLength) {
|
| - var nodeOrdinal = nodesToVisit[--nodesToVisitLength];
|
| - 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] & pageObjectFlag)
|
| - continue;
|
| - var type = containmentEdges[edgeIndex + edgeTypeOffset];
|
| - if (type === edgeWeakType)
|
| - continue;
|
| - nodesToVisit[nodesToVisitLength++] = childNodeOrdinal;
|
| - flags[childNodeOrdinal] |= pageObjectFlag;
|
| - }
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| + * @param {!WebInspector.HeapSnapshotEdge} edge
|
| + * @return {boolean}
|
| */
|
| - _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 distances = this._nodeDistances;
|
| - var sizeNative = 0;
|
| - var sizeCode = 0;
|
| - var sizeStrings = 0;
|
| - var sizeJSArrays = 0;
|
| - var sizeSystem = 0;
|
| - var node = this.rootNode();
|
| - for (var nodeIndex = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
|
| - var nodeSize = nodes[nodeIndex + nodeSizeOffset];
|
| - var ordinal = nodeIndex / nodeFieldCount;
|
| - if (distances[ordinal] >= WebInspector.HeapSnapshotCommon.baseSystemDistance) {
|
| - sizeSystem += nodeSize;
|
| - continue;
|
| - }
|
| - var nodeType = nodes[nodeIndex + nodeTypeOffset];
|
| - node.nodeIndex = nodeIndex;
|
| - 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;
|
| - this._statistics.system = sizeSystem;
|
| - },
|
| -
|
| + function filter(node, edge) {
|
| + if (node.isHidden())
|
| + return edge.name() !== 'sloppy_function_map' || node.rawName() !== 'system / NativeContext';
|
| + if (node.isArray()) {
|
| + // DescriptorArrays are fixed arrays used to hold instance descriptors.
|
| + // The format of the these objects is:
|
| + // [0]: Number of descriptors
|
| + // [1]: Either Smi(0) if uninitialized, or a pointer to small fixed array:
|
| + // [0]: pointer to fixed array with enum cache
|
| + // [1]: either Smi(0) or pointer to fixed array with indices
|
| + // [i*3+2]: i-th key
|
| + // [i*3+3]: i-th type
|
| + // [i*3+4]: i-th descriptor
|
| + // As long as maps may share descriptor arrays some of the descriptor
|
| + // links may not be valid for all the maps. We just skip
|
| + // all the descriptor links when calculating distances.
|
| + // For more details see http://crbug.com/413608
|
| + if (node.rawName() !== '(map descriptors)')
|
| + return true;
|
| + var index = edge.name();
|
| + return index < 2 || (index % 3) !== 1;
|
| + }
|
| + return true;
|
| + }
|
| + super.calculateDistances(filter);
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @protected
|
| + * @param {!WebInspector.HeapSnapshotNode} node
|
| + * @return {boolean}
|
| + */
|
| + isUserRoot(node) {
|
| + return node.isUserRoot() || node.isDocumentDOMTreesRoot();
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @param {function(!WebInspector.HeapSnapshotNode)} action
|
| + * @param {boolean=} userRootsOnly
|
| + */
|
| + forEachRoot(action, userRootsOnly) {
|
| /**
|
| * @param {!WebInspector.HeapSnapshotNode} node
|
| - * @return {number}
|
| + * @param {string} name
|
| + * @return {?WebInspector.HeapSnapshotNode}
|
| */
|
| - _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;
|
| - },
|
| + 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 = {};
|
| /**
|
| - * @return {!WebInspector.HeapSnapshotCommon.Statistics}
|
| + * @param {!WebInspector.HeapSnapshotNode} node
|
| */
|
| - getStatistics: function()
|
| - {
|
| - return this._statistics;
|
| - },
|
| -
|
| - __proto__: WebInspector.HeapSnapshot.prototype
|
| + 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());
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {?{map: !Uint32Array, flag: number}}
|
| + */
|
| + userObjectsMapAndFlag() {
|
| + return {map: this._flags, flag: this._nodeFlags.pageObject};
|
| + }
|
| +
|
| + /**
|
| + * @param {!WebInspector.HeapSnapshotNode} node
|
| + * @return {number}
|
| + */
|
| + _flagsOfNode(node) {
|
| + return this._flags[node.nodeIndex / this._nodeFieldCount];
|
| + }
|
| +
|
| + _markDetachedDOMTreeNodes() {
|
| + 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() {
|
| + // 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 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() {
|
| + 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 nodeFieldCount = this._nodeFieldCount;
|
| + var nodesCount = this.nodeCount;
|
| +
|
| + var flags = this._flags;
|
| + var pageObjectFlag = this._nodeFlags.pageObject;
|
| +
|
| + var nodesToVisit = new Uint32Array(nodesCount);
|
| + var nodesToVisitLength = 0;
|
| +
|
| + var rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount;
|
| + var node = this.rootNode();
|
| +
|
| + // Populate the entry points. They are Window objects and DOM Tree Roots.
|
| + 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] |= pageObjectFlag;
|
| + }
|
| +
|
| + // Mark everything reachable with the pageObject flag.
|
| + while (nodesToVisitLength) {
|
| + var nodeOrdinal = nodesToVisit[--nodesToVisitLength];
|
| + 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] & pageObjectFlag)
|
| + continue;
|
| + var type = containmentEdges[edgeIndex + edgeTypeOffset];
|
| + if (type === edgeWeakType)
|
| + continue;
|
| + nodesToVisit[nodesToVisitLength++] = childNodeOrdinal;
|
| + flags[childNodeOrdinal] |= pageObjectFlag;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + */
|
| + calculateStatistics() {
|
| + 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 distances = this._nodeDistances;
|
| + var sizeNative = 0;
|
| + var sizeCode = 0;
|
| + var sizeStrings = 0;
|
| + var sizeJSArrays = 0;
|
| + var sizeSystem = 0;
|
| + var node = this.rootNode();
|
| + for (var nodeIndex = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) {
|
| + var nodeSize = nodes[nodeIndex + nodeSizeOffset];
|
| + var ordinal = nodeIndex / nodeFieldCount;
|
| + if (distances[ordinal] >= WebInspector.HeapSnapshotCommon.baseSystemDistance) {
|
| + sizeSystem += nodeSize;
|
| + continue;
|
| + }
|
| + var nodeType = nodes[nodeIndex + nodeTypeOffset];
|
| + node.nodeIndex = nodeIndex;
|
| + 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;
|
| + this._statistics.system = sizeSystem;
|
| + }
|
| +
|
| + /**
|
| + * @param {!WebInspector.HeapSnapshotNode} node
|
| + * @return {number}
|
| + */
|
| + _calculateArraySize(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() {
|
| + return this._statistics;
|
| + }
|
| };
|
|
|
| /**
|
| - * @constructor
|
| - * @extends {WebInspector.HeapSnapshotNode}
|
| - * @param {!WebInspector.JSHeapSnapshot} snapshot
|
| - * @param {number=} nodeIndex
|
| + * @unrestricted
|
| */
|
| -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 {string}
|
| - */
|
| - rawName: WebInspector.HeapSnapshotNode.prototype.name,
|
| -
|
| - /**
|
| - * @override
|
| - * @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 this.rawName();
|
| - },
|
| -
|
| - /**
|
| - * @return {string}
|
| - */
|
| - _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;
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @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 + ")";
|
| +WebInspector.JSHeapSnapshotNode = class extends WebInspector.HeapSnapshotNode {
|
| + /**
|
| + * @param {!WebInspector.JSHeapSnapshot} snapshot
|
| + * @param {number=} nodeIndex
|
| + */
|
| + constructor(snapshot, nodeIndex) {
|
| + super(snapshot, nodeIndex);
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + canBeQueried() {
|
| + var flags = this._snapshot._flagsOfNode(this);
|
| + return !!(flags & this._snapshot._nodeFlags.canBeQueried);
|
| + }
|
| +
|
| + /**
|
| + * @return {string}
|
| + */
|
| + rawName() {
|
| + return super.name();
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {string}
|
| + */
|
| + name() {
|
| + var snapshot = this._snapshot;
|
| + if (this.rawType() === snapshot._nodeConsStringType) {
|
| + var string = snapshot._lazyStringCache[this.nodeIndex];
|
| + if (typeof string === 'undefined') {
|
| + string = this._consStringName();
|
| + snapshot._lazyStringCache[this.nodeIndex] = string;
|
| + }
|
| + return string;
|
| + }
|
| + return this.rawName();
|
| + }
|
| +
|
| + /**
|
| + * @return {string}
|
| + */
|
| + _consStringName() {
|
| + 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];
|
| }
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @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;
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @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}
|
| - */
|
| - isArray: function()
|
| - {
|
| - return this._type() === this._snapshot._nodeArrayType;
|
| - },
|
| -
|
| - /**
|
| - * @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)";
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @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
|
| + }
|
| + nodesStack.push(secondNodeIndex);
|
| + nodesStack.push(firstNodeIndex);
|
| + }
|
| + return name;
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {string}
|
| + */
|
| + className() {
|
| + 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 + ')';
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {number}
|
| + */
|
| + classIndex() {
|
| + 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;
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {number}
|
| + */
|
| + id() {
|
| + var snapshot = this._snapshot;
|
| + return snapshot.nodes[this.nodeIndex + snapshot._nodeIdOffset];
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isHidden() {
|
| + return this.rawType() === this._snapshot._nodeHiddenType;
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isArray() {
|
| + return this.rawType() === this._snapshot._nodeArrayType;
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isSynthetic() {
|
| + return this.rawType() === this._snapshot._nodeSyntheticType;
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isUserRoot() {
|
| + return !this.isSynthetic();
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isDocumentDOMTreesRoot() {
|
| + return this.isSynthetic() && this.name() === '(Document DOM trees)';
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {!WebInspector.HeapSnapshotCommon.Node}
|
| + */
|
| + serialize() {
|
| + var result = super.serialize();
|
| + 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;
|
| + }
|
| };
|
|
|
| /**
|
| - * @constructor
|
| - * @extends {WebInspector.HeapSnapshotEdge}
|
| - * @param {!WebInspector.JSHeapSnapshot} snapshot
|
| - * @param {number=} edgeIndex
|
| + * @unrestricted
|
| */
|
| -WebInspector.JSHeapSnapshotEdge = function(snapshot, edgeIndex)
|
| -{
|
| - WebInspector.HeapSnapshotEdge.call(this, snapshot, edgeIndex);
|
| +WebInspector.JSHeapSnapshotEdge = class extends WebInspector.HeapSnapshotEdge {
|
| + /**
|
| + * @param {!WebInspector.JSHeapSnapshot} snapshot
|
| + * @param {number=} edgeIndex
|
| + */
|
| + constructor(snapshot, edgeIndex) {
|
| + super(snapshot, edgeIndex);
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {!WebInspector.JSHeapSnapshotEdge}
|
| + */
|
| + clone() {
|
| + var snapshot = /** @type {!WebInspector.JSHeapSnapshot} */ (this._snapshot);
|
| + return new WebInspector.JSHeapSnapshotEdge(snapshot, this.edgeIndex);
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {boolean}
|
| + */
|
| + hasStringName() {
|
| + if (!this.isShortcut())
|
| + return this._hasStringName();
|
| + return isNaN(parseInt(this._name(), 10));
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isElement() {
|
| + return this.rawType() === this._snapshot._edgeElementType;
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isHidden() {
|
| + return this.rawType() === this._snapshot._edgeHiddenType;
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isWeak() {
|
| + return this.rawType() === this._snapshot._edgeWeakType;
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isInternal() {
|
| + return this.rawType() === this._snapshot._edgeInternalType;
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isInvisible() {
|
| + return this.rawType() === this._snapshot._edgeInvisibleType;
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isShortcut() {
|
| + return this.rawType() === this._snapshot._edgeShortcutType;
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {string}
|
| + */
|
| + name() {
|
| + var name = this._name();
|
| + if (!this.isShortcut())
|
| + return String(name);
|
| + var numName = parseInt(name, 10);
|
| + return String(isNaN(numName) ? name : numName);
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {string}
|
| + */
|
| + toString() {
|
| + 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 + '?';
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + _hasStringName() {
|
| + var type = this.rawType();
|
| + var snapshot = this._snapshot;
|
| + return type !== snapshot._edgeElementType && type !== snapshot._edgeHiddenType;
|
| + }
|
| +
|
| + /**
|
| + * @return {string|number}
|
| + */
|
| + _name() {
|
| + return this._hasStringName() ? this._snapshot.strings[this._nameOrIndex()] : this._nameOrIndex();
|
| + }
|
| +
|
| + /**
|
| + * @return {number}
|
| + */
|
| + _nameOrIndex() {
|
| + return this._edges[this.edgeIndex + this._snapshot._edgeNameOffset];
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {number}
|
| + */
|
| + rawType() {
|
| + return this._edges[this.edgeIndex + this._snapshot._edgeTypeOffset];
|
| + }
|
| };
|
|
|
| -WebInspector.JSHeapSnapshotEdge.prototype = {
|
| - /**
|
| - * @override
|
| - * @return {!WebInspector.JSHeapSnapshotEdge}
|
| - */
|
| - clone: function()
|
| - {
|
| - var snapshot = /** @type {!WebInspector.JSHeapSnapshot} */ (this._snapshot);
|
| - return new WebInspector.JSHeapSnapshotEdge(snapshot, this.edgeIndex);
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @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;
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @return {string}
|
| - */
|
| - name: function()
|
| - {
|
| - var name = this._name();
|
| - if (!this.isShortcut())
|
| - return String(name);
|
| - var numName = parseInt(name, 10);
|
| - return String(isNaN(numName) ? name : numName);
|
| - },
|
| -
|
| - /**
|
| - * @override
|
| - * @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 + "?";
|
| - },
|
| -
|
| - /**
|
| - * @return {boolean}
|
| - */
|
| - _hasStringName: function()
|
| - {
|
| - var type = this._type();
|
| - var snapshot = this._snapshot;
|
| - return type !== snapshot._edgeElementType && type !== snapshot._edgeHiddenType;
|
| - },
|
| -
|
| - /**
|
| - * @return {string|number}
|
| - */
|
| - _name: function()
|
| - {
|
| - return this._hasStringName() ? this._snapshot.strings[this._nameOrIndex()] : this._nameOrIndex();
|
| - },
|
| -
|
| - /**
|
| - * @return {number}
|
| - */
|
| - _nameOrIndex: function()
|
| - {
|
| - return this._edges[this.edgeIndex + this._snapshot._edgeNameOffset];
|
| - },
|
| -
|
| - /**
|
| - * @return {number}
|
| - */
|
| - _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
|
| + * @unrestricted
|
| */
|
| -WebInspector.JSHeapSnapshotRetainerEdge = function(snapshot, retainerIndex)
|
| -{
|
| - WebInspector.HeapSnapshotRetainerEdge.call(this, snapshot, retainerIndex);
|
| +WebInspector.JSHeapSnapshotRetainerEdge = class extends WebInspector.HeapSnapshotRetainerEdge {
|
| + /**
|
| + * @param {!WebInspector.JSHeapSnapshot} snapshot
|
| + * @param {number} retainerIndex
|
| + */
|
| + constructor(snapshot, retainerIndex) {
|
| + super(snapshot, retainerIndex);
|
| + }
|
| +
|
| + /**
|
| + * @override
|
| + * @return {!WebInspector.JSHeapSnapshotRetainerEdge}
|
| + */
|
| + clone() {
|
| + var snapshot = /** @type {!WebInspector.JSHeapSnapshot} */ (this._snapshot);
|
| + return new WebInspector.JSHeapSnapshotRetainerEdge(snapshot, this.retainerIndex());
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isHidden() {
|
| + return this._edge().isHidden();
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isInternal() {
|
| + return this._edge().isInternal();
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isInvisible() {
|
| + return this._edge().isInvisible();
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isShortcut() {
|
| + return this._edge().isShortcut();
|
| + }
|
| +
|
| + /**
|
| + * @return {boolean}
|
| + */
|
| + isWeak() {
|
| + return this._edge().isWeak();
|
| + }
|
| };
|
| -
|
| -WebInspector.JSHeapSnapshotRetainerEdge.prototype = {
|
| - /**
|
| - * @override
|
| - * @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
|
| -};
|
| -
|
|
|