Commit 9c15c055 authored by danno's avatar danno Committed by Commit bot

Add a html-based visualizer for TurboFan graphs

Review-Url: https://codereview.chromium.org/729913004
Cr-Commit-Position: refs/heads/master@{#36351}
parent 5a88c047
danno@chromium.org
Turbolizer is a HTML-based tool that visualizes optimized code along the various
phases of Turbofan's optimization pipeline, allowing easy navigation between
source code, Turbofan IR graphs, scheduled IR nodes and generated assembly code.
Turbolizer consumes .json files that are generated per-function by d8 by passing
the '--trace-turbo' command-line flag.
Host the turbolizer locally by starting a web server that serves the contents of
the turbolizer directory, e.g.:
cd src/tools/turbolizer
python -m SimpleHTTPServer 8000
Graph visualization and manipulation based on Mike Bostock's sample code for an
interactive tool for creating directed graphs. Original source is at
https://github.com/metacademy/directed-graph-creator and released under the
MIT/X license.
Icons dervied from the "White Olive Collection" created by Breezi released under
the Creative Commons BY license.
// Copyright 2015 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.
var CodeView = function(divID, PR, sourceText, sourcePosition, broker) {
"use strict";
var view = this;
view.divElement = document.getElementById(divID);
view.broker = broker;
view.codeSelection = null;
view.allSpans = [];
var selectionHandler = {
clear: function() {
broker.clear(selectionHandler);
},
select: function(items, selected) {
var handler = this;
var divElement = view.divElement;
var broker = view.broker;
for (let span of items) {
if (selected) {
span.classList.add("selected");
} else {
span.classList.remove("selected");
}
}
var ranges = [];
for (var span of items) {
ranges.push([span.start, span.end, null]);
}
broker.select(selectionHandler, ranges, selected);
},
selectionDifference: function(span1, inclusive1, span2, inclusive2) {
var pos1 = span1.start;
var pos2 = span2.start;
var result = [];
var lineListDiv = view.divElement.firstChild.firstChild.childNodes;
for (var i=0; i < lineListDiv.length; i++) {
var currentLineElement = lineListDiv[i];
var spans = currentLineElement.childNodes;
for (var j=0; j < spans.length; ++j) {
var currentSpan = spans[j];
if (currentSpan.start > pos1 || (inclusive1 && currentSpan.start == pos1)) {
if (currentSpan.start < pos2 || (inclusive2 && currentSpan.start == pos2)) {
result.push(currentSpan);
}
}
}
}
return result;
},
brokeredSelect: function(ranges, selected) {
var firstSelect = view.codeSelection.isEmpty();
for (var range of ranges) {
var start = range[0];
var end = range[1];
var lower = 0;
var upper = view.allSpans.length;
if (upper > 0) {
while ((upper - lower) > 1) {
var middle = Math.floor((upper + lower) / 2);
var lineStart = view.allSpans[middle].start;
if (lineStart < start) {
lower = middle;
} else if (lineStart > start) {
upper = middle;
} else {
lower = middle;
break;
}
}
var currentSpan = view.allSpans[lower];
var currentLineElement = currentSpan.parentNode;
if ((currentSpan.start <= start && start < currentSpan.end) ||
(currentSpan.start <= end && end < currentSpan.end)) {
if (firstSelect) {
makeContainerPosVisible(view.divElement, currentLineElement.offsetTop);
firstSelect = false;
}
view.codeSelection.select(currentSpan, selected);
}
}
}
},
brokeredClear: function() {
view.codeSelection.clear();
},
};
view.codeSelection = new Selection(selectionHandler);
broker.addSelectionHandler(selectionHandler);
var mouseDown = false;
this.handleSpanMouseDown = function(e) {
e.stopPropagation();
if (!e.shiftKey) {
view.codeSelection.clear();
}
view.codeSelection.select(this, true);
mouseDown = true;
}
this.handleSpanMouseMove = function(e) {
if (mouseDown) {
view.codeSelection.extendTo(this);
}
}
this.handleCodeMouseDown = function(e) {
view.codeSelection.clear();
}
document.addEventListener('mouseup', function(e){
mouseDown = false;
}, false);
this.initializeCode(sourceText, sourcePosition);
}
CodeView.prototype.initializeCode = function(sourceText, sourcePosition) {
var view = this;
if (sourceText == "") {
var newHtml = "<pre class=\"prettyprint\"</pre>";
view.divElement.innerHTML = newHtml;
} else {
var newHtml = "<pre class=\"prettyprint linenums\">"
+ sourceText + "</pre>";
view.divElement.innerHTML = newHtml;
try {
// Wrap in try to work when offline.
PR.prettyPrint();
} catch (e) {
}
view.divElement.onmousedown = this.handleCodeMouseDown;
var base = sourcePosition;
var current = 0;
var lineListDiv = view.divElement.firstChild.firstChild.childNodes;
for (i=0; i < lineListDiv.length; i++) {
var currentLineElement = lineListDiv[i];
currentLineElement.id = "li" + i;
var pos = base + current;
currentLineElement.pos = pos;
var spans = currentLineElement.childNodes;
for (j=0; j < spans.length; ++j) {
var currentSpan = spans[j];
if (currentSpan.nodeType == 1) {
currentSpan.start = pos;
currentSpan.end = pos + currentSpan.textContent.length;
currentSpan.onmousedown = this.handleSpanMouseDown;
currentSpan.onmousemove = this.handleSpanMouseMove;
view.allSpans.push(currentSpan);
}
current += currentSpan.textContent.length;
pos = base + current;
}
while ((current < sourceText.length) && (
sourceText[current] == '\n' ||
sourceText[current] == '\r')) {
++current;
}
}
}
this.resizeToParent();
}
CodeView.prototype.resizeToParent = function() {
var view = this;
var documentElement = document.documentElement;
var y = view.divElement.parentNode.clientHeight || documentElement.clientHeight;
view.divElement.style.height = y + "px";
}
// Copyright 2014 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.
var MAX_RANK_SENTINEL = 0;
var GRAPH_MARGIN = 250;
var WIDTH = 'width';
var HEIGHT = 'height';
var VISIBILITY = 'visibility';
var SOURCE_PANE_ID = 'left';
var SOURCE_COLLAPSE_ID = 'source-shrink';
var SOURCE_EXPAND_ID = 'source-expand';
var INTERMEDIATE_PANE_ID = 'middle';
var EMPTY_PANE_ID = 'empty';
var GRAPH_PANE_ID = 'graph';
var SCHEDULE_PANE_ID = 'schedule';
var GENERATED_PANE_ID = 'right';
var DISASSEMBLY_PANE_ID = 'disassembly';
var DISASSEMBLY_COLLAPSE_ID = 'disassembly-shrink';
var DISASSEMBLY_EXPAND_ID = 'disassembly-expand';
var COLLAPSE_PANE_BUTTON_VISIBLE = 'button-input';
var COLLAPSE_PANE_BUTTON_INVISIBLE = 'button-input-invisible';
// Copyright 2015 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.
"use strict";
class DisassemblyView extends TextView {
constructor(id, broker, sortedPositionList) {
super(id, broker, null, false);
this.pos_start = -1;
let view = this;
let ADDRESS_STYLE = {
css: 'tag',
location: function(text) {
ADDRESS_STYLE.last_address = text;
return undefined;
}
};
let ADDRESS_LINK_STYLE = {
css: 'tag',
link: function(text) {
view.select(function(location) { return location.address == text; }, true, true);
}
};
let UNCLASSIFIED_STYLE = {
css: 'com'
};
let NUMBER_STYLE = {
css: 'lit'
};
let COMMENT_STYLE = {
css: 'com'
};
let POSITION_STYLE = {
css: 'com',
location: function(text) {
view.pos_start = Number(text);
}
};
let OPCODE_STYLE = {
css: 'kwd',
location: function(text) {
return {
address: ADDRESS_STYLE.last_address
};
}
};
let patterns = [
[
[/^0x[0-9a-f]{8,16}/, ADDRESS_STYLE, 1],
[/^.*/, UNCLASSIFIED_STYLE, -1]
],
[
[/^\s+\d+\s+[0-9a-f]+\s+/, NUMBER_STYLE, 2],
[/^.*/, null, -1]
],
[
[/^\S+\s+/, OPCODE_STYLE, 3],
[/^\S+$/, OPCODE_STYLE, -1],
[/^.*/, null, -1]
],
[
[/^\s+/, null],
[/^[^\(;]+$/, null, -1],
[/^[^\(;]+/, null],
[/^\(/, null, 4],
[/^;/, COMMENT_STYLE, 5]
],
[
[/^0x[0-9a-f]{8,16}/, ADDRESS_LINK_STYLE],
[/^[^\)]/, null],
[/^\)$/, null, -1],
[/^\)/, null, 3]
],
[
[/^; debug\: position /, COMMENT_STYLE, 6],
[/^.+$/, COMMENT_STYLE, -1]
],
[
[/^\d+$/, POSITION_STYLE, -1],
]
];
view.setPatterns(patterns);
}
lineLocation(li) {
let view = this;
let result = undefined;
for (let i = 0; i < li.children.length; ++i) {
let fragment = li.children[i];
let location = fragment.location;
if (location != null) {
if (location.address != undefined) {
if (result === undefined) result = {};
result.address = location.address;
}
if (view.pos_start != -1) {
if (result === undefined) result = {};
result.pos_start = view.pos_start;
result.pos_end = result.pos_start + 1;
}
}
}
return result;
}
}
// Copyright 2014 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.
var MINIMUM_EDGE_SEPARATION = 20;
function isEdgeInitiallyVisible(target, index, source, type) {
return type == "control" && (target.cfg || source.cfg);
}
var Edge = function(target, index, source, type) {
this.target = target;
this.source = source;
this.index = index;
this.type = type;
this.backEdgeNumber = 0;
this.visible = isEdgeInitiallyVisible(target, index, source, type);
};
Edge.prototype.stringID = function() {
return this.source.id + "," + this.index + "," + this.target.id;
};
Edge.prototype.isVisible = function() {
return this.visible && this.source.visible && this.target.visible;
};
Edge.prototype.getInputHorizontalPosition = function(graph) {
if (this.backEdgeNumber > 0) {
return graph.maxGraphNodeX + this.backEdgeNumber * MINIMUM_EDGE_SEPARATION;
}
var source = this.source;
var target = this.target;
var index = this.index;
var input_x = target.x + target.getInputX(index);
var inputApproach = target.getInputApproach(this.index);
var outputApproach = source.getOutputApproach(graph);
if (inputApproach > outputApproach) {
return input_x;
} else {
var inputOffset = MINIMUM_EDGE_SEPARATION * (index + 1);
return (target.x < source.x)
? (target.x + target.getTotalNodeWidth() + inputOffset)
: (target.x - inputOffset)
}
}
Edge.prototype.generatePath = function(graph) {
var target = this.target;
var source = this.source;
var input_x = target.x + target.getInputX(this.index);
var output_x = source.x + source.getOutputX();
var output_y = source.y + DEFAULT_NODE_HEIGHT + DEFAULT_NODE_BUBBLE_RADIUS;
var inputApproach = target.getInputApproach(this.index);
var outputApproach = source.getOutputApproach(graph);
var horizontalPos = this.getInputHorizontalPosition(graph);
var result = "M" + output_x + "," + output_y +
"L" + output_x + "," + outputApproach +
"L" + horizontalPos + "," + outputApproach;
if (horizontalPos != input_x) {
result += "L" + horizontalPos + "," + inputApproach;
} else {
if (inputApproach < outputApproach) {
inputApproach = outputApproach;
}
}
result += "L" + input_x + "," + inputApproach +
"L" + input_x + "," + (target.y - DEFAULT_NODE_BUBBLE_RADIUS - 12);
return result;
}
Edge.prototype.isBackEdge = function() {
return this.target.hasBackEdges() && (this.target.rank < this.source.rank);
}
// Copyright 2015 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.
"use strict";
class EmptyView extends View {
constructor(id, broker) {
super(id, broker);
this.svg = this.divElement.append("svg").attr('version','1.1').attr("width", "100%");
}
initializeContent(data, rememberedSelection) {
this.svg.attr("height", document.documentElement.clientHeight + "px");
}
deleteContent() {
}
}
This diff is collapsed.
This diff is collapsed.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" href="turbo-visualizer.css" />
</head>
<body width="100%">
<div id="left">
<div id='source-text'>
<pre id='source-text-pre'\>
</div>
</div>
<div id="middle">
<span id="graph-toolbox">
<input id="layout" type="image" title="layout graph" src="layout-icon.png"
alt="layout graph" class="button-input">
<input id="show-all" type="image" title="show all nodes" src="expand-all.jpg"
alt="show all nodes" class="button-input">
<input id="hide-unselected" type="image" title="hide unselected nodes"
src="hide-unselected.png" alt="hide unselected nodes" class="button-input">
<input id="hide-selected" type="image" title="hide selected nodes"
src="hide-selected.png" alt="hide selected nodes" class="button-input">
<input id="zoom-selection" type="image" title="zoom to selection"
src="search.png" alt="zoom to selection" class="button-input">
<input id="toggle-types" type="image" title="show/hide types"
src="types.png" alt="show/hide types" class="button-input">
<input id="search-input" type="text" title="search nodes for regex"
alt="search node for regex" class="search-input">
<select id="display-selector"></select>
</span>
<div id="load-file">
<input type="file" id="hidden-file-upload">
<input id="upload" type="image" title="load graph" class="button-input"
src="upload-icon.png" alt="upload graph">
</div>
<div id="empty" width="100%" height="100%"></div>
<div id="graph" width="100%" height="100%"></div>
<div id="schedule" width="100%">
<pre id="schedule-text-pre" class='prettyprint prettyprinted'>
<ul id="schedule-list" class='nolinenums noindent'>
</ul>
</pre>
</div>
<div id='text-placeholder' width="0px" height="0px" style="position: absolute; top:100000px;" ><svg><text text-anchor="right">
<tspan white-space="inherit" id="text-measure"/>
</text></svg></div>
</div>
<div id="right">
<div id='disassembly'>
<pre id='disassembly-text-pre' class='prettyprint prettyprinted'>
<ul id='disassembly-list' class='nolinenums noindent'>
</ul>
</pre>
</div>
</div>
<div id="source-collapse" class="collapse-pane">
<input id="source-expand" type="image" title="show source"
src="right-arrow.png" class="button-input-invisible">
<input id="source-shrink" type="image" title="hide source"
src="left-arrow.png" class="button-input">
</div>
<div id="disassembly-collapse" class="collapse-pane">
<input id="disassembly-expand" type="image" title="show disassembly"
src="left-arrow.png" class="button-input">
<input id="disassembly-shrink" type="image" title="hide disassembly"
src="right-arrow.png" class="button-input-invisible">
</div>
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="https://cdn.jsdelivr.net/filesaver.js/0.1/FileSaver.min.js"></script>
<script src="monkey.js"></script>
<script src="util.js"></script>
<script src="lang-disassembly.js"></script>
<script src="node.js"></script>
<script src="edge.js"></script>
<script src="selection.js"></script>
<script src="selection-broker.js"></script>
<script src="constants.js"></script>
<script src="view.js"></script>
<script src="text-view.js"></script>
<script src="empty-view.js"></script>
<script src="code-view.js"></script>
<script src="graph-layout.js"></script>
<script src="graph-view.js"></script>
<script src="schedule-view.js"></script>
<script src="disassembly-view.js"></script>
<script src="turbo-visualizer.js"></script>
</body>
</html>
// Copyright 2015 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.
PR.registerLangHandler(
PR.createSimpleLexer(
[
[PR.PR_STRING, /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$))/, null, '\''],
[PR.PR_PLAIN, /^\s+/, null, ' \r\n\t\xA0']
],
[ // fallthroughStylePatterns
[PR.PR_COMMENT, /;; debug: position \d+/, null],
]),
['disassembly']);
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
// Copyright 2014 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.
Array.prototype.getStaggeredFromMiddle = function(i) {
if (i >= this.length) {
throw("getStaggeredFromMiddle: OOB");
}
var middle = Math.floor(this.length / 2);
var index = middle + (((i % 2) == 0) ? (i / 2) : (((1 - i) / 2) - 1));
return this[index];
}
Array.prototype.contains = function(obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
}
Math.alignUp = function(raw, multiple) {
return Math.floor((raw + multiple - 1) / multiple) * multiple;
}
// Copyright 2014 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.
var DEFAULT_NODE_WIDTH = 240;
var DEFAULT_NODE_HEIGHT = 40;
var TYPE_HEIGHT = 25;
var DEFAULT_NODE_BUBBLE_RADIUS = 4;
var NODE_INPUT_WIDTH = 20;
var MINIMUM_NODE_INPUT_APPROACH = 20;
var MINIMUM_NODE_OUTPUT_APPROACH = 15;
function isNodeInitiallyVisible(node) {
return node.cfg;
}
var Node = {
isControl: function() {
return this.control;
},
isInput: function() {
return this.opcode == 'Parameter' || this.opcode.endsWith('Constant');
},
isJavaScript: function() {
return this.opcode.startsWith('JS');
},
isSimplified: function() {
if (this.isJavaScript) return false;
return this.opcode.endsWith('Phi') ||
this.opcode.startsWith('Boolean') ||
this.opcode.startsWith('Number') ||
this.opcode.startsWith('String') ||
this.opcode.startsWith('Change') ||
this.opcode.startsWith('Object') ||
this.opcode.startsWith('Reference') ||
this.opcode.startsWith('Any') ||
this.opcode.endsWith('ToNumber') ||
(this.opcode == 'AnyToBoolean') ||
(this.opcode.startsWith('Load') && this.opcode.length > 4) ||
(this.opcode.startsWith('Store') && this.opcode.length > 5);
},
isMachine: function() {
return !(this.isControl() || this.isInput() ||
this.isJavaScript() || this.isSimplified());
},
getTotalNodeWidth: function() {
var inputWidth = this.inputs.length * NODE_INPUT_WIDTH;
return Math.max(inputWidth, this.width);
},
getLabel: function() {
return this.label;
},
getDisplayLabel: function() {
var result = this.id + ":" + this.label;
if (result.length > 30) {
return this.id + ":" + this.opcode;
} else {
return result;
}
},
getType: function() {
return this.type;
},
getDisplayType: function() {
var type_string = this.type;
if (type_string == undefined) return "";
if (type_string.length > 24) {
type_string = type_string.substr(0, 25) + "...";
}
return type_string;
},
deepestInputRank: function() {
var deepestRank = 0;
this.inputs.forEach(function(e) {
if (e.isVisible() && !e.isBackEdge()) {
if (e.source.rank > deepestRank) {
deepestRank = e.source.rank;
}
}
});
return deepestRank;
},
areAnyOutputsVisible: function() {
var visibleCount = 0;
this.outputs.forEach(function(e) { if (e.isVisible()) ++visibleCount; });
if (this.outputs.length == visibleCount) return 2;
if (visibleCount != 0) return 1;
return 0;
},
setOutputVisibility: function(v) {
var result = false;
this.outputs.forEach(function(e) {
e.visible = v;
if (v) {
if (!e.target.visible) {
e.target.visible = true;
result = true;
}
}
});
return result;
},
setInputVisibility: function(i, v) {
var edge = this.inputs[i];
edge.visible = v;
if (v) {
if (!edge.source.visible) {
edge.source.visible = true;
return true;
}
}
return false;
},
getInputApproach: function(index) {
return this.y - MINIMUM_NODE_INPUT_APPROACH -
(index % 4) * MINIMUM_EDGE_SEPARATION - DEFAULT_NODE_BUBBLE_RADIUS
},
getOutputApproach: function(graph, index) {
return this.y + this.outputApproach + graph.getNodeHeight() +
+ DEFAULT_NODE_BUBBLE_RADIUS;
},
getInputX: function(index) {
var result = this.getTotalNodeWidth() - (NODE_INPUT_WIDTH / 2) +
(index - this.inputs.length + 1) * NODE_INPUT_WIDTH;
return result;
},
getOutputX: function() {
return this.getTotalNodeWidth() - (NODE_INPUT_WIDTH / 2);
},
getFunctionRelativeSourcePosition: function(graph) {
return this.pos - graph.sourcePosition;
},
hasBackEdges: function() {
return (this.opcode == "Loop") ||
((this.opcode == "Phi" || this.opcode == "EffectPhi") &&
this.inputs[this.inputs.length - 1].source.opcode == "Loop");
}
};
This diff was suppressed by a .gitattributes entry.
// Copyright 2015 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.
"use strict";
class ScheduleView extends TextView {
constructor(id, broker, nodePositionMap) {
super(id, broker, null, false);
let view = this;
let BLOCK_STYLE = {
css: 'tag'
};
const BLOCK_HEADER_STYLE = {
css: 'com',
block_id: -1,
location: function(text) {
let matches = /\d+/.exec(text);
if (!matches) return undefined;
BLOCK_HEADER_STYLE.block_id = Number(matches[0]);
return {
block_id: BLOCK_HEADER_STYLE.block_id
};
},
};
const BLOCK_LINK_STYLE = {
css: 'tag',
link: function(text) {
let id = Number(text.substr(1));
view.select(function(location) { return location.block_id == id; }, true, true);
}
};
const ID_STYLE = {
css: 'tag',
location: function(text) {
let matches = /\d+/.exec(text);
return {
node_id: Number(matches[0]),
block_id: BLOCK_HEADER_STYLE.block_id
};
},
};
const ID_LINK_STYLE = {
css: 'tag',
link: function(text) {
let id = Number(text);
view.select(function(location) { return location.node_id == id; }, true, true);
}
};
const NODE_STYLE = { css: 'kwd' };
const GOTO_STYLE = { css: 'kwd',
goto_id: -2,
location: function(text) {
return {
node_id: GOTO_STYLE.goto_id--,
block_id: BLOCK_HEADER_STYLE.block_id
};
}
}
const ARROW_STYLE = { css: 'kwd' };
let patterns = [
[
[/^--- BLOCK B\d+/, BLOCK_HEADER_STYLE, 1],
[/^\s+\d+: /, ID_STYLE, 2],
[/^\s+Goto/, GOTO_STYLE, 6],
[/^.*/, null, -1]
],
[
[/^ +/, null],
[/^\(deferred\)/, BLOCK_HEADER_STYLE],
[/^B\d+/, BLOCK_LINK_STYLE],
[/^<-/, ARROW_STYLE],
[/^->/, ARROW_STYLE],
[/^,/, null],
[/^---/, BLOCK_HEADER_STYLE, -1]
],
// Parse opcode including []
[
[/^[A-Za-z0-9_]+(\[[^\]]+\])?$/, NODE_STYLE, -1],
[/^[A-Za-z0-9_]+(\[[^\]]+\])?/, NODE_STYLE, 3]
],
// Parse optional parameters
[
[/^ /, null, 4],
[/^\(/, null],
[/^\d+/, ID_LINK_STYLE],
[/^, /, null],
[/^\)$/, null, -1],
[/^\)/, null, 4],
],
[
[/^ -> /, ARROW_STYLE, 5],
[/^.*/, null, -1]
],
[
[/^B\d+$/, BLOCK_LINK_STYLE, -1],
[/^B\d+/, BLOCK_LINK_STYLE],
[/^, /, null]
],
[
[/^ -> /, ARROW_STYLE],
[/^B\d+$/, BLOCK_LINK_STYLE, -1]
]
];
this.setPatterns(patterns);
this.setNodePositionMap(nodePositionMap);
}
}
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
// Copyright 2015 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.
var SelectionBroker = function() {
this.brokers = [];
this.dispatching = false;
this.lastDispatchingHandler = null;
};
SelectionBroker.prototype.addSelectionHandler = function(handler) {
this.brokers.push(handler);
}
SelectionBroker.prototype.select = function(from, ranges, selected) {
if (!this.dispatching) {
this.lastDispatchingHandler = from;
try {
this.dispatching = true;
for (var b of this.brokers) {
if (b != from) {
b.brokeredSelect(ranges, selected);
}
}
}
finally {
this.dispatching = false;
}
}
}
SelectionBroker.prototype.clear = function(from) {
this.lastDispatchingHandler = null;
if (!this.dispatching) {
try {
this.dispatching = true;
this.brokers.forEach(function(b) {
if (b != from) {
b.brokeredClear();
}
});
} finally {
this.dispatching = false;
}
}
}
// Copyright 2015 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.
var Selection = function(handler) {
this.handler = handler;
this.selectionBase = null;
this.lastSelection = null;
this.selection = new Set();
}
Selection.prototype.isEmpty = function() {
return this.selection.size == 0;
}
Selection.prototype.clear = function() {
var handler = this.handler;
this.selectionBase = null;
this.lastSelection = null;
handler.select(this.selection, false);
handler.clear();
this.selection = new Set();
}
count = 0;
Selection.prototype.select = function(s, selected) {
var handler = this.handler;
if (this.selection.has(s) && !selected) {
handler.select([s], false);
this.selection.delete(s);
return;
}
if (selected) {
this.selection.add(s);
this.selectionBase = s;
this.lastSelection = s;
handler.select(this.selection, selected);
}
}
Selection.prototype.extendTo = function(pos) {
if (pos == this.lastSelection || this.lastSelection === null) return;
var handler = this.handler;
var pos_diff = handler.selectionDifference(pos, true, this.lastSelection, false);
var unselect_diff = [];
if (pos_diff.length == 0) {
pos_diff = handler.selectionDifference(this.selectionBase, false, pos, true);
if (pos_diff.length != 0) {
unselect_diff = handler.selectionDifference(this.lastSelection, true, this.selectionBase, false);
this.selection = new Set();
this.selection.add(this.selectionBase);
for (var d of pos_diff) {
this.selection.add(d);
}
} else {
unselect_diff = handler.selectionDifference(this.lastSelection, true, pos, false);
for (var d of unselect_diff) {
this.selection.delete(d);
}
}
} else {
unselect_diff = handler.selectionDifference(this.selectionBase, false, this.lastSelection, true);
if (unselect_diff != 0) {
pos_diff = handler.selectionDifference(pos, true, this.selectionBase, false);
if (pos_diff.length == 0) {
unselect_diff = handler.selectionDifference(pos, false, this.lastSelection, true);
}
for (var d of unselect_diff) {
this.selection.delete(d);
}
}
if (pos_diff.length != 0) {
for (var d of pos_diff) {
this.selection.add(d);
}
}
}
handler.select(unselect_diff, false);
handler.select(pos_diff, true);
this.lastSelection = pos;
}
Selection.prototype.detachSelection = function() {
var result = new Set();
for (var i of this.selection) {
result.add(i);
}
this.clear();
return result;
}
This diff is collapsed.
.visible-transition {
transition-delay: 0s;
transition-duration: 1s;
transition-property: all;
transition-timing-function: ease;
}
.collapse-pane {
background: #A0A0A0;
bottom: 0;
position: absolute;
margin-bottom: 0.5em;
margin-right: 0.5em;
margin-left: 0.5em;
border-radius: 5px;
padding: 0.5em;
z-index: 5;
opacity: 0.7;
}
.search-input {
vertical-align: middle;
width: 145px;
opacity: 1;
}
.button-input {
vertical-align: middle;
width: 24px;
opacity: 0.4;
cursor: pointer;
}
.button-input-toggled {
border-radius: 5px;
background-color: #505050;
}
.button-input:focus {
outline: none;
}
.button-input-invisible {
vertical-align: middle;
width: 0px;
visibility: hidden;
}
.selected {
background-color: #FFFF33;
}
.prettyprint ol.linenums > li {
list-style-type: decimal;
!important
}
body {
margin: 0;
padding: 0;
overflow:hidden;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
p {
text-align: center;
overflow: overlay;
position: relative;
}
marker {
fill: #080808;
}
g rect {
fill: #F0F0F0;
stroke: #080808;
stroke-width: 2px;
}
g.unsorted rect {
opacity: 0.5;
}
div.scrollable {
overflow-y: _croll; overflow-x: hidden;
}
g.control rect {
fill: #EFCC00;
stroke: #080808;
stroke-width: 5px;
}
g.javascript rect {
fill: #DD7E6B;
}
g.simplified rect {
fill: #3C78D8;
}
g.machine rect {
fill: #6AA84F;
}
g.input rect {
fill: #CFE2F3;
}
g.selected rect {
fill: #FFFF33;
}
circle.bubbleStyle {
fill: #080808;
fill-opacity: 0.0;
stroke: #080808;
stroke-width: 2px;
}
circle.bubbleStyle:hover {
stroke-width: 3px;
}
circle.filledBubbleStyle {
fill: #080808;
stroke: #080808;
stroke-width: 2px;
}
circle.filledBubbleStyle:hover {
fill: #080808;
stroke-width: 3px;
}
circle.halfFilledBubbleStyle {
fill: #808080;
stroke: #101010;
stroke-width: 2px;
}
circle.halfFilledBubbleStyle:hover {
fill: #808080;
stroke-width: 3px;
}
path.effect {
fill: none;
stroke: #080808;
stroke-width: 4px;
cursor: default;
}
path.effect:hover {
stroke-width: 6px;
}
path.control {
fill: none;
stroke: #080808;
stroke-width: 4px;
cursor: default;
}
path.control:hover {
stroke-width: 6px;
}
path.value {
fill: none;
stroke: #888888;
stroke-width: 4px;
cursor: default;
}
path.value:hover {
stroke-width: 6px;
}
path.frame-state {
fill: none;
stroke: #080808;
stroke-width: 4px;
cursor: default;
}
path.frame-state:hover{
stroke-width: 6px;
}
path.hidden {
fill: none;
stroke-width: 0;
}
path.link.selected {
stroke: #FFFF33;
}
pre.prettyprint {
border: none !important;
padding: 0px;
}
li.L1,
li.L3,
li.L5,
li.L7,
li.L9 {
background: none !important
}
li.nolinenums {
list-style-type:none;
}
ul.noindent {
-webkit-padding-start: 0px;
-webkit-margin-before: 0px;
-webkit-margin-after: 0px;
}
input:hover {
opacity: 1;
cursor: pointer;
}
span.linkable-text {
text-decoration: underline;
}
span.linkable-text:hover {
cursor: pointer;
font-weight: bold;
}
#left {
float: left; height: 100%; background-color: #FFFFFF;
-webkit-transition: all 1s ease-in-out;
-moz-transition: all 1s ease-in-out;
-o-transition: all 1s ease-in-out;
transition: all 1s ease-in-out;
transition-property: width;
transition-duration: 1s, 1s;
}
#middle {
float:left; height: 100%; background-color: #F8F8F8;
-webkit-transition: all 1s ease-in-out;
-moz-transition: all 1s ease-in-out;
-o-transition: all 1s ease-in-out;
transition: all 1s ease-in-out;
transition-property: width;
transition-duration: 1s, 1s;
}
#right {
float: right; background-color: #FFFFFF;
-webkit-transition: all 1s ease-in-out;
-moz-transition: all 1s ease-in-out;
-o-transition: all 1s ease-in-out;
transition: all 1s ease-in-out;
transition-property: width;
transition-duration: 1s, 1s;
}
#disassembly-collapse {
right: 0;
}
#source-collapse {
left: 0;
}
#graph-toolbox {
position: relative;
top: 1em;
left: 0.7em;
border: 2px solid #eee8d5;
border-radius: 5px;
padding: 0.7em;
z-index: 5;
}
#disassembly-collapse {
right: 0;
}
#source-collapse {
left: 0;
}
#graph-toolbox {
position: relative;
top: 1em;
left: 0.7em;
border: 2px solid #eee8d5;
border-radius: 5px;
padding: 0.7em;
z-index: 5;
}
#load-file {
background: #A0A0A0;
position: absolute;
top: 0;
right: 0;
margin-top: 0.5em;
margin-right: 0.5em;
border-radius: 5px;
padding: 0.5em;
z-index: 5;
opacity: 0.7;
}
#hidden-file-upload{
display: none;
}
// Copyright 2014 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.
document.onload = (function(d3){
"use strict";
var jsonObj;
var sourceExpandClassList = document.getElementById(SOURCE_EXPAND_ID).classList;
var sourceCollapseClassList = document.getElementById(SOURCE_COLLAPSE_ID).classList;
var sourceExpanded = sourceCollapseClassList.contains(COLLAPSE_PANE_BUTTON_VISIBLE);
var disassemblyExpandClassList = document.getElementById(DISASSEMBLY_EXPAND_ID).classList;
var disassemblyCollapseClassList = document.getElementById(DISASSEMBLY_COLLAPSE_ID).classList;
var disassemblyExpanded = disassemblyCollapseClassList.contains(COLLAPSE_PANE_BUTTON_VISIBLE);
var svg = null;
var graph = null;
var schedule = null;
var empty = null;
var currentPhaseView = null;
var disassemblyView = null;
var sourceView = null;
var selectionBroker = null;
function updatePanes() {
if (sourceExpanded) {
if (disassemblyExpanded) {
d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "30%");
d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "40%");
d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "30%");
} else {
d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "50%");
d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "50%");
d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "0%");
}
} else {
if (disassemblyExpanded) {
d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "0%");
d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "50%");
d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "50%");
} else {
d3.select("#" + SOURCE_PANE_ID).style(WIDTH, "0%");
d3.select("#" + INTERMEDIATE_PANE_ID).style(WIDTH, "100%");
d3.select("#" + GENERATED_PANE_ID).style(WIDTH, "0%");
}
}
}
function setSourceExpanded(newState) {
sourceExpanded = newState;
updatePanes();
if (newState) {
sourceCollapseClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
sourceCollapseClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
sourceExpandClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
sourceExpandClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
} else {
sourceCollapseClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
sourceCollapseClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
sourceExpandClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
sourceExpandClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
}
}
function setDisassemblyExpanded(newState) {
disassemblyExpanded = newState;
updatePanes();
if (newState) {
disassemblyCollapseClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
disassemblyCollapseClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
disassemblyExpandClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
disassemblyExpandClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
} else {
disassemblyCollapseClassList.add(COLLAPSE_PANE_BUTTON_INVISIBLE);
disassemblyCollapseClassList.remove(COLLAPSE_PANE_BUTTON_VISIBLE);
disassemblyExpandClassList.add(COLLAPSE_PANE_BUTTON_VISIBLE);
disassemblyExpandClassList.remove(COLLAPSE_PANE_BUTTON_INVISIBLE);
}
}
function hideCurrentPhase() {
var rememberedSelection = null;
if (currentPhaseView != null) {
rememberedSelection = currentPhaseView.detachSelection();
currentPhaseView.hide();
currentPhaseView = null;
}
return rememberedSelection;
}
function displayPhaseView(view, data) {
var rememberedSelection = hideCurrentPhase();
view.show(data, rememberedSelection);
d3.select("#middle").classed("scrollable", view.isScrollable());
currentPhaseView = view;
}
function displayPhase(phase) {
if (phase.type == 'graph') {
displayPhaseView(graph, phase.data);
} else if (phase.type == 'schedule') {
displayPhaseView(schedule, phase.data);
} else {
displayPhaseView(empty, null);
}
}
function fitPanesToParents() {
d3.select("#left").classed("scrollable", false)
d3.select("#right").classed("scrollable", false);
graph.fitGraphViewToWindow();
disassemblyView.resizeToParent();
sourceView.resizeToParent();
d3.select("#left").classed("scrollable", true);
d3.select("#right").classed("scrollable", true);
}
selectionBroker = new SelectionBroker();
function initializeHandlers(g) {
d3.select("#source-expand").on("click", function(){
setSourceExpanded(true);
setTimeout(function(){
g.fitGraphViewToWindow();
}, 1000);
});
d3.select("#source-shrink").on("click", function(){
setSourceExpanded(false);
setTimeout(function(){
g.fitGraphViewToWindow();
}, 1000);
});
d3.select("#disassembly-expand").on("click", function(){
setDisassemblyExpanded(true);
setTimeout(function(){
g.fitGraphViewToWindow();
}, 1000);
});
d3.select("#disassembly-shrink").on("click", function(){
setDisassemblyExpanded(false);
setTimeout(function(){
g.fitGraphViewToWindow();
}, 1000);
});
window.onresize = function(){
fitPanesToParents();
};
d3.select("#hidden-file-upload").on("change", function() {
if (window.File && window.FileReader && window.FileList) {
var uploadFile = this.files[0];
var filereader = new window.FileReader();
var consts = Node.consts;
filereader.onload = function(){
var txtRes = filereader.result;
// 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{
jsonObj = JSON.parse(txtRes);
sourceView.initializeCode(jsonObj.source, jsonObj.sourcePosition);
schedule.setNodePositionMap(jsonObj.nodePositions);
var selectMenu = document.getElementById('display-selector');
var disassemblyPhase = null;
selectMenu.innerHTML = '';
for (var i = 0; i < jsonObj.phases.length; ++i) {
var optionElement = document.createElement("option");
optionElement.text = jsonObj.phases[i].name;
if (optionElement.text == 'disassembly') {
disassemblyPhase = jsonObj.phases[i];
} else {
selectMenu.add(optionElement, null);
}
}
disassemblyView.setNodePositionMap(jsonObj.nodePositions);
disassemblyView.show(disassemblyPhase.data, null);
displayPhase(jsonObj.phases[0]);
selectMenu.onchange = function(item) {
displayPhase(jsonObj.phases[selectMenu.selectedIndex]);
}
fitPanesToParents();
}
catch(err) {
window.alert("Invalid TurboFan JSON file\n" +
"error: " + err.message);
return;
}
};
filereader.readAsText(uploadFile);
} else {
alert("Can't load graph");
}
});
}
sourceView = new CodeView(SOURCE_PANE_ID, PR, "", 0, selectionBroker);
disassemblyView = new DisassemblyView(DISASSEMBLY_PANE_ID, selectionBroker);
graph = new GraphView(d3, GRAPH_PANE_ID, [], [], selectionBroker);
schedule = new ScheduleView(SCHEDULE_PANE_ID, selectionBroker);
empty = new EmptyView(EMPTY_PANE_ID, selectionBroker);
initializeHandlers(graph);
setSourceExpanded(true);
setDisassemblyExpanded(false);
displayPhaseView(empty, null);
fitPanesToParents();
})(window.d3);
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
// Copyright 2015 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.
"use strict";
function makeContainerPosVisible(container, pos) {
var height = container.offsetHeight;
var margin = Math.floor(height / 4);
if (pos < container.scrollTop + margin) {
pos -= margin;
if (pos < 0) pos = 0;
container.scrollTop = pos;
return;
}
if (pos > (container.scrollTop + 3 * margin)) {
pos = pos - 3 * margin;
if (pos < 0) pos = 0;
container.scrollTop = pos;
}
}
function lowerBound(a, value, compare, lookup) {
let first = 0;
let count = a.length;
while (count > 0) {
let step = Math.floor(count / 2);
let middle = first + step;
let middle_value = (lookup === undefined) ? a[middle] : lookup(a, middle);
let result = (compare === undefined) ? (middle_value < value) : compare(middle_value, value);
if (result) {
first = middle + 1;
count -= step + 1;
} else {
count = step;
}
}
return first;
}
function upperBound(a, value, compare, lookup) {
let first = 0;
let count = a.length;
while (count > 0) {
let step = Math.floor(count / 2);
let middle = first + step;
let middle_value = (lookup === undefined) ? a[middle] : lookup(a, middle);
let result = (compare === undefined) ? (value < middle_value) : compare(value, middle_value);
if (!result) {
first = middle + 1;
count -= step + 1;
} else {
count = step;
}
}
return first;
}
function sortUnique(arr, f) {
arr = arr.sort(f);
let ret = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i-1] !== arr[i]) {
ret.push(arr[i]);
}
}
return ret;
}
// Copyright 2015 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.
"use strict";
class View {
constructor(id, broker) {
this.divElement = d3.select("#" + id);
this.divNode = this.divElement[0][0];
this.parentNode = this.divNode.parentNode;
this.hide();
}
isScrollable() {
return false;
}
show(data, rememberedSelection) {
this.parentNode.appendChild(this.divElement[0][0]);
this.initializeContent(data, rememberedSelection);
this.resizeToParent();
this.divElement.attr(VISIBILITY, 'visible');
}
resizeToParent() {
var view = this;
var documentElement = document.documentElement;
var y = this.parentNode.clientHeight || documentElement.clientHeight;
this.parentNode.style.height = y + 'px';
}
hide() {
this.divElement.attr(VISIBILITY, 'hidden');
this.deleteContent();
this.parentNode.removeChild(this.divNode);
}
detachSelection() {
return null;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment