1// Copyright 2015 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5import { Schedule, SourceResolver } from "../src/source-resolver"; 6import { TextView } from "../src/text-view"; 7 8export class ScheduleView extends TextView { 9 schedule: Schedule; 10 sourceResolver: SourceResolver; 11 12 createViewElement() { 13 const pane = document.createElement('div'); 14 pane.setAttribute('id', "schedule"); 15 pane.classList.add("scrollable"); 16 pane.setAttribute("tabindex", "0"); 17 return pane; 18 } 19 20 constructor(parentId, broker) { 21 super(parentId, broker); 22 this.sourceResolver = broker.sourceResolver; 23 } 24 25 attachSelection(s) { 26 const view = this; 27 if (!(s instanceof Set)) return; 28 view.selectionHandler.clear(); 29 view.blockSelectionHandler.clear(); 30 const selected = new Array(); 31 for (const key of s) selected.push(key); 32 view.selectionHandler.select(selected, true); 33 } 34 35 detachSelection() { 36 this.blockSelection.clear(); 37 return this.selection.detachSelection(); 38 } 39 40 initializeContent(data, rememberedSelection) { 41 this.divNode.innerHTML = ''; 42 this.schedule = data.schedule; 43 this.addBlocks(data.schedule.blocks); 44 this.attachSelection(rememberedSelection); 45 this.show(); 46 } 47 48 createElementFromString(htmlString) { 49 const div = document.createElement('div'); 50 div.innerHTML = htmlString.trim(); 51 return div.firstChild; 52 } 53 54 elementForBlock(block) { 55 const view = this; 56 function createElement(tag: string, cls: string, content?: string) { 57 const el = document.createElement(tag); 58 el.className = cls; 59 if (content != undefined) el.innerHTML = content; 60 return el; 61 } 62 63 function mkNodeLinkHandler(nodeId) { 64 return function (e) { 65 e.stopPropagation(); 66 if (!e.shiftKey) { 67 view.selectionHandler.clear(); 68 } 69 view.selectionHandler.select([nodeId], true); 70 }; 71 } 72 73 function getMarker(start, end) { 74 if (start != end) { 75 return ["⊙", `This node generated instructions in range [${start},${end}). ` + 76 `This is currently unreliable for constants.`]; 77 } 78 if (start != -1) { 79 return ["·", `The instruction selector did not generate instructions ` + 80 `for this node, but processed the node at instruction ${start}. ` + 81 `This usually means that this node was folded into another node; ` + 82 `the highlighted machine code is a guess.`]; 83 } 84 return ["", `This not is not in the final schedule.`]; 85 } 86 87 function createElementForNode(node) { 88 const nodeEl = createElement("div", "node"); 89 90 const [start, end] = view.sourceResolver.getInstruction(node.id); 91 const [marker, tooltip] = getMarker(start, end); 92 const instrMarker = createElement("div", "instr-marker com", marker); 93 instrMarker.setAttribute("title", tooltip); 94 instrMarker.onclick = mkNodeLinkHandler(node.id); 95 nodeEl.appendChild(instrMarker); 96 97 const nodeId = createElement("div", "node-id tag clickable", node.id); 98 nodeId.onclick = mkNodeLinkHandler(node.id); 99 view.addHtmlElementForNodeId(node.id, nodeId); 100 nodeEl.appendChild(nodeId); 101 const nodeLabel = createElement("div", "node-label", node.label); 102 nodeEl.appendChild(nodeLabel); 103 if (node.inputs.length > 0) { 104 const nodeParameters = createElement("div", "parameter-list comma-sep-list"); 105 for (const param of node.inputs) { 106 const paramEl = createElement("div", "parameter tag clickable", param); 107 nodeParameters.appendChild(paramEl); 108 paramEl.onclick = mkNodeLinkHandler(param); 109 view.addHtmlElementForNodeId(param, paramEl); 110 } 111 nodeEl.appendChild(nodeParameters); 112 } 113 114 return nodeEl; 115 } 116 117 function mkBlockLinkHandler(blockId) { 118 return function (e) { 119 e.stopPropagation(); 120 if (!e.shiftKey) { 121 view.blockSelectionHandler.clear(); 122 } 123 view.blockSelectionHandler.select(["" + blockId], true); 124 }; 125 } 126 127 const scheduleBlock = createElement("div", "schedule-block"); 128 scheduleBlock.classList.toggle("deferred", block.isDeferred); 129 130 const [start, end] = view.sourceResolver.getInstructionRangeForBlock(block.id); 131 const instrMarker = createElement("div", "instr-marker com", "⊙"); 132 instrMarker.setAttribute("title", `Instructions range for this block is [${start}, ${end})`); 133 instrMarker.onclick = mkBlockLinkHandler(block.id); 134 scheduleBlock.appendChild(instrMarker); 135 136 const blockId = createElement("div", "block-id com clickable", block.id); 137 blockId.onclick = mkBlockLinkHandler(block.id); 138 scheduleBlock.appendChild(blockId); 139 const blockPred = createElement("div", "predecessor-list block-list comma-sep-list"); 140 for (const pred of block.pred) { 141 const predEl = createElement("div", "block-id com clickable", pred); 142 predEl.onclick = mkBlockLinkHandler(pred); 143 blockPred.appendChild(predEl); 144 } 145 if (block.pred.length) scheduleBlock.appendChild(blockPred); 146 const nodes = createElement("div", "nodes"); 147 for (const node of block.nodes) { 148 nodes.appendChild(createElementForNode(node)); 149 } 150 scheduleBlock.appendChild(nodes); 151 const blockSucc = createElement("div", "successor-list block-list comma-sep-list"); 152 for (const succ of block.succ) { 153 const succEl = createElement("div", "block-id com clickable", succ); 154 succEl.onclick = mkBlockLinkHandler(succ); 155 blockSucc.appendChild(succEl); 156 } 157 if (block.succ.length) scheduleBlock.appendChild(blockSucc); 158 this.addHtmlElementForBlockId(block.id, scheduleBlock); 159 return scheduleBlock; 160 } 161 162 addBlocks(blocks) { 163 for (const block of blocks) { 164 const blockEl = this.elementForBlock(block); 165 this.divNode.appendChild(blockEl); 166 } 167 } 168 169 lineString(node) { 170 return `${node.id}: ${node.label}(${node.inputs.join(", ")})`; 171 } 172 173 searchInputAction(searchBar, e, onlyVisible) { 174 e.stopPropagation(); 175 this.selectionHandler.clear(); 176 const query = searchBar.value; 177 if (query.length == 0) return; 178 const select = []; 179 window.sessionStorage.setItem("lastSearch", query); 180 const reg = new RegExp(query); 181 for (const node of this.schedule.nodes) { 182 if (node === undefined) continue; 183 if (reg.exec(this.lineString(node)) != null) { 184 select.push(node.id); 185 } 186 } 187 this.selectionHandler.select(select, true); 188 } 189} 190