Commit ee0eb614 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[turbolizer] Improve disassembly view

This CL makes both absolute address and opcode literal (byte sequence
of the instruction) display optional, which improves readability.

Additionally, jump offsets are parsed and can now once again be clicked.

TBR=neis@chromium.org

Bug: v8:7327
Notry: true
Change-Id: I709f44540b32f6d4afabdd1e5eb27e932208e7fc
Reviewed-on: https://chromium-review.googlesource.com/c/1388540
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58444}
parent 9365d090
......@@ -10,6 +10,13 @@ import { MySelection } from "./selection";
import { anyToString } from "./util";
import { InstructionSelectionHandler } from "./selection-handler";
const toolboxHTML = `<div id="disassembly-toolbox">
<form>
<input id="show-instruction-address" type="checkbox" name="instruction-address">Show addresses</input>
<input id="show-instruction-binary" type="checkbox" name="instruction-binary">Show binary literal</input>
</form>
</div>`
export class DisassemblyView extends TextView {
SOURCE_POSITION_HEADER_REGEX: any;
addr_event_counts: any;
......@@ -18,6 +25,8 @@ export class DisassemblyView extends TextView {
pos_lines: Array<any>;
instructionSelectionHandler: InstructionSelectionHandler;
offsetSelection: MySelection;
showInstructionAddressHandler: () => void;
showInstructionBinaryHandler: () => void;
createViewElement() {
const pane = document.createElement('div');
......@@ -32,43 +41,63 @@ export class DisassemblyView extends TextView {
}
constructor(parentId, broker: SelectionBroker) {
super(parentId, broker, null);
super(parentId, broker);
let view = this;
let ADDRESS_STYLE = {
css: ['linkable-text', 'tag'],
associateData: (text, fragment) => {
const matches = text.match(/0?x?[0-9a-fA-F]{8,16}\s*(?<offset>[0-9a-f]+)/);
associateData: (text, fragment: HTMLElement) => {
const matches = text.match(/(?<address>0?x?[0-9a-fA-F]{8,16})(?<addressSpace>\s+)(?<offset>[0-9a-f]+)(?<offsetSpace>\s*)/);
const offset = Number.parseInt(matches.groups["offset"], 16);
const addressElement = document.createElement("SPAN");
addressElement.className = "instruction-address";
addressElement.innerText = matches.groups["address"];
const offsetElement = document.createElement("SPAN");
offsetElement.innerText = matches.groups["offset"];
fragment.appendChild(addressElement);
fragment.appendChild(document.createTextNode(matches.groups["addressSpace"]))
fragment.appendChild(offsetElement);
fragment.appendChild(document.createTextNode(matches.groups["offsetSpace"]))
fragment.classList.add('tag');
if (!Number.isNaN(offset)) {
fragment.dataset.pcOffset = view.sourceResolver.getKeyPcOffset(offset);
const pcOffset = view.sourceResolver.getKeyPcOffset(offset);
fragment.dataset.pcOffset = `${pcOffset}`;
addressElement.classList.add('linkable-text');
offsetElement.classList.add('linkable-text');
}
}
};
let ADDRESS_LINK_STYLE = {
css: 'tag'
};
let UNCLASSIFIED_STYLE = {
css: 'com'
};
let NUMBER_STYLE = {
css: 'lit'
css: ['instruction-binary', 'lit']
};
let COMMENT_STYLE = {
css: 'com'
};
let POSITION_STYLE = {
css: 'com',
let OPCODE_ARGS = {
associateData: function (text, fragment) {
fragment.innerHTML = text;
const replacer = (match, hexOffset, stringOffset, string) => {
const offset = Number.parseInt(hexOffset, 16);
const keyOffset = view.sourceResolver.getKeyPcOffset(offset)
return `<span class="tag linkable-text" data-pc-offset="${keyOffset}">${match}</span>`
}
const html = text.replace(/<.0?x?([0-9a-fA-F]+)>/g, replacer)
fragment.innerHTML = html;
}
};
let OPCODE_STYLE = {
css: 'kwd',
css: 'kwd'
};
const BLOCK_HEADER_STYLE = {
css: ['com', 'block'],
associateData: function (text, fragment) {
let matches = /\d+/.exec(text);
if (!matches) return;
const blockId = matches[0];
fragment.dataset.blockId = blockId;
fragment.innerHTML = text;
fragment.className = "com block";
}
};
const SOURCE_POSITION_HEADER_STYLE = {
......@@ -77,47 +106,38 @@ export class DisassemblyView extends TextView {
view.SOURCE_POSITION_HEADER_REGEX = /^\s*--[^<]*<.*(not inlined|inlined\((\d+)\)):(\d+)>\s*--/;
let patterns = [
[
[/^0?x?[0-9a-fA-F]{8,16}\s*[0-9a-f]+\ /, ADDRESS_STYLE, 1],
[/^0?x?[0-9a-fA-F]{8,16}\s+[0-9a-f]+\s+/, 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],
[/^\s*[0-9a-f]+\s+/, NUMBER_STYLE, 2],
[/^\s*[0-9a-f]+\s+[0-9a-f]+\s+/, NUMBER_STYLE, 2],
[/^.*/, null, -1]
],
[
[/^REX.W \S+\s+/, OPCODE_STYLE, 3],
[/^\S+\s+/, OPCODE_STYLE, 3],
[/^\S+$/, OPCODE_STYLE, -1],
[/^.*/, null, -1]
],
[
[/^\s+/, null],
[/^[^\(;]+$/, null, -1],
[/^[^\(;]+/, null],
[/^\(/, null, 4],
[/^[^;]+$/, OPCODE_ARGS, -1],
[/^[^;]+/, OPCODE_ARGS, 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);
const linkHandler = (e) => {
const offset = e.target.dataset.pcOffset;
if (typeof offset != "undefined" && !Number.isNaN(offset)) {
const linkHandler = (e: MouseEvent) => {
if (!(e.target instanceof HTMLElement)) return;
const offset = e.target.dataset.pcOffset ? e.target.dataset.pcOffset : e.target.parentElement.dataset.pcOffset;
if ((typeof offset) != "undefined" && !Number.isNaN(Number(offset))) {
view.offsetSelection.select([offset], true);
const [nodes, blockId] = view.sourceResolver.nodesForPCOffset(offset)
if (nodes.length > 0) {
......@@ -171,6 +191,34 @@ export class DisassemblyView extends TextView {
};
this.instructionSelectionHandler = instructionSelectionHandler;
broker.addInstructionHandler(instructionSelectionHandler);
const toolbox = document.createElement("div")
toolbox.id = "toolbox-anchor";
toolbox.innerHTML = toolboxHTML
view.divNode.insertBefore(toolbox, view.divNode.firstChild);
const instructionAddressInput: HTMLInputElement = view.divNode.querySelector("#show-instruction-address");
const lastShowInstructionAddress = window.sessionStorage.getItem("show-instruction-address");
instructionAddressInput.checked = lastShowInstructionAddress == 'true';
const showInstructionAddressHandler = () => {
window.sessionStorage.setItem("show-instruction-address", `${instructionAddressInput.checked}`);
for (const el of view.divNode.querySelectorAll(".instruction-address")) {
el.classList.toggle("invisible", !instructionAddressInput.checked);
}
};
instructionAddressInput.addEventListener("change", showInstructionAddressHandler);
this.showInstructionAddressHandler = showInstructionAddressHandler;
const instructionBinaryInput: HTMLInputElement = view.divNode.querySelector("#show-instruction-binary");
const lastShowInstructionBinary = window.sessionStorage.getItem("show-instruction-binary");
instructionBinaryInput.checked = lastShowInstructionAddress == 'true';
const showInstructionBinaryHandler = () => {
window.sessionStorage.setItem("show-instruction-binary", `${instructionBinaryInput.checked}`);
for (const el of view.divNode.querySelectorAll(".instruction-binary")) {
el.classList.toggle("invisible", !instructionBinaryInput.checked);
}
};
instructionBinaryInput.addEventListener("change", showInstructionBinaryHandler);
this.showInstructionBinaryHandler = showInstructionBinaryHandler;
}
updateSelection(scrollIntoView: boolean = false) {
......@@ -231,6 +279,14 @@ export class DisassemblyView extends TextView {
}
}
initializeContent(data, rememberedSelection) {
console.time("disassembly-view")
super.initializeContent(data, rememberedSelection);
this.showInstructionAddressHandler();
this.showInstructionBinaryHandler();
console.timeEnd("disassembly-view")
}
// Shorten decimals and remove trailing zeroes for readability.
humanize(num) {
return num.toFixed(3).replace(/\.?0+$/, "") + "%";
......
......@@ -12,7 +12,7 @@ import { View, PhaseView } from "../src/view"
const multiviewID = "multiview";
const toolboxHTML = `
<div id="graph-toolbox">
<div class="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="toggle-hide-dead" type="image" title="show only live nodes" src="live.png" alt="only live nodes"
......@@ -53,7 +53,7 @@ export class GraphMultiView extends View {
view.sourceResolver = sourceResolver;
view.selectionBroker = selectionBroker;
const toolbox = document.createElement("div")
toolbox.id = "graph-toolbox-anchor";
toolbox.className = "toolbox-anchor";
toolbox.innerHTML = toolboxHTML
view.divNode.appendChild(toolbox);
const searchInput = toolbox.querySelector("#search-input") as HTMLInputElement;
......
......@@ -18,7 +18,7 @@ export class ScheduleView extends TextView implements PhaseView {
}
constructor(parentId, broker) {
super(parentId, broker, null);
super(parentId, broker);
this.sourceResolver = broker.sourceResolver;
}
......
......@@ -19,7 +19,7 @@ export class SequenceView extends TextView implements PhaseView {
}
constructor(parentId, broker) {
super(parentId, broker, null);
super(parentId, broker);
}
attachSelection(s) {
......
......@@ -23,11 +23,11 @@ export abstract class TextView extends View {
sourceResolver: SourceResolver;
broker: SelectionBroker;
constructor(id, broker, patterns) {
constructor(id, broker) {
super(id);
let view = this;
view.textListNode = view.divNode.getElementsByTagName('ul')[0];
view.patterns = patterns;
view.patterns = null;
view.nodeIdToHtmlElementsMap = new Map();
view.blockIdToHtmlElementsMap = new Map();
view.blockIdtoNodeIds = new Map();
......@@ -157,8 +157,7 @@ export abstract class TextView extends View {
}
setPatterns(patterns) {
let view = this;
view.patterns = patterns;
this.patterns = patterns;
}
clearText() {
......@@ -172,25 +171,18 @@ export abstract class TextView extends View {
let view = this;
let fragment = document.createElement("SPAN");
if (typeof style.link == 'function') {
fragment.classList.add('linkable-text');
fragment.onmouseup = function (e) {
e.stopPropagation();
style.link(text)
};
}
if (typeof style.associateData == 'function') {
style.associateData(text, fragment);
}
if (style.css != undefined) {
const css = isIterable(style.css) ? style.css : [style.css];
for (const cls of css) {
fragment.classList.add(cls);
} else {
if (style.css != undefined) {
const css = isIterable(style.css) ? style.css : [style.css];
for (const cls of css) {
fragment.classList.add(cls);
}
}
fragment.innerHTML = text;
}
fragment.innerHTML = text;
return fragment;
}
......
......@@ -226,9 +226,9 @@ window.onload = function () {
const jsonObj = JSON.parse(txtRes);
let fnc = Object.assign(jsonObj.function, {backwardsCompatibility: false});
let fnc = null
// Backwards compatibility.
if (typeof fnc == 'string') {
if (typeof jsonObj.function == 'string') {
fnc = {
functionName: fnc,
sourceId: -1,
......@@ -237,6 +237,8 @@ window.onload = function () {
sourceText: jsonObj.source,
backwardsCompatibility: true
};
} else {
fnc = Object.assign(jsonObj.function, {backwardsCompatibility: false});
}
sourceResolver.setInlinings(jsonObj.inlinings);
......
......@@ -337,11 +337,11 @@ input:hover, .collapse-pane:hover input {
height: 100%;
}
#graph-toolbox-anchor {
.toolbox-anchor {
height: 0px;
}
#graph-toolbox {
.graph-toolbox {
position: relative;
border-bottom: 2px solid #eee8d5;
padding-bottom: 3px;
......@@ -353,14 +353,15 @@ input:hover, .collapse-pane:hover input {
margin-right: 4px;
}
#disassembly-toolbox {
.disassembly-toolbox {
position: relative;
top: 1em;
left: 0.7em;
border: 2px solid #eee8d5;
border-radius: 5px;
padding: 0.7em;
padding-bottom: 3px;
z-index: 5;
background: rgba(100%, 100%, 100%, 0.7);
padding-top: 3px;
box-sizing: border-box;
margin-left: 4px;
margin-right: 4px;
}
#load-file {
......
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