3cd0a367aa
Change-Id: I6d84e7ef500aecd83a77ed2ce3fed4e15b29b7ac Reviewed-on: https://chromium-review.googlesource.com/1065881 Commit-Queue: Sigurd Schneider <sigurds@chromium.org> Reviewed-by: Peter Marshall <petermarshall@chromium.org> Cr-Commit-Position: refs/heads/master@{#53289}
277 lines
9.6 KiB
JavaScript
277 lines
9.6 KiB
JavaScript
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
class Snapper {
|
|
|
|
constructor(resizer) {
|
|
let snapper = this;
|
|
snapper.resizer = resizer;
|
|
snapper.sourceExpand = d3.select("#" + SOURCE_EXPAND_ID);
|
|
snapper.sourceCollapse = d3.select("#" + SOURCE_COLLAPSE_ID);
|
|
snapper.disassemblyExpand = d3.select("#" + DISASSEMBLY_EXPAND_ID);
|
|
snapper.disassemblyCollapse = d3.select("#" + DISASSEMBLY_COLLAPSE_ID);
|
|
|
|
d3.select("#source-collapse").on("click", function () {
|
|
resizer.snapper.toggleSourceExpanded();
|
|
});
|
|
d3.select("#disassembly-collapse").on("click", function () {
|
|
resizer.snapper.toggleDisassemblyExpanded();
|
|
});
|
|
}
|
|
|
|
getLastExpandedState(type, default_state) {
|
|
var state = window.sessionStorage.getItem("expandedState-" + type);
|
|
if (state === null) return default_state;
|
|
return state === 'true';
|
|
}
|
|
|
|
setLastExpandedState(type, state) {
|
|
window.sessionStorage.setItem("expandedState-" + type, state);
|
|
}
|
|
|
|
toggleSourceExpanded() {
|
|
this.setSourceExpanded(!this.sourceExpand.classed("invisible"));
|
|
}
|
|
|
|
sourceExpandUpdate(newState) {
|
|
this.setLastExpandedState("source", newState);
|
|
this.sourceExpand.classed("invisible", newState);
|
|
this.sourceCollapse.classed("invisible", !newState);
|
|
}
|
|
|
|
setSourceExpanded(newState) {
|
|
if (this.sourceExpand.classed("invisible") === newState) return;
|
|
this.sourceExpandUpdate(newState);
|
|
let resizer = this.resizer;
|
|
if (newState) {
|
|
resizer.sep_left = resizer.sep_left_snap;
|
|
resizer.sep_left_snap = 0;
|
|
} else {
|
|
resizer.sep_left_snap = resizer.sep_left;
|
|
resizer.sep_left = 0;
|
|
}
|
|
resizer.updatePanes();
|
|
}
|
|
|
|
toggleDisassemblyExpanded() {
|
|
this.setDisassemblyExpanded(!this.disassemblyExpand.classed("invisible"));
|
|
}
|
|
|
|
disassemblyExpandUpdate(newState) {
|
|
this.setLastExpandedState("disassembly", newState);
|
|
this.disassemblyExpand.classed("invisible", newState);
|
|
this.disassemblyCollapse.classed("invisible", !newState);
|
|
}
|
|
|
|
setDisassemblyExpanded(newState) {
|
|
if (this.disassemblyExpand.classed("invisible") === newState) return;
|
|
this.disassemblyExpandUpdate(newState);
|
|
let resizer = this.resizer;
|
|
if (newState) {
|
|
resizer.sep_right = resizer.sep_right_snap;
|
|
resizer.sep_right_snap = resizer.client_width;
|
|
} else {
|
|
resizer.sep_right_snap = resizer.sep_right;
|
|
resizer.sep_right = resizer.client_width;
|
|
}
|
|
resizer.updatePanes();
|
|
}
|
|
|
|
panesUpated() {
|
|
this.sourceExpandUpdate(this.resizer.sep_left > this.resizer.dead_width);
|
|
this.disassemblyExpandUpdate(this.resizer.sep_right <
|
|
(this.resizer.client_width - this.resizer.dead_width));
|
|
}
|
|
}
|
|
|
|
class Resizer {
|
|
constructor(panes_updated_callback, dead_width) {
|
|
let resizer = this;
|
|
resizer.snapper = new Snapper(resizer)
|
|
resizer.panes_updated_callback = panes_updated_callback;
|
|
resizer.dead_width = dead_width
|
|
resizer.client_width = d3.select("body").node().getBoundingClientRect().width;
|
|
resizer.left = d3.select("#" + SOURCE_PANE_ID);
|
|
resizer.middle = d3.select("#" + INTERMEDIATE_PANE_ID);
|
|
resizer.right = d3.select("#" + GENERATED_PANE_ID);
|
|
resizer.resizer_left = d3.select('.resizer-left');
|
|
resizer.resizer_right = d3.select('.resizer-right');
|
|
resizer.sep_left = resizer.client_width / 3;
|
|
resizer.sep_right = resizer.client_width / 3 * 2;
|
|
resizer.sep_left_snap = 0;
|
|
resizer.sep_right_snap = 0;
|
|
// Offset to prevent resizers from sliding slightly over one another.
|
|
resizer.sep_width_offset = 7;
|
|
|
|
let dragResizeLeft = d3.behavior.drag()
|
|
.on('drag', function () {
|
|
let x = d3.mouse(this.parentElement)[0];
|
|
resizer.sep_left = Math.min(Math.max(0, x), resizer.sep_right - resizer.sep_width_offset);
|
|
resizer.updatePanes();
|
|
})
|
|
.on('dragstart', function () {
|
|
resizer.resizer_left.classed("dragged", true);
|
|
let x = d3.mouse(this.parentElement)[0];
|
|
if (x > dead_width) {
|
|
resizer.sep_left_snap = resizer.sep_left;
|
|
}
|
|
})
|
|
.on('dragend', function () {
|
|
resizer.resizer_left.classed("dragged", false);
|
|
});
|
|
resizer.resizer_left.call(dragResizeLeft);
|
|
|
|
let dragResizeRight = d3.behavior.drag()
|
|
.on('drag', function () {
|
|
let x = d3.mouse(this.parentElement)[0];
|
|
resizer.sep_right = Math.max(resizer.sep_left + resizer.sep_width_offset, Math.min(x, resizer.client_width));
|
|
resizer.updatePanes();
|
|
})
|
|
.on('dragstart', function () {
|
|
resizer.resizer_right.classed("dragged", true);
|
|
let x = d3.mouse(this.parentElement)[0];
|
|
if (x < (resizer.client_width - dead_width)) {
|
|
resizer.sep_right_snap = resizer.sep_right;
|
|
}
|
|
})
|
|
.on('dragend', function () {
|
|
resizer.resizer_right.classed("dragged", false);
|
|
});;
|
|
resizer.resizer_right.call(dragResizeRight);
|
|
window.onresize = function () {
|
|
resizer.updateWidths();
|
|
resizer.updatePanes();
|
|
};
|
|
}
|
|
|
|
updatePanes() {
|
|
let left_snapped = this.sep_left === 0;
|
|
let right_snapped = this.sep_right >= this.client_width - 1;
|
|
this.resizer_left.classed("snapped", left_snapped);
|
|
this.resizer_right.classed("snapped", right_snapped);
|
|
this.left.style('width', this.sep_left + 'px');
|
|
this.middle.style('width', (this.sep_right - this.sep_left) + 'px');
|
|
this.right.style('width', (this.client_width - this.sep_right) + 'px');
|
|
this.resizer_left.style('left', this.sep_left + 'px');
|
|
this.resizer_right.style('right', (this.client_width - this.sep_right - 1) + 'px');
|
|
|
|
this.snapper.panesUpated();
|
|
this.panes_updated_callback();
|
|
}
|
|
|
|
updateWidths() {
|
|
this.client_width = d3.select("body").node().getBoundingClientRect().width;
|
|
this.sep_right = Math.min(this.sep_right, this.client_width);
|
|
this.sep_left = Math.min(Math.max(0, this.sep_left), this.sep_right);
|
|
}
|
|
}
|
|
|
|
document.onload = (function (d3) {
|
|
"use strict";
|
|
var svg = null;
|
|
var multiview = null;
|
|
var disassemblyView = null;
|
|
var sourceViews = [];
|
|
var selectionBroker = null;
|
|
var sourceResolver = null;
|
|
let resizer = new Resizer(panesUpdatedCallback, 100);
|
|
|
|
function panesUpdatedCallback() {
|
|
if (multiview) multiview.onresize();
|
|
}
|
|
|
|
function loadFile(txtRes) {
|
|
// If the JSON isn't properly terminated, assume compiler crashed and
|
|
// add best-guess empty termination
|
|
if (txtRes[txtRes.length - 2] == ',') {
|
|
txtRes += '{"name":"disassembly","type":"disassembly","data":""}]}';
|
|
}
|
|
try {
|
|
sourceViews.forEach((sv) => sv.hide());
|
|
if (multiview) multiview.hide();
|
|
multiview = null;
|
|
if (disassemblyView) disassemblyView.hide();
|
|
sourceViews = [];
|
|
sourceResolver = new SourceResolver();
|
|
selectionBroker = new SelectionBroker(sourceResolver);
|
|
|
|
const jsonObj = JSON.parse(txtRes);
|
|
|
|
let fnc = jsonObj.function;
|
|
// Backwards compatibility.
|
|
if (typeof fnc == 'string') {
|
|
fnc = {
|
|
functionName: fnc,
|
|
sourceId: -1,
|
|
startPosition: jsonObj.sourcePosition,
|
|
endPosition: jsonObj.sourcePosition + jsonObj.source.length,
|
|
sourceText: jsonObj.source
|
|
};
|
|
}
|
|
|
|
sourceResolver.setInlinings(jsonObj.inlinings);
|
|
sourceResolver.setSources(jsonObj.sources, fnc)
|
|
sourceResolver.setNodePositionMap(jsonObj.nodePositions);
|
|
sourceResolver.parsePhases(jsonObj.phases);
|
|
|
|
let sourceView = new CodeView(SOURCE_PANE_ID, selectionBroker, sourceResolver, fnc, CodeView.MAIN_SOURCE);
|
|
sourceView.show(null, null);
|
|
sourceViews.push(sourceView);
|
|
|
|
sourceResolver.forEachSource((source) => {
|
|
let sourceView = new CodeView(SOURCE_PANE_ID, selectionBroker, sourceResolver, source, CodeView.INLINED_SOURCE);
|
|
sourceView.show(null, null);
|
|
sourceViews.push(sourceView);
|
|
});
|
|
|
|
disassemblyView = new DisassemblyView(GENERATED_PANE_ID, selectionBroker);
|
|
disassemblyView.initializeCode(fnc.sourceText);
|
|
if (sourceResolver.disassemblyPhase) {
|
|
disassemblyView.initializePerfProfile(jsonObj.eventCounts);
|
|
disassemblyView.show(sourceResolver.disassemblyPhase.data, null);
|
|
}
|
|
|
|
multiview = new GraphMultiView(INTERMEDIATE_PANE_ID, selectionBroker, sourceResolver);
|
|
multiview.show(jsonObj);
|
|
} catch (err) {
|
|
if (window.confirm("Error: Exception during load of TurboFan JSON file:\n" +
|
|
"error: " + err.message + "\nDo you want to clear session storage?")) {
|
|
window.sessionStorage.clear();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
function initializeUploadHandlers() {
|
|
// The <input> form #upload-helper with type file can't be a picture.
|
|
// We hence keep it hidden, and forward the click from the picture
|
|
// button #upload.
|
|
d3.select("#upload").on("click",
|
|
() => document.getElementById("upload-helper").click());
|
|
d3.select("#upload-helper").on("change", function () {
|
|
if (window.File && window.FileReader && window.FileList) {
|
|
var uploadFile = this.files && this.files[0];
|
|
var filereader = new window.FileReader();
|
|
filereader.onload = function (e) {
|
|
var txtRes = e.target.result;
|
|
loadFile(txtRes);
|
|
};
|
|
if (uploadFile)
|
|
filereader.readAsText(uploadFile);
|
|
} else {
|
|
alert("Can't load graph");
|
|
}
|
|
});
|
|
}
|
|
|
|
initializeUploadHandlers();
|
|
|
|
|
|
resizer.snapper.setSourceExpanded(resizer.snapper.getLastExpandedState("source", true));
|
|
resizer.snapper.setDisassemblyExpanded(resizer.snapper.getLastExpandedState("disassembly", false));
|
|
|
|
resizer.updatePanes();
|
|
|
|
})(window.d3);
|