Commit f423e485 authored by Danylo Boiko's avatar Danylo Boiko Committed by V8 LUCI CQ

[turbolizer] Graph layout caching

- "Remember graph layout" button
- Graph layout caching (almost 10x speed up)
- Camera position and zoom saving
- Refactored graph.ts, graph-layout.ts and graphmultiview.ts

Bug: v8:7327
Change-Id: I6a9db1ddbbaf506bff0b9d1c1e015f245c7c3974
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3714248
Commit-Queue: Danylo Boiko <danielboyko02@gmail.com>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81309}
parent c3f60e8c
This diff was suppressed by a .gitattributes entry.
...@@ -12,6 +12,7 @@ export const MINIMUM_EDGE_SEPARATION = 20; ...@@ -12,6 +12,7 @@ export const MINIMUM_EDGE_SEPARATION = 20;
export const MINIMUM_NODE_INPUT_APPROACH = 15 + 2 * DEFAULT_NODE_BUBBLE_RADIUS; export const MINIMUM_NODE_INPUT_APPROACH = 15 + 2 * DEFAULT_NODE_BUBBLE_RADIUS;
export const DEFAULT_NODE_ROW_SEPARATION = 150; export const DEFAULT_NODE_ROW_SEPARATION = 150;
export const TRACE_LAYOUT = false; export const TRACE_LAYOUT = false;
export const MULTIVIEW_ID = "multiview";
export const SOURCE_PANE_ID = "left"; export const SOURCE_PANE_ID = "left";
export const SOURCE_COLLAPSE_ID = "source-shrink"; export const SOURCE_COLLAPSE_ID = "source-shrink";
export const SOURCE_EXPAND_ID = "source-expand"; export const SOURCE_EXPAND_ID = "source-expand";
......
...@@ -78,3 +78,13 @@ export function createElement(tag: string, cls: string, content?: string): HTMLE ...@@ -78,3 +78,13 @@ export function createElement(tag: string, cls: string, content?: string): HTMLE
if (content !== undefined) el.innerText = content; if (content !== undefined) el.innerText = content;
return el; return el;
} }
export function storageGetItem(key: string, defaultValue?: any, parse: boolean = true): any {
let value = window.sessionStorage.getItem(key);
if (parse) value = JSON.parse(value);
return value === null ? defaultValue : value;
}
export function storageSetItem(key: string, value: any): void {
window.sessionStorage.setItem(key, value);
}
This diff is collapsed.
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
// found in the LICENSE file. // found in the LICENSE file.
import * as C from "./common/constants"; import * as C from "./common/constants";
import { GraphPhase } from "./phases/graph-phase"; import { GraphPhase, GraphStateType } from "./phases/graph-phase";
import { GraphEdge } from "./phases/graph-phase/graph-edge"; import { GraphEdge } from "./phases/graph-phase/graph-edge";
import { GraphNode } from "./phases/graph-phase/graph-node"; import { GraphNode } from "./phases/graph-phase/graph-node";
export class Graph { export class Graph {
graphPhase: GraphPhase;
nodeMap: Array<GraphNode>; nodeMap: Array<GraphNode>;
minGraphX: number; minGraphX: number;
maxGraphX: number; maxGraphX: number;
...@@ -19,57 +20,41 @@ export class Graph { ...@@ -19,57 +20,41 @@ export class Graph {
height: number; height: number;
constructor(graphPhase: GraphPhase) { constructor(graphPhase: GraphPhase) {
this.nodeMap = []; this.graphPhase = graphPhase;
this.nodeMap = graphPhase.nodeIdToNodeMap;
this.minGraphX = 0; this.minGraphX = 0;
this.maxGraphX = 1; this.maxGraphX = 1;
this.minGraphY = 0; this.minGraphY = 0;
this.maxGraphY = 1; this.maxGraphY = 1;
this.width = 1; this.width = 1;
this.height = 1; this.height = 1;
graphPhase.data.nodes.forEach((jsonNode: GraphNode) => {
this.nodeMap[jsonNode.id] = new GraphNode(jsonNode.nodeLabel);
});
graphPhase.data.edges.forEach((e: any) => {
const t = this.nodeMap[e.target.id];
const s = this.nodeMap[e.source.id];
const newEdge = new GraphEdge(t, e.index, s, e.type);
t.inputs.push(newEdge);
s.outputs.push(newEdge);
if (e.type == 'control') {
// Every source of a control edge is a CFG node.
s.cfg = true;
}
});
} }
*nodes(p = (n: GraphNode) => true) { public *nodes(func = (n: GraphNode) => true) {
for (const node of this.nodeMap) { for (const node of this.nodeMap) {
if (!node || !p(node)) continue; if (!node || !func(node)) continue;
yield node; yield node;
} }
} }
*filteredEdges(p: (e: GraphEdge) => boolean) { public *filteredEdges(func: (e: GraphEdge) => boolean) {
for (const node of this.nodes()) { for (const node of this.nodes()) {
for (const edge of node.inputs) { for (const edge of node.inputs) {
if (p(edge)) yield edge; if (func(edge)) yield edge;
} }
} }
} }
forEachEdge(p: (e: GraphEdge) => void) { public forEachEdge(func: (e: GraphEdge) => void) {
for (const node of this.nodeMap) { for (const node of this.nodeMap) {
if (!node) continue; if (!node) continue;
for (const edge of node.inputs) { for (const edge of node.inputs) {
p(edge); func(edge);
} }
} }
} }
redetermineGraphBoundingBox(showTypes: boolean): [[number, number], [number, number]] { public redetermineGraphBoundingBox(showTypes: boolean): [[number, number], [number, number]] {
this.minGraphX = 0; this.minGraphX = 0;
this.maxGraphNodeX = 1; this.maxGraphNodeX = 1;
this.maxGraphX = undefined; // see below this.maxGraphX = undefined; // see below
...@@ -77,36 +62,43 @@ export class Graph { ...@@ -77,36 +62,43 @@ export class Graph {
this.maxGraphY = 1; this.maxGraphY = 1;
for (const node of this.nodes()) { for (const node of this.nodes()) {
if (!node.visible) { if (!node.visible) continue;
continue;
}
if (node.x < this.minGraphX) { this.minGraphX = Math.min(this.minGraphX, node.x);
this.minGraphX = node.x; this.maxGraphNodeX = Math.max(this.maxGraphNodeX,
} node.x + node.getTotalNodeWidth());
if ((node.x + node.getTotalNodeWidth()) > this.maxGraphNodeX) {
this.maxGraphNodeX = node.x + node.getTotalNodeWidth(); this.minGraphY = Math.min(this.minGraphY, node.y - C.NODE_INPUT_WIDTH);
} this.maxGraphY = Math.max(this.maxGraphY,
if ((node.y - 50) < this.minGraphY) { node.y + node.getNodeHeight(showTypes) + C.NODE_INPUT_WIDTH);
this.minGraphY = node.y - 50;
}
if ((node.y + node.getNodeHeight(showTypes) + 50) > this.maxGraphY) {
this.maxGraphY = node.y + node.getNodeHeight(showTypes) + 50;
}
} }
this.maxGraphX = this.maxGraphNodeX + this.maxGraphX = this.maxGraphNodeX + this.maxBackEdgeNumber
this.maxBackEdgeNumber * C.MINIMUM_EDGE_SEPARATION; * C.MINIMUM_EDGE_SEPARATION;
this.width = this.maxGraphX - this.minGraphX; this.width = this.maxGraphX - this.minGraphX;
this.height = this.maxGraphY - this.minGraphY; this.height = this.maxGraphY - this.minGraphY;
const extent: [[number, number], [number, number]] = [ return [
[this.minGraphX - this.width / 2, this.minGraphY - this.height / 2], [this.minGraphX - this.width / 2, this.minGraphY - this.height / 2],
[this.maxGraphX + this.width / 2, this.maxGraphY + this.height / 2] [this.maxGraphX + this.width / 2, this.maxGraphY + this.height / 2]
]; ];
}
return extent; public makeEdgesVisible(): void {
if (this.graphPhase.stateType == GraphStateType.NeedToFullRebuild) {
this.forEachEdge(edge =>
edge.visible = edge.source.visible && edge.target.visible
);
} else {
this.forEachEdge(edge =>
edge.visible = edge.visible || (this.isRendered() &&
edge.type === "control" && edge.source.visible && edge.target.visible)
);
}
} }
public isRendered(): boolean {
return this.graphPhase.rendered;
}
} }
...@@ -2,16 +2,17 @@ ...@@ -2,16 +2,17 @@
// 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 * as C from "./common/constants";
import { GraphView } from "./views/graph-view"; import { GraphView } from "./views/graph-view";
import { ScheduleView } from "./views/schedule-view"; import { ScheduleView } from "./views/schedule-view";
import { SequenceView } from "./views/sequence-view"; import { SequenceView } from "./views/sequence-view";
import { SourceResolver } from "./source-resolver"; import { GenericPhase, SourceResolver } from "./source-resolver";
import { SelectionBroker } from "./selection/selection-broker"; import { SelectionBroker } from "./selection/selection-broker";
import { PhaseView, View } from "./views/view"; import { PhaseView, View } from "./views/view";
import { GraphPhase } from "./phases/graph-phase"; import { GraphPhase } from "./phases/graph-phase";
import { GraphNode } from "./phases/graph-phase/graph-node"; import { GraphNode } from "./phases/graph-phase/graph-node";
import { storageGetItem, storageSetItem } from "./common/util";
const multiviewID = "multiview"; import { PhaseType } from "./phases/phase";
const toolboxHTML = ` const toolboxHTML = `
<div class="graph-toolbox"> <div class="graph-toolbox">
...@@ -32,20 +33,6 @@ export class GraphMultiView extends View { ...@@ -32,20 +33,6 @@ export class GraphMultiView extends View {
selectMenu: HTMLSelectElement; selectMenu: HTMLSelectElement;
currentPhaseView: PhaseView; currentPhaseView: PhaseView;
createViewElement() {
const pane = document.createElement("div");
pane.setAttribute("id", multiviewID);
pane.setAttribute("tabindex", "1");
pane.className = "viewpane";
return pane;
}
hide() {
this.container.className = "";
this.hideCurrentPhase();
super.hide();
}
constructor(id, selectionBroker, sourceResolver) { constructor(id, selectionBroker, sourceResolver) {
super(id); super(id);
const view = this; const view = this;
...@@ -57,9 +44,8 @@ export class GraphMultiView extends View { ...@@ -57,9 +44,8 @@ export class GraphMultiView extends View {
view.divNode.appendChild(toolbox); view.divNode.appendChild(toolbox);
const searchInput = toolbox.querySelector("#search-input") as HTMLInputElement; const searchInput = toolbox.querySelector("#search-input") as HTMLInputElement;
const onlyVisibleCheckbox = toolbox.querySelector("#search-only-visible") as HTMLInputElement; const onlyVisibleCheckbox = toolbox.querySelector("#search-only-visible") as HTMLInputElement;
searchInput.addEventListener("keyup", e => { searchInput.addEventListener("keyup", (e: KeyboardEvent) => {
if (!view.currentPhaseView) return; view.currentPhaseView?.searchInputAction(searchInput, e, onlyVisibleCheckbox.checked);
view.currentPhaseView.searchInputAction(searchInput, e, onlyVisibleCheckbox.checked);
}); });
view.divNode.addEventListener("keyup", (e: KeyboardEvent) => { view.divNode.addEventListener("keyup", (e: KeyboardEvent) => {
if (e.keyCode == 191) { // keyCode == '/' if (e.keyCode == 191) { // keyCode == '/'
...@@ -70,7 +56,7 @@ export class GraphMultiView extends View { ...@@ -70,7 +56,7 @@ export class GraphMultiView extends View {
view.displayPreviousGraphPhase(); view.displayPreviousGraphPhase();
} }
}); });
searchInput.setAttribute("value", window.sessionStorage.getItem("lastSearch") || ""); searchInput.setAttribute("value", storageGetItem("lastSearch", "", false));
this.graph = new GraphView(this.divNode, selectionBroker, view.displayPhaseByName.bind(this), this.graph = new GraphView(this.divNode, selectionBroker, view.displayPhaseByName.bind(this),
toolbox.querySelector(".graph-toolbox")); toolbox.querySelector(".graph-toolbox"));
this.schedule = new ScheduleView(this.divNode, selectionBroker); this.schedule = new ScheduleView(this.divNode, selectionBroker);
...@@ -78,65 +64,65 @@ export class GraphMultiView extends View { ...@@ -78,65 +64,65 @@ export class GraphMultiView extends View {
this.selectMenu = toolbox.querySelector("#phase-select") as HTMLSelectElement; this.selectMenu = toolbox.querySelector("#phase-select") as HTMLSelectElement;
} }
initializeSelect() { public createViewElement(): HTMLDivElement {
const view = this; const pane = document.createElement("div");
view.selectMenu.innerHTML = ""; pane.setAttribute("id", C.MULTIVIEW_ID);
view.sourceResolver.forEachPhase(phase => { pane.setAttribute("tabindex", "1");
const optionElement = document.createElement("option"); pane.className = "viewpane";
let maxNodeId = ""; return pane;
if (phase instanceof GraphPhase && phase.highestNodeId != 0) {
maxNodeId = ` ${phase.highestNodeId}`;
}
optionElement.text = `${phase.name}${maxNodeId}`;
view.selectMenu.add(optionElement);
});
this.selectMenu.onchange = function (this: HTMLSelectElement) {
const phaseIndex = this.selectedIndex;
window.sessionStorage.setItem("lastSelectedPhase", phaseIndex.toString());
view.displayPhase(view.sourceResolver.getPhase(phaseIndex));
};
} }
show() { public hide(): void {
this.container.className = "";
this.hideCurrentPhase();
super.hide();
}
public show(): void {
// Insert before is used so that the display is inserted before the // Insert before is used so that the display is inserted before the
// resizer for the RangeView. // resizer for the RangeView.
this.container.insertBefore(this.divNode, this.container.firstChild); this.container.insertBefore(this.divNode, this.container.firstChild);
this.initializeSelect(); this.initializeSelect();
const lastPhaseIndex = +window.sessionStorage.getItem("lastSelectedPhase"); const lastPhaseIndex = storageGetItem("lastSelectedPhase");
const initialPhaseIndex = this.sourceResolver.repairPhaseId(lastPhaseIndex); const initialPhaseIndex = this.sourceResolver.repairPhaseId(lastPhaseIndex);
this.selectMenu.selectedIndex = initialPhaseIndex; this.selectMenu.selectedIndex = initialPhaseIndex;
this.displayPhase(this.sourceResolver.getPhase(initialPhaseIndex)); this.displayPhase(this.sourceResolver.getPhase(initialPhaseIndex));
} }
displayPhase(phase, selection?: Map<string, GraphNode>) { public onresize(): void {
if (phase.type == "graph") { this.currentPhaseView?.onresize();
}
private displayPhase(phase: GenericPhase, selection?: Map<string, GraphNode>): void {
if (phase.type == PhaseType.Graph) {
this.displayPhaseView(this.graph, phase, selection); this.displayPhaseView(this.graph, phase, selection);
} else if (phase.type == "schedule") { } else if (phase.type == PhaseType.Schedule) {
this.displayPhaseView(this.schedule, phase, selection); this.displayPhaseView(this.schedule, phase, selection);
} else if (phase.type == "sequence") { } else if (phase.type == PhaseType.Sequence) {
this.displayPhaseView(this.sequence, phase, selection); this.displayPhaseView(this.sequence, phase, selection);
} }
} }
displayPhaseView(view: PhaseView, data, selection?: Map<string, GraphNode>) { private displayPhaseView(view: PhaseView, data: GenericPhase, selection?: Map<string, GraphNode>):
void {
const rememberedSelection = selection ? selection : this.hideCurrentPhase(); const rememberedSelection = selection ? selection : this.hideCurrentPhase();
view.initializeContent(data, rememberedSelection); view.initializeContent(data, rememberedSelection);
this.currentPhaseView = view; this.currentPhaseView = view;
} }
displayPhaseByName(phaseName, selection?: Map<string, GraphNode>) { private displayPhaseByName(phaseName: string, selection?: Map<string, GraphNode>): void {
const phaseId = this.sourceResolver.getPhaseIdByName(phaseName); const phaseId = this.sourceResolver.getPhaseIdByName(phaseName);
this.selectMenu.selectedIndex = phaseId; this.selectMenu.selectedIndex = phaseId;
this.displayPhase(this.sourceResolver.getPhase(phaseId), selection); this.displayPhase(this.sourceResolver.getPhase(phaseId), selection);
} }
displayNextGraphPhase() { private displayNextGraphPhase(): void {
let nextPhaseIndex = this.selectMenu.selectedIndex + 1; let nextPhaseIndex = this.selectMenu.selectedIndex + 1;
while (nextPhaseIndex < this.sourceResolver.phases.length) { while (nextPhaseIndex < this.sourceResolver.phases.length) {
const nextPhase = this.sourceResolver.getPhase(nextPhaseIndex); const nextPhase = this.sourceResolver.getPhase(nextPhaseIndex);
if (nextPhase.type == "graph") { if (nextPhase.type == PhaseType.Graph) {
this.selectMenu.selectedIndex = nextPhaseIndex; this.selectMenu.selectedIndex = nextPhaseIndex;
window.sessionStorage.setItem("lastSelectedPhase", nextPhaseIndex.toString()); storageSetItem("lastSelectedPhase", nextPhaseIndex);
this.displayPhase(nextPhase); this.displayPhase(nextPhase);
break; break;
} }
...@@ -144,13 +130,13 @@ export class GraphMultiView extends View { ...@@ -144,13 +130,13 @@ export class GraphMultiView extends View {
} }
} }
displayPreviousGraphPhase() { private displayPreviousGraphPhase(): void {
let previousPhaseIndex = this.selectMenu.selectedIndex - 1; let previousPhaseIndex = this.selectMenu.selectedIndex - 1;
while (previousPhaseIndex >= 0) { while (previousPhaseIndex >= 0) {
const previousPhase = this.sourceResolver.getPhase(previousPhaseIndex); const previousPhase = this.sourceResolver.getPhase(previousPhaseIndex);
if (previousPhase.type == "graph") { if (previousPhase.type === PhaseType.Graph) {
this.selectMenu.selectedIndex = previousPhaseIndex; this.selectMenu.selectedIndex = previousPhaseIndex;
window.sessionStorage.setItem("lastSelectedPhase", previousPhaseIndex.toString()); storageSetItem("lastSelectedPhase", previousPhaseIndex);
this.displayPhase(previousPhase); this.displayPhase(previousPhase);
break; break;
} }
...@@ -158,7 +144,26 @@ export class GraphMultiView extends View { ...@@ -158,7 +144,26 @@ export class GraphMultiView extends View {
} }
} }
hideCurrentPhase() { private initializeSelect(): void {
const view = this;
view.selectMenu.innerHTML = "";
view.sourceResolver.forEachPhase((phase: GenericPhase) => {
const optionElement = document.createElement("option");
let maxNodeId = "";
if (phase instanceof GraphPhase && phase.highestNodeId != 0) {
maxNodeId = ` ${phase.highestNodeId}`;
}
optionElement.text = `${phase.name}${maxNodeId}`;
view.selectMenu.add(optionElement);
});
this.selectMenu.onchange = function (this: HTMLSelectElement) {
const phaseIndex = this.selectedIndex;
storageSetItem("lastSelectedPhase", phaseIndex);
view.displayPhase(view.sourceResolver.getPhase(phaseIndex));
};
}
private hideCurrentPhase(): Map<string, GraphNode> {
let rememberedSelection = null; let rememberedSelection = null;
if (this.currentPhaseView != null) { if (this.currentPhaseView != null) {
rememberedSelection = this.currentPhaseView.detachSelection(); rememberedSelection = this.currentPhaseView.detachSelection();
...@@ -167,12 +172,4 @@ export class GraphMultiView extends View { ...@@ -167,12 +172,4 @@ export class GraphMultiView extends View {
} }
return rememberedSelection; return rememberedSelection;
} }
onresize() {
if (this.currentPhaseView) this.currentPhaseView.onresize();
}
detachSelection() {
return null;
}
} }
...@@ -2,21 +2,27 @@ ...@@ -2,21 +2,27 @@
// 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 { BytecodeOrigin, NodeOrigin } from "./origin";
import { BytecodePosition, SourcePosition } from "./position";
export class NodeLabel { export class NodeLabel {
id: number; id: number;
label: string; label: string;
title: string; title: string;
live: boolean; live: boolean;
properties: string; properties: string;
sourcePosition: any; sourcePosition: SourcePosition | BytecodePosition;
origin: any; origin: NodeOrigin | BytecodeOrigin;
opcode: string; opcode: string;
control: boolean; control: boolean;
opinfo: string; opinfo: string;
type: string; type: string;
inplaceUpdatePhase: string; inplaceUpdatePhase: string;
constructor(id: number, label: string, title: string, live: boolean, properties: string, sourcePosition: any, origin: any, opcode: string, control: boolean, opinfo: string, type: string) { constructor(id: number, label: string, title: string, live: boolean,
properties: string, sourcePosition: SourcePosition | BytecodePosition,
origin: NodeOrigin | BytecodeOrigin, opcode: string, control: boolean,
opinfo: string, type: string) {
this.id = id; this.id = id;
this.label = label; this.label = label;
this.title = title; this.title = title;
...@@ -31,17 +37,17 @@ export class NodeLabel { ...@@ -31,17 +37,17 @@ export class NodeLabel {
this.inplaceUpdatePhase = null; this.inplaceUpdatePhase = null;
} }
equals(that?: NodeLabel) { public equals(that?: NodeLabel): boolean {
if (!that) return false; if (!that) return false;
if (this.id != that.id) return false; if (this.id !== that.id) return false;
if (this.label != that.label) return false; if (this.label !== that.label) return false;
if (this.title != that.title) return false; if (this.title !== that.title) return false;
if (this.live != that.live) return false; if (this.live !== that.live) return false;
if (this.properties != that.properties) return false; if (this.properties !== that.properties) return false;
if (this.opcode != that.opcode) return false; if (this.opcode !== that.opcode) return false;
if (this.control != that.control) return false; if (this.control !== that.control) return false;
if (this.opinfo != that.opinfo) return false; if (this.opinfo !== that.opinfo) return false;
return this.type == that.type; return this.type === that.type;
} }
public getTitle(): string { public getTitle(): string {
......
...@@ -12,16 +12,21 @@ import { GraphEdge } from "./graph-phase/graph-edge"; ...@@ -12,16 +12,21 @@ import { GraphEdge } from "./graph-phase/graph-edge";
export class GraphPhase extends Phase { export class GraphPhase extends Phase {
highestNodeId: number; highestNodeId: number;
data: GraphData; data: GraphData;
stateType: GraphStateType;
nodeLabelMap: Array<NodeLabel>; nodeLabelMap: Array<NodeLabel>;
nodeIdToNodeMap: Array<GraphNode>; nodeIdToNodeMap: Array<GraphNode>;
rendered: boolean;
transform: { x: number, y: number, scale: number };
constructor(name: string, highestNodeId: number, data?: GraphData, constructor(name: string, highestNodeId: number, data?: GraphData,
nodeLabelMap?: Array<NodeLabel>, nodeIdToNodeMap?: Array<GraphNode>) { nodeLabelMap?: Array<NodeLabel>, nodeIdToNodeMap?: Array<GraphNode>) {
super(name, PhaseType.Graph); super(name, PhaseType.Graph);
this.highestNodeId = highestNodeId; this.highestNodeId = highestNodeId;
this.data = data ?? new GraphData(); this.data = data ?? new GraphData();
this.stateType = GraphStateType.NeedToFullRebuild;
this.nodeLabelMap = nodeLabelMap ?? new Array<NodeLabel>(); this.nodeLabelMap = nodeLabelMap ?? new Array<NodeLabel>();
this.nodeIdToNodeMap = nodeIdToNodeMap ?? new Array<GraphNode>(); this.nodeIdToNodeMap = nodeIdToNodeMap ?? new Array<GraphNode>();
this.rendered = false;
} }
public parseDataFromJSON(dataJson, nodeLabelMap: Array<NodeLabel>): void { public parseDataFromJSON(dataJson, nodeLabelMap: Array<NodeLabel>): void {
...@@ -92,3 +97,8 @@ export class GraphData { ...@@ -92,3 +97,8 @@ export class GraphData {
this.edges = edges ?? new Array<GraphEdge>(); this.edges = edges ?? new Array<GraphEdge>();
} }
} }
export enum GraphStateType {
NeedToFullRebuild,
Cached
}
...@@ -18,7 +18,7 @@ export class GraphEdge extends Edge<GraphNode> { ...@@ -18,7 +18,7 @@ export class GraphEdge extends Edge<GraphNode> {
} }
public getInputHorizontalPosition(graph: Graph, showTypes: boolean): number { public getInputHorizontalPosition(graph: Graph, showTypes: boolean): number {
if (this.backEdgeNumber > 0) { if (graph.graphPhase.rendered && this.backEdgeNumber > 0) {
return graph.maxGraphNodeX + this.backEdgeNumber * C.MINIMUM_EDGE_SEPARATION; return graph.maxGraphNodeX + this.backEdgeNumber * C.MINIMUM_EDGE_SEPARATION;
} }
const source = this.source; const source = this.source;
......
...@@ -58,7 +58,7 @@ export class GraphNode extends Node<GraphEdge> { ...@@ -58,7 +58,7 @@ export class GraphNode extends Node<GraphEdge> {
opcode.startsWith("Reference") || opcode.startsWith("Reference") ||
opcode.startsWith("Any") || opcode.startsWith("Any") ||
opcode.endsWith("ToNumber") || opcode.endsWith("ToNumber") ||
(opcode == "AnyToBoolean") || (opcode === "AnyToBoolean") ||
(opcode.startsWith("Load") && opcode.length > 4) || (opcode.startsWith("Load") && opcode.length > 4) ||
(opcode.startsWith("Store") && opcode.length > 5); (opcode.startsWith("Store") && opcode.length > 5);
} }
...@@ -132,4 +132,13 @@ export class GraphNode extends Node<GraphEdge> { ...@@ -132,4 +132,13 @@ export class GraphNode extends Node<GraphEdge> {
this.nodeLabel.opcode === "InductionVariablePhi") && this.nodeLabel.opcode === "InductionVariablePhi") &&
this.inputs[this.inputs.length - 1].source.nodeLabel.opcode === "Loop"); this.inputs[this.inputs.length - 1].source.nodeLabel.opcode === "Loop");
} }
public compare(other: GraphNode): number {
if (this.visitOrderWithinRank < other.visitOrderWithinRank) {
return -1;
} else if (this.visitOrderWithinRank == other.visitOrderWithinRank) {
return 0;
}
return 1;
}
} }
...@@ -13,7 +13,6 @@ export class InstructionsPhase extends Phase { ...@@ -13,7 +13,6 @@ export class InstructionsPhase extends Phase {
// Maps instruction offsets to PC offset. // Maps instruction offsets to PC offset.
instructionOffsetToPCOffset?: Array<[number, number]>; instructionOffsetToPCOffset?: Array<[number, number]>;
codeOffsetsInfo?: CodeOffsetsInfo; codeOffsetsInfo?: CodeOffsetsInfo;
// Maps instruction numbers to PC offsets. // Maps instruction numbers to PC offsets.
instructionToPCOffset: Array<TurbolizerInstructionStartInfo>; instructionToPCOffset: Array<TurbolizerInstructionStartInfo>;
// Maps PC offsets to instructions. // Maps PC offsets to instructions.
......
...@@ -43,8 +43,8 @@ export function sourcePositionValid(l) { ...@@ -43,8 +43,8 @@ export function sourcePositionValid(l) {
&& typeof l.inliningId !== undefined) || typeof l.bytecodePosition != undefined; && typeof l.inliningId !== undefined) || typeof l.bytecodePosition != undefined;
} }
type GenericPosition = SourcePosition | BytecodePosition; export type GenericPosition = SourcePosition | BytecodePosition;
type GenericPhase = GraphPhase | TurboshaftGraphPhase | DisassemblyPhase export type GenericPhase = GraphPhase | TurboshaftGraphPhase | DisassemblyPhase
| InstructionsPhase | SchedulePhase | SequencePhase; | InstructionsPhase | SchedulePhase | SequencePhase;
export class SourceResolver { export class SourceResolver {
......
This diff is collapsed.
...@@ -316,7 +316,7 @@ class Helper { ...@@ -316,7 +316,7 @@ class Helper {
// There are two fixed live ranges for each register, one for normal, another for deferred. // There are two fixed live ranges for each register, one for normal, another for deferred.
// These are combined into a single row. // These are combined into a single row.
const fixedRegisterMap = new Map<string, {ranges: [Range, Range], registerIndex: number}>(); const fixedRegisterMap = new Map<string, {ranges: [Range, Range], registerIndex: number}>();
for (const [registerIndex, range] of rangeMap) { for (const [registerIndex, range] of Object.entries(rangeMap)) {
const registerName = this.fixedRegisterName(range); const registerName = this.fixedRegisterName(range);
if (fixedRegisterMap.has(registerName)) { if (fixedRegisterMap.has(registerName)) {
const entry = fixedRegisterMap.get(registerName); const entry = fixedRegisterMap.get(registerName);
...@@ -572,7 +572,7 @@ class RangeViewConstructor { ...@@ -572,7 +572,7 @@ class RangeViewConstructor {
private addVirtualRanges(row: number) { private addVirtualRanges(row: number) {
const source = this.view.sequenceView.sequence.registerAllocation; const source = this.view.sequenceView.sequence.registerAllocation;
for (const [registerIndex, range] of source.liveRanges) { for (const [registerIndex, range] of Object.entries(source.liveRanges)) {
const registerName = Helper.virtualRegisterName(registerIndex); const registerName = Helper.virtualRegisterName(registerIndex);
const registerEl = this.elementForVirtualRegister(registerName); const registerEl = this.elementForVirtualRegister(registerName);
this.addRowToGroup(row, this.elementForRow(row, registerIndex, this.addRowToGroup(row, this.elementForRow(row, registerIndex,
...@@ -768,7 +768,7 @@ class PhaseChangeHandler { ...@@ -768,7 +768,7 @@ class PhaseChangeHandler {
this.view.gridAccessor.addGrid(newGrid); this.view.gridAccessor.addGrid(newGrid);
const source = this.view.sequenceView.sequence.registerAllocation; const source = this.view.sequenceView.sequence.registerAllocation;
let row = 0; let row = 0;
for (const [registerIndex, range] of source.liveRanges) { for (const [registerIndex, range] of Object.entries(source.liveRanges)) {
this.addnewIntervalsInRange(currentGrid, newGrid, row, registerIndex, this.addnewIntervalsInRange(currentGrid, newGrid, row, registerIndex,
new RangePair([range, undefined])); new RangePair([range, undefined]));
++row; ++row;
......
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