WebKit Bugzilla
Attachment 361533 Details for
Bug 194448
: Web Inspector: Import / Export Heap Snapshots
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
[PATCH] Proposed Fix
export-1.patch (text/plain), 35.48 KB, created by
Joseph Pecoraro
on 2019-02-08 13:57:53 PST
(
hide
)
Description:
[PATCH] Proposed Fix
Filename:
MIME Type:
Creator:
Joseph Pecoraro
Created:
2019-02-08 13:57:53 PST
Size:
35.48 KB
patch
obsolete
>diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index 09d1db43699..d53ea4710c0 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,88 @@ >+2019-02-08 Joseph Pecoraro <pecoraro@apple.com> >+ >+ Web Inspector: Import / Export Heap Snapshots >+ https://bugs.webkit.org/show_bug.cgi?id=194448 >+ <rdar://problem/47928093> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * Localizations/en.lproj/localizedStrings.js: >+ New strings. >+ >+ * UserInterface/Proxies/HeapSnapshotProxy.js: >+ (WI.HeapSnapshotProxy): >+ (WI.HeapSnapshotProxy.deserialize): >+ (WI.HeapSnapshotProxy.prototype.get imported): >+ (WI.HeapSnapshotProxy.prototype.get snapshotStringData): >+ (WI.HeapSnapshotProxy.prototype.set snapshotStringData): >+ Include an "imported" state on the HeapSnapshot and allow for >+ stashing the snapshotStringData on the main thread side. >+ >+ * UserInterface/Proxies/HeapSnapshotWorkerProxy.js: >+ (WI.HeapSnapshotWorkerProxy.prototype.createImportedSnapshot): >+ * UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js: >+ (HeapSnapshotWorker.prototype.clearSnapshots): >+ (HeapSnapshotWorker.prototype.createSnapshot): >+ Provide a specialized way to create an imported HeapSnapshot. >+ Track imported snapshots separately since they won't want to >+ be searched for live/dead objects due to active recording GCs. >+ >+ * UserInterface/Workers/HeapSnapshot/HeapSnapshot.js: >+ (HeapSnapshot): >+ (HeapSnapshot.updateCategoriesAndMetadata): >+ (HeapSnapshot.allocationBucketCounts): >+ (HeapSnapshot.instancesWithClassName): >+ (HeapSnapshot.prototype.nodeWithIdentifier): >+ (HeapSnapshot.prototype.dominatedNodes): >+ (HeapSnapshot.prototype.retainedNodes): >+ (HeapSnapshot.prototype.retainers): >+ (HeapSnapshot.prototype.updateDeadNodesAndGatherCollectionData): >+ (HeapSnapshot.prototype.serialize): >+ (HeapSnapshot.prototype.serializeNode): >+ (HeapSnapshot.prototype._buildPostOrderIndexes): >+ (HeapSnapshot.prototype._buildDominatorIndexes): >+ (HeapSnapshot.prototype._buildRetainedSizes): >+ (HeapSnapshot.prototype._gcRootPathes.visitNode): >+ (HeapSnapshot.prototype._gcRootPathes): >+ Construct a HeapSnapshot knowinng whether or not it is imported. >+ Imported snapshots may be the "GCDebugging" snapshot type which >+ differs from "Inspector" by the number of node fields. So keep >+ the node field count a member instead of a global constant >+ in order to work with both snapshot types. >+ >+ * UserInterface/Models/HeapAllocationsInstrument.js: >+ (WI.HeapAllocationsInstrument.prototype._takeHeapSnapshot): >+ * UserInterface/Protocol/ConsoleObserver.js: >+ (WI.ConsoleObserver.prototype.heapSnapshot): >+ * UserInterface/Protocol/HeapObserver.js: >+ (WI.HeapObserver.prototype.trackingStart): >+ (WI.HeapObserver.prototype.trackingComplete): >+ Stash the original string JSON data on the main thread side >+ where we already have the data. >+ >+ * UserInterface/Views/HeapAllocationsTimelineOverviewGraph.js: >+ (WI.HeapAllocationsTimelineOverviewGraph.prototype.layout): >+ Don't show [S] icons for imported snapshots with no timestamp. >+ >+ * UserInterface/Views/HeapAllocationsTimelineView.js: >+ (WI.HeapAllocationsTimelineView): >+ (WI.HeapAllocationsTimelineView.prototype.get navigationItems): >+ (WI.HeapAllocationsTimelineView.prototype._importButtonNavigationItemClicked): >+ (WI.HeapAllocationsTimelineView.prototype._takeHeapSnapshotClicked): >+ Import button that just creates a new snapshot. >+ >+ * UserInterface/Views/HeapSnapshotContentView.js: >+ (WI.HeapSnapshotContentView): >+ (WI.HeapSnapshotContentView.prototype.get navigationItems): >+ (WI.HeapSnapshotContentView.prototype.get supportsSave): >+ (WI.HeapSnapshotContentView.prototype.get saveData): >+ (WI.HeapSnapshotContentView.prototype._exportSnapshot): >+ Export button that saves the original data. >+ >+ * UserInterface/Views/TimelineTabContentView.js: >+ (WI.TimelineTabContentView.displayNameForRecord): >+ Specialized display string for imported snapshots. >+ > 2019-02-08 Joseph Pecoraro <pecoraro@apple.com> > > Web Inspector: Add Debug setting to show Internal Object Classes in Heap Snapshot >diff --git a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >index 68c2f0b7207..241d48860d9 100644 >--- a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >+++ b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >@@ -422,6 +422,7 @@ localizedStrings["Export HAR"] = "Export HAR"; > localizedStrings["Export Result"] = "Export Result"; > localizedStrings["Export Test"] = "Export Test"; > localizedStrings["Export recording (%s)"] = "Export recording (%s)"; >+localizedStrings["Export snapshot (%s)"] = "Export snapshot (%s)"; > localizedStrings["Expression"] = "Expression"; > localizedStrings["Extension Scripts"] = "Extension Scripts"; > localizedStrings["Extensions"] = "Extensions"; >@@ -488,6 +489,7 @@ localizedStrings["HTML Attributes"] = "HTML Attributes"; > localizedStrings["Headers"] = "Headers"; > localizedStrings["Headers:"] = "Headers:"; > localizedStrings["Heading Level"] = "Heading Level"; >+localizedStrings["Heap Snapshot %s-%s-%s at %s.%s.%s"] = "Heap Snapshot %s-%s-%s at %s.%s.%s"; > localizedStrings["Heap Snapshot Object (%s)"] = "Heap Snapshot Object (%s)"; > localizedStrings["Height"] = "Height"; > localizedStrings["Hide Console"] = "Hide Console"; >@@ -517,8 +519,10 @@ localizedStrings["Image Size"] = "Image Size"; > localizedStrings["Images"] = "Images"; > localizedStrings["Immediate Pause Requested"] = "Immediate Pause Requested"; > localizedStrings["Import"] = "Import"; >+localizedStrings["Import snapshot"] = "Import snapshot"; > localizedStrings["Imported"] = "Imported"; > localizedStrings["Imported Recordings"] = "Imported Recordings"; >+localizedStrings["Imported \u2014 %s"] = "Imported \u2014 %s"; > localizedStrings["Incomplete"] = "Incomplete"; > localizedStrings["Indent width:"] = "Indent width:"; > localizedStrings["Index"] = "Index"; >diff --git a/Source/WebInspectorUI/UserInterface/Models/HeapAllocationsInstrument.js b/Source/WebInspectorUI/UserInterface/Models/HeapAllocationsInstrument.js >index 03c33b9b2e0..090906578bd 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/HeapAllocationsInstrument.js >+++ b/Source/WebInspectorUI/UserInterface/Models/HeapAllocationsInstrument.js >@@ -79,6 +79,7 @@ WI.HeapAllocationsInstrument = class HeapAllocationsInstrument extends WI.Instru > let workerProxy = WI.HeapSnapshotWorkerProxy.singleton(); > workerProxy.createSnapshot(snapshotStringData, ({objectId, snapshot: serializedSnapshot}) => { > let snapshot = WI.HeapSnapshotProxy.deserialize(objectId, serializedSnapshot); >+ snapshot.snapshotStringData = snapshotStringData; > WI.timelineManager.heapSnapshotAdded(timestamp, snapshot); > }); > }); >diff --git a/Source/WebInspectorUI/UserInterface/Protocol/ConsoleObserver.js b/Source/WebInspectorUI/UserInterface/Protocol/ConsoleObserver.js >index 047ee50acb0..136c2147314 100644 >--- a/Source/WebInspectorUI/UserInterface/Protocol/ConsoleObserver.js >+++ b/Source/WebInspectorUI/UserInterface/Protocol/ConsoleObserver.js >@@ -53,6 +53,7 @@ WI.ConsoleObserver = class ConsoleObserver > let workerProxy = WI.HeapSnapshotWorkerProxy.singleton(); > workerProxy.createSnapshot(snapshotStringData, title || null, ({objectId, snapshot: serializedSnapshot}) => { > let snapshot = WI.HeapSnapshotProxy.deserialize(objectId, serializedSnapshot); >+ snapshot.snapshotStringData = snapshotStringData; > WI.timelineManager.heapSnapshotAdded(timestamp, snapshot); > }); > } >diff --git a/Source/WebInspectorUI/UserInterface/Protocol/HeapObserver.js b/Source/WebInspectorUI/UserInterface/Protocol/HeapObserver.js >index 828bf53d2f8..1b9d4291d0a 100644 >--- a/Source/WebInspectorUI/UserInterface/Protocol/HeapObserver.js >+++ b/Source/WebInspectorUI/UserInterface/Protocol/HeapObserver.js >@@ -37,6 +37,7 @@ WI.HeapObserver = class HeapObserver > let workerProxy = WI.HeapSnapshotWorkerProxy.singleton(); > workerProxy.createSnapshot(snapshotStringData, ({objectId, snapshot: serializedSnapshot}) => { > let snapshot = WI.HeapSnapshotProxy.deserialize(objectId, serializedSnapshot); >+ snapshot.snapshotStringData = snapshotStringData; > WI.timelineManager.heapTrackingStarted(timestamp, snapshot); > }); > } >@@ -46,6 +47,7 @@ WI.HeapObserver = class HeapObserver > let workerProxy = WI.HeapSnapshotWorkerProxy.singleton(); > workerProxy.createSnapshot(snapshotStringData, ({objectId, snapshot: serializedSnapshot}) => { > let snapshot = WI.HeapSnapshotProxy.deserialize(objectId, serializedSnapshot); >+ snapshot.snapshotStringData = snapshotStringData; > WI.timelineManager.heapTrackingCompleted(timestamp, snapshot); > }); > } >diff --git a/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotProxy.js b/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotProxy.js >index dce225e6c52..7766f7938ce 100644 >--- a/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotProxy.js >+++ b/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotProxy.js >@@ -25,7 +25,7 @@ > > WI.HeapSnapshotProxy = class HeapSnapshotProxy extends WI.Object > { >- constructor(snapshotObjectId, identifier, title, totalSize, totalObjectCount, liveSize, categories) >+ constructor(snapshotObjectId, identifier, title, totalSize, totalObjectCount, liveSize, categories, imported) > { > super(); > >@@ -37,6 +37,8 @@ WI.HeapSnapshotProxy = class HeapSnapshotProxy extends WI.Object > this._totalObjectCount = totalObjectCount; > this._liveSize = liveSize; > this._categories = Map.fromObject(categories); >+ this._imported = imported; >+ this._snapshotStringData = null; > > console.assert(!this.invalid); > >@@ -49,8 +51,8 @@ WI.HeapSnapshotProxy = class HeapSnapshotProxy extends WI.Object > > static deserialize(objectId, serializedSnapshot) > { >- let {identifier, title, totalSize, totalObjectCount, liveSize, categories} = serializedSnapshot; >- return new WI.HeapSnapshotProxy(objectId, identifier, title, totalSize, totalObjectCount, liveSize, categories); >+ let {identifier, title, totalSize, totalObjectCount, liveSize, categories, imported} = serializedSnapshot; >+ return new WI.HeapSnapshotProxy(objectId, identifier, title, totalSize, totalObjectCount, liveSize, categories, imported); > } > > static invalidateSnapshotProxies() >@@ -73,8 +75,19 @@ WI.HeapSnapshotProxy = class HeapSnapshotProxy extends WI.Object > get totalObjectCount() { return this._totalObjectCount; } > get liveSize() { return this._liveSize; } > get categories() { return this._categories; } >+ get imported() { return this._imported; } > get invalid() { return this._proxyObjectId === 0; } > >+ get snapshotStringData() >+ { >+ return this._snapshotStringData; >+ } >+ >+ set snapshotStringData(x) >+ { >+ this._snapshotStringData = x; >+ } >+ > updateForCollectionEvent(event) > { > console.assert(!this.invalid); >diff --git a/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotWorkerProxy.js b/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotWorkerProxy.js >index 4c51b4a374a..d4c0a882d56 100644 >--- a/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotWorkerProxy.js >+++ b/Source/WebInspectorUI/UserInterface/Proxies/HeapSnapshotWorkerProxy.js >@@ -66,6 +66,12 @@ WI.HeapSnapshotWorkerProxy = class HeapSnapshotWorkerProxy extends WI.Object > this.performAction("createSnapshotDiff", ...arguments); > } > >+ createImportedSnapshot(snapshotStringData, title, callback) >+ { >+ const imported = true; >+ this.performAction("createSnapshot", snapshotStringData, title, imported, callback); >+ } >+ > // Public > > performAction(actionName) >diff --git a/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineOverviewGraph.js b/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineOverviewGraph.js >index eea29c8337f..6d3e2fc6535 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineOverviewGraph.js >+++ b/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineOverviewGraph.js >@@ -73,6 +73,9 @@ WI.HeapAllocationsTimelineOverviewGraph = class HeapAllocationsTimelineOverviewG > } > > for (let record of visibleRecords) { >+ if (isNaN(record.timestamp)) >+ continue; >+ > const halfImageWidth = 8; > let x = xScale(record.timestamp) - halfImageWidth; > if (x <= 1) >diff --git a/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js b/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js >index 73a604c7fbb..f1894b6a521 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js >@@ -59,6 +59,11 @@ WI.HeapAllocationsTimelineView = class HeapAllocationsTimelineView extends WI.Ti > }, > }; > >+ this._importButtonNavigationItem = new WI.ButtonNavigationItem("import", WI.UIString("Import"), "Images/Import.svg", 15, 15); >+ this._importButtonNavigationItem.toolTip = WI.UIString("Import snapshot"); >+ this._importButtonNavigationItem.buttonStyle = WI.ButtonNavigationItem.Style.ImageAndText; >+ this._importButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._importButtonNavigationItemClicked, this); >+ > let snapshotTooltip = WI.UIString("Take snapshot"); > this._takeHeapSnapshotButtonItem = new WI.ButtonNavigationItem("take-snapshot", snapshotTooltip, "Images/Camera.svg", 16, 16); > this._takeHeapSnapshotButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._takeHeapSnapshotClicked, this); >@@ -184,7 +189,7 @@ WI.HeapAllocationsTimelineView = class HeapAllocationsTimelineView extends WI.Ti > get navigationItems() > { > if (this._showingSnapshotList) { >- let items = [this._takeHeapSnapshotButtonItem, this._compareHeapSnapshotsButtonItem]; >+ let items = [this._importButtonNavigationItem, this._takeHeapSnapshotButtonItem, this._compareHeapSnapshotsButtonItem]; > if (this._selectingComparisonHeapSnapshots) > items.push(this._compareHeapSnapshotHelpTextItem); > return items; >@@ -214,6 +219,22 @@ WI.HeapAllocationsTimelineView = class HeapAllocationsTimelineView extends WI.Ti > return components.concat(this._contentViewContainer.currentContentView.selectionPathComponents); > } > >+ get supportsSave() >+ { >+ if (this._showingSnapshotList) >+ return false; >+ >+ if (!this._contentViewContainer.currentContentView) >+ return false; >+ >+ return this._contentViewContainer.currentContentView.supportsSave; >+ } >+ >+ get saveData() >+ { >+ return this._contentViewContainer.currentContentView.saveData; >+ } >+ > selectRecord(record) > { > if (record) >@@ -382,12 +403,27 @@ WI.HeapAllocationsTimelineView = class HeapAllocationsTimelineView extends WI.Ti > this._compareHeapSnapshotsButtonItem.enabled = hasAtLeastTwoValidSnapshots; > } > >+ _importButtonNavigationItemClicked() >+ { >+ WI.FileUtilities.importText(function(result) { >+ let snapshotStringData = result.text; >+ let workerProxy = WI.HeapSnapshotWorkerProxy.singleton(); >+ workerProxy.createImportedSnapshot(snapshotStringData, result.filename, ({objectId, snapshot: serializedSnapshot}) => { >+ let snapshot = WI.HeapSnapshotProxy.deserialize(objectId, serializedSnapshot); >+ snapshot.snapshotStringData = snapshotStringData; >+ const timestamp = NaN; >+ WI.timelineManager.heapSnapshotAdded(timestamp, snapshot); >+ }); >+ }); >+ } >+ > _takeHeapSnapshotClicked() > { > HeapAgent.snapshot(function(error, timestamp, snapshotStringData) { > let workerProxy = WI.HeapSnapshotWorkerProxy.singleton(); > workerProxy.createSnapshot(snapshotStringData, ({objectId, snapshot: serializedSnapshot}) => { > let snapshot = WI.HeapSnapshotProxy.deserialize(objectId, serializedSnapshot); >+ snapshot.snapshotStringData = snapshotStringData; > WI.timelineManager.heapSnapshotAdded(timestamp, snapshot); > }); > }); >diff --git a/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotContentView.js b/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotContentView.js >index 62cddbf11c7..be444505a71 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotContentView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/HeapSnapshotContentView.js >@@ -33,6 +33,12 @@ WI.HeapSnapshotContentView = class HeapSnapshotContentView extends WI.ContentVie > > this.element.classList.add("heap-snapshot"); > >+ this._exportButtonNavigationItem = new WI.ButtonNavigationItem("export", WI.UIString("Export"), "Images/Export.svg", 15, 15); >+ this._exportButtonNavigationItem.toolTip = WI.UIString("Export snapshot (%s)").format(WI.saveKeyboardShortcut.displayName); >+ this._exportButtonNavigationItem.buttonStyle = WI.ButtonNavigationItem.Style.ImageAndText; >+ this._exportButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.High; >+ this._exportButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, () => { this._exportSnapshot(); }); >+ > this._dataGrid = new WI.DataGrid(columns); > this._dataGrid.sortColumnIdentifier = "retainedSize"; > this._dataGrid.sortOrder = WI.DataGrid.SortOrder.Descending; >@@ -52,6 +58,23 @@ WI.HeapSnapshotContentView = class HeapSnapshotContentView extends WI.ContentVie > > // Protected > >+ get navigationItems() >+ { >+ if (this.representedObject instanceof WI.HeapSnapshotProxy) >+ return [this._exportButtonNavigationItem]; >+ return []; >+ } >+ >+ get supportsSave() >+ { >+ return this.representedObject instanceof WI.HeapSnapshotProxy; >+ } >+ >+ get saveData() >+ { >+ return {customSaveHandler: () => { this._exportSnapshot(); }}; >+ } >+ > shown() > { > super.shown(); >@@ -73,6 +96,31 @@ WI.HeapSnapshotContentView = class HeapSnapshotContentView extends WI.ContentVie > > // Private > >+ _exportSnapshot() >+ { >+ if (!this.representedObject.snapshotStringData) { >+ InspectorFrontendHost.beep(); >+ return; >+ } >+ >+ let date = new Date; >+ let values = [ >+ date.getFullYear(), >+ Number.zeroPad(date.getMonth() + 1, 2), >+ Number.zeroPad(date.getDate(), 2), >+ Number.zeroPad(date.getHours(), 2), >+ Number.zeroPad(date.getMinutes(), 2), >+ Number.zeroPad(date.getSeconds(), 2), >+ ]; >+ let filename = WI.UIString("Heap Snapshot %s-%s-%s at %s.%s.%s").format(...values); >+ let url = "web-inspector:///" + encodeURI(filename) + ".json"; >+ WI.FileUtilities.save({ >+ url, >+ content: this.representedObject.snapshotStringData, >+ forceSaveAs: true, >+ }); >+ } >+ > _sortDataGrid() > { > if (!this._heapSnapshotDataGridTree) >diff --git a/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js b/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js >index 596242d4766..e8f7db1397e 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js >@@ -147,8 +147,6 @@ WI.RecordingContentView = class RecordingContentView extends WI.ContentView > return {customSaveHandler: () => { this._exportRecording(); }}; > } > >- // Protected >- > initialLayout() > { > let previewHeader = this.element.appendChild(document.createElement("header")); >diff --git a/Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js b/Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js >index 1e91a77ffaa..e9d70cecdce 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js >@@ -277,6 +277,8 @@ WI.TimelineTabContentView = class TimelineTabContentView extends WI.ContentBrows > case WI.TimelineRecord.Type.RenderingFrame: > return WI.UIString("Frame %d").format(timelineRecord.frameNumber); > case WI.TimelineRecord.Type.HeapAllocations: >+ if (timelineRecord.heapSnapshot.imported) >+ return WI.UIString("Imported \u2014 %s").format(timelineRecord.heapSnapshot.title); > if (timelineRecord.heapSnapshot.title) > return WI.UIString("Snapshot %d \u2014 %s").format(timelineRecord.heapSnapshot.identifier, timelineRecord.heapSnapshot.title); > return WI.UIString("Snapshot %d").format(timelineRecord.heapSnapshot.identifier); >diff --git a/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js b/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js >index df454156994..5141b8171b5 100644 >--- a/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js >+++ b/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js >@@ -36,6 +36,7 @@ const nodeIdOffset = 0; > const nodeSizeOffset = 1; > const nodeClassNameOffset = 2; > const nodeInternalOffset = 3; >+const gcDebuggingNodeFieldCount = 7; > > // edges > // [<0:fromId>, <1:toId>, <2:typeTableIndex>, <3:edgeDataIndexOrEdgeNameIndex>] >@@ -73,21 +74,26 @@ let nextSnapshotIdentifier = 1; > > HeapSnapshot = class HeapSnapshot > { >- constructor(objectId, snapshotDataString, title = null) >+ constructor(objectId, snapshotDataString, title = null, imported = false) > { > this._identifier = nextSnapshotIdentifier++; > this._objectId = objectId; > this._title = title; >+ this._imported = imported; > > let json = JSON.parse(snapshotDataString); > snapshotDataString = null; > > let {version, type, nodes, nodeClassNames, edges, edgeTypes, edgeNames} = json; > console.assert(version === 1, "Expect JavaScriptCore Heap Snapshot version 1"); >- console.assert(!type || type === "Inspector", "Expect an Inspector Heap Snapshot"); >+ console.assert(!type || (type === "Inspector" || type === "GCDebugging"), "Expect an Inspector / GCDebugging Heap Snapshot"); >+ >+ this.nodeFieldCount = nodeFieldCount; >+ if (type === "GCDebugging") >+ this.nodeFieldCount = gcDebuggingNodeFieldCount; > > this._nodes = nodes; >- this._nodeCount = nodes.length / nodeFieldCount; >+ this._nodeCount = nodes.length / this.nodeFieldCount; > > this._edges = edges; > this._edgeCount = edges.length / edgeFieldCount; >@@ -99,8 +105,8 @@ HeapSnapshot = class HeapSnapshot > this._totalSize = 0; > this._nodeIdentifierToOrdinal = new Map; // <node identifier> => nodeOrdinal > this._lastNodeIdentifier = 0; >- for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { >- let nodeOrdinal = nodeIndex / nodeFieldCount; >+ for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += this.nodeFieldCount) { >+ let nodeOrdinal = nodeIndex / this.nodeFieldCount; > let nodeIdentifier = nodes[nodeIndex + nodeIdOffset]; > this._nodeIdentifierToOrdinal.set(nodeIdentifier, nodeOrdinal); > this._totalSize += nodes[nodeIndex + nodeSizeOffset]; >@@ -151,9 +157,9 @@ HeapSnapshot = class HeapSnapshot > let nodeOrdinalIsDead = snapshot._nodeOrdinalIsDead; > > // Skip the <root> node. >- let firstNodeIndex = nodeFieldCount; >+ let firstNodeIndex = snapshot.nodeFieldCount; > let firstNodeOrdinal = 1; >- for (let nodeIndex = firstNodeIndex, nodeOrdinal = firstNodeOrdinal; nodeIndex < nodes.length; nodeIndex += nodeFieldCount, nodeOrdinal++) { >+ for (let nodeIndex = firstNodeIndex, nodeOrdinal = firstNodeOrdinal; nodeIndex < nodes.length; nodeIndex += snapshot.nodeFieldCount, nodeOrdinal++) { > if (allowNodeIdentifierCallback && !allowNodeIdentifierCallback(nodes[nodeIndex + nodeIdOffset])) > continue; > >@@ -191,10 +197,10 @@ HeapSnapshot = class HeapSnapshot > let nodes = snapshot._nodes; > > // Skip the <root> node. >- let firstNodeIndex = nodeFieldCount; >+ let firstNodeIndex = snapshot.nodeFieldCount; > > outer: >- for (let nodeIndex = firstNodeIndex; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { >+ for (let nodeIndex = firstNodeIndex; nodeIndex < nodes.length; nodeIndex += snapshot.nodeFieldCount) { > if (allowNodeIdentifierCallback && !allowNodeIdentifierCallback(nodes[nodeIndex + nodeIdOffset])) > continue; > >@@ -219,9 +225,9 @@ HeapSnapshot = class HeapSnapshot > let nodeClassNamesTable = snapshot._nodeClassNamesTable; > > // Skip the <root> node. >- let firstNodeIndex = nodeFieldCount; >+ let firstNodeIndex = snapshot.nodeFieldCount; > let firstNodeOrdinal = 1; >- for (let nodeIndex = firstNodeIndex, nodeOrdinal = firstNodeOrdinal; nodeIndex < nodes.length; nodeIndex += nodeFieldCount, nodeOrdinal++) { >+ for (let nodeIndex = firstNodeIndex, nodeOrdinal = firstNodeOrdinal; nodeIndex < nodes.length; nodeIndex += snapshot.nodeFieldCount, nodeOrdinal++) { > if (allowNodeIdentifierCallback && !allowNodeIdentifierCallback(nodes[nodeIndex + nodeIdOffset])) > continue; > >@@ -253,7 +259,7 @@ HeapSnapshot = class HeapSnapshot > nodeWithIdentifier(nodeIdentifier) > { > let nodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier); >- let nodeIndex = nodeOrdinal * nodeFieldCount; >+ let nodeIndex = nodeOrdinal * this.nodeFieldCount; > return this.serializeNode(nodeIndex); > } > >@@ -297,7 +303,7 @@ HeapSnapshot = class HeapSnapshot > let targetNodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier); > for (let nodeOrdinal = 0; nodeOrdinal < this._nodeCount; ++nodeOrdinal) { > if (this._nodeOrdinalToDominatorNodeOrdinal[nodeOrdinal] === targetNodeOrdinal) >- dominatedNodes.push(nodeOrdinal * nodeFieldCount); >+ dominatedNodes.push(nodeOrdinal * this.nodeFieldCount); > } > > return dominatedNodes.map(this.serializeNode, this); >@@ -313,7 +319,7 @@ HeapSnapshot = class HeapSnapshot > for (; this._edges[edgeIndex + edgeFromIdOffset] === nodeIdentifier; edgeIndex += edgeFieldCount) { > let toNodeIdentifier = this._edges[edgeIndex + edgeToIdOffset]; > let toNodeOrdinal = this._nodeIdentifierToOrdinal.get(toNodeIdentifier); >- let toNodeIndex = toNodeOrdinal * nodeFieldCount; >+ let toNodeIndex = toNodeOrdinal * this.nodeFieldCount; > retainedNodes.push(toNodeIndex); > edges.push(edgeIndex); > } >@@ -334,7 +340,7 @@ HeapSnapshot = class HeapSnapshot > let incomingEdgeIndexEnd = this._nodeOrdinalToFirstIncomingEdge[nodeOrdinal + 1]; > for (let edgeIndex = incomingEdgeIndex; edgeIndex < incomingEdgeIndexEnd; ++edgeIndex) { > let fromNodeOrdinal = this._incomingNodes[edgeIndex]; >- let fromNodeIndex = fromNodeOrdinal * nodeFieldCount; >+ let fromNodeIndex = fromNodeOrdinal * this.nodeFieldCount; > retainers.push(fromNodeIndex); > edges.push(this._incomingEdges[edgeIndex]); > } >@@ -356,7 +362,7 @@ HeapSnapshot = class HeapSnapshot > > // All of the node identifiers that could have existed prior to this snapshot. > let known = new Map; >- for (let nodeIndex = 0; nodeIndex < this._nodes.length; nodeIndex += nodeFieldCount) { >+ for (let nodeIndex = 0; nodeIndex < this._nodes.length; nodeIndex += this.nodeFieldCount) { > let nodeIdentifier = this._nodes[nodeIndex + nodeIdOffset]; > if (nodeIdentifier > lastNodeIdentifier) > continue; >@@ -365,7 +371,7 @@ HeapSnapshot = class HeapSnapshot > > // Determine which node identifiers have since been deleted. > let collectedNodesList = []; >- for (let nodeIndex = 0; nodeIndex < previousSnapshot._nodes.length; nodeIndex += nodeFieldCount) { >+ for (let nodeIndex = 0; nodeIndex < previousSnapshot._nodes.length; nodeIndex += this.nodeFieldCount) { > let nodeIdentifier = previousSnapshot._nodes[nodeIndex + nodeIdOffset]; > let wasDeleted = !known.has(nodeIdentifier); > if (wasDeleted) >@@ -403,20 +409,21 @@ HeapSnapshot = class HeapSnapshot > totalObjectCount: this._nodeCount - 1, // <root>. > liveSize: this._liveSize, > categories: this._categories, >+ imported: this._imported, > }; > } > > serializeNode(nodeIndex) > { >- console.assert((nodeIndex % nodeFieldCount) === 0, "Invalid nodeIndex to serialize"); >+ console.assert((nodeIndex % this.nodeFieldCount) === 0, "Invalid nodeIndex to serialize"); > > let nodeIdentifier = this._nodes[nodeIndex + nodeIdOffset]; >- let nodeOrdinal = nodeIndex / nodeFieldCount; >+ let nodeOrdinal = nodeIndex / this.nodeFieldCount; > let edgeIndex = this._nodeOrdinalToFirstOutgoingEdge[nodeOrdinal]; > let hasChildren = this._edges[edgeIndex + edgeFromIdOffset] === nodeIdentifier; > > let dominatorNodeOrdinal = this._nodeOrdinalToDominatorNodeOrdinal[nodeOrdinal]; >- let dominatorNodeIndex = dominatorNodeOrdinal * nodeFieldCount; >+ let dominatorNodeIndex = dominatorNodeOrdinal * this.nodeFieldCount; > let dominatorNodeIdentifier = this._nodes[dominatorNodeIndex + nodeIdOffset]; > > return { >@@ -533,7 +540,7 @@ HeapSnapshot = class HeapSnapshot > > while (stackTop >= 0) { > let nodeOrdinal = stackNodes[stackTop]; >- let nodeIdentifier = this._nodes[(nodeOrdinal * nodeFieldCount) + nodeIdOffset]; >+ let nodeIdentifier = this._nodes[(nodeOrdinal * this.nodeFieldCount) + nodeIdOffset]; > let edgeIndex = stackEdges[stackTop]; > > if (this._edges[edgeIndex + edgeFromIdOffset] === nodeIdentifier) { >@@ -657,7 +664,7 @@ HeapSnapshot = class HeapSnapshot > changed = true; > > let outgoingEdgeIndex = this._nodeOrdinalToFirstOutgoingEdge[nodeOrdinal]; >- let nodeIdentifier = this._nodes[(nodeOrdinal * nodeFieldCount) + nodeIdOffset]; >+ let nodeIdentifier = this._nodes[(nodeOrdinal * this.nodeFieldCount) + nodeIdOffset]; > for (let edgeIndex = outgoingEdgeIndex; this._edges[edgeIndex + edgeFromIdOffset] === nodeIdentifier; edgeIndex += edgeFieldCount) { > let toNodeIdentifier = this._edges[edgeIndex + edgeToIdOffset]; > let toNodeOrdinal = this._nodeIdentifierToOrdinal.get(toNodeIdentifier); >@@ -678,7 +685,7 @@ HeapSnapshot = class HeapSnapshot > _buildRetainedSizes(postOrderIndexToNodeOrdinal) > { > // Self size. >- for (let nodeIndex = 0, nodeOrdinal = 0; nodeOrdinal < this._nodeCount; nodeIndex += nodeFieldCount, nodeOrdinal++) >+ for (let nodeIndex = 0, nodeOrdinal = 0; nodeOrdinal < this._nodeCount; nodeIndex += this.nodeFieldCount, nodeOrdinal++) > this._nodeOrdinalToRetainedSizes[nodeOrdinal] = this._nodes[nodeIndex + nodeSizeOffset]; > > // Attribute size to dominator. >@@ -731,7 +738,7 @@ HeapSnapshot = class HeapSnapshot > { > if (this._nodeOrdinalIsGCRoot[nodeOrdinal]) { > let fullPath = currentPath.slice(); >- let nodeIndex = nodeOrdinal * nodeFieldCount; >+ let nodeIndex = nodeOrdinal * this.nodeFieldCount; > fullPath.push({node: nodeIndex}); > paths.push(fullPath); > return; >@@ -741,7 +748,7 @@ HeapSnapshot = class HeapSnapshot > return; > visited[nodeOrdinal] = 1; > >- let nodeIndex = nodeOrdinal * nodeFieldCount; >+ let nodeIndex = nodeOrdinal * this.nodeFieldCount; > currentPath.push({node: nodeIndex}); > > // Loop in reverse order because edges were added in reverse order. >@@ -750,7 +757,7 @@ HeapSnapshot = class HeapSnapshot > let incomingEdgeIndexEnd = this._nodeOrdinalToFirstIncomingEdge[nodeOrdinal + 1]; > for (let incomingEdgeIndex = incomingEdgeIndexEnd - 1; incomingEdgeIndex >= incomingEdgeIndexStart; --incomingEdgeIndex) { > let fromNodeOrdinal = this._incomingNodes[incomingEdgeIndex]; >- let fromNodeIndex = fromNodeOrdinal * nodeFieldCount; >+ let fromNodeIndex = fromNodeOrdinal * this.nodeFieldCount; > let fromNodeIsInternal = this._nodes[fromNodeIndex + nodeInternalOffset]; > if (fromNodeIsInternal) > continue; >diff --git a/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js b/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js >index 13f68498312..8f206915587 100644 >--- a/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js >+++ b/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshotWorker.js >@@ -34,6 +34,7 @@ HeapSnapshotWorker = class HeapSnapshotWorker > this._nextObjectId = 1; > this._objects = new Map; > this._snapshots = []; >+ this._importedSnapshots = []; > > self.addEventListener("message", this._handleMessage.bind(this)); > } >@@ -45,22 +46,28 @@ HeapSnapshotWorker = class HeapSnapshotWorker > this._objects.clear(); > > this._snapshots = []; >+ this._importedSnapshots = []; > } > >- createSnapshot(snapshotString, title) >+ createSnapshot(snapshotString, title, imported) > { > let objectId = this._nextObjectId++; >- let snapshot = new HeapSnapshot(objectId, snapshotString, title); >- this._snapshots.push(snapshot); >+ let snapshot = new HeapSnapshot(objectId, snapshotString, title, imported); > this._objects.set(objectId, snapshot); > >- if (this._snapshots.length > 1) { >- setTimeout(() => { >- let collectionData = snapshot.updateDeadNodesAndGatherCollectionData(this._snapshots); >- if (!collectionData || !collectionData.affectedSnapshots.length) >- return; >- this.sendEvent("HeapSnapshot.CollectionEvent", collectionData); >- }, 0); >+ if (imported) >+ this._importedSnapshots.push(snapshot); >+ else { >+ this._snapshots.push(snapshot); >+ >+ if (this._snapshots.length > 1) { >+ setTimeout(() => { >+ let collectionData = snapshot.updateDeadNodesAndGatherCollectionData(this._snapshots); >+ if (!collectionData || !collectionData.affectedSnapshots.length) >+ return; >+ this.sendEvent("HeapSnapshot.CollectionEvent", collectionData); >+ }, 0); >+ } > } > > return {objectId, snapshot: snapshot.serialize()};
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
hi
:
review+
hi
:
commit-queue-
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 194448
:
361530
|
361531
| 361533 |
361540