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 5 import {Schedule,SourceResolver} from "./source-resolver.js" 6 import {isIterable} from "./util.js" 7 import {PhaseView} from "./view.js" 8 import {TextView} from "./text-view.js" 9 10 export class ScheduleView extends TextView implements PhaseView { 11 schedule: Schedule; 12 sourceResolver: SourceResolver; 13 14 createViewElement() { 15 const pane = document.createElement('div'); 16 pane.setAttribute('id', "schedule"); 17 return pane; 18 } 19 20 constructor(parentId, broker) { 21 super(parentId, broker, null); 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 } 46 47 createElementFromString(htmlString) { 48 var div = document.createElement('div'); 49 div.innerHTML = htmlString.trim(); 50 return div.firstChild; 51 } 52 53 elementForBlock(block) { 54 const view = this; 55 function createElement(tag: string, cls: string | Array<string>, content?: string) { 56 const el = document.createElement(tag); 57 if (isIterable(cls)) { 58 for (const c of cls) el.classList.add(c); 59 } else { 60 el.classList.add(cls); 61 } 62 if (content != undefined) el.innerHTML = content; 63 return el; 64 } 65 66 function mkNodeLinkHandler(nodeId) { 67 return function (e) { 68 e.stopPropagation(); 69 if (!e.shiftKey) { 70 view.selectionHandler.clear(); 71 } 72 view.selectionHandler.select([nodeId], true); 73 }; 74 } 75 76 function getMarker(start, end) { 77 if (start != end) { 78 return ["⊙", `This node generated instructions in range [${start},${end}). ` + 79 `This is currently unreliable for constants.`]; 80 } 81 if (start != -1) { 82 return ["·", `The instruction selector did not generate instructions ` + 83 `for this node, but processed the node at instruction ${start}. ` + 84 `This usually means that this node was folded into another node; ` + 85 `the highlighted machine code is a guess.`]; 86 } 87 return ["", `This not is not in the final schedule.`] 88 } 89 90 function createElementForNode(node) { 91 const nodeEl = createElement("div", "node"); 92 93 const [start, end] = view.sourceResolver.getInstruction(node.id); 94 const [marker, tooltip] = getMarker(start, end); 95 const instrMarker = createElement("div", ["instr-marker", "com"], marker); 96 instrMarker.setAttribute("title", tooltip); 97 instrMarker.onclick = mkNodeLinkHandler(node.id); 98 nodeEl.appendChild(instrMarker); 99 100 101 const node_id = createElement("div", ["node-id", "tag", "clickable"], node.id); 102 node_id.onclick = mkNodeLinkHandler(node.id); 103 view.addHtmlElementForNodeId(node.id, node_id); 104 nodeEl.appendChild(node_id); 105 const node_label = createElement("div", "node-label", node.label); 106 nodeEl.appendChild(node_label); 107 if (node.inputs.length > 0) { 108 const node_parameters = createElement("div", ["parameter-list", "comma-sep-list"]); 109 for (const param of node.inputs) { 110 const paramEl = createElement("div", ["parameter", "tag", "clickable"], param); 111 node_parameters.appendChild(paramEl); 112 paramEl.onclick = mkNodeLinkHandler(param); 113 view.addHtmlElementForNodeId(param, paramEl); 114 } 115 nodeEl.appendChild(node_parameters); 116 } 117 118 return nodeEl; 119 } 120 121 function mkBlockLinkHandler(blockId) { 122 return function (e) { 123 e.stopPropagation(); 124 if (!e.shiftKey) { 125 view.blockSelectionHandler.clear(); 126 } 127 view.blockSelectionHandler.select(["" + blockId], true); 128 }; 129 } 130 131 const schedule_block = createElement("div", "schedule-block"); 132 133 const [start, end] = view.sourceResolver.getInstructionRangeForBlock(block.id); 134 const instrMarker = createElement("div", ["instr-marker", "com"], "⊙"); 135 instrMarker.setAttribute("title", `Instructions range for this block is [${start}, ${end})`) 136 instrMarker.onclick = mkBlockLinkHandler(block.id); 137 schedule_block.appendChild(instrMarker); 138 139 const block_id = createElement("div", ["block-id", "com", "clickable"], block.id); 140 block_id.onclick = mkBlockLinkHandler(block.id); 141 schedule_block.appendChild(block_id); 142 const block_pred = createElement("div", ["predecessor-list", "block-list", "comma-sep-list"]); 143 for (const pred of block.pred) { 144 const predEl = createElement("div", ["block-id", "com", "clickable"], pred); 145 predEl.onclick = mkBlockLinkHandler(pred); 146 block_pred.appendChild(predEl); 147 } 148 if (block.pred.length) schedule_block.appendChild(block_pred); 149 const nodes = createElement("div", "nodes"); 150 for (const node of block.nodes) { 151 nodes.appendChild(createElementForNode(node)); 152 } 153 schedule_block.appendChild(nodes); 154 const block_succ = createElement("div", ["successor-list", "block-list", "comma-sep-list"]); 155 for (const succ of block.succ) { 156 const succEl = createElement("div", ["block-id", "com", "clickable"], succ); 157 succEl.onclick = mkBlockLinkHandler(succ); 158 block_succ.appendChild(succEl); 159 } 160 if (block.succ.length) schedule_block.appendChild(block_succ); 161 this.addHtmlElementForBlockId(block.id, schedule_block); 162 return schedule_block; 163 } 164 165 addBlocks(blocks) { 166 for (const block of blocks) { 167 const blockEl = this.elementForBlock(block); 168 this.divNode.appendChild(blockEl); 169 } 170 } 171 172 lineString(node) { 173 return `${node.id}: ${node.label}(${node.inputs.join(", ")})` 174 } 175 176 searchInputAction(searchBar, e) { 177 e.stopPropagation(); 178 this.selectionHandler.clear(); 179 const query = searchBar.value; 180 if (query.length == 0) return; 181 const select = []; 182 window.sessionStorage.setItem("lastSearch", query); 183 const reg = new RegExp(query); 184 for (const node of this.schedule.nodes) { 185 if (node === undefined) continue; 186 if (reg.exec(this.lineString(node)) != null) { 187 select.push(node.id) 188 } 189 } 190 this.selectionHandler.select(select, true); 191 } 192 193 onresize() { } 194 } 195