Commit 0382ca40 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[turbolizer] Improve load time of code and disassembly view

This CL improves load times by up to 6x. This is achieved by not setting
event handlers per-line, but setting one event handler on the container.

Unfortunately, load times are dominated by the graph view, which needs
to be addressed in another CL.

Bug: v8:7327
Notry: true
Change-Id: Ie9a999f4150617fd763b770fcacca6096f457880
Reviewed-on: https://chromium-review.googlesource.com/c/1384312Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58370}
parent 635f938f
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import { PROF_COLS, UNICODE_BLOCK } from "../src/constants" import { PROF_COLS, UNICODE_BLOCK } from "../src/constants"
import { SelectionBroker } from "../src/selection-broker" import { SelectionBroker } from "../src/selection-broker"
import { TextView } from "../src/text-view" import { TextView } from "../src/text-view"
import { SourceResolver } from "./source-resolver";
export class DisassemblyView extends TextView { export class DisassemblyView extends TextView {
SOURCE_POSITION_HEADER_REGEX: any; SOURCE_POSITION_HEADER_REGEX: any;
...@@ -21,34 +22,21 @@ export class DisassemblyView extends TextView { ...@@ -21,34 +22,21 @@ export class DisassemblyView extends TextView {
<ul id='disassembly-list' class='nolinenums noindent'> <ul id='disassembly-list' class='nolinenums noindent'>
</ul> </ul>
</pre>`; </pre>`;
return pane; return pane;
} }
constructor(parentId, broker: SelectionBroker) { constructor(parentId, broker: SelectionBroker) {
super(parentId, broker, null); super(parentId, broker, null);
let view = this; let view = this;
const sourceResolver = broker.sourceResolver;
let ADDRESS_STYLE = { let ADDRESS_STYLE = {
css: 'tag', css: ['linkable-text', 'tag'],
linkHandler: function (text, fragment) { associateData: (text, fragment) => {
const matches = text.match(/0?x?[0-9a-fA-F]{8,16}\s*(?<offset>[0-9a-f]+)/); const matches = text.match(/0?x?[0-9a-fA-F]{8,16}\s*(?<offset>[0-9a-f]+)/);
const offset = Number.parseInt(matches.groups["offset"], 16); const offset = Number.parseInt(matches.groups["offset"], 16);
if (!Number.isNaN(offset)) { if (!Number.isNaN(offset)) {
const [nodes, blockId] = sourceResolver.nodesForPCOffset(offset) fragment.dataset.pcOffset = view.sourceResolver.getKeyPcOffset(offset);
if (nodes.length > 0) {
for (const nodeId of nodes) {
view.addHtmlElementForNodeId(nodeId, fragment);
} }
return (e) => {
e.stopPropagation();
if (!e.shiftKey) {
view.selectionHandler.clear();
}
view.selectionHandler.select(nodes, true);
};
}
}
return undefined;
} }
}; };
let ADDRESS_LINK_STYLE = { let ADDRESS_LINK_STYLE = {
...@@ -78,17 +66,11 @@ export class DisassemblyView extends TextView { ...@@ -78,17 +66,11 @@ export class DisassemblyView extends TextView {
BLOCK_HEADER_STYLE.block_id = Number(matches[0]); BLOCK_HEADER_STYLE.block_id = Number(matches[0]);
return BLOCK_HEADER_STYLE.block_id; return BLOCK_HEADER_STYLE.block_id;
}, },
linkHandler: function (text) { associateData: function (text, fragment) {
let matches = /\d+/.exec(text); let matches = /\d+/.exec(text);
if (!matches) return undefined; if (!matches) return;
const blockId = matches[0]; const blockId = matches[0];
return function (e) { fragment.dataset.blockId = blockId;
e.stopPropagation();
if (!e.shiftKey) {
view.selectionHandler.clear();
}
view.blockSelectionHandler.select([blockId], true);
};
} }
}; };
const SOURCE_POSITION_HEADER_STYLE = { const SOURCE_POSITION_HEADER_STYLE = {
...@@ -134,6 +116,34 @@ export class DisassemblyView extends TextView { ...@@ -134,6 +116,34 @@ export class DisassemblyView extends TextView {
] ]
]; ];
view.setPatterns(patterns); view.setPatterns(patterns);
const linkHandler = (e) => {
const offset = e.target.dataset.pcOffset;
if (typeof offset != "undefined" && !Number.isNaN(offset)) {
const [nodes, blockId] = view.sourceResolver.nodesForPCOffset(offset)
if (nodes.length > 0) {
e.stopPropagation();
if (!e.shiftKey) {
view.selectionHandler.clear();
}
view.selectionHandler.select(nodes, true);
}
}
return undefined;
}
view.divNode.addEventListener('click', linkHandler);
const linkHandlerBlock = (e) => {
const blockId = e.target.dataset.blockId;
if (typeof blockId != "undefined" && !Number.isNaN(blockId)) {
e.stopPropagation();
if (!e.shiftKey) {
view.selectionHandler.clear();
}
view.blockSelectionHandler.select([blockId], true);
};
}
view.divNode.addEventListener('click', linkHandlerBlock);
} }
initializeCode(sourceText, sourcePosition) { initializeCode(sourceText, sourcePosition) {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import {sortUnique, anyToString} from "../src/util" import { sortUnique, anyToString } from "../src/util"
function sourcePositionLe(a, b) { function sourcePositionLe(a, b) {
if (a.inliningId == b.inliningId) { if (a.inliningId == b.inliningId) {
...@@ -331,13 +331,13 @@ export class SourceResolver { ...@@ -331,13 +331,13 @@ export class SourceResolver {
} }
} }
getInstruction(nodeId):[number, number] { getInstruction(nodeId): [number, number] {
const X = this.nodeIdToInstructionRange[nodeId]; const X = this.nodeIdToInstructionRange[nodeId];
if (X === undefined) return [-1, -1]; if (X === undefined) return [-1, -1];
return X; return X;
} }
getInstructionRangeForBlock(blockId):[number, number] { getInstructionRangeForBlock(blockId): [number, number] {
const X = this.blockIdToInstructionRange[blockId]; const X = this.blockIdToInstructionRange[blockId];
if (X === undefined) return [-1, -1]; if (X === undefined) return [-1, -1];
return X; return X;
...@@ -358,9 +358,32 @@ export class SourceResolver { ...@@ -358,9 +358,32 @@ export class SourceResolver {
return this.pcOffsetToInstructions.size > 0; return this.pcOffsetToInstructions.size > 0;
} }
getKeyPcOffset(offset): number {
if (this.pcOffsets.length === 0) return -1;
for (const key of this.pcOffsets) {
if (key <= offset) {
return key;
}
}
}
instructionRangeToKeyPcOffsets([start, end]) {
if (start == end) return [this.instructionToPCOffset[start]];
return this.instructionToPCOffset.slice(start, end);
}
nodesToKeyPcOffsets(nodes) {
let offsets = [];
for (const node of nodes) {
const range = this.nodeIdToInstructionRange[node];
if (!range) continue;
offsets = offsets.concat(this.instructionRangeToKeyPcOffsets(range))
}
return offsets;
}
nodesForPCOffset(offset): [Array<String>, Array<String>] { nodesForPCOffset(offset): [Array<String>, Array<String>] {
if (this.pcOffsets.length === 0) return [[],[]]; if (this.pcOffsets.length === 0) return [[], []];
for (const key of this.pcOffsets) { for (const key of this.pcOffsets) {
if (key <= offset) { if (key <= offset) {
const instrs = this.pcOffsetToInstructions.get(key); const instrs = this.pcOffsetToInstructions.get(key);
...@@ -381,7 +404,7 @@ export class SourceResolver { ...@@ -381,7 +404,7 @@ export class SourceResolver {
return [nodes, blocks]; return [nodes, blocks];
} }
} }
return [[],[]]; return [[], []];
} }
parsePhases(phases) { parsePhases(phases) {
......
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import {View} from "../src/view" import { View } from "../src/view"
import {anyToString, ViewElements, isIterable} from "../src/util" import { anyToString, ViewElements, isIterable } from "../src/util"
import {MySelection} from "../src/selection" import { MySelection } from "../src/selection"
import { SourceResolver } from "./source-resolver";
export abstract class TextView extends View { export abstract class TextView extends View {
selectionHandler: NodeSelectionHandler; selectionHandler: NodeSelectionHandler;
...@@ -18,6 +19,7 @@ export abstract class TextView extends View { ...@@ -18,6 +19,7 @@ export abstract class TextView extends View {
blockIdtoNodeIds: Map<string, Array<string>>; blockIdtoNodeIds: Map<string, Array<string>>;
nodeIdToBlockId: Array<string>; nodeIdToBlockId: Array<string>;
patterns: any; patterns: any;
sourceResolver: SourceResolver;
constructor(id, broker, patterns) { constructor(id, broker, patterns) {
super(id); super(id);
...@@ -30,6 +32,7 @@ export abstract class TextView extends View { ...@@ -30,6 +32,7 @@ export abstract class TextView extends View {
view.nodeIdToBlockId = []; view.nodeIdToBlockId = [];
view.selection = new MySelection(anyToString); view.selection = new MySelection(anyToString);
view.blockSelection = new MySelection(anyToString); view.blockSelection = new MySelection(anyToString);
view.sourceResolver = broker.sourceResolver;
const selectionHandler = { const selectionHandler = {
clear: function () { clear: function () {
view.selection.clear(); view.selection.clear();
...@@ -129,6 +132,17 @@ export abstract class TextView extends View { ...@@ -129,6 +132,17 @@ export abstract class TextView extends View {
element.classList.toggle("selected", isSelected); element.classList.toggle("selected", isSelected);
} }
} }
const elementsToSelect = view.divNode.querySelectorAll(`[data-pc-offset]`)
for (const el of elementsToSelect) {
el.classList.toggle("selected", false);
}
const keyPcOffsets = view.sourceResolver.nodesToKeyPcOffsets(view.selection.selectedKeys());
for (const keyPcOffset of keyPcOffsets) {
const elementsToSelect = view.divNode.querySelectorAll(`[data-pc-offset='${keyPcOffset}']`)
for (const el of elementsToSelect) {
el.classList.toggle("selected", true);
}
}
for (const key of this.nodeIdToHtmlElementsMap.keys()) { for (const key of this.nodeIdToHtmlElementsMap.keys()) {
for (const element of this.nodeIdToHtmlElementsMap.get(key)) { for (const element of this.nodeIdToHtmlElementsMap.get(key)) {
element.classList.toggle("selected", false); element.classList.toggle("selected", false);
...@@ -190,12 +204,8 @@ export abstract class TextView extends View { ...@@ -190,12 +204,8 @@ export abstract class TextView extends View {
this.addNodeIdToBlockId(fragment.nodeId, fragment.blockId); this.addNodeIdToBlockId(fragment.nodeId, fragment.blockId);
} }
if (typeof style.linkHandler == 'function') { if (typeof style.associateData == 'function') {
const handler = style.linkHandler(text, fragment) style.associateData(text, fragment);
if (handler !== undefined) {
fragment.classList.add('linkable-text');
fragment.onmouseup = handler;
}
} }
if (style.css != undefined) { if (style.css != undefined) {
......
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