Home | History | Annotate | Download | only in src
      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 ["&#8857;", `This node generated instructions in range [${start},${end}). ` +
     79                            `This is currently unreliable for constants.`];
     80       }
     81       if (start != -1) {
     82         return ["&#183;", `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"], "&#8857;");
    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