%PDF- <> %âãÏÓ endobj 2 0 obj <> endobj 3 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 28 0 R 29 0 R] /MediaBox[ 0 0 595.5 842.25] /Contents 4 0 R/Group<>/Tabs/S>> endobj ºaâÚÎΞ-ÌE1ÍØÄ÷{òò2ÿ ÛÖ^ÔÀá TÎ{¦?§®¥kuµùÕ5sLOšuY>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<> endobj 2 0 obj<>endobj 2 0 obj<>es 3 0 R>> endobj 2 0 obj<> ox[ 0.000000 0.000000 609.600000 935.600000]/Fi endobj 3 0 obj<> endobj 7 1 obj<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Subtype/Form>> stream
// Copyright 2018 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. import { Sequence } from "../src/source-resolver"; import { createElement } from "../src/util"; import { TextView } from "../src/text-view"; import { RangeView } from "../src/range-view"; export class SequenceView extends TextView { sequence: Sequence; searchInfo: Array<any>; phaseSelect: HTMLSelectElement; numInstructions: number; currentPhaseIndex: number; phaseIndexes: Set<number>; isShown: boolean; rangeView: RangeView; showRangeView: boolean; toggleRangeViewEl: HTMLElement; createViewElement() { const pane = document.createElement('div'); pane.setAttribute('id', "sequence"); pane.classList.add("scrollable"); pane.setAttribute("tabindex", "0"); return pane; } constructor(parentId, broker) { super(parentId, broker); this.numInstructions = 0; this.phaseIndexes = new Set<number>(); this.isShown = false; this.showRangeView = false; this.rangeView = null; 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); } detachSelection() { this.blockSelection.clear(); return this.selection.detachSelection(); } show() { this.currentPhaseIndex = this.phaseSelect.selectedIndex; if (!this.isShown) { this.isShown = true; this.phaseIndexes.add(this.currentPhaseIndex); this.container.appendChild(this.divNode); this.container.getElementsByClassName("graph-toolbox")[0].appendChild(this.toggleRangeViewEl); } if (this.showRangeView) this.rangeView.show(); } hide() { // A single SequenceView object is used for two phases (i.e before and after // register allocation), tracking the indexes lets the redundant hides and // shows be avoided when switching between the two. this.currentPhaseIndex = this.phaseSelect.selectedIndex; if (!this.phaseIndexes.has(this.currentPhaseIndex)) { this.isShown = false; this.container.removeChild(this.divNode); this.container.getElementsByClassName("graph-toolbox")[0].removeChild(this.toggleRangeViewEl); if (this.showRangeView) this.rangeView.hide(); } } onresize() { if (this.showRangeView) this.rangeView.onresize(); } initializeContent(data, rememberedSelection) { this.divNode.innerHTML = ''; this.sequence = data.sequence; this.searchInfo = []; this.divNode.onclick = (e: MouseEvent) => { if (!(e.target instanceof HTMLElement)) return; const instructionId = Number.parseInt(e.target.dataset.instructionId, 10); if (!instructionId) return; if (!e.shiftKey) this.broker.broadcastClear(null); this.broker.broadcastInstructionSelect(null, [instructionId], true); }; this.phaseSelect = (document.getElementById('phase-select') as HTMLSelectElement); this.currentPhaseIndex = this.phaseSelect.selectedIndex; this.addBlocks(this.sequence.blocks); 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(); } elementForBlock(block) { const view = this; function mkLinkHandler(id, handler) { return function (e) { e.stopPropagation(); if (!e.shiftKey) { handler.clear(); } handler.select(["" + id], true); }; } function mkBlockLinkHandler(blockId) { return mkLinkHandler(blockId, view.blockSelectionHandler); } function mkInstructionLinkHandler(instrId) { return mkLinkHandler(instrId, view.registerAllocationSelectionHandler); } function mkOperandLinkHandler(text) { return mkLinkHandler(text, view.selectionHandler); } function elementForOperandWithSpan(span, text, searchInfo, isVirtual) { const selectionText = isVirtual ? "virt_" + text : text; span.onclick = mkOperandLinkHandler(selectionText); searchInfo.push(text); view.addHtmlElementForNodeId(selectionText, span); const container = createElement("div", ""); container.appendChild(span); return container; } function elementForOperand(operand, searchInfo) { let isVirtual = false; let className = "parameter tag clickable " + operand.type; if (operand.text[0] == 'v' && !(operand.tooltip && operand.tooltip.includes("Float"))) { isVirtual = true; className += " virtual-reg"; } const span = createElement("span", className, operand.text); if (operand.tooltip) { span.setAttribute("title", operand.tooltip); } return elementForOperandWithSpan(span, operand.text, searchInfo, isVirtual); } function elementForPhiOperand(text, searchInfo) { const span = createElement("span", "parameter tag clickable virtual-reg", text); return elementForOperandWithSpan(span, text, searchInfo, true); } function elementForInstruction(instruction, searchInfo) { const instNodeEl = createElement("div", "instruction-node"); const instId = createElement("div", "instruction-id", instruction.id); const offsets = view.sourceResolver.instructionToPcOffsets(instruction.id); instId.classList.add("clickable"); view.addHtmlElementForInstructionId(instruction.id, instId); instId.onclick = mkInstructionLinkHandler(instruction.id); instId.dataset.instructionId = instruction.id; if (offsets) { instId.setAttribute("title", `This instruction generated gap code at pc-offset 0x${offsets.gap.toString(16)}, code at pc-offset 0x${offsets.arch.toString(16)}, condition handling at pc-offset 0x${offsets.condition.toString(16)}.`); } instNodeEl.appendChild(instId); const instContentsEl = createElement("div", "instruction-contents"); instNodeEl.appendChild(instContentsEl); // Print gap moves. const gapEl = createElement("div", "gap", "gap"); let hasGaps = false; for (const gap of instruction.gaps) { const moves = createElement("div", "comma-sep-list gap-move"); for (const move of gap) { hasGaps = true; const moveEl = createElement("div", "move"); const destinationEl = elementForOperand(move[0], searchInfo); moveEl.appendChild(destinationEl); const assignEl = createElement("div", "assign", "="); moveEl.appendChild(assignEl); const sourceEl = elementForOperand(move[1], searchInfo); moveEl.appendChild(sourceEl); moves.appendChild(moveEl); } gapEl.appendChild(moves); } if (hasGaps) { instContentsEl.appendChild(gapEl); } const instEl = createElement("div", "instruction"); instContentsEl.appendChild(instEl); if (instruction.outputs.length > 0) { const outputs = createElement("div", "comma-sep-list input-output-list"); for (const output of instruction.outputs) { const outputEl = elementForOperand(output, searchInfo); outputs.appendChild(outputEl); } instEl.appendChild(outputs); const assignEl = createElement("div", "assign", "="); instEl.appendChild(assignEl); } const text = instruction.opcode + instruction.flags; const instLabel = createElement("div", "node-label", text); if (instruction.opcode == "ArchNop" && instruction.outputs.length == 1 && instruction.outputs[0].tooltip) { instLabel.innerText = instruction.outputs[0].tooltip; } searchInfo.push(text); view.addHtmlElementForNodeId(text, instLabel); instEl.appendChild(instLabel); if (instruction.inputs.length > 0) { const inputs = createElement("div", "comma-sep-list input-output-list"); for (const input of instruction.inputs) { const inputEl = elementForOperand(input, searchInfo); inputs.appendChild(inputEl); } instEl.appendChild(inputs); } if (instruction.temps.length > 0) { const temps = createElement("div", "comma-sep-list input-output-list temps"); for (const temp of instruction.temps) { const tempEl = elementForOperand(temp, searchInfo); temps.appendChild(tempEl); } instEl.appendChild(temps); } return instNodeEl; } const sequenceBlock = createElement("div", "schedule-block"); sequenceBlock.classList.toggle("deferred", block.deferred); const blockId = createElement("div", "block-id com clickable", block.id); blockId.onclick = mkBlockLinkHandler(block.id); sequenceBlock.appendChild(blockId); const blockPred = createElement("div", "predecessor-list block-list comma-sep-list"); for (const pred of block.predecessors) { const predEl = createElement("div", "block-id com clickable", pred); predEl.onclick = mkBlockLinkHandler(pred); blockPred.appendChild(predEl); } if (block.predecessors.length > 0) sequenceBlock.appendChild(blockPred); const phis = createElement("div", "phis"); sequenceBlock.appendChild(phis); const phiLabel = createElement("div", "phi-label", "phi:"); phis.appendChild(phiLabel); const phiContents = createElement("div", "phi-contents"); phis.appendChild(phiContents); for (const phi of block.phis) { const phiEl = createElement("div", "phi"); phiContents.appendChild(phiEl); const outputEl = elementForOperand(phi.output, this.searchInfo); phiEl.appendChild(outputEl); const assignEl = createElement("div", "assign", "="); phiEl.appendChild(assignEl); for (const input of phi.operands) { const inputEl = elementForPhiOperand(input, this.searchInfo); phiEl.appendChild(inputEl); } } const instructions = createElement("div", "instructions"); for (const instruction of block.instructions) { instructions.appendChild(elementForInstruction(instruction, this.searchInfo)); } sequenceBlock.appendChild(instructions); const blockSucc = createElement("div", "successor-list block-list comma-sep-list"); for (const succ of block.successors) { const succEl = createElement("div", "block-id com clickable", succ); succEl.onclick = mkBlockLinkHandler(succ); blockSucc.appendChild(succEl); } if (block.successors.length > 0) sequenceBlock.appendChild(blockSucc); this.addHtmlElementForBlockId(block.id, sequenceBlock); return sequenceBlock; } addBlocks(blocks) { for (const block of blocks) { const blockEl = this.elementForBlock(block); this.divNode.appendChild(blockEl); } } addRangeView() { const preventRangeView = reason => { const toggleRangesInput = this.toggleRangeViewEl.firstChild as HTMLInputElement; if (this.rangeView) { toggleRangesInput.checked = false; this.toggleRangeView(toggleRangesInput); } toggleRangesInput.disabled = true; this.toggleRangeViewEl.style.textDecoration = "line-through"; this.toggleRangeViewEl.setAttribute("title", reason); }; if (this.sequence.register_allocation) { if (!this.rangeView) { this.rangeView = new RangeView(this); } const source = this.sequence.register_allocation; if (source.fixedLiveRanges.size == 0 && source.liveRanges.size == 0) { preventRangeView("No live ranges to show"); } else if (this.numInstructions >= 249) { // This is due to the css grid-column being limited to 1000 columns. // Performance issues would otherwise impose some limit. // TODO(george.wort@arm.com): Allow the user to specify an instruction range // to display that spans less than 249 instructions. preventRangeView( "Live range display is only supported for sequences with less than 249 instructions"); } if (this.showRangeView) { this.rangeView.initializeContent(this.sequence.blocks); } } else { preventRangeView("No live range data provided"); } } elementForToggleRangeView() { const toggleRangeViewEl = createElement("label", "", "show live ranges"); const toggleRangesInput = createElement("input", "range-toggle-show") as HTMLInputElement; toggleRangesInput.setAttribute("type", "checkbox"); toggleRangesInput.oninput = () => this.toggleRangeView(toggleRangesInput); toggleRangeViewEl.insertBefore(toggleRangesInput, toggleRangeViewEl.firstChild); return toggleRangeViewEl; } toggleRangeView(toggleRangesInput: HTMLInputElement) { toggleRangesInput.disabled = true; this.showRangeView = toggleRangesInput.checked; if (this.showRangeView) { this.rangeView.initializeContent(this.sequence.blocks); this.rangeView.show(); } else { this.rangeView.hide(); } window.dispatchEvent(new Event('resize')); toggleRangesInput.disabled = false; } searchInputAction(searchBar, e) { e.stopPropagation(); this.selectionHandler.clear(); const query = searchBar.value; if (query.length == 0) return; const select = []; window.sessionStorage.setItem("lastSearch", query); const reg = new RegExp(query); for (const item of this.searchInfo) { if (reg.exec(item) != null) { select.push(item); } } this.selectionHandler.select(select, true); } }