[turbolizer] Bytecode sources view

Bug: v8:7327
Change-Id: I0de7ee31762db6b95a631eedffd0f82fa2f0ce3b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3812034
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Commit-Queue: Danylo Boiko <danielboyko02@gmail.com>
Cr-Commit-Position: refs/heads/main@{#82500}
This commit is contained in:
Danylo Boiko 2022-08-12 22:50:23 +03:00 committed by V8 LUCI CQ
parent aa541f1c9c
commit 1c44d07958
8 changed files with 189 additions and 9 deletions

View File

@ -76,6 +76,11 @@ ol.linenums {
-webkit-padding-start: 8px;
}
ol.linenums.constants {
margin-top: 3px;
color: #298f45;
}
.line-number {
display: inline-block;
min-width: 3ex;
@ -110,7 +115,7 @@ li.selected .line-number {
display: block;
}
.source-container {
.source-container, .bytecode-source-container {
border-bottom: 2px solid #AAAAAA;
}

View File

@ -11,7 +11,7 @@ import { InstructionsPhase } from "./phases/instructions-phase";
import { SchedulePhase } from "./phases/schedule-phase";
import { SequencePhase } from "./phases/sequence-phase";
import { BytecodeOrigin } from "./origin";
import { Source } from "./source";
import { BytecodeSource, BytecodeSourceData, Source } from "./source";
import { NodeLabel } from "./node-label";
import { TurboshaftCustomDataPhase } from "./phases/turboshaft-custom-data-phase";
import { TurboshaftGraphPhase } from "./phases/turboshaft-graph-phase/turboshaft-graph-phase";
@ -23,6 +23,7 @@ export type GenericPhase = GraphPhase | TurboshaftGraphPhase | TurboshaftCustomD
export class SourceResolver {
nodePositionMap: Array<GenericPosition>;
sources: Array<Source>;
bytecodeSources: Map<number, BytecodeSource>;
inlinings: Array<InliningPosition>;
inliningsMap: Map<string, InliningPosition>;
positionToNodes: Map<string, Array<string>>;
@ -37,6 +38,8 @@ export class SourceResolver {
this.nodePositionMap = new Array<GenericPosition>();
// Maps source ids to source objects.
this.sources = new Array<Source>();
// Maps bytecode source ids to bytecode source objects.
this.bytecodeSources = new Map<number, BytecodeSource>();
// Maps inlining ids to inlining objects.
this.inlinings = new Array<InliningPosition>();
// Maps source position keys to inlinings.
@ -96,6 +99,22 @@ export class SourceResolver {
}
}
public setBytecodeSources(bytecodeSourcesJson): void {
if (!bytecodeSourcesJson) return;
for (const [sourceId, source] of Object.entries<any>(bytecodeSourcesJson)) {
const bytecodeSource = source.bytecodeSource;
const data = new Array<BytecodeSourceData>();
for (const bytecode of Object.values<BytecodeSourceData>(bytecodeSource.data)) {
data.push(new BytecodeSourceData(bytecode.offset, bytecode.disassembly));
}
const numSourceId = Number(sourceId);
this.bytecodeSources.set(numSourceId, new BytecodeSource(source.sourceId, source.functionName,
data, bytecodeSource.constantPool));
}
}
public setNodePositionMap(mapJson): void {
if (!mapJson) return;
if (typeof mapJson[0] !== "object") {

View File

@ -31,3 +31,28 @@ export class Source {
return `${this.sourceName}:${this.functionName}`;
}
}
export class BytecodeSource {
sourceId: number;
functionName: string;
data: Array<BytecodeSourceData>;
constantPool: Array<string>;
constructor(sourceId: number, functionName: string, data: Array<BytecodeSourceData>,
constantPool: Array<string>) {
this.sourceId = sourceId;
this.functionName = functionName;
this.data = data;
this.constantPool = constantPool;
}
}
export class BytecodeSourceData {
offset: number;
disassembly: string;
constructor(offset: number, disassembly: string) {
this.offset = offset;
this.disassembly = disassembly;
}
}

View File

@ -7,16 +7,19 @@ import { SourceResolver } from "./source-resolver";
import { SelectionBroker } from "./selection/selection-broker";
import { DisassemblyView } from "./views/disassembly-view";
import { GraphMultiView } from "./graphmultiview";
import { CodeMode, CodeView } from "./views/code-view";
import { CodeView } from "./views/code-view";
import { Tabs } from "./tabs";
import { Resizer } from "./resizer";
import { InfoView } from "./views/info-view";
import { HistoryView } from "./views/history-view";
import { CodeMode } from "./views/view";
import { BytecodeSourceView } from "./views/bytecode-source-view";
window.onload = function () {
let multiview: GraphMultiView;
let disassemblyView: DisassemblyView;
let sourceViews: Array<CodeView> = new Array<CodeView>();
let bytecodeSourceViews: Array<BytecodeSourceView> = new Array<BytecodeSourceView>();
let historyView: HistoryView;
let selectionBroker: SelectionBroker;
let sourceResolver: SourceResolver;
@ -47,6 +50,7 @@ window.onload = function () {
}
try {
sourceViews.forEach(sv => sv.hide());
bytecodeSourceViews.forEach(bsv => bsv.hide());
multiview?.hide();
multiview = null;
document.getElementById("ranges").innerHTML = "";
@ -55,6 +59,7 @@ window.onload = function () {
disassemblyView?.hide();
historyView?.hide();
sourceViews = new Array<CodeView>();
bytecodeSourceViews = new Array<BytecodeSourceView>();
sourceResolver = new SourceResolver();
selectionBroker = new SelectionBroker(sourceResolver);
@ -64,6 +69,7 @@ window.onload = function () {
sourceResolver.setInlinings(jsonObj.inlinings);
sourceResolver.setSourceLineToBytecodePosition(jsonObj.sourceLineToBytecodePosition);
sourceResolver.setSources(jsonObj.sources, mainFunction);
sourceResolver.setBytecodeSources(jsonObj.bytecodeSources);
sourceResolver.setNodePositionMap(jsonObj.nodePositions);
sourceResolver.parsePhases(jsonObj.phases);
@ -83,6 +89,20 @@ window.onload = function () {
sourceViews.push(sourceView);
}
if (sourceResolver.bytecodeSources.size > 0) {
const [_, bytecodeContainer] = sourceTabs.addTabAndContent("Bytecode");
bytecodeContainer.classList.add("viewpane", "scrollable");
const bytecodeSources = Array.from(sourceResolver.bytecodeSources.values()).reverse();
for (const source of bytecodeSources) {
const codeMode = source.sourceId == -1 ? CodeMode.MainSource : CodeMode.InlinedSource;
const bytecodeSourceView = new BytecodeSourceView(bytecodeContainer, selectionBroker,
source, sourceResolver, codeMode);
bytecodeSourceView.show();
bytecodeSourceViews.push(bytecodeSourceView);
}
}
const [disassemblyTab, disassemblyContainer] = disassemblyTabs.addTabAndContent("Disassembly");
disassemblyContainer.classList.add("viewpane", "scrollable");
disassemblyTabs.activateTab(disassemblyTab);

View File

@ -0,0 +1,110 @@
// Copyright 2022 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 { createElement } from "../common/util";
import { CodeMode, View } from "./view";
import { SelectionBroker } from "../selection/selection-broker";
import { BytecodeSource } from "../source";
import { SourceResolver } from "../source-resolver";
export class BytecodeSourceView extends View {
broker: SelectionBroker;
source: BytecodeSource;
sourceResolver: SourceResolver;
codeMode: CodeMode;
bytecodeOffsetToHtmlElement: Map<number, HTMLElement>;
constructor(parent: HTMLElement, broker: SelectionBroker, sourceFunction: BytecodeSource,
sourceResolver: SourceResolver, codeMode: CodeMode) {
super(parent);
this.broker = broker;
this.source = sourceFunction;
this.sourceResolver = sourceResolver;
this.codeMode = codeMode;
this.bytecodeOffsetToHtmlElement = new Map<number, HTMLElement>();
this.initializeCode();
}
protected createViewElement(): HTMLElement {
return createElement("div", "bytecode-source-container");
}
private initializeCode(): void {
const view = this;
const source = this.source;
const bytecodeContainer = this.divNode;
bytecodeContainer.classList.add(view.getSourceClass());
const bytecodeHeader = createElement("div", "code-header");
bytecodeHeader.setAttribute("id", view.getBytecodeHeaderHtmlElementName());
const codeFileFunction = createElement("div", "code-file-function", source.functionName);
bytecodeHeader.appendChild(codeFileFunction);
const codeMode = createElement("div", "code-mode", view.codeMode);
bytecodeHeader.appendChild(codeMode);
const clearElement = document.createElement("div");
clearElement.style.clear = "both";
bytecodeHeader.appendChild(clearElement);
bytecodeContainer.appendChild(bytecodeHeader);
const codePre = createElement("pre", "prettyprint linenums");
codePre.setAttribute("id", view.getBytecodeHtmlElementName());
bytecodeContainer.appendChild(codePre);
bytecodeHeader.onclick = () => {
codePre.style.display = codePre.style.display === "none" ? "block" : "none";
};
const sourceList = createElement("ol", "linenums");
for (const bytecodeSource of view.source.data) {
const currentLine = createElement("li", `L${bytecodeSource.offset}`);
currentLine.setAttribute("id", `li${bytecodeSource.offset}`);
view.insertLineContent(currentLine, bytecodeSource.disassembly);
view.insertLineNumber(currentLine, bytecodeSource.offset);
view.bytecodeOffsetToHtmlElement.set(bytecodeSource.offset, currentLine);
sourceList.appendChild(currentLine);
}
codePre.appendChild(sourceList);
if (view.source.constantPool.length === 0) return;
const constantList = createElement("ol", "linenums constants");
const constantListHeader = createElement("li", "");
view.insertLineContent(constantListHeader,
`Constant pool (size = ${view.source.constantPool.length})`);
constantList.appendChild(constantListHeader);
for (const [idx, constant] of view.source.constantPool.entries()) {
const currentLine = createElement("li", `C${idx}`);
view.insertLineContent(currentLine, `${idx}: ${constant}`);
constantList.appendChild(currentLine);
}
codePre.appendChild(constantList);
}
private getBytecodeHeaderHtmlElementName(): string {
return `source-pre-${this.source.sourceId}-header`;
}
private getBytecodeHtmlElementName(): string {
return `source-pre-${this.source.sourceId}`;
}
private getSourceClass(): string {
return this.codeMode == CodeMode.MainSource ? "main-source" : "inlined-source";
}
private insertLineContent(lineElement: HTMLElement, content: string): void {
const lineContentElement = createElement("span", "", content);
lineElement.appendChild(lineContentElement);
}
private insertLineNumber(lineElement: HTMLElement, lineNumber: number): void {
const lineNumberElement = createElement("div", "line-number", String(lineNumber));
lineElement.insertBefore(lineNumberElement, lineElement.firstChild);
}
}

View File

@ -5,7 +5,7 @@
import { Source } from "../source";
import { GenericPosition, SourceResolver } from "../source-resolver";
import { SelectionBroker } from "../selection/selection-broker";
import { View } from "./view";
import { CodeMode, View } from "./view";
import { SelectionMap } from "../selection/selection-map";
import { ViewElements } from "../common/view-elements";
import { ClearableHandler, SourcePositionSelectionHandler } from "../selection/selection-handler";
@ -19,11 +19,6 @@ declare global {
const PR: PR;
}
export enum CodeMode {
MainSource = "main function",
InlinedSource = "inlined function"
}
export class CodeView extends View {
broker: SelectionBroker;
source: Source;

View File

@ -37,3 +37,8 @@ export abstract class PhaseView extends View {
super(idOrContainer);
}
}
export enum CodeMode {
MainSource = "main function",
InlinedSource = "inlined function"
}

View File

@ -36,6 +36,7 @@
"src/selection/selection-handler.ts",
"src/views/view.ts",
"src/views/code-view.ts",
"src/views/bytecode-source-view.ts",
"src/views/graph-view.ts",
"src/views/history-view.ts",
"src/views/schedule-view.ts",