Commit 0b4552c7 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[turbolizer] Display instruction ranges in turbolizer

Bug: v8:7327
Change-Id: I8cd57abf612393852532a695663175dff8e3a199
Reviewed-on: https://chromium-review.googlesource.com/1098955
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53713}
parent e5e15e57
......@@ -255,9 +255,10 @@ class CodeView extends View {
}
lineElement.insertBefore(lineNumberElement, lineElement.firstChild)
// Don't add lines to source positions of not in backwardsCompatibility mode.
if (typeof this.source['backwardsCompatibility'] === undefined) return;
for (const sourcePosition of this.sourceResolver.linetoSourcePositions(lineNumber - 1)) {
view.addHtmlElementToSourcePosition(sourcePosition, lineElement);
if (this.source.backwardsCompatibility === true) {
for (const sourcePosition of this.sourceResolver.linetoSourcePositions(lineNumber - 1)) {
view.addHtmlElementToSourcePosition(sourcePosition, lineElement);
}
}
}
......
......@@ -22,23 +22,33 @@ class DisassemblyView extends TextView {
return pane;
}
constructor(parentId, broker) {
constructor(parentId, broker: SelectionBroker) {
super(parentId, broker, null);
let view = this;
const sourceResolver = broker.sourceResolver;
let ADDRESS_STYLE = {
css: 'tag',
assignSourcePosition: function (text) {
return SOURCE_POSITION_HEADER_STYLE.currentSourcePosition;
},
linkHandler: function (text, fragment) {
if (fragment.sourcePosition === undefined) return undefined;
return (e) => {
e.stopPropagation();
if (!e.shiftKey) {
view.sourcePositionSelectionHandler.clear();
const matches = text.match(/0x[0-9a-f]{8,16}\s*(?<offset>[0-9a-f]+)/);
const offset = Number.parseInt(matches.groups["offset"], 16);
if (!Number.isNaN(offset)) {
const [nodes, blockId] = sourceResolver.nodesForPCOffset(offset)
console.log("nodes for", offset, offset.toString(16), " are ", nodes);
if (nodes.length > 0) {
for (const nodeId of nodes) {
view.addHtmlElementForNodeId(nodeId, fragment);
}
return (e) => {
console.log(offset, nodes);
e.stopPropagation();
if (!e.shiftKey) {
view.selectionHandler.clear();
}
view.selectionHandler.select(nodes, true);
};
}
view.sourcePositionSelectionHandler.select([fragment.sourcePosition], true);
};
}
return undefined;
}
};
let ADDRESS_LINK_STYLE = {
......@@ -82,27 +92,18 @@ class DisassemblyView extends TextView {
}
};
const SOURCE_POSITION_HEADER_STYLE = {
css: 'com',
currentSourcePosition: undefined,
sourcePosition: function (text) {
let matches = view.SOURCE_POSITION_HEADER_REGEX.exec(text);
if (!matches) return undefined;
const scriptOffset = Number(matches[3]);
const inliningId = matches[1] === 'not inlined' ? -1 : Number(matches[2]);
const sp = { scriptOffset: scriptOffset, inliningId: inliningId };
SOURCE_POSITION_HEADER_STYLE.currentSourcePosition = sp;
return sp;
},
css: 'com'
};
view.SOURCE_POSITION_HEADER_REGEX = /^\s*--[^<]*<.*(not inlined|inlined\((\d+)\)):(\d+)>\s*--/;
let patterns = [
[
[/^0x[0-9a-f]{8,16}/, ADDRESS_STYLE, 1],
[/^0x[0-9a-f]{8,16}\s*[0-9a-f]+\ /, ADDRESS_STYLE, 1],
[view.SOURCE_POSITION_HEADER_REGEX, SOURCE_POSITION_HEADER_STYLE, -1],
[/^\s+-- B\d+ start.*/, BLOCK_HEADER_STYLE, -1],
[/^.*/, UNCLASSIFIED_STYLE, -1]
],
[
[/^\s+[0-9a-f]+\s+/, NUMBER_STYLE, 2],
[/^\s+[0-9a-f]+\s+[0-9a-f]+\s+/, NUMBER_STYLE, 2],
[/^.*/, null, -1]
],
......
......@@ -6,20 +6,17 @@
class ScheduleView extends TextView implements PhaseView {
schedule: Schedule;
sourceResolver: SourceResolver;
createViewElement() {
const pane = document.createElement('div');
pane.setAttribute('id', "schedule");
pane.innerHTML =
`<pre id='schedule-text-pre' class='prettyprint prettyprinted'>
<ul id='schedule-list' class='nolinenums noindent'>
</ul>
</pre>`;
return pane;
}
constructor(parentId, broker) {
super(parentId, broker, null);
this.sourceResolver = broker.sourceResolver;
}
attachSelection(s) {
......@@ -27,19 +24,29 @@ class ScheduleView extends TextView implements PhaseView {
if (!(s instanceof Set)) return;
view.selectionHandler.clear();
view.blockSelectionHandler.clear();
view.sourcePositionSelectionHandler.clear();
const selected = new Array();
for (const key of s) selected.push(key);
view.selectionHandler.select(selected, true);
}
detachSelection() {
this.blockSelection.clear();
return this.selection.detachSelection();
}
initializeContent(data, rememberedSelection) {
this.divNode.innerHTML = '';
this.schedule = data.schedule
this.addBlocks(data.schedule.blocks);
this.attachSelection(rememberedSelection);
}
createElementFromString(htmlString) {
var div = document.createElement('div');
div.innerHTML = htmlString.trim();
return div.firstChild;
}
elementForBlock(block) {
const view = this;
function createElement(tag: string, cls: string | Array<string>, content?: string) {
......@@ -63,8 +70,31 @@ class ScheduleView extends TextView implements PhaseView {
};
}
function getMarker(start, end) {
if (start != end) {
return ["&#8857;", `This node generated instructions in range [${start},${end}). ` +
`This is currently unreliable for constants.`];
}
if (start != -1) {
return ["&#183;", `The instruction selector did not generate instructions ` +
`for this node, but processed the node at instruction ${start}. ` +
`This usually means that this node was folded into another node; ` +
`the highlighted machine code is a guess.`];
}
return ["", `This not is not in the final schedule.`]
}
function createElementForNode(node) {
const nodeEl = createElement("div", "node");
const [start, end] = view.sourceResolver.getInstruction(node.id);
const [marker, tooltip] = getMarker(start, end);
const instrMarker = createElement("div", ["instr-marker", "com"], marker);
instrMarker.setAttribute("title", tooltip);
instrMarker.onclick = mkNodeLinkHandler(node.id);
nodeEl.appendChild(instrMarker);
const node_id = createElement("div", ["node-id", "tag", "clickable"], node.id);
node_id.onclick = mkNodeLinkHandler(node.id);
view.addHtmlElementForNodeId(node.id, node_id);
......@@ -81,6 +111,7 @@ class ScheduleView extends TextView implements PhaseView {
}
nodeEl.appendChild(node_parameters);
}
return nodeEl;
}
......@@ -95,6 +126,13 @@ class ScheduleView extends TextView implements PhaseView {
}
const schedule_block = createElement("div", "schedule-block");
const [start, end] = view.sourceResolver.getInstructionRangeForBlock(block.id);
const instrMarker = createElement("div", ["instr-marker", "com"], "&#8857;");
instrMarker.setAttribute("title", `Instructions range for this block is [${start}, ${end})`)
instrMarker.onclick = mkBlockLinkHandler(block.id);
schedule_block.appendChild(instrMarker);
const block_id = createElement("div", ["block-id", "com", "clickable"], block.id);
block_id.onclick = mkBlockLinkHandler(block.id);
schedule_block.appendChild(block_id);
......@@ -128,19 +166,6 @@ class ScheduleView extends TextView implements PhaseView {
}
}
initializeContent(data, rememberedSelection) {
this.clearText();
this.schedule = data.schedule
this.addBlocks(data.schedule.blocks);
this.attachSelection(rememberedSelection);
}
detachSelection() {
this.blockSelection.clear();
this.sourcePositionSelection.clear();
return this.selection.detachSelection();
}
lineString(node) {
return `${node.id}: ${node.label}(${node.inputs.join(", ")})`
}
......
......@@ -84,6 +84,10 @@ class SourceResolver {
phaseNames: Map<string, number>;
disassemblyPhase: Phase;
lineToSourcePositions: Map<string, Array<AnyPosition>>;
nodeIdToInstructionRange: Array<[number, number]>;
blockIdToInstructionRange: Array<[number, number]>;
instructionToPCOffset: Array<number>;
pcOffsetToInstructions: Map<number, Array<number>>;
constructor() {
......@@ -105,6 +109,14 @@ class SourceResolver {
this.disassemblyPhase = undefined;
// Maps line numbers to source positions
this.lineToSourcePositions = new Map();
// Maps node ids to instruction ranges.
this.nodeIdToInstructionRange = [];
// Maps block ids to instruction ranges.
this.blockIdToInstructionRange = [];
// Maps instruction numbers to PC offsets.
this.instructionToPCOffset = [];
// Maps PC offsets to instructions.
this.pcOffsetToInstructions = new Map();
}
setSources(sources, mainBackup) {
......@@ -298,6 +310,72 @@ class SourceResolver {
}
}
readNodeIdToInstructionRange(nodeIdToInstructionRange) {
for (const [nodeId, range] of Object.entries<[number, number]>(nodeIdToInstructionRange)) {
this.nodeIdToInstructionRange[nodeId] = range;
}
}
readBlockIdToInstructionRange(blockIdToInstructionRange) {
for (const [blockId, range] of Object.entries<[number, number]>(blockIdToInstructionRange)) {
this.blockIdToInstructionRange[blockId] = range;
}
}
getInstruction(nodeId):[number, number] {
const X = this.nodeIdToInstructionRange[nodeId];
if (X === undefined) return [-1, -1];
return X;
}
getInstructionRangeForBlock(blockId):[number, number] {
const X = this.blockIdToInstructionRange[blockId];
if (X === undefined) return [-1, -1];
return X;
}
readInstructionOffsetToPCOffset(instructionToPCOffset) {
for (const [instruction, offset] of Object.entries<number>(instructionToPCOffset)) {
this.instructionToPCOffset[instruction] = offset;
if (!this.pcOffsetToInstructions.has(offset)) {
this.pcOffsetToInstructions.set(offset, []);
}
this.pcOffsetToInstructions.get(offset).push(instruction);
}
console.log(this.pcOffsetToInstructions);
}
hasPCOffsets() {
return this.pcOffsetToInstructions.size > 0;
}
nodesForPCOffset(offset): [Array<String>, Array<String>] {
const keys = Array.from(this.pcOffsetToInstructions.keys()).sort((a, b) => b - a);
if (keys.length === 0) return [[],[]];
for (const key of keys) {
if (key <= offset) {
const instrs = this.pcOffsetToInstructions.get(key);
const nodes = [];
const blocks = [];
for (const instr of instrs) {
for (const [nodeId, range] of this.nodeIdToInstructionRange.entries()) {
if (!range) continue;
const [start, end] = range;
if (start == end && instr == start) {
nodes.push("" + nodeId);
}
if (start <= instr && instr < end) {
nodes.push("" + nodeId);
}
}
}
return [nodes, blocks];
}
}
return [[],[]];
}
parsePhases(phases) {
for (const [phaseId, phase] of Object.entries<Phase>(phases)) {
if (phase.type == 'disassembly') {
......@@ -305,6 +383,16 @@ class SourceResolver {
} else if (phase.type == 'schedule') {
this.phases.push(this.parseSchedule(phase))
this.phaseNames.set(phase.name, this.phases.length);
} else if (phase.type == 'instructions') {
if (phase.nodeIdToInstructionRange) {
this.readNodeIdToInstructionRange(phase.nodeIdToInstructionRange);
}
if (phase.blockIdtoInstructionRange) {
this.readBlockIdToInstructionRange(phase.blockIdtoInstructionRange);
}
if (phase.instructionOffsetToPCOffset) {
this.readInstructionOffsetToPCOffset(phase.instructionOffsetToPCOffset);
}
} else {
this.phases.push(phase);
this.recordOrigins(phase);
......
......@@ -12,14 +12,11 @@ abstract class TextView extends View {
selectionHandler: NodeSelectionHandler;
blockSelectionHandler: BlockSelectionHandler;
nodeSelectionHandler: NodeSelectionHandler;
sourcePositionSelectionHandler: SelectionHandler;
selection: MySelection;
blockSelection: MySelection;
sourcePositionSelection: MySelection;
textListNode: HTMLUListElement;
nodeIdToHtmlElementsMap: Map<string, Array<HTMLElement>>;
blockIdToHtmlElementsMap: Map<string, Array<HTMLElement>>;
sourcePositionToHtmlElementsMap: Map<string, Array<HTMLElement>>;
blockIdtoNodeIds: Map<string, Array<string>>;
nodeIdToBlockId: Array<string>;
patterns: any;
......@@ -31,12 +28,10 @@ abstract class TextView extends View {
view.patterns = patterns;
view.nodeIdToHtmlElementsMap = new Map();
view.blockIdToHtmlElementsMap = new Map();
view.sourcePositionToHtmlElementsMap = new Map();
view.blockIdtoNodeIds = new Map();
view.nodeIdToBlockId = [];
view.selection = new MySelection(anyToString);
view.blockSelection = new MySelection(anyToString);
view.sourcePositionSelection = new MySelection(sourcePositionToStringKey);
const selectionHandler = {
clear: function () {
view.selection.clear();
......@@ -45,17 +40,12 @@ abstract class TextView extends View {
},
select: function (nodeIds, selected) {
view.selection.select(nodeIds, selected);
const blockIds = view.blockIdsForNodeIds(nodeIds);
view.blockSelection.select(blockIds, selected);
view.updateSelection();
broker.broadcastNodeSelect(selectionHandler, view.selection.selectedKeys(), selected);
broker.broadcastBlockSelect(view.blockSelectionHandler, blockIds, selected);
},
brokeredNodeSelect: function (nodeIds, selected) {
const firstSelect = view.blockSelection.isEmpty();
view.selection.select(nodeIds, selected);
const blockIds = view.blockIdsForNodeIds(nodeIds);
view.blockSelection.select(blockIds, selected);
view.updateSelection(firstSelect);
},
brokeredClear: function () {
......@@ -93,29 +83,6 @@ abstract class TextView extends View {
};
this.blockSelectionHandler = blockSelectionHandler;
broker.addBlockHandler(blockSelectionHandler);
const sourcePositionSelectionHandler = {
clear: function () {
view.sourcePositionSelection.clear();
view.updateSelection();
broker.broadcastClear(sourcePositionSelectionHandler);
},
select: function (sourcePositions, selected) {
view.sourcePositionSelection.select(sourcePositions, selected);
view.updateSelection();
broker.broadcastSourcePositionSelect(sourcePositionSelectionHandler, sourcePositions, selected);
},
brokeredSourcePositionSelect: function (sourcePositions, selected) {
const firstSelect = view.sourcePositionSelection.isEmpty();
view.sourcePositionSelection.select(sourcePositions, selected);
view.updateSelection(firstSelect);
},
brokeredClear: function () {
view.sourcePositionSelection.clear();
view.updateSelection();
}
};
view.sourcePositionSelectionHandler = sourcePositionSelectionHandler;
broker.addSourcePositionHandler(sourcePositionSelectionHandler);
}
addHtmlElementForNodeId(anyNodeId: any, htmlElement: HTMLElement) {
......@@ -126,14 +93,6 @@ abstract class TextView extends View {
this.nodeIdToHtmlElementsMap.get(nodeId).push(htmlElement);
}
addHtmlElementForSourcePosition(sourcePosition, htmlElement) {
const key = sourcePositionToStringKey(sourcePosition);
if (!this.sourcePositionToHtmlElementsMap.has(key)) {
this.sourcePositionToHtmlElementsMap.set(key, []);
}
this.sourcePositionToHtmlElementsMap.get(key).push(htmlElement);
}
addHtmlElementForBlockId(anyBlockId, htmlElement) {
const blockId = anyToString(anyBlockId);
if (!this.blockIdToHtmlElementsMap.has(blockId)) {
......@@ -165,13 +124,6 @@ abstract class TextView extends View {
if (this.divNode.parentNode == null) return;
const mkVisible = new ViewElements(this.divNode.parentNode as HTMLElement);
const view = this;
for (const [nodeId, elements] of this.nodeIdToHtmlElementsMap.entries()) {
const isSelected = view.selection.isSelected(nodeId);
for (const element of elements) {
mkVisible.consider(element, isSelected);
element.classList.toggle("selected", isSelected);
}
}
for (const [blockId, elements] of this.blockIdToHtmlElementsMap.entries()) {
const isSelected = view.blockSelection.isSelected(blockId);
for (const element of elements) {
......@@ -179,11 +131,17 @@ abstract class TextView extends View {
element.classList.toggle("selected", isSelected);
}
}
for (const [sourcePositionKey, elements] of this.sourcePositionToHtmlElementsMap.entries()) {
const isSelected = view.sourcePositionSelection.isKeySelected(sourcePositionKey);
for (const key of this.nodeIdToHtmlElementsMap.keys()) {
for (const element of this.nodeIdToHtmlElementsMap.get(key)) {
element.classList.toggle("selected", false);
}
}
for (const nodeId of view.selection.selectedKeys()) {
const elements = this.nodeIdToHtmlElementsMap.get(nodeId);
if (!elements) continue;
for (const element of elements) {
mkVisible.consider(element, isSelected);
element.classList.toggle("selected", isSelected);
mkVisible.consider(element, true);
element.classList.toggle("selected", true);
}
}
mkVisible.apply(scrollIntoView);
......@@ -229,19 +187,6 @@ abstract class TextView extends View {
}
}
if (typeof style.sourcePosition === 'function') {
const sourcePosition = style.sourcePosition(text);
if (sourcePosition != undefined) {
fragment.sourcePosition = sourcePosition;
//this.addHtmlElementForNodeId(nodeId, fragment);
}
}
if (typeof style.assignSourcePosition === 'function') {
fragment.sourcePosition = style.assignSourcePosition();
this.addHtmlElementForSourcePosition(fragment.sourcePosition, fragment)
}
if (typeof style.assignBlockId === 'function') {
fragment.blockId = style.assignBlockId();
this.addNodeIdToBlockId(fragment.nodeId, fragment.blockId);
......@@ -310,7 +255,7 @@ abstract class TextView extends View {
for (let line of textLines) {
let li = document.createElement("LI");
li.className = "nolinenums";
li.lineNo = lineNo++;
li.dataset.lineNo = "" + lineNo++;
let fragments = view.processLine(line);
for (let fragment of fragments) {
li.appendChild(fragment);
......
{
"tabSize": 2,
"indentSize": 2,
"convertTabsToSpaces": true,
"insertSpaceAfterCommaDelimiter": true,
"insertSpaceAfterSemicolonInForStatements": true,
"insertSpaceBeforeAndAfterBinaryOperators": true,
"insertSpaceAfterKeywordsInControlFlowStatements": true,
"insertSpaceAfterFunctionKeywordForAnonymousFunctions": true,
"insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false,
"insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false,
"insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false,
"insertSpaceBeforeFunctionParenthesis": false,
"placeOpenBraceOnNewLineForFunctions": false,
"placeOpenBraceOnNewLineForControlBlocks": false
"tabSize": 2,
"indentSize": 2,
"convertTabsToSpaces": true,
"insertSpaceAfterCommaDelimiter": true,
"insertSpaceAfterSemicolonInForStatements": true,
"insertSpaceBeforeAndAfterBinaryOperators": true,
"insertSpaceAfterKeywordsInControlFlowStatements": true,
"insertSpaceAfterFunctionKeywordForAnonymousFunctions": true,
"insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false,
"insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false,
"insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false,
"insertSpaceBeforeFunctionParenthesis": false,
"placeOpenBraceOnNewLineForFunctions": false,
"placeOpenBraceOnNewLineForControlBlocks": false
}
\ No newline at end of file
......@@ -487,17 +487,20 @@ text {
#schedule {
font-family: monospace;
margin-top: 50px;
}
.schedule-block {
margin: 5px;
background-color: white;
padding-left: 5px;
}
.schedule-block .block-id {
display: inline-block;
font-size:large;
text-decoration: underline;
padding-left: 1ex;
}
.schedule-block .block-id:hover {
......@@ -538,10 +541,6 @@ text {
padding-right: 1ex;
}
.schedule-block .nodes {
padding-left: 5px;
}
.schedule-block .nodes .node * {
display:inline-block;
}
......@@ -568,6 +567,18 @@ text {
content: ")";
}
.schedule-block .instr-marker {
padding-right: .5ex;
padding-left: .5ex;
min-width: 1ex;
background: #EEEEEE;
/* display: none; */
}
.schedule-block > .instr-marker {
display: inline;
}
.clickable:hover {
text-decoration: underline;
}
......
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