/* 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 {PluralForm} = require("devtools/shared/plural-form"); const { DOM: dom, PropTypes, createClass, createFactory } = require("devtools/client/shared/vendor/react"); const Frame = createFactory(require("devtools/client/shared/components/frame")); const PROPNAME_MAX_LENGTH = 4; // 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; const OPTIMIZATION_ITEM_TYPES = ["site", "attempts", "types", "attempt", "type", "observedtype"]; /* 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. */ const { JITOptimizations, hasSuccessfulOutcome, isSuccessfulOutcome } = require("devtools/client/performance/modules/logic/jit"); const OPTIMIZATION_FAILURE = L10N.getStr("jit.optimizationFailure"); const JIT_SAMPLES = L10N.getStr("jit.samples"); const JIT_TYPES = L10N.getStr("jit.types"); const JIT_ATTEMPTS = L10N.getStr("jit.attempts"); /* eslint-enable no-unused-vars */ const JITOptimizationsItem = createClass({ displayName: "JITOptimizationsItem", propTypes: { onViewSourceInDebugger: PropTypes.func.isRequired, frameData: PropTypes.object.isRequired, type: PropTypes.oneOf(OPTIMIZATION_ITEM_TYPES).isRequired, }, _renderSite({ item: site, onViewSourceInDebugger, frameData }) { let attempts = site.data.attempts; let lastStrategy = attempts[attempts.length - 1].strategy; let propString = ""; let propertyName = site.data.propertyName; // Display property name if it exists if (propertyName) { if (propertyName.length > PROPNAME_MAX_LENGTH) { propString = ` (.${propertyName.substr(0, PROPNAME_MAX_LENGTH)}…)`; } else { propString = ` (.${propertyName})`; } } let sampleString = PluralForm.get(site.samples, JIT_SAMPLES) .replace("#1", site.samples); let text = dom.span( { className: "optimization-site-title" }, `${lastStrategy}${propString} – (${sampleString})` ); let frame = Frame({ onClick: () => onViewSourceInDebugger(frameData.url, site.data.line), frame: { source: frameData.url, line: +site.data.line, column: site.data.column, } }); let children = [text, frame]; if (!hasSuccessfulOutcome(site)) { children.unshift(dom.span({ className: "opt-icon warning" })); } return dom.span({ className: "optimization-site" }, ...children); }, _renderAttempts({ item: attempts }) { return dom.span({ className: "optimization-attempts" }, `${JIT_ATTEMPTS} (${attempts.length})` ); }, _renderTypes({ item: types }) { return dom.span({ className: "optimization-types" }, `${JIT_TYPES} (${types.length})` ); }, _renderAttempt({ item: attempt }) { let success = isSuccessfulOutcome(attempt.outcome); let { strategy, outcome } = attempt; return dom.span({ className: "optimization-attempt" }, dom.span({ className: "optimization-strategy" }, strategy), " → ", dom.span({ className: `optimization-outcome ${success ? "success" : "failure"}` }, outcome) ); }, _renderType({ item: type }) { return dom.span({ className: "optimization-ion-type" }, `${type.site}:${type.mirType}`); }, _renderObservedType({ onViewSourceInDebugger, item: type }) { let children = [ dom.span({ className: "optimization-observed-type-keyed" }, `${type.keyedBy}${type.name ? ` → ${type.name}` : ""}`) ]; // If we have a line and location, make a link to the debugger if (type.location && type.line) { children.push( Frame({ onClick: () => onViewSourceInDebugger(type.location, type.line), frame: { source: type.location, line: type.line, column: type.column, } }) ); // Otherwise if we just have a location, it's probably just a memory location. } else if (type.location) { children.push(`@${type.location}`); } return dom.span({ className: "optimization-observed-type" }, ...children); }, render() { /* eslint-disable no-unused-vars */ /** * TODO - Re-enable this eslint rule. The JIT tool is a work in progress, and these * undefined variables may represent intended functionality. */ let { depth, arrow, type, // TODO - The following are currently unused. item, focused, frameData, onViewSourceInDebugger, } = this.props; /* eslint-enable no-unused-vars */ let content; switch (type) { case "site": content = this._renderSite(this.props); break; case "attempts": content = this._renderAttempts(this.props); break; case "types": content = this._renderTypes(this.props); break; case "attempt": content = this._renderAttempt(this.props); break; case "type": content = this._renderType(this.props); break; case "observedtype": content = this._renderObservedType(this.props); break; } return dom.div( { className: `optimization-tree-item optimization-tree-item-${type}`, style: { marginInlineStart: depth * TREE_ROW_HEIGHT } }, arrow, content ); }, }); module.exports = JITOptimizationsItem;