[turbolizer] Refactor NodeLabel from GNode
Refactor NodeLabel from GNode, which saves memory and is a step towards decoupling the node layout from the graph structure. Change-Id: I095a2f7a7ab28067161deffbc37952ae15410e0a Notry: true Bug: v8:7327 Reviewed-on: https://chromium-review.googlesource.com/c/1396418 Commit-Queue: Sigurd Schneider <sigurds@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#58571}
This commit is contained in:
parent
76f8893699
commit
c0f6220914
@ -13,7 +13,7 @@ const DEFAULT_NODE_ROW_SEPARATION = 130
|
||||
|
||||
var traceLayout = false;
|
||||
|
||||
function newGraphOccupation(graph:Graph) {
|
||||
function newGraphOccupation(graph: Graph) {
|
||||
var isSlotFilled = [];
|
||||
var maxSlot = 0;
|
||||
var minSlot = 0;
|
||||
@ -122,12 +122,12 @@ function newGraphOccupation(graph:Graph) {
|
||||
}
|
||||
|
||||
var occupation = {
|
||||
occupyNodeInputs: function (node) {
|
||||
occupyNodeInputs: function (node: GNode, showTypes: boolean) {
|
||||
for (var i = 0; i < node.inputs.length; ++i) {
|
||||
if (node.inputs[i].isVisible()) {
|
||||
var edge = node.inputs[i];
|
||||
if (!edge.isBackEdge()) {
|
||||
var horizontalPos = edge.getInputHorizontalPosition(graph);
|
||||
var horizontalPos = edge.getInputHorizontalPosition(graph, showTypes);
|
||||
if (traceLayout) {
|
||||
console.log("Occupying input " + i + " of " + node.id + " at " + horizontalPos);
|
||||
}
|
||||
@ -201,13 +201,13 @@ function newGraphOccupation(graph:Graph) {
|
||||
});
|
||||
nodeOccupation = [];
|
||||
},
|
||||
clearNodeOutputs: function (source) {
|
||||
clearNodeOutputs: function (source: GNode, showTypes: boolean) {
|
||||
source.outputs.forEach(function (edge) {
|
||||
if (edge.isVisible()) {
|
||||
var target = edge.target;
|
||||
for (var i = 0; i < target.inputs.length; ++i) {
|
||||
if (target.inputs[i].source === source) {
|
||||
var horizontalPos = edge.getInputHorizontalPosition(graph);
|
||||
var horizontalPos = edge.getInputHorizontalPosition(graph, showTypes);
|
||||
clearPositionRangeWithMargin(horizontalPos,
|
||||
horizontalPos,
|
||||
NODE_INPUT_WIDTH / 2);
|
||||
@ -343,7 +343,7 @@ export function layoutNodeGraph(graph: Graph, showTypes: boolean): void {
|
||||
}
|
||||
firstInput = false;
|
||||
}
|
||||
if (n.opcode != "Start" && n.opcode != "Phi" && n.opcode != "EffectPhi") {
|
||||
if (n.nodeLabel.opcode != "Start" && n.nodeLabel.opcode != "Phi" && n.nodeLabel.opcode != "EffectPhi" && n.nodeLabel.opcode != "InductionVariablePhi") {
|
||||
n.rank = newRank;
|
||||
}
|
||||
}
|
||||
@ -371,7 +371,7 @@ export function layoutNodeGraph(graph: Graph, showTypes: boolean): void {
|
||||
n.rank = maxRank + 1;
|
||||
});
|
||||
|
||||
var rankSets = [];
|
||||
const rankSets: Array<Array<GNode>> = [];
|
||||
// Collect sets for each rank.
|
||||
for (const n of graph.nodes()) {
|
||||
n.y = n.rank * (DEFAULT_NODE_ROW_SEPARATION + n.getNodeHeight(showTypes) +
|
||||
@ -390,10 +390,10 @@ export function layoutNodeGraph(graph: Graph, showTypes: boolean): void {
|
||||
// compact and not overlapping live input lines.
|
||||
var occupation = newGraphOccupation(graph);
|
||||
|
||||
rankSets.reverse().forEach(function (rankSet) {
|
||||
rankSets.reverse().forEach(function (rankSet: Array<GNode>) {
|
||||
|
||||
for (var i = 0; i < rankSet.length; ++i) {
|
||||
occupation.clearNodeOutputs(rankSet[i]);
|
||||
occupation.clearNodeOutputs(rankSet[i], showTypes);
|
||||
}
|
||||
|
||||
if (traceLayout) {
|
||||
@ -402,8 +402,14 @@ export function layoutNodeGraph(graph: Graph, showTypes: boolean): void {
|
||||
}
|
||||
|
||||
var placedCount = 0;
|
||||
rankSet = rankSet.sort(function (a, b) {
|
||||
return a.visitOrderWithinRank < b.visitOrderWithinRank;
|
||||
rankSet = rankSet.sort((a: GNode, b: GNode) => {
|
||||
if (a.visitOrderWithinRank < b.visitOrderWithinRank) {
|
||||
return -1
|
||||
} else if (a.visitOrderWithinRank == b.visitOrderWithinRank) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
for (var i = 0; i < rankSet.length; ++i) {
|
||||
var nodeToPlace = rankSet[i];
|
||||
@ -434,7 +440,7 @@ export function layoutNodeGraph(graph: Graph, showTypes: boolean): void {
|
||||
|
||||
for (var i = 0; i < rankSet.length; ++i) {
|
||||
var node = rankSet[i];
|
||||
occupation.occupyNodeInputs(node);
|
||||
occupation.occupyNodeInputs(node, showTypes);
|
||||
}
|
||||
|
||||
if (traceLayout) {
|
||||
@ -449,7 +455,7 @@ export function layoutNodeGraph(graph: Graph, showTypes: boolean): void {
|
||||
});
|
||||
|
||||
graph.maxBackEdgeNumber = 0;
|
||||
graph.forEachEdge((e) => {
|
||||
graph.forEachEdge((e: Edge) => {
|
||||
if (e.isBackEdge()) {
|
||||
e.backEdgeNumber = ++graph.maxBackEdgeNumber;
|
||||
} else {
|
||||
|
@ -32,7 +32,7 @@ interface GraphState {
|
||||
export class GraphView extends View implements PhaseView {
|
||||
divElement: d3.Selection<any, any, any, any>;
|
||||
svg: d3.Selection<any, any, any, any>;
|
||||
showPhaseByName: (string) => void;
|
||||
showPhaseByName: (s: string) => void;
|
||||
state: GraphState;
|
||||
selectionHandler: NodeSelectionHandler & ClearableHandler;
|
||||
graphElement: d3.Selection<any, any, any, any>;
|
||||
@ -53,8 +53,8 @@ export class GraphView extends View implements PhaseView {
|
||||
return pane;
|
||||
}
|
||||
|
||||
constructor(id, broker, showPhaseByName: (string) => void) {
|
||||
super(id);
|
||||
constructor(idOrContainer: string | HTMLElement, broker: SelectionBroker, showPhaseByName: (s: string) => void) {
|
||||
super(idOrContainer);
|
||||
const view = this;
|
||||
this.broker = broker;
|
||||
this.showPhaseByName = showPhaseByName;
|
||||
@ -83,21 +83,21 @@ export class GraphView extends View implements PhaseView {
|
||||
broker.broadcastClear(this);
|
||||
view.updateGraphVisibility();
|
||||
},
|
||||
select: function (nodes, selected) {
|
||||
select: function (nodes: Iterable<GNode>, selected: boolean) {
|
||||
let locations = [];
|
||||
for (const node of nodes) {
|
||||
if (node.sourcePosition) {
|
||||
locations.push(node.sourcePosition);
|
||||
if (node.nodeLabel.sourcePosition) {
|
||||
locations.push(node.nodeLabel.sourcePosition);
|
||||
}
|
||||
if (node.origin && node.origin.bytecodePosition) {
|
||||
locations.push({ bytecodePosition: node.origin.bytecodePosition });
|
||||
if (node.nodeLabel.origin && node.nodeLabel.origin.bytecodePosition) {
|
||||
locations.push({ bytecodePosition: node.nodeLabel.origin.bytecodePosition });
|
||||
}
|
||||
}
|
||||
view.state.selection.select(nodes, selected);
|
||||
broker.broadcastSourcePositionSelect(this, locations, selected);
|
||||
view.updateGraphVisibility();
|
||||
},
|
||||
brokeredNodeSelect: function (locations, selected) {
|
||||
brokeredNodeSelect: function (locations, selected: boolean) {
|
||||
if (!view.graph) return;
|
||||
let selection = view.graph.nodes((n) => {
|
||||
return locations.has(nodeToStringKey(n))
|
||||
@ -772,7 +772,7 @@ export class GraphView extends View implements PhaseView {
|
||||
.text(function (l) {
|
||||
return d.getTitle();
|
||||
})
|
||||
if (d.type != undefined) {
|
||||
if (d.nodeLabel.type != undefined) {
|
||||
d3.select(this).append("text")
|
||||
.classed("label", true)
|
||||
.classed("type", true)
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { GNode, MINIMUM_NODE_OUTPUT_APPROACH, NODE_INPUT_WIDTH } from "./node";
|
||||
import { MAX_RANK_SENTINEL } from "./constants";
|
||||
import { alignUp, measureText } from "./util";
|
||||
import { GNode } from "./node";
|
||||
import { Edge, MINIMUM_EDGE_SEPARATION } from "./edge";
|
||||
|
||||
export class Graph {
|
||||
@ -20,30 +18,8 @@ export class Graph {
|
||||
this.minGraphY = 0;
|
||||
this.maxGraphY = 1;
|
||||
|
||||
data.nodes.forEach((n: any) => {
|
||||
n.__proto__ = GNode.prototype;
|
||||
n.visible = false;
|
||||
n.x = 0;
|
||||
n.y = 0;
|
||||
if (typeof n.pos === "number") {
|
||||
// Backwards compatibility.
|
||||
n.sourcePosition = { scriptOffset: n.pos, inliningId: -1 };
|
||||
}
|
||||
n.rank = MAX_RANK_SENTINEL;
|
||||
n.inputs = [];
|
||||
n.outputs = [];
|
||||
n.outputApproach = MINIMUM_NODE_OUTPUT_APPROACH;
|
||||
// Every control node is a CFG node.
|
||||
n.cfg = n.control;
|
||||
this.nodeMap[n.id] = n;
|
||||
n.displayLabel = n.getDisplayLabel();
|
||||
n.labelbbox = measureText(n.displayLabel);
|
||||
const typebbox = measureText(n.getDisplayType());
|
||||
const innerwidth = Math.max(n.labelbbox.width, typebbox.width);
|
||||
n.width = alignUp(innerwidth + NODE_INPUT_WIDTH * 2,
|
||||
NODE_INPUT_WIDTH);
|
||||
const innerheight = Math.max(n.labelbbox.height, typebbox.height);
|
||||
n.normalheight = innerheight + 20;
|
||||
data.nodes.forEach((json_node: any) => {
|
||||
this.nodeMap[json_node.id] = new GNode(json_node.nodeLabel);
|
||||
});
|
||||
|
||||
data.edges.forEach((e: any) => {
|
||||
|
77
tools/turbolizer/src/node-label.ts
Normal file
77
tools/turbolizer/src/node-label.ts
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
function formatOrigin(origin) {
|
||||
if (origin.nodeId) {
|
||||
return `#${origin.nodeId} in phase ${origin.phase}/${origin.reducer}`;
|
||||
}
|
||||
if (origin.bytecodePosition) {
|
||||
return `Bytecode line ${origin.bytecodePosition} in phase ${origin.phase}/${origin.reducer}`;
|
||||
}
|
||||
return "unknown origin";
|
||||
}
|
||||
|
||||
export class NodeLabel {
|
||||
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: any, origin: any, opcode: string, control: boolean, opinfo: string, type: string) {
|
||||
this.id = id;
|
||||
this.label = label;
|
||||
this.title = title;
|
||||
this.live = live;
|
||||
this.properties = properties;
|
||||
this.sourcePosition = sourcePosition;
|
||||
this.opcode = opcode;
|
||||
this.control = control;
|
||||
this.opinfo = opinfo;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
equals(that?: NodeLabel) {
|
||||
if (!that) return false;
|
||||
if (this.id != that.id) return false;
|
||||
if (this.label != that.label) return false;
|
||||
if (this.title != that.title) return false;
|
||||
if (this.live != that.live) return false;
|
||||
if (this.properties != that.properties) return false;
|
||||
if (this.opcode != that.opcode) return false;
|
||||
if (this.control != that.control) return false;
|
||||
if (this.opinfo != that.opinfo) return false;
|
||||
if (this.type != that.type) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
getTitle() {
|
||||
let propsString = "";
|
||||
if (this.properties === "") {
|
||||
propsString = "no properties";
|
||||
} else {
|
||||
propsString = "[" + this.properties + "]";
|
||||
}
|
||||
let title = this.title + "\n" + propsString + "\n" + this.opinfo;
|
||||
if (this.origin) {
|
||||
title += `\nOrigin: ${formatOrigin(this.origin)}`;
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
getDisplayLabel() {
|
||||
const result = `${this.id}: ${this.label}`;
|
||||
if (result.length > 40) {
|
||||
return `${this.id}: ${this.opcode}`;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -2,74 +2,83 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import { NodeOrigin } from "../src/source-resolver"
|
||||
import { MINIMUM_EDGE_SEPARATION, Edge } from "../src/edge"
|
||||
import { NodeLabel } from "./node-label";
|
||||
import { MAX_RANK_SENTINEL } from "./constants";
|
||||
import { alignUp, measureText } from "./util";
|
||||
|
||||
export const DEFAULT_NODE_BUBBLE_RADIUS = 12;
|
||||
export const NODE_INPUT_WIDTH = 50;
|
||||
export const MINIMUM_NODE_OUTPUT_APPROACH = 15;
|
||||
const MINIMUM_NODE_INPUT_APPROACH = 15 + 2 * DEFAULT_NODE_BUBBLE_RADIUS;
|
||||
|
||||
function formatOrigin(origin) {
|
||||
if (origin.nodeId) {
|
||||
return `#${origin.nodeId} in phase ${origin.phase}/${origin.reducer}`;
|
||||
}
|
||||
if (origin.bytecodePosition) {
|
||||
return `Bytecode line ${origin.bytecodePosition} in phase ${origin.phase}/${origin.reducer}`;
|
||||
}
|
||||
return "unknown origin";
|
||||
}
|
||||
|
||||
export class GNode {
|
||||
control: boolean;
|
||||
opcode: string;
|
||||
live: boolean;
|
||||
inputs: Array<Edge>;
|
||||
width: number;
|
||||
properties: string;
|
||||
title: string;
|
||||
label: string;
|
||||
origin: NodeOrigin;
|
||||
outputs: Array<Edge>;
|
||||
outputApproach: number;
|
||||
type: string;
|
||||
id: number;
|
||||
nodeLabel: NodeLabel;
|
||||
displayLabel: string;
|
||||
inputs: Array<Edge>;
|
||||
outputs: Array<Edge>;
|
||||
visible: boolean;
|
||||
x: number;
|
||||
y: number;
|
||||
visible: boolean;
|
||||
rank: number;
|
||||
opinfo: string;
|
||||
labelbbox: { width: number, height: number };
|
||||
visitOrderWithinRank: number;
|
||||
outputApproach: number;
|
||||
cfg: boolean;
|
||||
labelbbox: { width: number, height: number };
|
||||
width: number;
|
||||
normalheight: number;
|
||||
visitOrderWithinRank: number;
|
||||
|
||||
constructor(nodeLabel: NodeLabel) {
|
||||
this.id = nodeLabel.id;
|
||||
this.nodeLabel = nodeLabel;
|
||||
this.displayLabel = nodeLabel.getDisplayLabel();
|
||||
this.inputs = [];
|
||||
this.outputs = [];
|
||||
this.visible = false;
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.rank = MAX_RANK_SENTINEL;
|
||||
this.outputApproach = MINIMUM_NODE_OUTPUT_APPROACH;
|
||||
// Every control node is a CFG node.
|
||||
this.cfg = nodeLabel.control;
|
||||
this.labelbbox = measureText(this.displayLabel);
|
||||
const typebbox = measureText(this.getDisplayType());
|
||||
const innerwidth = Math.max(this.labelbbox.width, typebbox.width);
|
||||
this.width = alignUp(innerwidth + NODE_INPUT_WIDTH * 2,
|
||||
NODE_INPUT_WIDTH);
|
||||
const innerheight = Math.max(this.labelbbox.height, typebbox.height);
|
||||
this.normalheight = innerheight + 20;
|
||||
this.visitOrderWithinRank = 0;
|
||||
}
|
||||
|
||||
isControl() {
|
||||
return this.control;
|
||||
return this.nodeLabel.control;
|
||||
}
|
||||
isInput() {
|
||||
return this.opcode == 'Parameter' || this.opcode.endsWith('Constant');
|
||||
return this.nodeLabel.opcode == 'Parameter' || this.nodeLabel.opcode.endsWith('Constant');
|
||||
}
|
||||
isLive() {
|
||||
return this.live !== false;
|
||||
return this.nodeLabel.live !== false;
|
||||
}
|
||||
isJavaScript() {
|
||||
return this.opcode.startsWith('JS');
|
||||
return this.nodeLabel.opcode.startsWith('JS');
|
||||
}
|
||||
isSimplified() {
|
||||
if (this.isJavaScript()) return false;
|
||||
return this.opcode.endsWith('Phi') ||
|
||||
this.opcode.startsWith('Boolean') ||
|
||||
this.opcode.startsWith('Number') ||
|
||||
this.opcode.startsWith('String') ||
|
||||
this.opcode.startsWith('Change') ||
|
||||
this.opcode.startsWith('Object') ||
|
||||
this.opcode.startsWith('Reference') ||
|
||||
this.opcode.startsWith('Any') ||
|
||||
this.opcode.endsWith('ToNumber') ||
|
||||
(this.opcode == 'AnyToBoolean') ||
|
||||
(this.opcode.startsWith('Load') && this.opcode.length > 4) ||
|
||||
(this.opcode.startsWith('Store') && this.opcode.length > 5);
|
||||
const opcode = this.nodeLabel.opcode;
|
||||
return opcode.endsWith('Phi') ||
|
||||
opcode.startsWith('Boolean') ||
|
||||
opcode.startsWith('Number') ||
|
||||
opcode.startsWith('String') ||
|
||||
opcode.startsWith('Change') ||
|
||||
opcode.startsWith('Object') ||
|
||||
opcode.startsWith('Reference') ||
|
||||
opcode.startsWith('Any') ||
|
||||
opcode.endsWith('ToNumber') ||
|
||||
(opcode == 'AnyToBoolean') ||
|
||||
(opcode.startsWith('Load') && opcode.length > 4) ||
|
||||
(opcode.startsWith('Store') && opcode.length > 5);
|
||||
}
|
||||
isMachine() {
|
||||
return !(this.isControl() || this.isInput() ||
|
||||
@ -80,33 +89,16 @@ export class GNode {
|
||||
return Math.max(inputWidth, this.width);
|
||||
}
|
||||
getTitle() {
|
||||
var propsString;
|
||||
if (this.properties === undefined) {
|
||||
propsString = "";
|
||||
} else if (this.properties === "") {
|
||||
propsString = "no properties";
|
||||
} else {
|
||||
propsString = "[" + this.properties + "]";
|
||||
}
|
||||
let title = this.title + "\n" + propsString + "\n" + this.opinfo;
|
||||
if (this.origin) {
|
||||
title += `\nOrigin: ${formatOrigin(this.origin)}`;
|
||||
}
|
||||
return title;
|
||||
return this.nodeLabel.getTitle();
|
||||
}
|
||||
getDisplayLabel() {
|
||||
var result = this.id + ":" + this.label;
|
||||
if (result.length > 40) {
|
||||
return this.id + ":" + this.opcode;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
return this.nodeLabel.getDisplayLabel();
|
||||
}
|
||||
getType() {
|
||||
return this.type;
|
||||
return this.nodeLabel.type;
|
||||
}
|
||||
getDisplayType() {
|
||||
var type_string = this.type;
|
||||
var type_string = this.nodeLabel.type;
|
||||
if (type_string == undefined) return "";
|
||||
if (type_string.length > 24) {
|
||||
type_string = type_string.substr(0, 25) + "...";
|
||||
@ -159,14 +151,14 @@ export class GNode {
|
||||
return this.y - MINIMUM_NODE_INPUT_APPROACH -
|
||||
(index % 4) * MINIMUM_EDGE_SEPARATION - DEFAULT_NODE_BUBBLE_RADIUS
|
||||
}
|
||||
getNodeHeight(showTypes:boolean): number {
|
||||
getNodeHeight(showTypes: boolean): number {
|
||||
if (showTypes) {
|
||||
return this.normalheight + this.labelbbox.height;
|
||||
} else {
|
||||
return this.normalheight;
|
||||
}
|
||||
}
|
||||
getOutputApproach(showTypes:boolean) {
|
||||
getOutputApproach(showTypes: boolean) {
|
||||
return this.y + this.outputApproach + this.getNodeHeight(showTypes) +
|
||||
+ DEFAULT_NODE_BUBBLE_RADIUS;
|
||||
}
|
||||
@ -179,9 +171,9 @@ export class GNode {
|
||||
return this.getTotalNodeWidth() - (NODE_INPUT_WIDTH / 2);
|
||||
}
|
||||
hasBackEdges() {
|
||||
return (this.opcode == "Loop") ||
|
||||
((this.opcode == "Phi" || this.opcode == "EffectPhi") &&
|
||||
this.inputs[this.inputs.length - 1].source.opcode == "Loop");
|
||||
return (this.nodeLabel.opcode == "Loop") ||
|
||||
((this.nodeLabel.opcode == "Phi" || this.nodeLabel.opcode == "EffectPhi" || this.nodeLabel.opcode == "InductionVariablePhi") &&
|
||||
this.inputs[this.inputs.length - 1].source.nodeLabel.opcode == "Loop");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import { sortUnique, anyToString } from "../src/util"
|
||||
import { NodeLabel } from "./node-label";
|
||||
|
||||
function sourcePositionLe(a, b) {
|
||||
if (a.inliningId == b.inliningId) {
|
||||
@ -87,6 +88,7 @@ interface GraphPhase {
|
||||
name: string;
|
||||
data: any;
|
||||
highestNodeId: number;
|
||||
nodeLabelMap: Array<NodeLabel>;
|
||||
}
|
||||
|
||||
type Phase = GraphPhase | InstructionsPhase | OtherPhase;
|
||||
@ -333,8 +335,14 @@ export class SourceResolver {
|
||||
this.positionToNodes.set(key, []);
|
||||
}
|
||||
const A = this.positionToNodes.get(key);
|
||||
if (!A.includes(node.id)) A.push("" + node.id);
|
||||
if (!A.includes(node.id)) A.push(`${node.id}`);
|
||||
}
|
||||
|
||||
// Backwards compatibility.
|
||||
if (typeof node.pos === "number") {
|
||||
node.sourcePosition = { scriptOffset: node.pos, inliningId: -1 };
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,6 +443,7 @@ export class SourceResolver {
|
||||
}
|
||||
|
||||
parsePhases(phases) {
|
||||
const nodeLabelMap = [];
|
||||
for (const [, phase] of Object.entries<Phase>(phases)) {
|
||||
switch (phase.type) {
|
||||
case 'disassembly':
|
||||
@ -463,6 +472,8 @@ export class SourceResolver {
|
||||
const graphPhase: GraphPhase = Object.assign(phase, { highestNodeId: 0 });
|
||||
this.phases.push(graphPhase);
|
||||
this.recordOrigins(graphPhase);
|
||||
this.internNodeLabels(graphPhase, nodeLabelMap);
|
||||
graphPhase.nodeLabelMap = nodeLabelMap.slice();
|
||||
this.phaseNames.set(graphPhase.name, this.phases.length);
|
||||
break;
|
||||
default:
|
||||
@ -471,6 +482,19 @@ export class SourceResolver {
|
||||
}
|
||||
}
|
||||
|
||||
internNodeLabels(phase: GraphPhase, nodeLabelMap: Array<NodeLabel>) {
|
||||
for (const n of phase.data.nodes) {
|
||||
const label = new NodeLabel(n.id, n.label, n.title, n.live,
|
||||
n.properties, n.sourcePosition, n.origin, n.opcode, n.control,
|
||||
n.opinfo, n.type);
|
||||
const previous = nodeLabelMap[label.id];
|
||||
if (!label.equals(previous)) {
|
||||
nodeLabelMap[label.id] = label;
|
||||
}
|
||||
n.nodeLabel = nodeLabelMap[label.id];
|
||||
}
|
||||
}
|
||||
|
||||
repairPhaseId(anyPhaseId) {
|
||||
return Math.max(0, Math.min(anyPhaseId, this.phases.length - 1))
|
||||
}
|
||||
|
@ -31,6 +31,6 @@ export abstract class View {
|
||||
}
|
||||
|
||||
export interface PhaseView {
|
||||
onresize();
|
||||
searchInputAction(searchInput: HTMLInputElement, e: Event);
|
||||
onresize(): void;
|
||||
searchInputAction(searchInput: HTMLInputElement, e: Event): void;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
"src/node.ts",
|
||||
"src/edge.ts",
|
||||
"src/graph.ts",
|
||||
"src/node-label.ts",
|
||||
"src/source-resolver.ts",
|
||||
"src/selection.ts",
|
||||
"src/selection-broker.ts",
|
||||
|
Loading…
Reference in New Issue
Block a user