mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 00:05:36 +00:00
5213ac90af
MozReview-Commit-ID: 80ebj9CJODR --HG-- rename : devtools/client/shared/components/Tree.js => devtools/client/shared/components/VirtualizedTree.js extra : rebase_source : 78d24d5411b2d1dadae6778ba7f05c58641b6a00
256 lines
7.9 KiB
JavaScript
256 lines
7.9 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
"use strict";
|
|
|
|
const { LocalizationHelper } = require("devtools/shared/l10n");
|
|
const STRINGS_URI = "devtools/client/locales/jit-optimizations.properties";
|
|
const L10N = new LocalizationHelper(STRINGS_URI);
|
|
|
|
const { assert } = require("devtools/shared/DevToolsUtils");
|
|
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
|
|
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
|
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
|
const Tree = createFactory(require("devtools/client/shared/components/VirtualizedTree"));
|
|
const OptimizationsItem = createFactory(require("./jit-optimizations-item"));
|
|
const FrameView = createFactory(require("../../shared/components/Frame"));
|
|
const JIT_TITLE = L10N.getStr("jit.title");
|
|
// If TREE_ROW_HEIGHT changes, be sure to change `var(--jit-tree-row-height)`
|
|
// in `devtools/client/themes/jit-optimizations.css`
|
|
const TREE_ROW_HEIGHT = 14;
|
|
|
|
/* eslint-disable no-unused-vars */
|
|
/**
|
|
* TODO - Re-enable this eslint rule. The JIT tool is a work in progress, and isn't fully
|
|
* integrated as of yet, and this may represent intended functionality.
|
|
*/
|
|
const onClickTooltipString = frame =>
|
|
L10N.getFormatStr("viewsourceindebugger",
|
|
`${frame.source}:${frame.line}:${frame.column}`);
|
|
/* eslint-enable no-unused-vars */
|
|
|
|
const optimizationAttemptModel = {
|
|
id: PropTypes.number.isRequired,
|
|
strategy: PropTypes.string.isRequired,
|
|
outcome: PropTypes.string.isRequired,
|
|
};
|
|
|
|
const optimizationObservedTypeModel = {
|
|
keyedBy: PropTypes.string.isRequired,
|
|
name: PropTypes.string,
|
|
location: PropTypes.string,
|
|
line: PropTypes.string,
|
|
};
|
|
|
|
const optimizationIonTypeModel = {
|
|
id: PropTypes.number.isRequired,
|
|
typeset: PropTypes.arrayOf(optimizationObservedTypeModel),
|
|
site: PropTypes.number.isRequired,
|
|
mirType: PropTypes.number.isRequired,
|
|
};
|
|
|
|
const optimizationSiteModel = {
|
|
id: PropTypes.number.isRequired,
|
|
propertyName: PropTypes.string,
|
|
line: PropTypes.number.isRequired,
|
|
column: PropTypes.number.isRequired,
|
|
data: PropTypes.shape({
|
|
attempts: PropTypes.arrayOf(optimizationAttemptModel).isRequired,
|
|
types: PropTypes.arrayOf(optimizationIonTypeModel).isRequired,
|
|
}).isRequired,
|
|
};
|
|
|
|
class JITOptimizations extends Component {
|
|
static get propTypes() {
|
|
return {
|
|
onViewSourceInDebugger: PropTypes.func.isRequired,
|
|
frameData: PropTypes.object.isRequired,
|
|
optimizationSites: PropTypes.arrayOf(optimizationSiteModel).isRequired,
|
|
autoExpandDepth: PropTypes.number,
|
|
};
|
|
}
|
|
|
|
static get defaultProps() {
|
|
return {
|
|
autoExpandDepth: 0
|
|
};
|
|
}
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
expanded: new Set()
|
|
};
|
|
|
|
this._createHeader = this._createHeader.bind(this);
|
|
this._createTree = this._createTree.bind(this);
|
|
}
|
|
|
|
/**
|
|
* Frame data generated from `frameNode.getInfo()`, or an empty
|
|
* object, as well as a handler for clicking on the frame component.
|
|
*
|
|
* @param {?Object} .frameData
|
|
* @param {Function} .onViewSourceInDebugger
|
|
* @return {ReactElement}
|
|
*/
|
|
_createHeader({ frameData, onViewSourceInDebugger }) {
|
|
let { isMetaCategory, url, line } = frameData;
|
|
let name = isMetaCategory ? frameData.categoryData.label :
|
|
frameData.functionName || "";
|
|
|
|
// Simulate `SavedFrame`s interface
|
|
let frame = { source: url, line: +line, functionDisplayName: name };
|
|
|
|
// Neither Meta Category nodes, or the lack of a selected frame node,
|
|
// renders out a frame source, like "file.js:123"; so just use
|
|
// an empty span.
|
|
let frameComponent;
|
|
if (isMetaCategory || !name) {
|
|
frameComponent = dom.span();
|
|
} else {
|
|
frameComponent = FrameView({
|
|
frame,
|
|
onClick: () => onViewSourceInDebugger(frame),
|
|
});
|
|
}
|
|
|
|
return dom.div({ className: "optimization-header" },
|
|
dom.span({ className: "header-title" }, JIT_TITLE),
|
|
dom.span({ className: "header-function-name" }, name),
|
|
frameComponent
|
|
);
|
|
}
|
|
|
|
_createTree(props) {
|
|
let {
|
|
autoExpandDepth,
|
|
frameData,
|
|
onViewSourceInDebugger,
|
|
optimizationSites: sites
|
|
} = this.props;
|
|
|
|
let getSite = id => sites.find(site => site.id === id);
|
|
let getIonTypeForObserved = type => {
|
|
return getSite(type.id).data.types
|
|
.find(iontype => (iontype.typeset || [])
|
|
.indexOf(type) !== -1);
|
|
};
|
|
let isSite = site => getSite(site.id) === site;
|
|
let isAttempts = attempts => getSite(attempts.id).data.attempts === attempts;
|
|
let isAttempt = attempt => getSite(attempt.id).data.attempts.indexOf(attempt) !== -1;
|
|
let isTypes = types => getSite(types.id).data.types === types;
|
|
let isType = type => getSite(type.id).data.types.indexOf(type) !== -1;
|
|
let isObservedType = type => getIonTypeForObserved(type);
|
|
|
|
let getRowType = node => {
|
|
if (isSite(node)) {
|
|
return "site";
|
|
}
|
|
if (isAttempts(node)) {
|
|
return "attempts";
|
|
}
|
|
if (isTypes(node)) {
|
|
return "types";
|
|
}
|
|
if (isAttempt(node)) {
|
|
return "attempt";
|
|
}
|
|
if (isType(node)) {
|
|
return "type";
|
|
}
|
|
if (isObservedType(node)) {
|
|
return "observedtype";
|
|
}
|
|
return null;
|
|
};
|
|
|
|
// Creates a unique key for each node in the
|
|
// optimizations data
|
|
let getKey = node => {
|
|
let site = getSite(node.id);
|
|
if (isSite(node)) {
|
|
return node.id;
|
|
} else if (isAttempts(node)) {
|
|
return `${node.id}-A`;
|
|
} else if (isTypes(node)) {
|
|
return `${node.id}-T`;
|
|
} else if (isType(node)) {
|
|
return `${node.id}-T-${site.data.types.indexOf(node)}`;
|
|
} else if (isAttempt(node)) {
|
|
return `${node.id}-A-${site.data.attempts.indexOf(node)}`;
|
|
} else if (isObservedType(node)) {
|
|
let iontype = getIonTypeForObserved(node);
|
|
return `${getKey(iontype)}-O-${iontype.typeset.indexOf(node)}`;
|
|
}
|
|
return "";
|
|
};
|
|
|
|
return Tree({
|
|
autoExpandDepth,
|
|
getParent: node => {
|
|
let site = getSite(node.id);
|
|
let parent;
|
|
if (isAttempts(node) || isTypes(node)) {
|
|
parent = site;
|
|
} else if (isType(node)) {
|
|
parent = site.data.types;
|
|
} else if (isAttempt(node)) {
|
|
parent = site.data.attempts;
|
|
} else if (isObservedType(node)) {
|
|
parent = getIonTypeForObserved(node);
|
|
}
|
|
assert(parent, "Could not find a parent for optimization data node");
|
|
|
|
return parent;
|
|
},
|
|
getChildren: node => {
|
|
if (isSite(node)) {
|
|
return [node.data.types, node.data.attempts];
|
|
} else if (isAttempts(node) || isTypes(node)) {
|
|
return node;
|
|
} else if (isType(node)) {
|
|
return node.typeset || [];
|
|
}
|
|
return [];
|
|
},
|
|
isExpanded: node => this.state.expanded.has(node),
|
|
onExpand: node => this.setState(state => {
|
|
let expanded = new Set(state.expanded);
|
|
expanded.add(node);
|
|
return { expanded };
|
|
}),
|
|
onCollapse: node => this.setState(state => {
|
|
let expanded = new Set(state.expanded);
|
|
expanded.delete(node);
|
|
return { expanded };
|
|
}),
|
|
onFocus: function () {},
|
|
getKey,
|
|
getRoots: () => sites || [],
|
|
itemHeight: TREE_ROW_HEIGHT,
|
|
renderItem: (item, depth, focused, arrow, expanded) =>
|
|
new OptimizationsItem({
|
|
onViewSourceInDebugger,
|
|
item,
|
|
depth,
|
|
focused,
|
|
arrow,
|
|
expanded,
|
|
type: getRowType(item),
|
|
frameData,
|
|
}),
|
|
});
|
|
}
|
|
|
|
render() {
|
|
let header = this._createHeader(this.props);
|
|
let tree = this._createTree(this.props);
|
|
|
|
return dom.div({}, header, tree);
|
|
}
|
|
}
|
|
|
|
module.exports = JITOptimizations;
|