[turbolizer] Selection refactoring

- Moved graph-phase.ts to graph-phase folder
- Refactored selection.ts, selection-broker.ts, selection-handler.ts, source-resolver.ts

Bug: v8:7327
Change-Id: I922c8730f89c53a73a55414378ac1e29a6397a80
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3714945
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Danylo Boiko <danielboyko02@gmail.com>
Cr-Commit-Position: refs/heads/main@{#81385}
This commit is contained in:
Danylo Boiko 2022-06-23 21:39:09 +03:00 committed by V8 LUCI CQ
parent 087d225520
commit 8e49ce29cd
13 changed files with 281 additions and 329 deletions

View File

@ -6,7 +6,7 @@ import * as C from "./common/constants";
import { Graph } from "./graph";
import { GraphNode } from "./phases/graph-phase/graph-node";
import { GraphEdge } from "./phases/graph-phase/graph-edge";
import { GraphStateType } from "./phases/graph-phase";
import { GraphStateType } from "./phases/graph-phase/graph-phase";
export class GraphLayout {
graph: Graph;

View File

@ -3,7 +3,7 @@
// found in the LICENSE file.
import * as C from "./common/constants";
import { GraphPhase, GraphStateType } from "./phases/graph-phase";
import { GraphPhase, GraphStateType } from "./phases/graph-phase/graph-phase";
import { GraphEdge } from "./phases/graph-phase/graph-edge";
import { GraphNode } from "./phases/graph-phase/graph-node";

View File

@ -9,7 +9,7 @@ import { SequenceView } from "./views/sequence-view";
import { GenericPhase, SourceResolver } from "./source-resolver";
import { SelectionBroker } from "./selection/selection-broker";
import { PhaseView, View } from "./views/view";
import { GraphPhase } from "./phases/graph-phase";
import { GraphPhase } from "./phases/graph-phase/graph-phase";
import { GraphNode } from "./phases/graph-phase/graph-node";
import { storageGetItem, storageSetItem } from "./common/util";
import { PhaseType } from "./phases/phase";
@ -147,7 +147,7 @@ export class GraphMultiView extends View {
private initializeSelect(): void {
const view = this;
view.selectMenu.innerHTML = "";
view.sourceResolver.forEachPhase((phase: GenericPhase) => {
for (const phase of view.sourceResolver.phases) {
const optionElement = document.createElement("option");
let maxNodeId = "";
if (phase instanceof GraphPhase && phase.highestNodeId != 0) {
@ -155,7 +155,7 @@ export class GraphMultiView extends View {
}
optionElement.text = `${phase.name}${maxNodeId}`;
view.selectMenu.add(optionElement);
});
}
this.selectMenu.onchange = function (this: HTMLSelectElement) {
const phaseIndex = this.selectedIndex;
storageSetItem("lastSelectedPhase", phaseIndex);

View File

@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { Phase, PhaseType } from "./phase";
import { NodeLabel } from "../node-label";
import { BytecodeOrigin, NodeOrigin } from "../origin";
import { SourcePosition } from "../position";
import { GraphNode } from "./graph-phase/graph-node";
import { GraphEdge } from "./graph-phase/graph-edge";
import { Phase, PhaseType } from "../phase";
import { NodeLabel } from "../../node-label";
import { BytecodeOrigin, NodeOrigin } from "../../origin";
import { SourcePosition } from "../../position";
import { GraphNode } from "./graph-node";
import { GraphEdge } from "./graph-edge";
export class GraphPhase extends Phase {
highestNodeId: number;

View File

@ -29,8 +29,7 @@ export class SourcePosition {
}
public equals(other: SourcePosition): boolean {
if (this.scriptOffset != other.scriptOffset) return false;
return this.inliningId == other.inliningId;
return this.inliningId == other.inliningId && this.scriptOffset == other.scriptOffset;
}
public isValid(): boolean {

View File

@ -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 { SourceResolver, sourcePositionValid } from "../source-resolver";
import { SourceResolver } from "../source-resolver";
import { ClearableHandler, SelectionHandler, NodeSelectionHandler, BlockSelectionHandler, InstructionSelectionHandler, RegisterAllocationSelectionHandler } from "./selection-handler";
export class SelectionBroker {
@ -14,137 +14,141 @@ export class SelectionBroker {
instructionHandlers: Array<InstructionSelectionHandler>;
registerAllocationHandlers: Array<RegisterAllocationSelectionHandler>;
constructor(sourceResolver) {
this.allHandlers = [];
this.sourcePositionHandlers = [];
this.nodeHandlers = [];
this.blockHandlers = [];
this.instructionHandlers = [];
this.registerAllocationHandlers = [];
constructor(sourceResolver: SourceResolver) {
this.sourceResolver = sourceResolver;
this.allHandlers = new Array<ClearableHandler>();
this.sourcePositionHandlers = new Array<SelectionHandler>();
this.nodeHandlers = new Array<NodeSelectionHandler>();
this.blockHandlers = new Array<BlockSelectionHandler>();
this.instructionHandlers = new Array<InstructionSelectionHandler>();
this.registerAllocationHandlers = new Array<RegisterAllocationSelectionHandler>();
}
addSourcePositionHandler(handler: SelectionHandler & ClearableHandler) {
public addSourcePositionHandler(handler: SelectionHandler & ClearableHandler): void {
this.allHandlers.push(handler);
this.sourcePositionHandlers.push(handler);
}
addNodeHandler(handler: NodeSelectionHandler & ClearableHandler) {
public addNodeHandler(handler: NodeSelectionHandler & ClearableHandler): void {
this.allHandlers.push(handler);
this.nodeHandlers.push(handler);
}
addBlockHandler(handler: BlockSelectionHandler & ClearableHandler) {
public addBlockHandler(handler: BlockSelectionHandler & ClearableHandler): void {
this.allHandlers.push(handler);
this.blockHandlers.push(handler);
}
addInstructionHandler(handler: InstructionSelectionHandler & ClearableHandler) {
public addInstructionHandler(handler: InstructionSelectionHandler & ClearableHandler): void {
this.allHandlers.push(handler);
this.instructionHandlers.push(handler);
}
addRegisterAllocatorHandler(handler: RegisterAllocationSelectionHandler & ClearableHandler) {
public addRegisterAllocatorHandler(handler: RegisterAllocationSelectionHandler
& ClearableHandler): void {
this.allHandlers.push(handler);
this.registerAllocationHandlers.push(handler);
}
broadcastInstructionSelect(from, instructionOffsets, selected) {
public broadcastInstructionSelect(from, instructionOffsets, selected: boolean): void {
// Select the lines from the disassembly (right panel)
for (const b of this.instructionHandlers) {
if (b != from) b.brokeredInstructionSelect(instructionOffsets, selected);
for (const handler of this.instructionHandlers) {
if (handler != from) handler.brokeredInstructionSelect(instructionOffsets, selected);
}
// Select the lines from the source panel (left panel)
const pcOffsets = this.sourceResolver.instructionsPhase
.instructionsToKeyPcOffsets(instructionOffsets);
for (const offset of pcOffsets) {
const nodes = this.sourceResolver.instructionsPhase.nodesForPCOffset(offset);
const sourcePositions = this.sourceResolver.nodeIdsToSourcePositions(nodes);
for (const b of this.sourcePositionHandlers) {
if (b != from) b.brokeredSourcePositionSelect(sourcePositions, selected);
for (const handler of this.sourcePositionHandlers) {
if (handler != from) handler.brokeredSourcePositionSelect(sourcePositions, selected);
}
}
// The middle panel lines have already been selected so there's no need to reselect them.
}
broadcastSourcePositionSelect(from, sourcePositions, selected) {
sourcePositions = sourcePositions.filter(l => {
if (!sourcePositionValid(l)) {
console.log("Warning: invalid source position");
public broadcastSourcePositionSelect(from, sourcePositions, selected: boolean): void {
sourcePositions = sourcePositions.filter(sourcePosition => {
if (!sourcePosition.isValid()) {
console.warn("Invalid source position");
return false;
}
return true;
});
// Select the lines from the source panel (left panel)
for (const b of this.sourcePositionHandlers) {
if (b != from) b.brokeredSourcePositionSelect(sourcePositions, selected);
for (const handler of this.sourcePositionHandlers) {
if (handler != from) handler.brokeredSourcePositionSelect(sourcePositions, selected);
}
// Select the nodes (middle panel)
const nodes = this.sourceResolver.sourcePositionsToNodeIds(sourcePositions);
for (const b of this.nodeHandlers) {
if (b != from) b.brokeredNodeSelect(nodes, selected);
for (const handler of this.nodeHandlers) {
if (handler != from) handler.brokeredNodeSelect(nodes, selected);
}
for (const node of nodes) {
const instructionOffsets = this.sourceResolver.instructionsPhase
.nodeIdToInstructionRange[node];
// Skip nodes which do not have an associated instruction range.
if (instructionOffsets == undefined) continue;
// Select the lines from the disassembly (right panel)
for (const b of this.instructionHandlers) {
if (b != from) b.brokeredInstructionSelect(instructionOffsets, selected);
for (const handler of this.instructionHandlers) {
if (handler != from) handler.brokeredInstructionSelect(instructionOffsets, selected);
}
// Select the lines from the middle panel for the register allocation phase.
for (const b of this.registerAllocationHandlers) {
if (b != from) b.brokeredRegisterAllocationSelect(instructionOffsets, selected);
for (const handler of this.registerAllocationHandlers) {
if (handler != from) handler.brokeredRegisterAllocationSelect(instructionOffsets, selected);
}
}
}
broadcastNodeSelect(from, nodes, selected) {
public broadcastNodeSelect(from, nodes, selected: boolean): void {
// Select the nodes (middle panel)
for (const b of this.nodeHandlers) {
if (b != from) b.brokeredNodeSelect(nodes, selected);
for (const handler of this.nodeHandlers) {
if (handler != from) handler.brokeredNodeSelect(nodes, selected);
}
// Select the lines from the source panel (left panel)
const sourcePositions = this.sourceResolver.nodeIdsToSourcePositions(nodes);
for (const b of this.sourcePositionHandlers) {
if (b != from) b.brokeredSourcePositionSelect(sourcePositions, selected);
for (const handler of this.sourcePositionHandlers) {
if (handler != from) handler.brokeredSourcePositionSelect(sourcePositions, selected);
}
for (const node of nodes) {
const instructionOffsets = this.sourceResolver.instructionsPhase
.nodeIdToInstructionRange[node];
// Skip nodes which do not have an associated instruction range.
if (instructionOffsets == undefined) continue;
// Select the lines from the disassembly (right panel)
for (const b of this.instructionHandlers) {
if (b != from) b.brokeredInstructionSelect(instructionOffsets, selected);
for (const handler of this.instructionHandlers) {
if (handler != from) handler.brokeredInstructionSelect(instructionOffsets, selected);
}
// Select the lines from the middle panel for the register allocation phase.
for (const b of this.registerAllocationHandlers) {
if (b != from) b.brokeredRegisterAllocationSelect(instructionOffsets, selected);
for (const handler of this.registerAllocationHandlers) {
if (handler != from) handler.brokeredRegisterAllocationSelect(instructionOffsets, selected);
}
}
}
broadcastBlockSelect(from, blocks, selected) {
for (const b of this.blockHandlers) {
if (b != from) b.brokeredBlockSelect(blocks, selected);
public broadcastBlockSelect(from, blocks, selected: boolean): void {
for (const handler of this.blockHandlers) {
if (handler != from) handler.brokeredBlockSelect(blocks, selected);
}
}
broadcastClear(from) {
this.allHandlers.forEach(function (b) {
if (b != from) b.brokeredClear();
public broadcastClear(from): void {
this.allHandlers.forEach(handler => {
if (handler != from) handler.brokeredClear();
});
}
}

View File

@ -4,56 +4,56 @@
import { GraphNode } from "../phases/graph-phase/graph-node";
export class MySelection {
selection: any;
stringKey: (o: any) => string;
export class SelectionMap {
selection: Map<string, any>;
stringKey: (obj: any) => string;
originStringKey: (node: GraphNode) => string;
constructor(stringKeyFnc, originStringKeyFnc?) {
this.selection = new Map();
this.selection = new Map<string, any>();
this.stringKey = stringKeyFnc;
this.originStringKey = originStringKeyFnc;
}
isEmpty(): boolean {
public isEmpty(): boolean {
return this.selection.size == 0;
}
clear(): void {
this.selection = new Map();
public clear(): void {
this.selection = new Map<string, any>();
}
select(s: Iterable<any>, isSelected?: boolean) {
for (const i of s) {
if (i == undefined) continue;
if (isSelected == undefined) {
isSelected = !this.selection.has(this.stringKey(i));
public select(items: Iterable<any>, isSelected?: boolean): void {
for (const item of items) {
if (item === undefined) continue;
if (isSelected === undefined) {
isSelected = !this.selection.has(this.stringKey(item));
}
if (isSelected) {
this.selection.set(this.stringKey(i), i);
this.selection.set(this.stringKey(item), item);
} else {
this.selection.delete(this.stringKey(i));
this.selection.delete(this.stringKey(item));
}
}
}
isSelected(i: any): boolean {
return this.selection.has(this.stringKey(i));
public isSelected(obj: any): boolean {
return this.selection.has(this.stringKey(obj));
}
isKeySelected(key: string): boolean {
public isKeySelected(key: string): boolean {
return this.selection.has(key);
}
selectedKeys(): Set<string> {
public selectedKeys(): Set<string> {
const result = new Set<string>();
for (const i of this.selection.keys()) {
result.add(i);
for (const key of this.selection.keys()) {
result.add(key);
}
return result;
}
detachSelection() {
public detachSelection(): Map<string, any> {
const result = this.selection;
this.clear();
return result;

View File

@ -4,7 +4,7 @@
import { anyToString, camelize, sortUnique } from "./common/util";
import { PhaseType } from "./phases/phase";
import { GraphPhase } from "./phases/graph-phase";
import { GraphPhase } from "./phases/graph-phase/graph-phase";
import { DisassemblyPhase } from "./phases/disassembly-phase";
import { BytecodePosition, InliningPosition, SourcePosition } from "./position";
import { InstructionsPhase } from "./phases/instructions-phase";
@ -15,34 +15,6 @@ import { Source } from "./source";
import { NodeLabel } from "./node-label";
import { TurboshaftGraphPhase } from "./phases/turboshaft-graph-phase/turboshaft-graph-phase";
function sourcePositionLe(a, b) {
if (a.inliningId == b.inliningId) {
return a.scriptOffset - b.scriptOffset;
}
return a.inliningId - b.inliningId;
}
function sourcePositionEq(a, b) {
return a.inliningId == b.inliningId &&
a.scriptOffset == b.scriptOffset;
}
export function sourcePositionToStringKey(sourcePosition: GenericPosition): string {
if (!sourcePosition) return "undefined";
if ('inliningId' in sourcePosition && 'scriptOffset' in sourcePosition) {
return "SP:" + sourcePosition.inliningId + ":" + sourcePosition.scriptOffset;
}
if (sourcePosition.bytecodePosition) {
return "BCP:" + sourcePosition.bytecodePosition;
}
return "undefined";
}
export function sourcePositionValid(l) {
return (typeof l.scriptOffset !== undefined
&& typeof l.inliningId !== undefined) || typeof l.bytecodePosition != undefined;
}
export type GenericPosition = SourcePosition | BytecodePosition;
export type GenericPhase = GraphPhase | TurboshaftGraphPhase | DisassemblyPhase
| InstructionsPhase | SchedulePhase | SequencePhase;
@ -61,29 +33,29 @@ export class SourceResolver {
constructor() {
// Maps node ids to source positions.
this.nodePositionMap = [];
this.nodePositionMap = new Array<GenericPosition>();
// Maps source ids to source objects.
this.sources = [];
this.sources = new Array<Source>();
// Maps inlining ids to inlining objects.
this.inlinings = [];
this.inlinings = new Array<InliningPosition>();
// Maps source position keys to inlinings.
this.inliningsMap = new Map();
this.inliningsMap = new Map<string, InliningPosition>();
// Maps source position keys to node ids.
this.positionToNodes = new Map();
this.positionToNodes = new Map<string, Array<string>>();
// Maps phase ids to phases.
this.phases = [];
this.phases = new Array<GenericPhase>();
// Maps phase names to phaseIds.
this.phaseNames = new Map();
this.phaseNames = new Map<string, number>();
// The disassembly phase is stored separately.
this.disassemblyPhase = undefined;
// Maps line numbers to source positions
this.linePositionMap = new Map();
this.linePositionMap = new Map<string, Array<GenericPosition>>();
}
public getMainFunction(jsonObj): Source {
const fncJson = jsonObj.function;
// Backwards compatibility.
if (typeof fncJson === 'string') {
if (typeof fncJson === "string") {
return new Source(null, null, jsonObj.source, -1, true,
new Array<SourcePosition>(), jsonObj.sourcePosition,
jsonObj.sourcePosition + jsonObj.source.length);
@ -93,191 +65,66 @@ export class SourceResolver {
fncJson.endPosition);
}
setSources(sources, mainBackup) {
if (sources) {
for (const [sourceId, source] of Object.entries(sources)) {
this.sources[sourceId] = source;
this.sources[sourceId].sourcePositions = [];
}
}
// This is a fallback if the JSON is incomplete (e.g. due to compiler crash).
if (!this.sources[-1]) {
this.sources[-1] = mainBackup;
this.sources[-1].sourcePositions = [];
}
}
setInlinings(inlinings) {
if (inlinings) {
for (const [inliningId, inlining] of Object.entries<InliningPosition>(inlinings)) {
this.inlinings[inliningId] = inlining;
this.inliningsMap.set(sourcePositionToStringKey(inlining.inliningPosition), inlining);
public setInlinings(inliningsJson): void {
if (inliningsJson) {
for (const [inliningIdStr, inlining] of Object.entries<InliningPosition>(inliningsJson)) {
const scriptOffset = inlining.inliningPosition.scriptOffset;
const inliningId = inlining.inliningPosition.inliningId;
const inl = new InliningPosition(inlining.sourceId,
new SourcePosition(scriptOffset, inliningId));
this.inlinings[inliningIdStr] = inl;
this.inliningsMap.set(inl.inliningPosition.toString(), inl);
}
}
// This is a default entry for the script itself that helps
// keep other code more uniform.
this.inlinings[-1] = { sourceId: -1, inliningPosition: null };
this.inlinings[-1] = new InliningPosition(-1, null);
}
setNodePositionMap(map) {
if (!map) return;
if (typeof map[0] != 'object') {
const alternativeMap = {};
for (const [nodeId, scriptOffset] of Object.entries<number>(map)) {
alternativeMap[nodeId] = { scriptOffset: scriptOffset, inliningId: -1 };
public setSources(sourcesJson, mainFunc: Source): void {
if (sourcesJson) {
for (const [sourceId, source] of Object.entries<Source>(sourcesJson)) {
const src = new Source(source.sourceName, source.functionName, source.sourceText,
source.sourceId, source.backwardsCompatibility, new Array<SourcePosition>(),
source.startPosition, source.endPosition);
this.sources[sourceId] = src;
}
}
// This is a fallback if the JSON is incomplete (e.g. due to compiler crash).
if (!this.sources[-1]) {
this.sources[-1] = mainFunc;
}
map = alternativeMap;
}
for (const [nodeId, sourcePosition] of Object.entries<SourcePosition>(map)) {
if (sourcePosition == undefined) {
console.log("Warning: undefined source position ", sourcePosition, " for nodeId ", nodeId);
public setNodePositionMap(mapJson): void {
if (!mapJson) return;
if (typeof mapJson[0] !== "object") {
const alternativeMap = new Map<string, SourcePosition>();
for (const [nodeId, scriptOffset] of Object.entries<number>(mapJson)) {
alternativeMap[nodeId] = new SourcePosition(scriptOffset, -1);
}
const inliningId = sourcePosition.inliningId;
const inlining = this.inlinings[inliningId];
if (inlining) {
const sourceId = inlining.sourceId;
this.sources[sourceId].sourcePositions.push(sourcePosition);
mapJson = alternativeMap;
}
this.nodePositionMap[nodeId] = sourcePosition;
const key = sourcePositionToStringKey(sourcePosition);
for (const [nodeId, sourcePosition] of Object.entries<SourcePosition>(mapJson)) {
if (sourcePosition === undefined) {
console.warn(`Undefined source position for node id ${nodeId}`);
}
const inlining = this.inlinings[sourcePosition.inliningId];
const sp = new SourcePosition(sourcePosition.scriptOffset, sourcePosition.inliningId);
if (inlining) this.sources[inlining.sourceId].sourcePositions.push(sp);
this.nodePositionMap[nodeId] = sp;
const key = sp.toString();
if (!this.positionToNodes.has(key)) {
this.positionToNodes.set(key, []);
this.positionToNodes.set(key, new Array<string>());
}
this.positionToNodes.get(key).push(nodeId);
}
for (const [, source] of Object.entries(this.sources)) {
for (const [, source] of Object.entries<Source>(this.sources)) {
source.sourcePositions = sortUnique(source.sourcePositions,
sourcePositionLe, sourcePositionEq);
}
}
sourcePositionsToNodeIds(sourcePositions) {
const nodeIds = new Set<string>();
for (const sp of sourcePositions) {
const key = sourcePositionToStringKey(sp);
const nodeIdsForPosition = this.positionToNodes.get(key);
if (!nodeIdsForPosition) continue;
for (const nodeId of nodeIdsForPosition) {
nodeIds.add(nodeId);
}
}
return nodeIds;
}
nodeIdsToSourcePositions(nodeIds): Array<GenericPosition> {
const sourcePositions = new Map();
for (const nodeId of nodeIds) {
const sp = this.nodePositionMap[nodeId];
const key = sourcePositionToStringKey(sp);
sourcePositions.set(key, sp);
}
const sourcePositionArray = [];
for (const sp of sourcePositions.values()) {
sourcePositionArray.push(sp);
}
return sourcePositionArray;
}
translateToSourceId(sourceId: number, location?: SourcePosition) {
for (const position of this.getInlineStack(location)) {
const inlining = this.inlinings[position.inliningId];
if (!inlining) continue;
if (inlining.sourceId == sourceId) {
return position;
}
}
return location;
}
addInliningPositions(sourcePosition: GenericPosition, locations: Array<SourcePosition>) {
const inlining = this.inliningsMap.get(sourcePositionToStringKey(sourcePosition));
if (!inlining) return;
const sourceId = inlining.sourceId;
const source = this.sources[sourceId];
for (const sp of source.sourcePositions) {
locations.push(sp);
this.addInliningPositions(sp, locations);
}
}
getInliningForPosition(sourcePosition: GenericPosition) {
return this.inliningsMap.get(sourcePositionToStringKey(sourcePosition));
}
getSource(sourceId: number) {
return this.sources[sourceId];
}
getSourceName(sourceId: number) {
const source = this.sources[sourceId];
return `${source.sourceName}:${source.functionName}`;
}
sourcePositionFor(sourceId: number, scriptOffset: number) {
if (!this.sources[sourceId]) {
return null;
}
const list = this.sources[sourceId].sourcePositions;
for (let i = 0; i < list.length; i++) {
const sourcePosition = list[i];
const position = sourcePosition.scriptOffset;
const nextPosition = list[Math.min(i + 1, list.length - 1)].scriptOffset;
if ((position <= scriptOffset && scriptOffset < nextPosition)) {
return sourcePosition;
}
}
return null;
}
sourcePositionsInRange(sourceId: number, start: number, end: number) {
if (!this.sources[sourceId]) return [];
const res = [];
const list = this.sources[sourceId].sourcePositions;
for (const sourcePosition of list) {
if (start <= sourcePosition.scriptOffset && sourcePosition.scriptOffset < end) {
res.push(sourcePosition);
}
}
return res;
}
getInlineStack(sourcePosition?: SourcePosition) {
if (!sourcePosition) return [];
const inliningStack = [];
let cur = sourcePosition;
while (cur && cur.inliningId != -1) {
inliningStack.push(cur);
const inlining = this.inlinings[cur.inliningId];
if (!inlining) {
break;
}
cur = inlining.inliningPosition;
}
if (cur && cur.inliningId == -1) {
inliningStack.push(cur);
}
return inliningStack;
}
private recordOrigins(graphPhase: GraphPhase): void {
if (graphPhase.type !== PhaseType.Graph) return;
for (const node of graphPhase.data.nodes) {
graphPhase.highestNodeId = Math.max(graphPhase.highestNodeId, node.id);
const origin = node.nodeLabel.origin;
const isBytecode = origin instanceof BytecodeOrigin;
if (isBytecode) {
const position = new BytecodePosition(origin.bytecodePosition);
this.nodePositionMap[node.id] = position;
const key = position.toString();
if (!this.positionToNodes.has(key)) {
this.positionToNodes.set(key, []);
}
const nodes = this.positionToNodes.get(key);
const identifier = node.identifier();
if (!nodes.includes(identifier)) nodes.push(identifier);
}
(a, b) => a.lessOrEquals(b),
(a, b) => a.equals(b));
}
}
@ -347,41 +194,144 @@ export class SourceResolver {
}
}
repairPhaseId(anyPhaseId) {
public sourcePositionsToNodeIds(sourcePositions: Array<GenericPosition>): Set<string> {
const nodeIds = new Set<string>();
for (const sp of sourcePositions) {
const nodeIdsForPosition = this.positionToNodes.get(sp.toString());
if (!nodeIdsForPosition) continue;
for (const nodeId of nodeIdsForPosition) {
nodeIds.add(nodeId);
}
}
return nodeIds;
}
public nodeIdsToSourcePositions(nodeIds: Array<string>): Array<GenericPosition> {
const sourcePositions = new Map<string, GenericPosition>();
for (const nodeId of nodeIds) {
const position = this.nodePositionMap[nodeId];
if (!position) continue;
sourcePositions.set(position.toString(), position);
}
const sourcePositionArray = new Array<GenericPosition>();
for (const sourcePosition of sourcePositions.values()) {
sourcePositionArray.push(sourcePosition);
}
return sourcePositionArray;
}
public translateToSourceId(sourceId: number, location?: SourcePosition): SourcePosition {
for (const position of this.getInlineStack(location)) {
const inlining = this.inlinings[position.inliningId];
if (!inlining) continue;
if (inlining.sourceId == sourceId) {
return position;
}
}
return location;
}
public addInliningPositions(sourcePosition: GenericPosition, locations: Array<SourcePosition>):
void {
const inlining = this.inliningsMap.get(sourcePosition.toString());
if (!inlining) return;
const source = this.sources[inlining.sourceId];
for (const sp of source.sourcePositions) {
locations.push(sp);
this.addInliningPositions(sp, locations);
}
}
public getInliningForPosition(sourcePosition: GenericPosition): InliningPosition {
return this.inliningsMap.get(sourcePosition.toString());
}
public getSource(sourceId: number): Source {
return this.sources[sourceId];
}
public addAnyPositionToLine(lineNumber: number | string, sourcePosition: GenericPosition): void {
const lineNumberString = anyToString(lineNumber);
if (!this.linePositionMap.has(lineNumberString)) {
this.linePositionMap.set(lineNumberString, new Array<GenericPosition>());
}
const storedPositions = this.linePositionMap.get(lineNumberString);
if (!storedPositions.includes(sourcePosition)) storedPositions.push(sourcePosition);
}
public repairPhaseId(anyPhaseId: number): number {
return Math.max(0, Math.min(anyPhaseId | 0, this.phases.length - 1));
}
getPhase(phaseId: number) {
public getPhase(phaseId: number): GenericPhase {
return this.phases[phaseId];
}
getPhaseIdByName(phaseName: string) {
public getPhaseIdByName(phaseName: string): number {
return this.phaseNames.get(phaseName);
}
forEachPhase(f: (value: GenericPhase, index: number, array: Array<GenericPhase>) => void) {
this.phases.forEach(f);
public lineToSourcePositions(lineNumber: number | string): Array<GenericPosition> {
return this.linePositionMap.get(anyToString(lineNumber)) ?? new Array<GenericPosition>();
}
addAnyPositionToLine(lineNumber: number | string, sourcePosition: GenericPosition) {
const lineNumberString = anyToString(lineNumber);
if (!this.linePositionMap.has(lineNumberString)) {
this.linePositionMap.set(lineNumberString, []);
}
const A = this.linePositionMap.get(lineNumberString);
if (!A.includes(sourcePosition)) A.push(sourcePosition);
public getSourceName(sourceId: number): string {
const source = this.sources[sourceId];
return `${source.sourceName}:${source.functionName}`;
}
setSourceLineToBytecodePosition(sourceLineToBytecodePosition: Array<number> | undefined) {
if (!sourceLineToBytecodePosition) return;
sourceLineToBytecodePosition.forEach((pos, i) => {
this.addAnyPositionToLine(i, new BytecodePosition(pos));
public sourcePositionsInRange(sourceId: number, start: number, end: number):
Array<SourcePosition> {
const inRange = Array<SourcePosition>();
if (!this.sources[sourceId]) return inRange;
const list = this.sources[sourceId].sourcePositions;
for (const sourcePosition of list) {
if (start <= sourcePosition.scriptOffset && sourcePosition.scriptOffset < end) {
inRange.push(sourcePosition);
}
}
return inRange;
}
public setSourceLineToBytecodePosition(sourceLineToBytecodePositionJson): void {
if (!sourceLineToBytecodePositionJson) return;
sourceLineToBytecodePositionJson.forEach((position, idx) => {
this.addAnyPositionToLine(idx, new BytecodePosition(position));
});
}
lineToSourcePositions(lineNumber: number | string) {
const positions = this.linePositionMap.get(anyToString(lineNumber));
if (positions === undefined) return [];
return positions;
private getInlineStack(sourcePosition?: SourcePosition): Array<SourcePosition> {
const inliningStack = Array<SourcePosition>();
if (!sourcePosition) return inliningStack;
let cur = sourcePosition;
while (cur && cur.inliningId != -1) {
inliningStack.push(cur);
const inlining = this.inlinings[cur.inliningId];
if (!inlining) break;
cur = inlining.inliningPosition;
}
if (cur && cur.inliningId == -1) {
inliningStack.push(cur);
}
return inliningStack;
}
private recordOrigins(graphPhase: GraphPhase): void {
if (graphPhase.type !== PhaseType.Graph) return;
for (const node of graphPhase.data.nodes) {
graphPhase.highestNodeId = Math.max(graphPhase.highestNodeId, node.id);
const origin = node.nodeLabel.origin;
if (origin instanceof BytecodeOrigin) {
const position = new BytecodePosition(origin.bytecodePosition);
this.nodePositionMap[node.id] = position;
const key = position.toString();
if (!this.positionToNodes.has(key)) {
this.positionToNodes.set(key, new Array<string>());
}
const nodes = this.positionToNodes.get(key);
const identifier = node.identifier();
if (!nodes.includes(identifier)) nodes.push(identifier);
}
}
}
}

View File

@ -12,10 +12,10 @@ declare global {
const PR: PR;
}
import { SourceResolver, sourcePositionToStringKey } from "../source-resolver";
import { GenericPosition, SourceResolver } from "../source-resolver";
import { SelectionBroker } from "../selection/selection-broker";
import { View } from "./view";
import { MySelection } from "../selection/selection";
import { SelectionMap } from "../selection/selection";
import { ViewElements } from "../common/view-elements";
import { SelectionHandler } from "../selection/selection-handler";
@ -32,7 +32,7 @@ export class CodeView extends View {
sourcePositionToHtmlElements: Map<string, Array<HTMLElement>>;
showAdditionalInliningPosition: boolean;
selectionHandler: SelectionHandler;
selection: MySelection;
selection: SelectionMap;
createViewElement() {
const sourceContainer = document.createElement("div");
@ -81,14 +81,14 @@ export class CodeView extends View {
view.updateSelection();
},
};
view.selection = new MySelection(sourcePositionToStringKey);
view.selection = new SelectionMap((sp: GenericPosition) => sp.toString());
broker.addSourcePositionHandler(selectionHandler);
this.selectionHandler = selectionHandler;
this.initializeCode();
}
addHtmlElementToSourcePosition(sourcePosition, element) {
const key = sourcePositionToStringKey(sourcePosition);
const key = sourcePosition.toString();
if (!this.sourcePositionToHtmlElements.has(key)) {
this.sourcePositionToHtmlElements.set(key, []);
}
@ -96,8 +96,7 @@ export class CodeView extends View {
}
getHtmlElementForSourcePosition(sourcePosition) {
const key = sourcePositionToStringKey(sourcePosition);
return this.sourcePositionToHtmlElements.get(key);
return this.sourcePositionToHtmlElements.get(sourcePosition.toString());
}
updateSelection(scrollIntoView: boolean = false): void {
@ -248,7 +247,7 @@ export class CodeView extends View {
offset += splitLength;
const replacementNode = textnode.splitText(splitLength);
const span = document.createElement('span');
span.setAttribute("scriptOffset", sourcePosition.scriptOffset);
span.setAttribute("scriptOffset", sourcePosition.scriptOffset.toString());
span.classList.add("source-position");
const marker = document.createElement('span');
marker.classList.add("marker");

View File

@ -5,7 +5,7 @@
import { PROF_COLS, UNICODE_BLOCK } from "../common/constants";
import { SelectionBroker } from "../selection/selection-broker";
import { TextView } from "./text-view";
import { MySelection } from "../selection/selection";
import { SelectionMap } from "../selection/selection";
import { anyToString, interpolate } from "../common/util";
import { InstructionSelectionHandler } from "../selection/selection-handler";
import { TurbolizerInstructionStartInfo } from "../phases/instructions-phase";
@ -25,7 +25,7 @@ export class DisassemblyView extends TextView {
maxEventCounts: any;
posLines: Array<any>;
instructionSelectionHandler: InstructionSelectionHandler;
offsetSelection: MySelection;
offsetSelection: SelectionMap;
showInstructionAddressHandler: () => void;
showInstructionBinaryHandler: () => void;
highlightGapInstructionsHandler: () => void;
@ -197,7 +197,7 @@ export class DisassemblyView extends TextView {
};
view.divNode.addEventListener('click', linkHandlerBlock);
this.offsetSelection = new MySelection(anyToString);
this.offsetSelection = new SelectionMap(anyToString);
const instructionSelectionHandler = {
clear: function () {
view.offsetSelection.clear();

View File

@ -6,20 +6,20 @@ import * as C from "../common/constants";
import * as d3 from "d3";
import { partial, storageGetItem, storageSetItem } from "../common/util";
import { PhaseView } from "./view";
import { MySelection } from "../selection/selection";
import { SelectionMap } from "../selection/selection";
import { ClearableHandler, NodeSelectionHandler } from "../selection/selection-handler";
import { Graph } from "../graph";
import { SelectionBroker } from "../selection/selection-broker";
import { GraphNode } from "../phases/graph-phase/graph-node";
import { GraphEdge } from "../phases/graph-phase/graph-edge";
import { GraphLayout } from "../graph-layout";
import { GraphPhase, GraphStateType } from "../phases/graph-phase";
import { GraphPhase, GraphStateType } from "../phases/graph-phase/graph-phase";
import { BytecodePosition } from "../position";
import { BytecodeOrigin } from "../origin";
interface GraphState {
showTypes: boolean;
selection: MySelection;
selection: SelectionMap;
mouseDownNode: any;
justDragged: boolean;
justScaleTransGraph: boolean;
@ -131,7 +131,7 @@ export class GraphView extends PhaseView {
}
};
view.state.selection = new MySelection(n => n.identifier(),
view.state.selection = new SelectionMap(n => n.identifier(),
n => n.nodeLabel?.origin?.identifier());
const defs = svg.append('svg:defs');

View File

@ -4,7 +4,7 @@
import { PhaseView } from "./view";
import { anyToString, isIterable } from "../common/util";
import { MySelection } from "../selection/selection";
import { SelectionMap } from "../selection/selection";
import { SourceResolver } from "../source-resolver";
import { SelectionBroker } from "../selection/selection-broker";
import { NodeSelectionHandler, BlockSelectionHandler, RegisterAllocationSelectionHandler } from "../selection/selection-handler";
@ -14,9 +14,9 @@ export abstract class TextView extends PhaseView {
selectionHandler: NodeSelectionHandler;
blockSelectionHandler: BlockSelectionHandler;
registerAllocationSelectionHandler: RegisterAllocationSelectionHandler;
selection: MySelection;
blockSelection: MySelection;
registerAllocationSelection: MySelection;
selection: SelectionMap;
blockSelection: SelectionMap;
registerAllocationSelection: SelectionMap;
textListNode: HTMLUListElement;
instructionIdToHtmlElementsMap: Map<string, Array<HTMLElement>>;
nodeIdToHtmlElementsMap: Map<string, Array<HTMLElement>>;
@ -37,8 +37,8 @@ export abstract class TextView extends PhaseView {
view.blockIdToHtmlElementsMap = new Map();
view.blockIdToNodeIds = new Map();
view.nodeIdToBlockId = [];
view.selection = new MySelection(anyToString);
view.blockSelection = new MySelection(anyToString);
view.selection = new SelectionMap(anyToString);
view.blockSelection = new SelectionMap(anyToString);
view.broker = broker;
view.sourceResolver = broker.sourceResolver;
const selectionHandler = {
@ -95,7 +95,7 @@ export abstract class TextView extends PhaseView {
this.blockSelectionHandler = blockSelectionHandler;
broker.addBlockHandler(blockSelectionHandler);
view.registerAllocationSelection = new MySelection(anyToString);
view.registerAllocationSelection = new SelectionMap(anyToString);
const registerAllocationSelectionHandler = {
clear: function () {
view.registerAllocationSelection.clear();

View File

@ -17,6 +17,7 @@
"src/common/util.ts",
"src/common/constants.ts",
"src/common/view-elements.ts",
"src/phases/graph-phase/graph-phase.ts",
"src/phases/graph-phase/graph-node.ts",
"src/phases/graph-phase/graph-edge.ts",
"src/phases/turboshaft-graph-phase/turboshaft-graph-phase.ts",
@ -24,7 +25,6 @@
"src/phases/turboshaft-graph-phase/turboshaft-graph-node.ts",
"src/phases/turboshaft-graph-phase/turboshaft-graph-edge.ts",
"src/phases/disassembly-phase.ts",
"src/phases/graph-phase.ts",
"src/phases/instructions-phase.ts",
"src/phases/phase.ts",
"src/phases/schedule-phase.ts",