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 @@
import { PROF_COLS, UNICODE_BLOCK } from "../src/constants"
import { SelectionBroker } from "../src/selection-broker"
import { TextView } from "../src/text-view"
import { SourceResolver } from "./source-resolver";
export class DisassemblyView extends TextView {
SOURCE_POSITION_HEADER_REGEX: any;
......@@ -21,34 +22,21 @@ export class DisassemblyView extends TextView {
<ul id='disassembly-list' class='nolinenums noindent'>
</ul>
</pre>`;
return pane;
}
constructor(parentId, broker: SelectionBroker) {
super(parentId, broker, null);
let view = this;
const sourceResolver = broker.sourceResolver;
let ADDRESS_STYLE = {
css: 'tag',
linkHandler: function (text, fragment) {
css: ['linkable-text', 'tag'],
associateData: (text, fragment) => {
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);
if (!Number.isNaN(offset)) {
const [nodes, blockId] = sourceResolver.nodesForPCOffset(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);
};
}
fragment.dataset.pcOffset = view.sourceResolver.getKeyPcOffset(offset);
}
return undefined;
}
};
let ADDRESS_LINK_STYLE = {
......@@ -78,17 +66,11 @@ export class DisassemblyView extends TextView {
BLOCK_HEADER_STYLE.block_id = Number(matches[0]);
return BLOCK_HEADER_STYLE.block_id;
},
linkHandler: function (text) {
associateData: function (text, fragment) {
let matches = /\d+/.exec(text);
if (!matches) return undefined;
if (!matches) return;
const blockId = matches[0];
return function (e) {
e.stopPropagation();
if (!e.shiftKey) {
view.selectionHandler.clear();
}
view.blockSelectionHandler.select([blockId], true);
};
fragment.dataset.blockId = blockId;
}
};
const SOURCE_POSITION_HEADER_STYLE = {
......@@ -134,6 +116,34 @@ export class DisassemblyView extends TextView {
]
];
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) {
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {sortUnique, anyToString} from "../src/util"
import { sortUnique, anyToString } from "../src/util"
function sourcePositionLe(a, b) {
if (a.inliningId == b.inliningId) {
......@@ -331,13 +331,13 @@ export class SourceResolver {
}
}
getInstruction(nodeId):[number, number] {
getInstruction(nodeId): [number, number] {
const X = this.nodeIdToInstructionRange[nodeId];
if (X === undefined) return [-1, -1];
return X;
}
getInstructionRangeForBlock(blockId):[number, number] {
getInstructionRangeForBlock(blockId): [number, number] {
const X = this.blockIdToInstructionRange[blockId];
if (X === undefined) return [-1, -1];
return X;
......@@ -358,9 +358,32 @@ export class SourceResolver {
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>] {
if (this.pcOffsets.length === 0) return [[],[]];
if (this.pcOffsets.length === 0) return [[], []];
for (const key of this.pcOffsets) {
if (key <= offset) {
const instrs = this.pcOffsetToInstructions.get(key);
......@@ -381,7 +404,7 @@ export class SourceResolver {
return [nodes, blocks];
}
}
return [[],[]];
return [[], []];
}
parsePhases(phases) {
......
......@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {View} from "../src/view"
import {anyToString, ViewElements, isIterable} from "../src/util"
import {MySelection} from "../src/selection"
import { View } from "../src/view"
import { anyToString, ViewElements, isIterable } from "../src/util"
import { MySelection } from "../src/selection"
import { SourceResolver } from "./source-resolver";
export abstract class TextView extends View {
selectionHandler: NodeSelectionHandler;
......@@ -18,6 +19,7 @@ export abstract class TextView extends View {
blockIdtoNodeIds: Map<string, Array<string>>;
nodeIdToBlockId: Array<string>;
patterns: any;
sourceResolver: SourceResolver;
constructor(id, broker, patterns) {
super(id);
......@@ -30,6 +32,7 @@ export abstract class TextView extends View {
view.nodeIdToBlockId = [];
view.selection = new MySelection(anyToString);
view.blockSelection = new MySelection(anyToString);
view.sourceResolver = broker.sourceResolver;
const selectionHandler = {
clear: function () {
view.selection.clear();
......@@ -129,6 +132,17 @@ export abstract class TextView extends View {
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 element of this.nodeIdToHtmlElementsMap.get(key)) {
element.classList.toggle("selected", false);
......@@ -190,12 +204,8 @@ export abstract class TextView extends View {
this.addNodeIdToBlockId(fragment.nodeId, fragment.blockId);
}
if (typeof style.linkHandler == 'function') {
const handler = style.linkHandler(text, fragment)
if (handler !== undefined) {
fragment.classList.add('linkable-text');
fragment.onmouseup = handler;
}
if (typeof style.associateData == 'function') {
style.associateData(text, fragment);
}
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