From 3f8607bfc8a5a64dad5148d5c7e081a117b8e92e Mon Sep 17 00:00:00 2001 From: Sigurd Schneider Date: Mon, 11 Jun 2018 13:56:45 +0200 Subject: [PATCH] [turbolizer] Wasm integration This CL allows selection/highlighting of wasm source when a graph node is clicked. Bug: v8:7327 Change-Id: I4a3347a83c8a38804feabffefaefd761596005c3 Reviewed-on: https://chromium-review.googlesource.com/1092712 Commit-Queue: Sigurd Schneider Reviewed-by: Georg Neis Cr-Commit-Position: refs/heads/master@{#53636} --- tools/turbolizer/src/code-view.ts | 28 ++++---- tools/turbolizer/src/graph-view.ts | 3 + tools/turbolizer/src/node.ts | 12 +++- tools/turbolizer/src/selection-broker.ts | 3 +- tools/turbolizer/src/source-resolver.ts | 86 +++++++++++++++++++++--- tools/turbolizer/src/turbo-visualizer.ts | 4 +- tools/turbolizer/turbo-visualizer.css | 19 ++++-- 7 files changed, 121 insertions(+), 34 deletions(-) diff --git a/tools/turbolizer/src/code-view.ts b/tools/turbolizer/src/code-view.ts index ad76479079..de393be6fd 100644 --- a/tools/turbolizer/src/code-view.ts +++ b/tools/turbolizer/src/code-view.ts @@ -14,7 +14,6 @@ class CodeView extends View { source: Source; sourceResolver: SourceResolver; codeMode: CodeMode; - lineToSourcePositions: Map>; sourcePositionToHtmlElement: Map; showAdditionalInliningPosition: boolean; selectionHandler: SelectionHandler; @@ -34,7 +33,6 @@ class CodeView extends View { view.sourceResolver = sourceResolver; view.source = sourceFunction; view.codeMode = codeMode; - this.lineToSourcePositions = new Map(); this.sourcePositionToHtmlElement = new Map(); this.showAdditionalInliningPosition = false; @@ -75,14 +73,6 @@ class CodeView extends View { this.initializeCode(); } - addSourcePositionToLine(lineNumber, sourcePosition) { - const lineNumberString = anyToString(lineNumber); - if (!this.lineToSourcePositions.has(lineNumberString)) { - this.lineToSourcePositions.set(lineNumberString, []); - } - this.lineToSourcePositions.get(lineNumberString).push(sourcePosition); - } - addHtmlElementToSourcePosition(sourcePosition, element) { const key = sourcePositionToStringKey(sourcePosition); if (this.sourcePositionToHtmlElement.has(key)) { @@ -122,13 +112,15 @@ class CodeView extends View { return ordereList.childNodes as NodeListOf; } - onSelectLine(lineNumber, doClear) { - const sourcePositions = this.lineToSourcePositions.get(anyToString(lineNumber)); + onSelectLine(lineNumber:number, doClear:boolean) { + const key = anyToString(lineNumber); if (doClear) { this.selectionHandler.clear(); } - if (!sourcePositions) return; - this.selectionHandler.select(sourcePositions, undefined); + const positions = this.sourceResolver.linetoSourcePositions(lineNumber - 1); + if (positions !== undefined) { + this.selectionHandler.select(positions, undefined); + } } onSelectSourcePosition(sourcePosition, doClear) { @@ -225,7 +217,7 @@ class CodeView extends View { const view = this; const sps = this.sourceResolver.sourcePositionsInRange(this.source.sourceId, pos - adjust, end); for (const sourcePosition of sps) { - view.addSourcePositionToLine(lineNumber, sourcePosition); + this.sourceResolver.addAnyPositionToLine(lineNumber, sourcePosition); const textnode = currentSpan.tagName == 'SPAN' ? currentSpan.firstChild : currentSpan; const replacementNode = textnode.splitText(Math.max(0, sourcePosition.scriptOffset - pos)); const span = document.createElement('span'); @@ -255,12 +247,18 @@ class CodeView extends View { const view = this; const lineNumberElement = document.createElement("div"); lineNumberElement.classList.add("line-number"); + lineNumberElement.dataset.lineNumber = lineNumber; lineNumberElement.innerText = lineNumber; lineNumberElement.onclick = function (e) { e.stopPropagation(); view.onSelectLine(lineNumber, !e.shiftKey); } lineElement.insertBefore(lineNumberElement, lineElement.firstChild) + // Don't add lines to source positions of not in backwardsCompatibility mode. + if (typeof this.source['backwardsCompatibility'] === undefined) return; + for (const sourcePosition of this.sourceResolver.linetoSourcePositions(lineNumber - 1)) { + view.addHtmlElementToSourcePosition(sourcePosition, lineElement); + } } deleteContent() { } diff --git a/tools/turbolizer/src/graph-view.ts b/tools/turbolizer/src/graph-view.ts index 103bdb3453..44c3745338 100644 --- a/tools/turbolizer/src/graph-view.ts +++ b/tools/turbolizer/src/graph-view.ts @@ -91,6 +91,9 @@ class GraphView extends View implements PhaseView { if (node.sourcePosition) { locations.push(node.sourcePosition); } + if (node.origin && node.origin.bytecodePosition) { + locations.push({bytecodePosition: node.origin.bytecodePosition}); + } } graph.state.selection.select(nodes, selected); broker.broadcastSourcePositionSelect(this, locations, selected); diff --git a/tools/turbolizer/src/node.ts b/tools/turbolizer/src/node.ts index 82da5d9204..8d5783f126 100644 --- a/tools/turbolizer/src/node.ts +++ b/tools/turbolizer/src/node.ts @@ -12,6 +12,16 @@ function isNodeInitiallyVisible(node) { return node.cfg; } +function formatOrigin(origin) { + if (origin.nodeId) { + return `#${origin.nodeId} in phase ${origin.phase}/${origin.reducer}`; + } + if (origin.bytecodePosition) { + return `Bytecode line ${origin.bytecodePosition} in phase ${origin.phase}/${origin.reducer}`; + } + return "unknown origin"; +} + class GNode { control: boolean; opcode: string; @@ -79,7 +89,7 @@ class GNode { } let title = this.title + "\n" + propsString + "\n" + this.opinfo; if (this.origin) { - title += `\nOrigin: #${this.origin.nodeId} in phase ${this.origin.phase}/${this.origin.reducer}`; + title += `\nOrigin: ${formatOrigin(this.origin)}`; } return title; } diff --git a/tools/turbolizer/src/selection-broker.ts b/tools/turbolizer/src/selection-broker.ts index 2e025dfb08..973e945da4 100644 --- a/tools/turbolizer/src/selection-broker.ts +++ b/tools/turbolizer/src/selection-broker.ts @@ -30,8 +30,7 @@ class SelectionBroker { broadcastSourcePositionSelect(from, sourcePositions, selected) { let broker = this; sourcePositions = sourcePositions.filter((l) => { - if (typeof l.scriptOffset == 'undefined' - || typeof l.inliningId == 'undefined') { + if (!sourcePositionValid(l)) { console.log("Warning: invalid source position"); return false; } diff --git a/tools/turbolizer/src/source-resolver.ts b/tools/turbolizer/src/source-resolver.ts index d143016342..8286f88a14 100644 --- a/tools/turbolizer/src/source-resolver.ts +++ b/tools/turbolizer/src/source-resolver.ts @@ -14,9 +14,18 @@ function sourcePositionEq(a, b) { a.scriptOffset == b.scriptOffset; } -function sourcePositionToStringKey(sourcePosition) { +function sourcePositionToStringKey(sourcePosition): string { if (!sourcePosition) return "undefined"; - return "" + sourcePosition.inliningId + ":" + sourcePosition.scriptOffset; + if (sourcePosition.inliningId && sourcePosition.scriptOffset) + return "SP:" + sourcePosition.inliningId + ":" + sourcePosition.scriptOffset; + if (sourcePosition.bytecodePosition) + return "BCP:" + sourcePosition.bytecodePosition; + return "undefined"; +} + +function sourcePositionValid(l) { + return (typeof l.scriptOffset !== undefined + && typeof l.inliningId !== undefined) || typeof l.bytecodePosition != undefined; } interface SourcePosition { @@ -24,6 +33,25 @@ interface SourcePosition { inliningId: number; } +interface TurboFanOrigin { + phase: string; + reducer: string; +} + +interface NodeOrigin { + nodeId: number; +} + +interface BytecodePosition { + bytecodePosition: number; +} + +type Origin = NodeOrigin | BytecodePosition; +type TurboFanNodeOrigin = NodeOrigin & TurboFanOrigin; +type TurboFanBytecodeOrigin = BytecodePosition & TurboFanOrigin; + +type AnyPosition = SourcePosition | BytecodePosition; + interface Source { sourcePositions: Array; sourceName: string; @@ -46,14 +74,8 @@ interface Schedule { nodes: Array; } -interface NodeOrigin { - nodeId: number; - phase: string; - reducer: string; -} - class SourceResolver { - nodePositionMap: Array; + nodePositionMap: Array; sources: Array; inlinings: Array; inliningsMap: Map; @@ -61,6 +83,8 @@ class SourceResolver { phases: Array; phaseNames: Map; disassemblyPhase: Phase; + lineToSourcePositions: Map>; + constructor() { // Maps node ids to source positions. @@ -79,6 +103,8 @@ class SourceResolver { this.phaseNames = new Map(); // The disassembly phase is stored separately. this.disassemblyPhase = undefined; + // Maps line numbers to source positions + this.lineToSourcePositions = new Map(); } setSources(sources, mainBackup) { @@ -153,7 +179,7 @@ class SourceResolver { return nodeIds; } - nodeIdsToSourcePositions(nodeIds) { + nodeIdsToSourcePositions(nodeIds): Array { const sourcePositions = new Map(); for (const nodeId of nodeIds) { let sp = this.nodePositionMap[nodeId]; @@ -255,6 +281,23 @@ class SourceResolver { return inliningStack; } + recordOrigins(phase) { + if (phase.type != "graph") return; + for (const node of phase.data.nodes) { + if (node.origin != undefined && + node.origin.bytecodePosition != undefined) { + const position = {bytecodePosition: node.origin.bytecodePosition}; + this.nodePositionMap[node.id] = position; + let key = sourcePositionToStringKey(position); + if (!this.positionToNodes.has(key)) { + this.positionToNodes.set(key, []); + } + const A = this.positionToNodes.get(key); + if (!A.includes(node.id)) A.push("" + node.id); + } + } + } + parsePhases(phases) { for (const [phaseId, phase] of Object.entries(phases)) { if (phase.type == 'disassembly') { @@ -264,6 +307,7 @@ class SourceResolver { this.phaseNames.set(phase.name, this.phases.length); } else { this.phases.push(phase); + this.recordOrigins(phase); this.phaseNames.set(phase.name, this.phases.length); } } @@ -285,6 +329,28 @@ class SourceResolver { this.phases.forEach(f); } + addAnyPositionToLine(lineNumber:number|String, sourcePosition:AnyPosition) { + const lineNumberString = anyToString(lineNumber); + if (!this.lineToSourcePositions.has(lineNumberString)) { + this.lineToSourcePositions.set(lineNumberString, []); + } + const A = this.lineToSourcePositions.get(lineNumberString); + if (!A.includes(sourcePosition)) A.push(sourcePosition); + } + + setSourceLineToBytecodePosition(sourceLineToBytecodePosition:Array|undefined) { + if (!sourceLineToBytecodePosition) return; + sourceLineToBytecodePosition.forEach((pos, i) => { + this.addAnyPositionToLine(i, {bytecodePosition: pos}); + }); + } + + linetoSourcePositions(lineNumber:number|String) { + const positions = this.lineToSourcePositions.get(anyToString(lineNumber)); + if (positions === undefined) return []; + return positions; + } + parseSchedule(phase) { function createNode(state, match) { let inputs = []; diff --git a/tools/turbolizer/src/turbo-visualizer.ts b/tools/turbolizer/src/turbo-visualizer.ts index fdf375aaf2..9d41042300 100644 --- a/tools/turbolizer/src/turbo-visualizer.ts +++ b/tools/turbolizer/src/turbo-visualizer.ts @@ -226,11 +226,13 @@ window.onload = function () { sourceId: -1, startPosition: jsonObj.sourcePosition, endPosition: jsonObj.sourcePosition + jsonObj.source.length, - sourceText: jsonObj.source + sourceText: jsonObj.source, + backwardsCompatibility: true }; } sourceResolver.setInlinings(jsonObj.inlinings); + sourceResolver.setSourceLineToBytecodePosition(jsonObj.sourceLineToBytecodePosition); sourceResolver.setSources(jsonObj.sources, fnc) sourceResolver.setNodePositionMap(jsonObj.nodePositions); sourceResolver.parsePhases(jsonObj.phases); diff --git a/tools/turbolizer/turbo-visualizer.css b/tools/turbolizer/turbo-visualizer.css index 80fcb8e5c0..8485a211c2 100644 --- a/tools/turbolizer/turbo-visualizer.css +++ b/tools/turbolizer/turbo-visualizer.css @@ -45,7 +45,6 @@ display: none; } - .selected { background-color: #FFFF33; } @@ -64,19 +63,29 @@ ol.linenums { display:inline-block; min-width: 3ex; text-align: right; - color: gray; - padding-right:1ex; - font-size: 10px; + color: #444444; + margin-right: 0.5ex; + padding-right: 0.5ex; + background: #EEEEEE; + /* font-size: 80%; */ user-select: none; + height: 120%; } .line-number:hover { background-color: #CCCCCC; } +.prettyprint ol.linenums > li.selected { + background-color: #FFFF33 !important; +} + +li.selected .line-number { + background-color: #FFFF33; +} + .prettyprint ol.linenums > li { list-style-type: decimal; - padding-top: 3px; display: block; }