summaryrefslogtreecommitdiffstats
path: root/devtools/client/memory/components/DominatorTreeItem.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/memory/components/DominatorTreeItem.js')
-rw-r--r--devtools/client/memory/components/DominatorTreeItem.js174
1 files changed, 174 insertions, 0 deletions
diff --git a/devtools/client/memory/components/DominatorTreeItem.js b/devtools/client/memory/components/DominatorTreeItem.js
new file mode 100644
index 0000000000..59cb542a3a
--- /dev/null
+++ b/devtools/client/memory/components/DominatorTreeItem.js
@@ -0,0 +1,174 @@
+/* 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 {
+ assert,
+ isSavedFrame,
+} = require("resource://devtools/shared/DevToolsUtils.js");
+const {
+ Component,
+ createFactory,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
+const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
+const {
+ L10N,
+ formatNumber,
+ formatPercent,
+} = require("resource://devtools/client/memory/utils.js");
+const Frame = createFactory(
+ require("resource://devtools/client/shared/components/Frame.js")
+);
+const {
+ TREE_ROW_HEIGHT,
+} = require("resource://devtools/client/memory/constants.js");
+
+class SeparatorClass extends Component {
+ render() {
+ return dom.span({ className: "separator" }, "›");
+ }
+}
+
+const Separator = createFactory(SeparatorClass);
+
+class DominatorTreeItem extends Component {
+ static get propTypes() {
+ return {
+ item: PropTypes.object.isRequired,
+ depth: PropTypes.number.isRequired,
+ arrow: PropTypes.object,
+ expanded: PropTypes.bool.isRequired,
+ focused: PropTypes.bool.isRequired,
+ getPercentSize: PropTypes.func.isRequired,
+ onViewSourceInDebugger: PropTypes.func.isRequired,
+ };
+ }
+
+ shouldComponentUpdate(nextProps, nextState) {
+ return (
+ this.props.item != nextProps.item ||
+ this.props.depth != nextProps.depth ||
+ this.props.expanded != nextProps.expanded ||
+ this.props.focused != nextProps.focused
+ );
+ }
+
+ render() {
+ const {
+ item,
+ depth,
+ arrow,
+ focused,
+ getPercentSize,
+ onViewSourceInDebugger,
+ } = this.props;
+
+ const retainedSize = formatNumber(item.retainedSize);
+ const percentRetainedSize = formatPercent(
+ getPercentSize(item.retainedSize)
+ );
+
+ const shallowSize = formatNumber(item.shallowSize);
+ const percentShallowSize = formatPercent(getPercentSize(item.shallowSize));
+
+ // Build up our label UI as an array of each label piece, which is either a
+ // string or a frame, and separators in between them.
+
+ assert(!!item.label.length, "Our label should not be empty");
+ const label = Array(item.label.length * 2 - 1);
+ label.fill(undefined);
+
+ for (let i = 0, length = item.label.length; i < length; i++) {
+ const piece = item.label[i];
+ const key = `${item.nodeId}-label-${i}`;
+
+ // `i` is the index of the label piece we are rendering, `label[i*2]` is
+ // where the rendered label piece belngs, and `label[i*2+1]` (if it isn't
+ // out of bounds) is where the separator belongs.
+
+ if (isSavedFrame(piece)) {
+ label[i * 2] = Frame({
+ key,
+ onClick: onViewSourceInDebugger,
+ frame: piece,
+ showFunctionName: true,
+ });
+ } else if (piece === "noStack") {
+ label[i * 2] = dom.span(
+ { key, className: "not-available" },
+ L10N.getStr("tree-item.nostack")
+ );
+ } else if (piece === "noFilename") {
+ label[i * 2] = dom.span(
+ { key, className: "not-available" },
+ L10N.getStr("tree-item.nofilename")
+ );
+ } else if (piece === "JS::ubi::RootList") {
+ // Don't use the usual labeling machinery for root lists: replace it
+ // with the "GC Roots" string.
+ label.splice(0, label.length);
+ label.push(L10N.getStr("tree-item.rootlist"));
+ break;
+ } else {
+ label[i * 2] = piece;
+ }
+
+ // If this is not the last piece of the label, add a separator.
+ if (i < length - 1) {
+ label[i * 2 + 1] = Separator({ key: `${item.nodeId}-separator-${i}` });
+ }
+ }
+
+ return dom.div(
+ {
+ className: `heap-tree-item ${focused ? "focused" : ""} node-${
+ item.nodeId
+ }`,
+ },
+
+ dom.span(
+ {
+ className: "heap-tree-item-field heap-tree-item-bytes",
+ },
+ dom.span(
+ {
+ className: "heap-tree-number",
+ },
+ retainedSize
+ ),
+ dom.span({ className: "heap-tree-percent" }, percentRetainedSize)
+ ),
+
+ dom.span(
+ {
+ className: "heap-tree-item-field heap-tree-item-bytes",
+ },
+ dom.span(
+ {
+ className: "heap-tree-number",
+ },
+ shallowSize
+ ),
+ dom.span({ className: "heap-tree-percent" }, percentShallowSize)
+ ),
+
+ dom.span(
+ {
+ className: "heap-tree-item-field heap-tree-item-name",
+ style: { marginInlineStart: depth * TREE_ROW_HEIGHT },
+ },
+ arrow,
+ label,
+ dom.span(
+ { className: "heap-tree-item-address" },
+ `@ 0x${item.nodeId.toString(16)}`
+ )
+ )
+ );
+ }
+}
+
+module.exports = DominatorTreeItem;