91ddeb062c
- Show related code object for Maps - Fix opening transition trees - Rename *LogEntry.prototype.codeLogEntry to .code - Show Arrays as dropdowns in tooltips - Avoid hiding the tooltip when clicking on the tooltip itself - Show links to code variants (bytecode/baseline/optimized) - Fix chunk offset calculation - Fix code for browsers that don't support navigator.scheduling.isInputPending Bug: v8:10644 Change-Id: I858dc410657d26d076214368814a52177b124f4c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2964592 Auto-Submit: Camillo Bruni <cbruni@chromium.org> Commit-Queue: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/master@{#75169}
182 lines
5.7 KiB
JavaScript
182 lines
5.7 KiB
JavaScript
// Copyright 2020 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 {FocusEvent, SelectRelatedEvent, ToolTipEvent} from '../events.mjs';
|
|
import {CSSColor} from '../helper.mjs';
|
|
import {DOM, V8CustomElement} from '../helper.mjs';
|
|
|
|
DOM.defineCustomElement('./view/map-panel/map-transitions',
|
|
(templateText) =>
|
|
class MapTransitions extends V8CustomElement {
|
|
_timeline;
|
|
_map;
|
|
_edgeToColor = new Map();
|
|
_selectedLogEntries;
|
|
_displayedMapsInTree;
|
|
_toggleSubtreeHandler = this._handleToggleSubtree.bind(this);
|
|
_mapClickHandler = this._handleMapClick.bind(this);
|
|
_mapDoubleClickHandler = this._handleMapDoubleClick.bind(this);
|
|
_mouseoverMapHandler = this._handleMouseoverMap.bind(this);
|
|
|
|
constructor() {
|
|
super(templateText);
|
|
this.currentNode = this.transitionView;
|
|
}
|
|
|
|
get transitionView() {
|
|
return this.$('#transitionView');
|
|
}
|
|
|
|
set timeline(timeline) {
|
|
this._timeline = timeline;
|
|
this._edgeToColor.clear();
|
|
timeline.getBreakdown().forEach(breakdown => {
|
|
this._edgeToColor.set(breakdown.key, CSSColor.at(breakdown.id));
|
|
});
|
|
}
|
|
|
|
set selectedLogEntries(list) {
|
|
this._selectedLogEntries = list;
|
|
this.requestUpdate();
|
|
}
|
|
|
|
_update() {
|
|
this.transitionView.style.display = 'none';
|
|
DOM.removeAllChildren(this.transitionView);
|
|
if (this._selectedLogEntries.length == 0) return;
|
|
this._displayedMapsInTree = new Set();
|
|
// Limit view to 200 maps for performance reasons.
|
|
this._selectedLogEntries.slice(0, 200).forEach(
|
|
(map) => this._addMapAndParentTransitions(map));
|
|
this._displayedMapsInTree = undefined;
|
|
this.transitionView.style.display = '';
|
|
}
|
|
|
|
_addMapAndParentTransitions(map) {
|
|
if (map === undefined) return;
|
|
if (this._displayedMapsInTree.has(map)) return;
|
|
this._displayedMapsInTree.add(map);
|
|
this.currentNode = this.transitionView;
|
|
let parents = map.getParents();
|
|
if (parents.length > 0) {
|
|
this._addTransitionTo(parents.pop());
|
|
parents.reverse().forEach((each) => this._addTransitionTo(each));
|
|
}
|
|
let mapNode = this._addSubtransitions(map);
|
|
// Mark and show the selected map.
|
|
mapNode.classList.add('selected');
|
|
if (this.selectedMap == map) {
|
|
setTimeout(
|
|
() => mapNode.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'nearest',
|
|
inline: 'nearest',
|
|
}),
|
|
1);
|
|
}
|
|
}
|
|
|
|
_addSubtransitions(map) {
|
|
let mapNode = this._addTransitionTo(map);
|
|
// Draw outgoing linear transition line.
|
|
let current = map;
|
|
while (current.children.length == 1) {
|
|
current = current.children[0].to;
|
|
this._addTransitionTo(current);
|
|
}
|
|
return mapNode;
|
|
}
|
|
|
|
_addTransitionEdge(map) {
|
|
let classes = ['transitionEdge'];
|
|
let edge = DOM.div(classes);
|
|
edge.style.backgroundColor = this._edgeToColor.get(map.edge.type);
|
|
let labelNode = DOM.div('transitionLabel');
|
|
labelNode.innerText = map.edge.toString();
|
|
edge.appendChild(labelNode);
|
|
return edge;
|
|
}
|
|
|
|
_addTransitionTo(map) {
|
|
// transition[ transitions[ transition[...], transition[...], ...]];
|
|
this._displayedMapsInTree?.add(map);
|
|
let transition = DOM.div('transition');
|
|
if (map.isDeprecated()) transition.classList.add('deprecated');
|
|
if (map.edge) {
|
|
transition.appendChild(this._addTransitionEdge(map));
|
|
}
|
|
let mapNode = this._addMapNode(map);
|
|
transition.appendChild(mapNode);
|
|
|
|
let subtree = DOM.div('transitions');
|
|
transition.appendChild(subtree);
|
|
|
|
this.currentNode.appendChild(transition);
|
|
this.currentNode = subtree;
|
|
|
|
return mapNode;
|
|
}
|
|
|
|
_addMapNode(map) {
|
|
let node = DOM.div('map');
|
|
if (map.edge)
|
|
node.style.backgroundColor = this._edgeToColor.get(map.edge.type);
|
|
node.map = map;
|
|
node.onclick = this._mapClickHandler
|
|
node.ondblclick = this._mapDoubleClickHandler
|
|
node.onmouseover = this._mouseoverMapHandler
|
|
if (map.children.length > 1) {
|
|
node.innerText = map.children.length;
|
|
const showSubtree = DOM.div('showSubtransitions');
|
|
showSubtree.onclick = this._toggleSubtreeHandler
|
|
node.appendChild(showSubtree);
|
|
}
|
|
else if (map.children.length == 0) {
|
|
node.innerHTML = '●';
|
|
}
|
|
this.currentNode.appendChild(node);
|
|
return node;
|
|
}
|
|
|
|
_handleMapClick(event) {
|
|
const map = event.currentTarget.map;
|
|
this.dispatchEvent(new FocusEvent(map));
|
|
}
|
|
|
|
_handleMapDoubleClick(event) {
|
|
this.dispatchEvent(new SelectRelatedEvent(event.currentTarget.map));
|
|
}
|
|
|
|
_handleMouseoverMap(event) {
|
|
this.dispatchEvent(
|
|
new ToolTipEvent(event.currentTarget.map, event.currentTarget));
|
|
}
|
|
|
|
_handleToggleSubtree(event) {
|
|
event.stopImmediatePropagation();
|
|
const node = event.currentTarget.parentElement;
|
|
const map = node.map;
|
|
event.target.classList.toggle('opened');
|
|
const transitionsNode = node.parentElement.querySelector('.transitions');
|
|
const subtransitionNodes = transitionsNode.children;
|
|
if (subtransitionNodes.length <= 1) {
|
|
// Add subtransitions except the one that's already shown.
|
|
let visibleTransitionMap = subtransitionNodes.length == 1 ?
|
|
transitionsNode.querySelector('.map').map :
|
|
undefined;
|
|
map.children.forEach((edge) => {
|
|
if (edge.to != visibleTransitionMap) {
|
|
this.currentNode = transitionsNode;
|
|
this._addSubtransitions(edge.to);
|
|
}
|
|
});
|
|
} else {
|
|
// remove all but the first (currently selected) subtransition
|
|
for (let i = subtransitionNodes.length - 1; i > 0; i--) {
|
|
transitionsNode.removeChild(subtransitionNodes[i]);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
});
|