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

[turbolizer] Turboshaft nodes/blocks selection and collapsing

Implemented:
- Remember nodes/blocks selection for Turboshaft layout
- Test version of adapting nodes positions while changing op properties visibility
- Turboshaft blocks collapsing

Refactored:
- text-view.ts
- resizer.ts

Solved previous comments:
- https://chromium-review.googlesource.com/c/v8/v8/+/3706603/comments/62ffc361_7827e282
- https://chromium-review.googlesource.com/c/v8/v8/+/3700078/comments/d29ea456_f3c197d6

Bug: v8:7327
Change-Id: I9e141eb882ab0e22bd079b067e2229f5baa69433
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3752805
Commit-Queue: Danylo Boiko <danielboyko02@gmail.com>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81817}
parent 509ee760
......@@ -73,7 +73,7 @@ g.loop rect {
fill: var(--select);
}
.inline-node-properties tspan {
.inline-node-properties tspan, .block-collapsed-label tspan {
fill: #ca48f6;
}
......
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M24 38 12 26l2.1-2.1 9.9 9.9 9.9-9.9L36 26Zm0-12.65-12-12 2.1-2.1 9.9 9.9 9.9-9.9 2.1 2.1Z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="m14.1 36.75-2.1-2.1 12-12 12 12-2.1 2.1-9.9-9.9Zm0-12.65L12 22l12-12 12 12-2.1 2.1-9.9-9.9Z"/></svg>
\ No newline at end of file
......@@ -6,7 +6,9 @@ export const MAX_RANK_SENTINEL = 0;
export const BEZIER_CONSTANT = 0.3;
export const GRAPH_MARGIN = 250;
export const TURBOSHAFT_NODE_X_INDENT = 25;
export const TURBOSHAFT_COLLAPSE_ICON_X_INDENT = 20;
export const TURBOSHAFT_BLOCK_BORDER_RADIUS = 35;
export const TURBOSHAFT_NODE_BORDER_RADIUS = 20;
export const TURBOSHAFT_BLOCK_ROW_SEPARATION = 200;
export const ARROW_HEAD_HEIGHT = 7;
export const DEFAULT_NODE_BUBBLE_RADIUS = 12;
......@@ -15,8 +17,16 @@ export const MINIMUM_NODE_OUTPUT_APPROACH = 15;
export const MINIMUM_EDGE_SEPARATION = 20;
export const MINIMUM_NODE_INPUT_APPROACH = 15 + 2 * DEFAULT_NODE_BUBBLE_RADIUS;
export const DEFAULT_NODE_ROW_SEPARATION = 150;
export const SOURCE_PANE_DEFAULT_PERCENT = 1 / 4;
export const DISASSEMBLY_PANE_DEFAULT_PERCENT = 3 / 4;
export const RANGES_PANE_HEIGHT_DEFAULT_PERCENT = 3 / 4;
export const RANGES_PANE_WIDTH_DEFAULT_PERCENT = 1 / 2;
export const RESIZER_RANGES_HEIGHT_BUFFER_PERCENTAGE = 5;;
export const TRACE_LAYOUT = false;
export const MULTIVIEW_ID = "multiview";
export const SHOW_HIDE_RANGES_ID = "show-hide-ranges";
export const SHOW_HIDE_SOURCE_ID = "show-hide-source";
export const SHOW_HIDE_DISASSEMBLY_ID = "show-hide-disassembly";
export const SOURCE_PANE_ID = "left";
export const SOURCE_COLLAPSE_ID = "source-shrink";
export const SOURCE_EXPAND_ID = "source-expand";
......
......@@ -2,10 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export function anyToString(obj: any): string {
return `${obj}`;
}
export function snakeToCamel(str: string): string {
return str.toLowerCase().replace(/([-_][a-z])/g, group =>
group
......@@ -89,3 +85,7 @@ export function storageGetItem(key: string, defaultValue?: any, parse: boolean =
export function storageSetItem(key: string, value: any): void {
window.sessionStorage.setItem(key, value);
}
export function storageSetIfIsNotExist(key: string, toSet: any): void {
if (storageGetItem(key, null, false) === null) storageSetItem(key, toSet);
}
......@@ -35,9 +35,7 @@ export abstract class Edge<NodeType extends GraphNode | TurboshaftGraphNode
const inputX = target.x + target.getInputX(index);
const inputApproach = target.getInputApproach(this.index);
const outputApproach = source.getOutputApproach(extendHeight);
if (inputApproach > outputApproach) {
return inputX;
}
if (inputApproach > outputApproach) return inputX;
const inputOffset = C.MINIMUM_EDGE_SEPARATION * (index + 1);
return target.x < source.x
? target.x + target.getWidth() + inputOffset
......
......@@ -45,7 +45,6 @@ export class Graph extends MovableContainer<GraphPhase> {
public redetermineGraphBoundingBox(showTypes: boolean): [[number, number], [number, number]] {
this.minGraphX = 0;
this.maxGraphNodeX = 1;
this.maxGraphX = undefined; // see below
this.minGraphY = 0;
this.maxGraphY = 1;
......@@ -72,6 +71,10 @@ export class Graph extends MovableContainer<GraphPhase> {
];
}
public makeNodeVisible(identifier: string): void {
if (this.nodeMap[identifier]) this.nodeMap[identifier].visible = true;
}
public makeEdgesVisible(): void {
if (this.graphPhase.stateType == GraphStateType.NeedToFullRebuild) {
this.forEachEdge(edge =>
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import * as C from "./common/constants";
import { storageGetItem, storageSetItem } from "./common/util";
import { GraphView } from "./views/graph-view";
import { ScheduleView } from "./views/schedule-view";
import { SequenceView } from "./views/sequence-view";
......@@ -10,10 +11,9 @@ import { GenericPhase, SourceResolver } from "./source-resolver";
import { SelectionBroker } from "./selection/selection-broker";
import { PhaseView, View } from "./views/view";
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";
import { TurboshaftGraphView } from "./views/turboshaft-graph-view";
import { SelectionStorage } from "./selection/selection-storage";
const toolboxHTML = `
<div class="graph-toolbox">
......@@ -97,7 +97,7 @@ export class GraphMultiView extends View {
this.currentPhaseView?.onresize();
}
private displayPhase(phase: GenericPhase, selection?: Map<string, GraphNode>): void {
private displayPhase(phase: GenericPhase, selection?: SelectionStorage): void {
if (phase.type == PhaseType.Graph) {
this.displayPhaseView(this.graph, phase, selection);
} else if (phase.type == PhaseType.TurboshaftGraph) {
......@@ -109,14 +109,14 @@ export class GraphMultiView extends View {
}
}
private displayPhaseView(view: PhaseView, data: GenericPhase, selection?: Map<string, GraphNode>):
private displayPhaseView(view: PhaseView, data: GenericPhase, selection?: SelectionStorage):
void {
const rememberedSelection = selection ? selection : this.hideCurrentPhase();
view.initializeContent(data, rememberedSelection);
this.currentPhaseView = view;
}
private displayPhaseByName(phaseName: string, selection?: Map<string, GraphNode>): void {
private displayPhaseByName(phaseName: string, selection?: SelectionStorage): void {
const phaseId = this.sourceResolver.getPhaseIdByName(phaseName);
this.selectMenu.selectedIndex = phaseId;
this.displayPhase(this.sourceResolver.getPhase(phaseId), selection);
......@@ -169,7 +169,7 @@ export class GraphMultiView extends View {
};
}
private hideCurrentPhase(): Map<string, GraphNode> {
private hideCurrentPhase(): SelectionStorage {
let rememberedSelection = null;
if (this.currentPhaseView != null) {
rememberedSelection = this.currentPhaseView.detachSelection();
......
......@@ -23,12 +23,12 @@ export class LayoutOccupation {
this.maxSlot = 0;
}
public clearOutputs(source: GraphNode | TurboshaftGraphBlock, showTypes: boolean): void {
public clearOutputs(source: GraphNode | TurboshaftGraphBlock, extendHeight: boolean): void {
for (const edge of source.outputs) {
if (!edge.isVisible()) continue;
for (const inputEdge of edge.target.inputs) {
if (inputEdge.source === source) {
const horizontalPos = edge.getInputHorizontalPosition(this.graph, showTypes);
const horizontalPos = edge.getInputHorizontalPosition(this.graph, extendHeight);
this.clearPositionRangeWithMargin(horizontalPos, horizontalPos, C.NODE_INPUT_WIDTH / 2);
}
}
......@@ -63,12 +63,12 @@ export class LayoutOccupation {
}
}
public occupyInputs(item: GraphNode | TurboshaftGraphBlock, showTypes: boolean): void {
public occupyInputs(item: GraphNode | TurboshaftGraphBlock, extendHeight: boolean): void {
for (let i = 0; i < item.inputs.length; ++i) {
if (item.inputs[i].isVisible()) {
const edge = item.inputs[i];
if (!edge.isBackEdge()) {
const horizontalPos = edge.getInputHorizontalPosition(this.graph, showTypes);
const horizontalPos = edge.getInputHorizontalPosition(this.graph, extendHeight);
this.trace(`Occupying input ${i} of ${item.id} at ${horizontalPos}`);
this.occupyPositionRangeWithMargin(horizontalPos, horizontalPos, C.NODE_INPUT_WIDTH / 2);
}
......
......@@ -51,7 +51,7 @@ export class NodeLabel {
}
public getTitle(): string {
const propsString = this.properties === "" ? "no properties" : `[${this.properties}]`;
const propsString = this.properties.length == 0 ? "no properties" : `[${this.properties}]`;
let title = `${this.title}\n${propsString}\n${this.opinfo}`;
if (this.origin) {
title += `\nOrigin: ${this.origin.toString()}`;
......
......@@ -92,8 +92,8 @@ export abstract class Node<EdgeType extends GraphEdge | TurboshaftGraphEdge<Turb
(index % 4) * C.MINIMUM_EDGE_SEPARATION - C.DEFAULT_NODE_BUBBLE_RADIUS;
}
public getOutputApproach(showTypes: boolean): number {
return this.y + this.outputApproach + this.getHeight(showTypes) +
public getOutputApproach(extendHeight: boolean): number {
return this.y + this.outputApproach + this.getHeight(extendHeight) +
+ C.DEFAULT_NODE_BUBBLE_RADIUS;
}
......
......@@ -9,12 +9,13 @@ export class DisassemblyPhase extends Phase {
blockIdToOffset: Array<number>;
blockStartPCtoBlockIds: Map<number, Array<number>>;
constructor(name: string, data: string) {
constructor(name: string, data: string, blockIdToOffsetJson) {
super(name, PhaseType.Disassembly);
this.data = data;
this.blockIdToOffset = new Array<number>() ;
this.blockIdToOffset = new Array<number>();
this.blockStartPCtoBlockIds = new Map<number, Array<number>>();
this.parseBlockIdToOffsetFromJSON(blockIdToOffsetJson);
}
public hasBlockStartInfo(): boolean {
......@@ -25,7 +26,7 @@ export class DisassemblyPhase extends Phase {
return this.blockStartPCtoBlockIds.get(offset);
}
public parseBlockIdToOffsetFromJSON(blockIdToOffsetJson): void {
private parseBlockIdToOffsetFromJSON(blockIdToOffsetJson): void {
if (!blockIdToOffsetJson) return;
for (const [blockId, offset] of Object.entries<number>(blockIdToOffsetJson)) {
this.blockIdToOffset[blockId] = offset;
......
......@@ -19,19 +19,19 @@ export class GraphPhase extends Phase {
rendered: boolean;
transform: { x: number, y: number, scale: number };
constructor(name: string, highestNodeId: number, data?: GraphData,
nodeLabelMap?: Array<NodeLabel>, nodeIdToNodeMap?: Array<GraphNode>) {
constructor(name: string, highestNodeId: number, dataJson, nodeLabelMap?: Array<NodeLabel>) {
super(name, PhaseType.Graph);
this.highestNodeId = highestNodeId;
this.data = data ?? new GraphData();
this.data = new GraphData();
this.stateType = GraphStateType.NeedToFullRebuild;
this.nodeLabelMap = nodeLabelMap ?? new Array<NodeLabel>();
this.nodeIdToNodeMap = nodeIdToNodeMap ?? new Array<GraphNode>();
this.nodeIdToNodeMap = new Array<GraphNode>();
this.originIdToNodesMap = new Map<string, Array<GraphNode>>();
this.rendered = false;
this.parseDataFromJSON(dataJson, nodeLabelMap);
this.nodeLabelMap = nodeLabelMap?.slice();
}
public parseDataFromJSON(dataJson, nodeLabelMap: Array<NodeLabel>): void {
private parseDataFromJSON(dataJson, nodeLabelMap: Array<NodeLabel>): void {
this.data = new GraphData();
this.nodeIdToNodeMap = this.parseNodesFromJSON(dataJson.nodes, nodeLabelMap);
this.parseEdgesFromJSON(dataJson.edges);
......@@ -101,9 +101,9 @@ export class GraphData {
nodes: Array<GraphNode>;
edges: Array<GraphEdge>;
constructor(nodes?: Array<GraphNode>, edges?: Array<GraphEdge>) {
this.nodes = nodes ?? new Array<GraphNode>();
this.edges = edges ?? new Array<GraphEdge>();
constructor() {
this.nodes = new Array<GraphNode>();
this.edges = new Array<GraphEdge>();
}
}
......
......@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { anyToString } from "../common/util";
import { Phase, PhaseType } from "./phase";
export class InstructionsPhase extends Phase {
......@@ -19,14 +18,10 @@ export class InstructionsPhase extends Phase {
pcOffsetToInstructions: Map<number, Array<number>>;
pcOffsets: Array<number>;
constructor(name: string, nodeIdToInstructionRange?: Array<[number, number]>,
blockIdToInstructionRange?: Array<[number, number]>,
codeOffsetsInfo?: CodeOffsetsInfo) {
constructor(name: string = "") {
super(name, PhaseType.Instructions);
this.nodeIdToInstructionRange = nodeIdToInstructionRange ?? new Array<[number, number]>();
this.blockIdToInstructionRange = blockIdToInstructionRange ?? new Array<[number, number]>();
this.codeOffsetsInfo = codeOffsetsInfo;
this.nodeIdToInstructionRange = new Array<[number, number]>();
this.blockIdToInstructionRange = new Array<[number, number]>();
this.instructionToPCOffset = new Array<TurbolizerInstructionStartInfo>();
this.pcOffsetToInstructions = new Map<number, Array<number>>();
this.pcOffsets = new Array<number>();
......@@ -66,10 +61,10 @@ export class InstructionsPhase extends Phase {
if (!range) continue;
const [start, end] = range;
if (start == end && instruction == start) {
nodes.push(anyToString(nodeId));
nodes.push(String(nodeId));
}
if (start <= instruction && instruction < end) {
nodes.push(anyToString(nodeId));
nodes.push(String(nodeId));
}
}
}
......
......@@ -8,17 +8,18 @@ export class SchedulePhase extends Phase {
data: string;
schedule: { currentBlock, blocks: Array<any>, nodes: Array<any> };
constructor(name: string, data: string, schedule?: any) {
constructor(name: string, data: string) {
super(name, PhaseType.Schedule);
this.data = data;
this.schedule = schedule ?? {
this.schedule = {
currentBlock: undefined,
blocks: new Array<any>(),
nodes: new Array<any>()
};
this.parseScheduleFromJSON(data);
}
public parseScheduleFromJSON(scheduleDataJson): void {
private parseScheduleFromJSON(scheduleDataJson): void {
const lines = scheduleDataJson.split(/[\n]/);
nextLine:
for (const line of lines) {
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import * as C from "../../common/constants";
import { measureText } from "../../common/util";
import { TurboshaftGraphNode } from "./turboshaft-graph-node";
import { Node } from "../../node";
import { TurboshaftGraphEdge } from "./turboshaft-graph-edge";
......@@ -13,6 +14,9 @@ export class TurboshaftGraphBlock extends Node<TurboshaftGraphEdge<TurboshaftGra
predecessors: Array<string>;
nodes: Array<TurboshaftGraphNode>;
showProperties: boolean;
collapsed: boolean;
collapsedLabel: string;
collapsedLabelBox: { width: number, height: number };
width: number;
height: number;
......@@ -27,24 +31,39 @@ export class TurboshaftGraphBlock extends Node<TurboshaftGraphEdge<TurboshaftGra
}
public getHeight(showProperties: boolean): number {
if (this.collapsed) return this.labelBox.height + this.collapsedLabelBox.height;
if (this.showProperties != showProperties) {
this.height = this.nodes.reduce<number>((accumulator: number, node: TurboshaftGraphNode) => {
return accumulator + node.getHeight(showProperties);
}, this.labelBox.height);
this.showProperties = showProperties;
}
return this.height;
}
public getWidth(): number {
if (!this.width) {
const labelWidth = this.labelBox.width + this.labelBox.height
+ C.TURBOSHAFT_COLLAPSE_ICON_X_INDENT;
const maxNodesWidth = Math.max(...this.nodes.map((node: TurboshaftGraphNode) =>
node.getWidth()));
this.width = Math.max(maxNodesWidth, this.labelBox.width) + C.TURBOSHAFT_NODE_X_INDENT * 2;
this.width = Math.max(maxNodesWidth, labelWidth, this.collapsedLabelBox.width)
+ C.TURBOSHAFT_NODE_X_INDENT * 2;
}
return this.width;
}
public getRankIndent() {
return this.rank * (C.TURBOSHAFT_BLOCK_ROW_SEPARATION + 2 * C.DEFAULT_NODE_BUBBLE_RADIUS);
}
public initCollapsedLabel() {
this.collapsedLabel = `${this.nodes.length} operations`;
this.collapsedLabelBox = measureText(this.collapsedLabel);
}
public hasBackEdges(): boolean {
return (this.type == TurboshaftGraphBlockType.Loop) ||
(this.type == TurboshaftGraphBlockType.Merge &&
......
......@@ -51,7 +51,7 @@ export class TurboshaftGraphNode extends Node<TurboshaftGraphEdge<TurboshaftGrap
title += `\nOutputs: ${this.outputs.map(i => i.target.id).join(", ")}`;
}
const opPropertiesStr = this.properties.length > 0 ? this.properties : "No op properties";
return title + `\n${opPropertiesStr}`;
return `${title}\n${opPropertiesStr}`;
}
public getInlineLabel(): string {
......
......@@ -8,28 +8,23 @@ import { TurboshaftGraphEdge } from "./turboshaft-graph-edge";
import { TurboshaftGraphBlock } from "./turboshaft-graph-block";
export class TurboshaftGraphPhase extends Phase {
highestBlockId: number; // TODO (danylo boiko) Delete this field
data: TurboshaftGraphData;
stateType: GraphStateType;
layoutType: TurboshaftLayoutType;
nodeIdToNodeMap: Array<TurboshaftGraphNode>;
blockIdToBlockMap: Array<TurboshaftGraphBlock>;
rendered: boolean;
transform: { x: number, y: number, scale: number };
constructor(name: string, highestBlockId: number, data?: TurboshaftGraphData,
nodeIdToNodeMap?: Array<TurboshaftGraphNode>,
blockIdToBlockMap?: Array<TurboshaftGraphBlock>) {
constructor(name: string, dataJson) {
super(name, PhaseType.TurboshaftGraph);
this.highestBlockId = highestBlockId;
this.data = data ?? new TurboshaftGraphData();
this.stateType = GraphStateType.NeedToFullRebuild;
this.nodeIdToNodeMap = nodeIdToNodeMap ?? new Array<TurboshaftGraphNode>();
this.blockIdToBlockMap = blockIdToBlockMap ?? new Array<TurboshaftGraphBlock>();
this.nodeIdToNodeMap = new Array<TurboshaftGraphNode>();
this.blockIdToBlockMap = new Array<TurboshaftGraphBlock>();
this.rendered = false;
this.parseDataFromJSON(dataJson);
}
public parseDataFromJSON(dataJson): void {
private parseDataFromJSON(dataJson): void {
this.data = new TurboshaftGraphData();
this.parseBlocksFromJSON(dataJson.blocks);
this.parseNodesFromJSON(dataJson.nodes);
......@@ -62,6 +57,9 @@ export class TurboshaftGraphPhase extends Phase {
this.data.nodes.push(node);
this.nodeIdToNodeMap[node.identifier()] = node;
}
for (const block of this.blockIdToBlockMap) {
block.initCollapsedLabel();
}
}
private parseEdgesFromJSON(edgesJson): void {
......@@ -84,16 +82,9 @@ export class TurboshaftGraphData {
edges: Array<TurboshaftGraphEdge<TurboshaftGraphNode>>;
blocks: Array<TurboshaftGraphBlock>;
constructor(nodes?: Array<TurboshaftGraphNode>,
edges?: Array<TurboshaftGraphEdge<TurboshaftGraphNode>>,
blocks?: Array<TurboshaftGraphBlock>) {
this.nodes = nodes ?? new Array<TurboshaftGraphNode>();
this.edges = edges ?? new Array<TurboshaftGraphEdge<TurboshaftGraphNode>>();
this.blocks = blocks ?? new Array<TurboshaftGraphBlock>();
constructor() {
this.nodes = new Array<TurboshaftGraphNode>();
this.edges = new Array<TurboshaftGraphEdge<TurboshaftGraphNode>>();
this.blocks = new Array<TurboshaftGraphBlock>();
}
}
export enum TurboshaftLayoutType {
Inline,
Nodes
}
This diff is collapsed.
......@@ -3,7 +3,14 @@
// found in the LICENSE file.
import { SourceResolver } from "../source-resolver";
import { ClearableHandler, SelectionHandler, NodeSelectionHandler, BlockSelectionHandler, InstructionSelectionHandler, RegisterAllocationSelectionHandler } from "./selection-handler";
import {
ClearableHandler,
SelectionHandler,
NodeSelectionHandler,
BlockSelectionHandler,
InstructionSelectionHandler,
RegisterAllocationSelectionHandler
} from "./selection-handler";
export class SelectionBroker {
sourceResolver: SourceResolver;
......
......@@ -7,32 +7,32 @@ export interface ClearableHandler {
}
export interface SelectionHandler {
clear(): void;
select(nodeIds: any, selected: any): void;
clear(): void;
brokeredSourcePositionSelect(sourcePositions: any, selected: any): void;
}
export interface NodeSelectionHandler {
clear(): void;
select(nodeIds: any, selected: any): void;
clear(): void;
brokeredNodeSelect(nodeIds: any, selected: any): void;
}
export interface BlockSelectionHandler {
clear(): void;
select(nodeIds: any, selected: any): void;
clear(): void;
brokeredBlockSelect(blockIds: any, selected: any): void;
}
export interface InstructionSelectionHandler {
clear(): void;
select(instructionIds: any, selected: any): void;
clear(): void;
brokeredInstructionSelect(instructionIds: any, selected: any): void;
}
export interface RegisterAllocationSelectionHandler {
clear(): void;
// These are called instructionIds since the class of the divs is "instruction-id"
select(instructionIds: any, selected: any): void;
clear(): void;
brokeredRegisterAllocationSelect(instructionIds: any, selected: any): void;
}
// Copyright 2022 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.
export class SelectionStorage {
nodes: Map<string, any>;
blocks: Map<string, any>;
adaptedNodes: Set<string>;
adaptedBocks: Set<string>;
constructor(nodes?: Map<string, any>, blocks?: Map<string, any>) {
this.nodes = nodes ?? new Map<string, any>();
this.blocks = blocks ?? new Map<string, any>();
this.adaptedNodes = new Set<string>();
this.adaptedBocks = new Set<string>();
}
public adaptNode(nodeKey: string): void {
this.adaptedNodes.add(nodeKey);
}
public adaptBlock(blockKey: string): void {
this.adaptedBocks.add(blockKey);
}
public isAdapted(): boolean {
return this.adaptedNodes.size != 0 || this.adaptedBocks.size != 0;
}
}
......@@ -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 { anyToString, camelize, sortUnique } from "./common/util";
import { camelize, sortUnique } from "./common/util";
import { PhaseType } from "./phases/phase";
import { GraphPhase } from "./phases/graph-phase/graph-phase";
import { DisassemblyPhase } from "./phases/disassembly-phase";
......@@ -46,9 +46,7 @@ export class SourceResolver {
this.phases = new Array<GenericPhase>();
// Maps phase names to phaseIds.
this.phaseNames = new Map<string, number>();
this.instructionsPhase = new InstructionsPhase("");
// The disassembly phase is stored separately.
this.disassemblyPhase = undefined;
this.instructionsPhase = new InstructionsPhase();
// Maps line numbers to source positions
this.linePositionMap = new Map<string, Array<GenericPosition>>();
}
......@@ -136,15 +134,13 @@ export class SourceResolver {
case PhaseType.Disassembly:
const castedDisassembly = genericPhase as DisassemblyPhase;
const disassemblyPhase = new DisassemblyPhase(castedDisassembly.name,
castedDisassembly.data);
disassemblyPhase.parseBlockIdToOffsetFromJSON(castedDisassembly?.blockIdToOffset);
castedDisassembly.data, castedDisassembly?.blockIdToOffset);
this.disassemblyPhase = disassemblyPhase;
break;
case PhaseType.Schedule:
const castedSchedule = genericPhase as SchedulePhase;
const schedulePhase = new SchedulePhase(castedSchedule.name, castedSchedule.data);
this.phaseNames.set(schedulePhase.name, this.phases.length);
schedulePhase.parseScheduleFromJSON(castedSchedule.data);
this.phases.push(schedulePhase);
break;
case PhaseType.Sequence:
......@@ -172,17 +168,15 @@ export class SourceResolver {
break;
case PhaseType.Graph:
const castedGraph = genericPhase as GraphPhase;
const graphPhase = new GraphPhase(castedGraph.name, 0);
graphPhase.parseDataFromJSON(castedGraph.data, nodeLabelMap);
graphPhase.nodeLabelMap = nodeLabelMap.slice();
const graphPhase = new GraphPhase(castedGraph.name, 0, castedGraph.data, nodeLabelMap);
this.recordOrigins(graphPhase);
this.phaseNames.set(graphPhase.name, this.phases.length);
this.phases.push(graphPhase);
break;
case PhaseType.TurboshaftGraph:
const castedTurboshaftGraph = genericPhase as TurboshaftGraphPhase;
const turboshaftGraphPhase = new TurboshaftGraphPhase(castedTurboshaftGraph.name, 0);
turboshaftGraphPhase.parseDataFromJSON(castedTurboshaftGraph.data);
const turboshaftGraphPhase = new TurboshaftGraphPhase(castedTurboshaftGraph.name,
castedTurboshaftGraph.data);
this.phaseNames.set(turboshaftGraphPhase.name, this.phases.length);
this.phases.push(turboshaftGraphPhase);
break;
......@@ -249,7 +243,7 @@ export class SourceResolver {
}
public addAnyPositionToLine(lineNumber: number | string, sourcePosition: GenericPosition): void {
const lineNumberString = anyToString(lineNumber);
const lineNumberString = String(lineNumber);
if (!this.linePositionMap.has(lineNumberString)) {
this.linePositionMap.set(lineNumberString, new Array<GenericPosition>());
}
......@@ -270,7 +264,7 @@ export class SourceResolver {
}
public lineToSourcePositions(lineNumber: number | string): Array<GenericPosition> {
return this.linePositionMap.get(anyToString(lineNumber)) ?? new Array<GenericPosition>();
return this.linePositionMap.get(String(lineNumber)) ?? new Array<GenericPosition>();
}
public getSourceName(sourceId: number): string {
......
......@@ -69,13 +69,13 @@ window.onload = function () {
sourceTabs.activateTab(sourceTab);
const sourceView = new CodeView(sourceContainer, selectionBroker, sourceResolver,
mainFunction, CodeMode.MAIN_SOURCE);
mainFunction, CodeMode.MainSource);
sourceView.show();
sourceViews.push(sourceView);
for (const source of sourceResolver.sources) {
const sourceView = new CodeView(sourceContainer, selectionBroker, sourceResolver,
source, CodeMode.INLINED_SOURCE);
source, CodeMode.InlinedSource);
sourceView.show();
sourceViews.push(sourceView);
}
......
......@@ -5,11 +5,11 @@
import * as C from "./common/constants";
import { TurboshaftGraph } from "./turboshaft-graph";
import { GraphStateType } from "./phases/phase";
import { LayoutOccupation } from "./layout-occupation";
import {
TurboshaftGraphBlock,
TurboshaftGraphBlockType
} from "./phases/turboshaft-graph-phase/turboshaft-graph-block";
import { LayoutOccupation } from "./layout-occupation";
export class TurboshaftGraphLayout {
graph: TurboshaftGraph;
......@@ -22,7 +22,6 @@ export class TurboshaftGraphLayout {
this.graph = graph;
this.layoutOccupation = new LayoutOccupation(graph);
this.maxRank = 0;
this.visitOrderWithinRank = 0;
}
public rebuild(showProperties: boolean): void {
......@@ -67,6 +66,7 @@ export class TurboshaftGraphLayout {
// basis for top-down DFS to determine rank and block placement.
const blocksHasNoInputs = new Array<boolean>();
for (const block of this.graph.blocks()) {
block.collapsed = false;
blocksHasNoInputs[block.id] = true;
}
for (const edge of this.graph.blocksEdges()) {
......@@ -143,7 +143,7 @@ export class TurboshaftGraphLayout {
}
isFirstInput = false;
}
if (block.hasBackEdges()) {
if (block.type != TurboshaftGraphBlockType.Merge) {
block.rank = newRank;
}
}
......
......@@ -81,4 +81,15 @@ export class TurboshaftGraph extends MovableContainer<TurboshaftGraphPhase> {
[this.maxGraphX + this.width / 2, this.maxGraphY + this.height / 2]
];
}
public getRanksMaxBlockHeight(showProperties: boolean): Array<number> {
const ranksMaxBlockHeight = new Array<number>();
for (const block of this.blocks()) {
ranksMaxBlockHeight[block.rank] = Math.max(ranksMaxBlockHeight[block.rank] ?? 0,
block.getHeight(showProperties));
}
return ranksMaxBlockHeight;
}
}
......@@ -6,7 +6,7 @@ import { Source } from "../source";
import { GenericPosition, SourceResolver } from "../source-resolver";
import { SelectionBroker } from "../selection/selection-broker";
import { View } from "./view";
import { SelectionMap } from "../selection/selection";
import { SelectionMap } from "../selection/selection-map";
import { ViewElements } from "../common/view-elements";
import { SelectionHandler } from "../selection/selection-handler";
......@@ -19,8 +19,8 @@ declare global {
}
export enum CodeMode {
MAIN_SOURCE = "main function",
INLINED_SOURCE = "inlined function"
MainSource = "main function",
InlinedSource = "inlined function"
}
export class CodeView extends View {
......@@ -146,7 +146,7 @@ export class CodeView extends View {
const sourceText = source.sourceText;
if (!sourceText) return;
const sourceContainer = view.divNode;
if (this.codeMode == CodeMode.MAIN_SOURCE) {
if (this.codeMode == CodeMode.MainSource) {
sourceContainer.classList.add("main-source");
} else {
sourceContainer.classList.add("inlined-source");
......
......@@ -2,21 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { PROF_COLS, UNICODE_BLOCK } from "../common/constants";
import * as C from "../common/constants";
import { interpolate } from "../common/util";
import { SelectionBroker } from "../selection/selection-broker";
import { TextView } from "./text-view";
import { SelectionMap } from "../selection/selection";
import { anyToString, interpolate } from "../common/util";
import { SelectionMap } from "../selection/selection-map";
import { InstructionSelectionHandler } from "../selection/selection-handler";
import { TurbolizerInstructionStartInfo } from "../phases/instructions-phase";
import { SelectionStorage } from "../selection/selection-storage";
const toolboxHTML = `<div id="disassembly-toolbox">
<form>
<label><input id="show-instruction-address" type="checkbox" name="instruction-address">Show addresses</label>
<label><input id="show-instruction-binary" type="checkbox" name="instruction-binary">Show binary literal</label>
<label><input id="highlight-gap-instructions" type="checkbox" name="instruction-binary">Highlight gap instructions</label>
</form>
</div>`;
const toolboxHTML =
`<div id="disassembly-toolbox">
<form>
<label><input id="show-instruction-address" type="checkbox" name="instruction-address">Show addresses</label>
<label><input id="show-instruction-binary" type="checkbox" name="instruction-binary">Show binary literal</label>
<label><input id="highlight-gap-instructions" type="checkbox" name="instruction-binary">Highlight gap instructions</label>
</form>
</div>`;
export class DisassemblyView extends TextView {
SOURCE_POSITION_HEADER_REGEX: any;
......@@ -30,18 +32,6 @@ export class DisassemblyView extends TextView {
showInstructionBinaryHandler: () => void;
highlightGapInstructionsHandler: () => void;
createViewElement() {
const pane = document.createElement('div');
pane.setAttribute('id', "disassembly");
pane.innerHTML =
`<pre id='disassembly-text-pre' class='prettyprint prettyprinted'>
<ul class='disassembly-list nolinenums noindent'>
</ul>
</pre>`;
return pane;
}
constructor(parentId, broker: SelectionBroker) {
super(parentId, broker);
const view = this;
......@@ -197,7 +187,7 @@ export class DisassemblyView extends TextView {
};
view.divNode.addEventListener('click', linkHandlerBlock);
this.offsetSelection = new SelectionMap(anyToString);
this.offsetSelection = new SelectionMap(offset => String(offset));
const instructionSelectionHandler = {
clear: function () {
view.offsetSelection.clear();
......@@ -264,15 +254,25 @@ export class DisassemblyView extends TextView {
this.highlightGapInstructionsHandler = highlightGapInstructionsHandler;
}
updateSelection(scrollIntoView: boolean = false) {
public createViewElement(): HTMLDivElement {
const pane = document.createElement("div");
pane.setAttribute("id", C.DISASSEMBLY_PANE_ID);
pane.innerHTML =
`<pre id="disassembly-text-pre" class="prettyprint prettyprinted">
<ul class="disassembly-list nolinenums noindent"></ul>
</pre>`;
return pane;
}
public updateSelection(scrollIntoView: boolean = false): void {
super.updateSelection(scrollIntoView);
const selectedKeys = this.selection.selectedKeys();
const keyPcOffsets: Array<TurbolizerInstructionStartInfo | number> = [
const keyPcOffsets: Array<TurbolizerInstructionStartInfo | string> = [
...this.sourceResolver.instructionsPhase.nodesToKeyPcOffsets(selectedKeys)
];
if (this.offsetSelection) {
for (const key of this.offsetSelection.selectedKeys()) {
keyPcOffsets.push(Number(key));
keyPcOffsets.push(key);
}
}
for (const keyPcOffset of keyPcOffsets) {
......@@ -283,6 +283,18 @@ export class DisassemblyView extends TextView {
}
}
public searchInputAction(searchInput: HTMLInputElement, e: Event, onlyVisible: boolean): void {
throw new Error("Method not implemented.");
}
public detachSelection(): SelectionStorage {
return null;
}
public adaptSelection(selection: SelectionStorage): SelectionStorage {
return selection;
}
initializeCode(sourceText, sourcePosition: number = 0) {
const view = this;
view.addrEventCounts = null;
......@@ -326,7 +338,7 @@ export class DisassemblyView extends TextView {
}
}
showContent(data): void {
public showContent(data): void {
console.time("disassembly-view");
super.initializeContent(data, null);
this.showInstructionAddressHandler();
......@@ -358,16 +370,16 @@ export class DisassemblyView extends TextView {
const perc = count / view.totalEventCounts[event] * 100;
let col = { r: 255, g: 255, b: 255 };
for (let i = 0; i < PROF_COLS.length; i++) {
if (perc === PROF_COLS[i].perc) {
col = PROF_COLS[i].col;
for (let i = 0; i < C.PROF_COLS.length; i++) {
if (perc === C.PROF_COLS[i].perc) {
col = C.PROF_COLS[i].col;
break;
} else if (perc > PROF_COLS[i].perc && perc < PROF_COLS[i + 1].perc) {
const col1 = PROF_COLS[i].col;
const col2 = PROF_COLS[i + 1].col;
} else if (perc > C.PROF_COLS[i].perc && perc < C.PROF_COLS[i + 1].perc) {
const col1 = C.PROF_COLS[i].col;
const col2 = C.PROF_COLS[i + 1].col;
const val = perc - PROF_COLS[i].perc;
const max = PROF_COLS[i + 1].perc - PROF_COLS[i].perc;
const val = perc - C.PROF_COLS[i].perc;
const max = C.PROF_COLS[i + 1].perc - C.PROF_COLS[i].perc;
col.r = Math.round(interpolate(val, max, col1.r, col2.r));
col.g = Math.round(interpolate(val, max, col1.g, col2.g));
......@@ -376,7 +388,7 @@ export class DisassemblyView extends TextView {
}
}
str = UNICODE_BLOCK;
str = C.UNICODE_BLOCK;
const fragment = view.createFragment(str, cssCls);
fragment.title = event + ": " + view.humanize(perc) + " (" + count + ")";
......@@ -392,10 +404,4 @@ export class DisassemblyView extends TextView {
}
return fragments;
}
detachSelection() { return null; }
public searchInputAction(searchInput: HTMLInputElement, e: Event, onlyVisible: boolean): void {
throw new Error("Method not implemented.");
}
}
This diff is collapsed.
......@@ -7,23 +7,24 @@ import * as d3 from "d3";
import { storageGetItem, storageSetItem } from "../common/util";
import { PhaseView } from "./view";
import { SelectionBroker } from "../selection/selection-broker";
import { SelectionMap } from "../selection/selection";
import { SelectionMap } from "../selection/selection-map";
import { ClearableHandler, NodeSelectionHandler } from "../selection/selection-handler";
import { GraphStateType } from "../phases/graph-phase/graph-phase";
import { Edge } from "../edge";
import { Node } from "../node";
import { TurboshaftGraph } from "../turboshaft-graph";
import { Graph } from "../graph";
import { TurboshaftLayoutType } from "../phases/turboshaft-graph-phase/turboshaft-graph-phase";
import { TurboshaftGraphNode } from "../phases/turboshaft-graph-phase/turboshaft-graph-node";
import { GraphNode } from "../phases/graph-phase/graph-node";
export abstract class MovableView<GraphType extends Graph | TurboshaftGraph> extends PhaseView {
phaseName: string;
graph: GraphType;
showPhaseByName: (name: string, selection: Set<any>) => void;
broker: SelectionBroker;
showPhaseByName: (name: string, selection: Set<any>) => void;
toolbox: HTMLElement;
state: MovableViewState;
nodesSelectionHandler: NodeSelectionHandler & ClearableHandler;
nodeSelectionHandler: NodeSelectionHandler & ClearableHandler;
divElement: d3.Selection<any, any, any, any>;
graphElement: d3.Selection<any, any, any, any>;
svg: d3.Selection<any, any, any, any>;
......@@ -85,10 +86,6 @@ export abstract class MovableView<GraphType extends Graph | TurboshaftGraph> ext
return pane;
}
public detachSelection(): Map<string, any> {
return this.state.selection.detachSelection();
}
public onresize() {
const trans = d3.zoomTransform(this.svg.node());
const ctrans = this.panZoom.constrain()(trans, this.getSvgExtent(),
......@@ -98,16 +95,26 @@ export abstract class MovableView<GraphType extends Graph | TurboshaftGraph> ext
public hide(): void {
if (this.state.cacheLayout) {
const matrix = this.graphElement.node().transform.baseVal.consolidate().matrix;
this.graph.graphPhase.transform = { scale: matrix.a, x: matrix.e, y: matrix.f };
this.graph.graphPhase.transform = this.getTransformMatrix();
} else {
this.graph.graphPhase.transform = null;
}
this.broker.deleteNodeHandler(this.nodesSelectionHandler);
this.broker.deleteNodeHandler(this.nodeSelectionHandler);
super.hide();
this.deleteContent();
}
protected getTransformMatrix(): { scale: number, x: number, y: number } {
const matrix = this.graphElement.node().transform.baseVal.consolidate().matrix;
return { scale: matrix.a, x: matrix.e, y: matrix.f };
}
protected viewTransformMatrix(matrix: { scale: number, x: number, y: number }): void {
this.svg.call(this.panZoom.transform, d3.zoomIdentity
.translate(matrix.x, matrix.y)
.scale(matrix.scale));
}
protected focusOnSvg(): void {
const svg = document.getElementById(C.GRAPH_PANE_ID).childNodes[0] as HTMLElement;
svg.focus();
......@@ -140,10 +147,10 @@ export abstract class MovableView<GraphType extends Graph | TurboshaftGraph> ext
this.toolbox.appendChild(input);
}
protected minScale(graphWidth: number, graphHeight: number): number {
protected minScale(): number {
const [clientWith, clientHeight] = this.getSvgViewDimensions();
const minXScale = clientWith / (2 * graphWidth);
const minYScale = clientHeight / (2 * graphHeight);
const minXScale = clientWith / (2 * this.graph.width);
const minYScale = clientHeight / (2 * this.graph.height);
const minScale = Math.min(minXScale, minYScale);
this.panZoom.scaleExtent([minScale, 40]);
return minScale;
......@@ -202,8 +209,8 @@ export abstract class MovableView<GraphType extends Graph | TurboshaftGraph> ext
return frontier;
}
protected connectVisibleSelectedElements(): void {
for (const element of this.state.selection) {
protected connectVisibleSelectedElements(selection: SelectionMap): void {
for (const element of selection) {
element.inputs.forEach((edge: Edge<any>) => {
if (edge.source.visible && edge.target.visible) {
edge.visible = true;
......@@ -230,6 +237,18 @@ export abstract class MovableView<GraphType extends Graph | TurboshaftGraph> ext
this.graph.minGraphY + this.graph.height / 2);
}
protected searchNodes(filterFunction: (node: TurboshaftGraphNode | GraphNode) =>
boolean | RegExpExecArray, e: KeyboardEvent, onlyVisible: boolean):
Array<TurboshaftGraphNode | GraphNode> {
return [...this.graph.nodes(node => {
if ((e.ctrlKey || node.visible || !onlyVisible) && filterFunction(node)) {
if (e.ctrlKey || !onlyVisible) node.visible = true;
return true;
}
return false;
})];
}
private deleteContent(): void {
for (const item of this.toolbox.querySelectorAll(".graph-toolbox-item")) {
item.parentElement.removeChild(item);
......@@ -305,12 +324,4 @@ export class MovableViewState {
public set cacheLayout(value: boolean) {
storageSetItem("toggle-cache-layout", value);
}
public get turboshaftLayoutType() {
return storageGetItem("turboshaft-layout-type", TurboshaftLayoutType.Inline);
}
public set turboshaftLayoutType(layoutType: TurboshaftLayoutType) {
storageSetItem("turboshaft-layout-type", layoutType);
}
}
......@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { SourceResolver } from "../source-resolver";
import { TextView } from "./text-view";
import { SchedulePhase } from "../phases/schedule-phase";
import { SelectionStorage } from "../selection/selection-storage";
export class ScheduleView extends TextView {
schedule: SchedulePhase;
sourceResolver: SourceResolver;
createViewElement() {
const pane = document.createElement('div');
......@@ -23,27 +22,34 @@ export class ScheduleView extends TextView {
this.sourceResolver = broker.sourceResolver;
}
attachSelection(s) {
const view = this;
if (!(s instanceof Set)) return;
view.selectionHandler.clear();
view.blockSelectionHandler.clear();
const selected = new Array();
for (const key of s) selected.push(key);
view.selectionHandler.select(selected, true);
private attachSelection(adaptedSelection: SelectionStorage): void {
if (!(adaptedSelection instanceof SelectionStorage)) return;
this.selectionHandler.clear();
this.blockSelectionHandler.clear();
this.selectionHandler.select(adaptedSelection.adaptedNodes, true);
this.blockSelectionHandler.select(adaptedSelection.adaptedBocks, true);
}
detachSelection() {
this.blockSelection.clear();
return this.selection.detachSelection();
public detachSelection(): SelectionStorage {
return new SelectionStorage(this.selection.detachSelection(),
this.blockSelection.detachSelection());
}
initializeContent(data, rememberedSelection) {
this.divNode.innerHTML = '';
this.schedule = data.schedule;
this.addBlocks(data.schedule.blocks);
this.attachSelection(rememberedSelection);
public adaptSelection(selection: SelectionStorage): SelectionStorage {
for (const key of selection.nodes.keys()) selection.adaptedNodes.add(key);
for (const key of selection.blocks.keys()) selection.adaptedBocks.add(key);
return selection;
}
public initializeContent(schedule: SchedulePhase, rememberedSelection: SelectionStorage): void {
this.divNode.innerHTML = "";
this.schedule = schedule;
this.addBlocks(schedule.schedule.blocks);
this.show();
if (rememberedSelection) {
const adaptedSelection = this.adaptSelection(rememberedSelection);
this.attachSelection(adaptedSelection);
}
}
createElementFromString(htmlString) {
......
......@@ -6,6 +6,7 @@ import { createElement } from "../common/util";
import { TextView } from "./text-view";
import { RangeView } from "./range-view";
import { SequencePhase } from "../phases/sequence-phase";
import { SelectionStorage } from "../selection/selection-storage";
export class SequenceView extends TextView {
sequence: SequencePhase;
......@@ -37,19 +38,23 @@ export class SequenceView extends TextView {
this.toggleRangeViewEl = this.elementForToggleRangeView();
}
attachSelection(s) {
const view = this;
if (!(s instanceof Set)) return;
view.selectionHandler.clear();
view.blockSelectionHandler.clear();
const selected = new Array();
for (const key of s) selected.push(key);
view.selectionHandler.select(selected, true);
private attachSelection(adaptedSelection: SelectionStorage): void {
if (!(adaptedSelection instanceof SelectionStorage)) return;
this.selectionHandler.clear();
this.blockSelectionHandler.clear();
this.selectionHandler.select(adaptedSelection.adaptedNodes, true);
this.blockSelectionHandler.select(adaptedSelection.adaptedBocks, true);
}
detachSelection() {
this.blockSelection.clear();
return this.selection.detachSelection();
public detachSelection(): SelectionStorage {
return new SelectionStorage(this.selection.detachSelection(),
this.blockSelection.detachSelection());
}
public adaptSelection(selection: SelectionStorage): SelectionStorage {
for (const key of selection.nodes.keys()) selection.adaptedNodes.add(key);
for (const key of selection.blocks.keys()) selection.adaptedBocks.add(key);
return selection;
}
show() {
......@@ -80,7 +85,7 @@ export class SequenceView extends TextView {
if (this.showRangeView) this.rangeView.onresize();
}
initializeContent(sequence, rememberedSelection) {
initializeContent(sequence, rememberedSelection: SelectionStorage) {
this.divNode.innerHTML = '';
this.sequence = sequence;
this.searchInfo = [];
......@@ -97,8 +102,11 @@ export class SequenceView extends TextView {
const lastBlock = this.sequence.blocks[this.sequence.blocks.length - 1];
this.numInstructions = lastBlock.instructions[lastBlock.instructions.length - 1].id + 1;
this.addRangeView();
this.attachSelection(rememberedSelection);
this.show();
if (rememberedSelection) {
const adaptedSelection = this.adaptSelection(rememberedSelection);
this.attachSelection(adaptedSelection);
}
}
elementForBlock(block) {
......
This diff is collapsed.
......@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { GraphNode } from "../phases/graph-phase/graph-node";
import { GenericPhase } from "../source-resolver";
import { SelectionStorage } from "../selection/selection-storage";
export abstract class View {
protected container: HTMLElement;
......@@ -24,10 +25,13 @@ export abstract class View {
}
export abstract class PhaseView extends View {
public abstract initializeContent(data: any, rememberedSelection: Map<string, GraphNode>): void;
public abstract detachSelection(): Map<string, GraphNode>;
public abstract initializeContent(data: GenericPhase, rememberedSelection: SelectionStorage):
void;
public abstract detachSelection(): SelectionStorage;
public abstract adaptSelection(rememberedSelection: SelectionStorage): SelectionStorage;
public abstract onresize(): void;
public abstract searchInputAction(searchInput: HTMLInputElement, e: Event, onlyVisible: boolean): void;
public abstract searchInputAction(searchInput: HTMLInputElement, e: KeyboardEvent,
onlyVisible: boolean): void;
constructor(idOrContainer: string | HTMLElement) {
super(idOrContainer);
......
......@@ -29,7 +29,8 @@
"src/phases/phase.ts",
"src/phases/schedule-phase.ts",
"src/phases/sequence-phase.ts",
"src/selection/selection.ts",
"src/selection/selection-storage.ts",
"src/selection/selection-map.ts",
"src/selection/selection-broker.ts",
"src/selection/selection-handler.ts",
"src/views/view.ts",
......
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