Backed out changeset b6571a4222fb (bug 1885054) for causing bug 1909068 CLOSED TREE

This commit is contained in:
Sandor Molnar 2024-07-22 18:24:44 +03:00
parent 7a0280d255
commit 4c9152a87a
44 changed files with 164 additions and 1893 deletions

View File

@ -46,11 +46,6 @@
type="text/css"
href="chrome://devtools/content/shared/components/tabs/Tabs.css"
/>
<link
rel="stylesheet"
type="text/css"
href="chrome://devtools/skin/components-frame.css"
/>
</head>
<body>

View File

@ -72,7 +72,6 @@ class DebuggerPanel {
constructor(iframeWindow, toolbox, commands) {
this.panelWin = iframeWindow;
this.panelWin.L10N = L10N;
this.panelWin.sourceMapURLService = toolbox.sourceMapURLService;
this.toolbox = toolbox;
this.commands = commands;
@ -368,17 +367,9 @@ class DebuggerPanel {
this._actions.selectThread(threadActorID);
}
showTracerSidebar() {
this._actions.setPrimaryPaneTab("tracer");
}
destroy() {
this.panelWin.Debugger.destroy();
this.emit("destroyed");
this.panelWin.L10N = null;
this.panelWin.sourceMapURLService = null;
this.panelWin = null;
this.commands = null;
}
}

View File

@ -36,7 +36,6 @@ import {
hasSourceActor,
hasPrettyTab,
isSourceActorWithSourceMap,
getSourceByActorId,
} from "../../selectors/index";
// This is only used by jest tests (and within this module)
@ -89,24 +88,6 @@ export function selectSourceURL(url, options) {
};
}
export function selectSourceBySourceActorID(sourceActorId, options) {
return async thunkArgs => {
const { dispatch, getState } = thunkArgs;
const source = getSourceByActorId(getState(), sourceActorId);
if (!source) {
throw new Error(`Unable to find source actor with id ${sourceActorId}`);
}
const generatedLocation = createLocation({ ...options, source });
const originalLocation = await getOriginalLocation(
generatedLocation,
thunkArgs
);
return dispatch(selectLocation(originalLocation));
};
}
/**
* Wrapper around selectLocation, which creates the location object for us.
* Note that it ignores the currently selected source and will select

View File

@ -2,68 +2,15 @@
* 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/>. */
import {
getAllTraces,
getTraceFrames,
getIsCurrentlyTracing,
} from "../selectors/index";
import { selectSourceBySourceActorID } from "./sources/select.js";
const {
TRACER_FIELDS_INDEXES,
} = require("resource://devtools/server/actors/tracer.js");
/**
* Called when tracing is toggled ON/OFF on a particular thread.
*/
export function tracingToggled(thread, enabled) {
return {
type: "TRACING_TOGGLED",
thread,
enabled,
};
}
export function clearTracerData() {
return {
type: "TRACING_CLEAR",
};
}
export function addTraces(traces) {
return async function ({ dispatch, getState }) {
if (!getIsCurrentlyTracing(getState())) {
return null;
}
return dispatch({
type: "ADD_TRACES",
traces,
});
};
}
export function selectTrace(traceIndex) {
return async function ({ dispatch, getState }) {
return ({ dispatch }) => {
dispatch({
type: "SELECT_TRACE",
traceIndex,
type: "TRACING_TOGGLED",
thread,
enabled,
});
const traces = getAllTraces(getState());
const trace = traces[traceIndex];
// Ignore DOM Event traces, which aren't related to a particular location in source.
if (!trace || trace[TRACER_FIELDS_INDEXES.TYPE] == "event") {
return;
}
const frameIndex = trace[TRACER_FIELDS_INDEXES.FRAME_INDEX];
const frames = getTraceFrames(getState());
const frame = frames[frameIndex];
await dispatch(
selectSourceBySourceActorID(frame.sourceId, {
line: frame.line,
column: frame.column,
})
);
};
}

View File

@ -8,9 +8,6 @@ import { features } from "../utils/prefs";
import { recordEvent } from "../utils/telemetry";
import sourceQueue from "../utils/source-queue";
const {
TRACER_LOG_METHODS,
} = require("resource://devtools/shared/specs/tracer.js");
let actions;
let commands;
@ -75,6 +72,10 @@ export async function onConnect(_commands, _resourceCommand, _actions, store) {
await resourceCommand.watchResources([resourceCommand.TYPES.THREAD_STATE], {
onAvailable: onThreadStateAvailable,
});
await resourceCommand.watchResources([resourceCommand.TYPES.JSTRACER_STATE], {
onAvailable: onTracingStateAvailable,
});
await resourceCommand.watchResources([resourceCommand.TYPES.ERROR_MESSAGE], {
onAvailable: actions.addExceptionFromResources,
});
@ -83,17 +84,6 @@ export async function onConnect(_commands, _resourceCommand, _actions, store) {
// we only care about future events for DOCUMENT_EVENT
ignoreExistingResources: true,
});
await resourceCommand.watchResources([resourceCommand.TYPES.JSTRACER_STATE], {
onAvailable: onTracingStateAvailable,
});
await resourceCommand.watchResources([resourceCommand.TYPES.JSTRACER_TRACE], {
onAvailable: actions.addTraces,
});
// Also register a toggle listener, in addition to JSTRACER_TRACE in order
// to be able to clear the tracer data on tracing start, that, even if the
// tracer is waiting for next interation/load.
commands.tracerCommand.on("toggle", onTracingToggled);
}
export function onDisconnect() {
@ -117,13 +107,6 @@ export function onDisconnect() {
resourceCommand.unwatchResources([resourceCommand.TYPES.DOCUMENT_EVENT], {
onAvailable: onDocumentEventAvailable,
});
resourceCommand.unwatchResources([resourceCommand.TYPES.JSTRACER_STATE], {
onAvailable: onTracingStateAvailable,
});
resourceCommand.unwatchResources([resourceCommand.TYPES.JSTRACER_TRACE], {
onAvailable: actions.addTraces,
});
commands.tracerCommand.off("toggle", onTracingToggled);
sourceQueue.clear();
}
@ -192,29 +175,11 @@ async function onTracingStateAvailable(resources) {
if (resource.targetFront.isDestroyed()) {
continue;
}
// Ignore if the tracer is logging to any other output
if (resource.logMethod != TRACER_LOG_METHODS.DEBUGGER_SIDEBAR) {
continue;
}
// For now, only consider the top level target
if (!resource.targetFront.isTopLevel) {
continue;
}
const threadFront = await resource.targetFront.getFront("thread");
await actions.tracingToggled(threadFront.actor, resource.enabled);
}
}
async function onTracingToggled() {
const { tracerCommand } = commands;
if (!tracerCommand.isTracingEnabled) {
return;
}
// We only notify about global enabling of the tracer in order to clear data
await actions.clearTracerData();
}
function onDocumentEventAvailable(events) {
for (const event of events) {
// Only consider top level document, and ignore remote iframes top document

View File

@ -1,334 +0,0 @@
/* 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/>. */
/**
* Store variable on the root element, as it may be used by HTMLTooltip elements,
* which are added outside of .tracer-container.
*/
:root {
--tracer-event-color: var(--grey-50);
--tracer-mouse-event-color: var(--green-60);
--tracer-key-event-color: var(--teal-60);
--tracer-mutation-color: var(--purple-30);
--tracer-mutation-darker-color: oklch(from var(--tracer-mutation-color) calc(l * 0.6) c h);
--slider-bar-background: var(--blue-55);
}
.tracer-container {
height: 100%;
max-height: 100%;
display: grid;
grid-template-areas: "toolbar toolbar"
"timeline-toolbar timeline-toolbar"
"timeline tree";
grid-template-columns: auto 1fr;
grid-template-rows: auto auto 1fr;
& > .tracer-toolbar {
grid-area: toolbar;
}
& > .tracer-timeline-toolbar {
grid-area: timeline-toolbar;
}
& > .tracer-timeline {
grid-area: timeline;
}
& > :is(.tracer-message, .tree) {
grid-area: tree;
}
}
.tracer-toolbar .tracer-experimental-notice {
--icon-size: 16px;
--icon-inline-padding: 4px;
background-color: var(--theme-body-alternate-emphasized-background);
border-block-end: 1px solid var(--theme-splitter-color);
padding: 1em;
padding-inline-start: calc(var(--icon-inline-padding) * 2 + var(--icon-size));
background-image: url("chrome://global/skin/icons/experiments.svg");
background-position-x: var(--icon-inline-padding);
background-position-y: 50%;
background-repeat: no-repeat;
background-size: var(--icon-size);
-moz-context-properties: fill;
fill: var(--theme-icon-checked-color);
}
.tracer-tab .tracer-message {
display: flex;
justify-content: center;
align-items: center;
font-style: italic;
text-align: center;
padding: 0.5em;
font-size: 12px;
user-select: none;
}
.tracer-tab .tree {
overflow-x: auto;
overflow-y: auto;
border-inline-start: 1px solid var(--theme-splitter-color);
padding-inline-start: 4px !important;
}
.tracer-tab .tree-node {
/* This matches `itemHeight` set on VirtualizedTree component */
height: var(--tree-node-height);
line-height: var(--tree-node-height);
text-wrap: nowrap;
margin-inline-start: calc(5px * var(--tree-node-depth));
/* make the tree node at least as wide as its content so the hover style isn't weird */
width: min-content;
min-width: 100%;
}
.tracer-tab .tree-node .trace-line {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
}
.tracer-tab .frame-link {
display: flex;
width: 100%;
padding: 0 10px;
gap: 10px;
}
/* Force the smart trace link to be light color when the focused style make the background blue */
.tracer-tab .tree-node.focused .frame-link-source {
color: var(--theme-selection-color);
}
.tracer-tab .frame-link.match, .tracer-tab .frame-link.match .frame-link-source {
background: var(--theme-contrast-background);
color: var(--theme-contrast-color);
}
.tracer-tab .tree-node:has(.frame-link.onstack) {
background-color: light-dark(lightblue, var(--theme-body-alternate-emphasized-background));
}
.tracer-tab .frame-link-source {
max-width:200px;
overflow: hidden;
text-overflow: ellipsis;
text-wrap: nowrap;
color: var(--theme-internal-link-color);
}
.tracer-tab .frame-link-function-display-name {
flex: 1;
text-overflow: ellipsis;
overflow: hidden;
text-wrap: nowrap;
font-family: var(--monospace-font-family);
}
.tracer-dom-event, .tracer-dom-mutation {
padding-inline: 4px;
margin-inline: 5px;
&.mouse {
--event-color: var(--tracer-mouse-event-color);
}
&.key {
--event-color: var(--tracer-key-event-color);
}
&.tracer-dom-mutation {
--event-color: var(--tracer-mutation-color);
}
&::before {
content: "";
height: 8px;
aspect-ratio: 1 / 1;
margin-inline-end: 4px;
background-color: var(--event-color, var(--tracer-event-color));
display: inline-block;
vertical-align: baseline;
outline: 1px solid;
}
}
.tracer-timeline {
width: 50px;
padding-inline: 2px 4px;
display: flex;
flex-direction: column;
background-color: var(--theme-body-alternate-emphasized-background);
&.hidden {
display: none;
}
}
.tracer-timeline-toolbar {
border-bottom: 1px solid var(--theme-splitter-color);
.tracer-reset-zoom {
padding: 0.5em 2em;
margin-inline: auto;
display: block;
}
}
.tracer-slider-box {
flex: 1;
position: relative;
}
/**
* .selected-before and .selected-after are little blue arrows shown
* on top and bottom of the slider to indicate when the selected trace
* is outside of the current viewport.
*/
.tracer-slider-box.selected-before .tracer-slice-slider::before,
.tracer-slider-box.selected-after .tracer-slice-slider::after {
content: "";
position: absolute;
width: 10px;
height: 10px;
left: 0;
z-index: 10;
background-image: url("chrome://devtools/skin/images/arrow.svg");
background-position: top center;
background-repeat: no-repeat;
background-size: 10px;
-moz-context-properties: fill;
}
.tracer-slider-box.selected-before .tracer-slice-slider::before {
top: 0;
transform: rotate(180deg);
fill: var(--slider-bar-background);
}
.tracer-slider-box.selected-after .tracer-slice-slider::after {
bottom: 0;
left: -2px;
fill: white;
}
.tracer-slider-box:is(.cut-start, .cut-end) {
--shadow-size: 10px;
--shadow-color: rgb(0 0 0 / 0.3);
}
.tracer-slider-box.cut-start::before {
content: "";
height: var(--shadow-size);
position: absolute;
top: 0;
left: 0;
right: 0;
background: linear-gradient(to bottom, var(--shadow-color), transparent);
}
.tracer-slider-box.cut-end::after {
content: "";
height: var(--shadow-size);
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(to top, var(--shadow-color), transparent);
}
.tracer-slice-slider {
position: absolute;
cursor: pointer;
height: 100%;
width: 100%;
/* ignore overflows of mutations icons going over limits on top or bottom */
overflow: hidden;
}
.tracer-slider-bar {
width: 8px;
height: 100%;
background: linear-gradient(
var(--slider-bar-background) var(--slider-bar-progress, 0%),
transparent var(--slider-bar-progress, 0%)
);
background-color: var(--theme-body-background);
border: 1px solid var(--theme-splitter-color);
position: absolute;
z-index: 5;
}
.tracer-slider-position {
position: absolute;
top: var(--slider-bar-progress);
z-index: 15;
width: 100%;
height: 3px;
background-color: var(--slider-bar-background);
border-inline-start: 1px solid var(--theme-splitter-color);
}
.tracer-slider-event, .tracer-slider-mutation {
position: absolute;
width: 3px;
left: 12px;
z-index: 8;
}
.tracer-slider-event {
background-color: var(--tracer-event-color);
--top-line-height: 2px;
--left-line-width: 10px;
clip-path: polygon(0% 0%, 100% 0%, 100% var(--top-line-height), var(--left-line-width) var(--top-line-height), var(--left-line-width) 100%, 0px 100%);
width: 30px;
&.mouse {
background-color: var(--tracer-mouse-event-color);
}
&.key {
background-color: var(--tracer-key-event-color);
}
&:hover {
background-color: var(--blue-30);
}
}
.tracer-slider-mutation {
position: absolute;
aspect-ratio: 1 / 1;
width: 18px;
align-content: center;
text-align: center;
border: 1px solid var(--tracer-mutation-darker-color);
/**
* Move the element at its middle of its coordinate so that the JS code
* defining its coordinate doesn't have to care about its size
*/
transform: translateX(6px) translateY(-50%);
font-size: 12px;
font-weight: bold;
border-radius: 50%;
}
.tracer-slider-mutation, .tracer-slider-mutation div {
background-color: var(--tracer-mutation-color);
color: var(--tracer-mutation-darker-color);
font-size: 12px;
font-weight: bold;
}
.event-tooltip .tooltip-panel {
padding: 10px;
hr {
border: none;
border-block-end: 1px solid var(--theme-splitter-color);
}
}

View File

@ -1,823 +0,0 @@
/* 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/>. */
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
import React, {
Component,
createFactory,
} from "devtools/client/shared/vendor/react";
import { div, button } from "devtools/client/shared/vendor/react-dom-factories";
import SearchInput from "../shared/SearchInput";
import { connect } from "devtools/client/shared/vendor/react-redux";
import {
getSelectedTraceIndex,
getTopTraces,
getAllTraces,
getTraceChildren,
getTraceParents,
getTraceFrames,
getAllMutationTraces,
getAllTraceCount,
getIsCurrentlyTracing,
} from "../../selectors/index";
const VirtualizedTree = require("resource://devtools/client/shared/components/VirtualizedTree.js");
const FrameView = createFactory(
require("resource://devtools/client/shared/components/Frame.js")
);
const {
TRACER_FIELDS_INDEXES,
} = require("resource://devtools/server/actors/tracer.js");
const {
HTMLTooltip,
} = require("resource://devtools/client/shared/widgets/tooltip/HTMLTooltip.js");
import actions from "../../actions/index";
const isMacOS = AppConstants.platform == "macosx";
const TREE_NODE_HEIGHT = 20;
const DEBUG = false;
export class Tracer extends Component {
constructor(props) {
super(props);
this.state = {
// List of expanded traces in the tree
expanded: new Set(),
// First visible trace's index.
// Note that these two indexes aren't related to the VirtualizedTree viewport.
// That's the possibly visible traces when scrolling top/bottom of the whole Tree.
startIndex: 0,
// Last visible trace's index. -1 is we should show all of them at the end.
// As soon as we start scrolling via the left slider, new traces are added outside of the selected viewport.
endIndex: -1,
// Number of trace rendered in the timeline and the tree (considering the tree is expanded, less may be displayed based on collapsing)
renderedTraceCount: 0,
};
this.onSliderClick = this.onSliderClick.bind(this);
this.onSliderWheel = this.onSliderWheel.bind(this);
this.resetZoom = this.resetZoom.bind(this);
}
UNSAFE_componentWillReceiveProps(nextProps) {
const { traceParents } = this.props;
if (
nextProps.selectedTraceIndex != this.props.selectedTraceIndex &&
nextProps.selectedTraceIndex != null
) {
const { expanded } = this.state;
let index = traceParents[nextProps.selectedTraceIndex];
while (index) {
expanded.add(index);
index = traceParents[index];
}
this.setState({ expanded });
}
// Force update the renderedTraceCount when we receive new traces
if (nextProps.traceCount != this.props.traceCount) {
if (nextProps.traceCount == 0) {
// Reset the indexes when the view is cleared (i.e. when we just started recording a new trace)
this.updateIndexes(
{
startIndex: 0,
endIndex: -1,
},
nextProps
);
} else {
this.updateIndexes(
{
startIndex: this.state.startIndex,
endIndex: this.state.endIndex,
},
nextProps
);
}
}
}
componentDidMount() {
// Prevent toolbox zooming when using Ctrl+Wheel on the slider.
// (for some reason... React doesn't seem to register the right "wheel", event listener via `onWheel`,
// which is the one to cancel to prevent toolbox zooming code to work.)
this.refs.timeline.onwheel = e => e.preventDefault();
if (!this.tooltip) {
this.instantiateTooltip();
}
}
instantiateTooltip() {
this.tooltip = new HTMLTooltip(this.refs.timeline.ownerDocument, {
className: "event-tooltip",
type: "arrow",
// Avoid consuming the first click on the anchored UI element in the slider
consumeOutsideClicks: false,
});
this.tooltip.setContentSize({ height: "auto" });
this.tooltip.startTogglingOnHover(this.refs.timeline, (target, tooltip) => {
if (target.classList.contains("tracer-slider-event")) {
const { traceIndex } = target.dataset;
const trace = this.props.allTraces[traceIndex];
const eventName = trace[TRACER_FIELDS_INDEXES.EVENT_NAME];
const eventType = getEventClassNameFromTraceEventName(eventName);
tooltip.panel.innerHTML = "";
const el = document.createElement("div");
el.classList.add("tracer-dom-event", eventType);
el.textContent = eventName;
tooltip.panel.append(
el,
document.createElement("hr"),
document.createTextNode(
"Double click to focus on the executions related to this event."
)
);
return true;
} else if (target.classList.contains("tracer-slider-mutation")) {
const { traceIndex } = target.dataset;
const trace = this.props.allTraces[traceIndex];
const mutationType = trace[TRACER_FIELDS_INDEXES.DOM_MUTATION_TYPE];
tooltip.panel.innerHTML = "";
const el = document.createElement("div");
el.classList.add("tracer-dom-mutation");
el.textContent = `DOM Mutation | ${mutationType}`;
tooltip.panel.append(
el,
document.createElement("hr"),
document.createTextNode(
"Click to find the call tree leading to this mutation."
)
);
return true;
}
return false;
});
}
componentDidUpdate() {
if (DEBUG) {
dump(
` # start: ${this.state.startIndex} end: ${this.state.endIndex} rendered: ${this.state.renderedTraceCount} traceCount:${this.props.traceCount}\n`
);
}
}
renderTree() {
let {
selectedTraceIndex,
topTraces,
allTraces,
traceChildren,
traceParents,
} = this.props;
if (!topTraces.length) {
if (!this.props.isTracing) {
return div(
{ className: "tracer-message" },
"Tracer is off, or pending for next interation/load."
);
}
return div(
{ className: "tracer-message" },
"Waiting for the first JavaScript executions"
);
}
const { searchStrings, startIndex, endIndex } = this.state;
if (startIndex != 0 || endIndex != -1) {
// When we start zooming, only consider traces whose top level frame
// is in the zoomed section.
// Lookup for the first top trace after the start index
let topTracesStartIndex = 0;
if (startIndex != 0) {
for (let i = 0; i < topTraces.length; i++) {
const traceIndex = topTraces[i];
if (traceIndex >= startIndex) {
topTracesStartIndex = i;
break;
}
}
}
// Lookup for the first top trace from the end before the end index
let topTracesEndIndex = topTraces.length;
if (endIndex != -1) {
for (let i = topTraces.length; i >= 0; i--) {
const traceIndex = topTraces[i];
if (traceIndex <= endIndex) {
topTracesEndIndex = i + 1;
break;
}
}
}
topTraces = topTraces.slice(topTracesStartIndex, topTracesEndIndex);
// When the top trace isn't the top most one (`!0`) and isn't a top trace (`!topTraces[0]`),
// We need to add the current start trace as a top trace, as well as all its following siblings
// and the following siblings of parent traces recursively.
// This help show partial call tree when scrolling/zooming with a partial view on a call stack.
//
// Note that for endIndex, the cut is being done in VirtualizedTree's getChildren function.
if (startIndex != 0 && topTraces[0] != startIndex) {
const results = [];
// indexes are floating number, so convert it to a decimal number as index in the trace array
results.push(Math.floor(startIndex));
collectAllSiblings(traceParents, traceChildren, startIndex, results);
topTraces.unshift(...results);
}
}
if (searchStrings) {
topTraces = topTraces.filter(traceIndex => {
const trace = allTraces[traceIndex];
if (trace[TRACER_FIELDS_INDEXES.TYPE] != "event") {
return false;
}
let label = trace[TRACER_FIELDS_INDEXES.EVENT_NAME];
if (!label) {
return false;
}
label = label.toLowerCase();
return searchStrings.some(search => label.includes(search));
});
if (!topTraces.length) {
return div(
{ className: "tracer-message" },
"No trace matches for the current search"
);
}
}
return React.createElement(VirtualizedTree, {
itemHeight: TREE_NODE_HEIGHT,
autoExpandDepth: 1,
getRoots() {
return topTraces;
},
getKey(traceIndex) {
return `${traceIndex}`;
},
getParent(traceIndex) {
return traceParents[traceIndex];
},
getChildren(traceIndex) {
// When we aren't displaying all children up to the end of the record,
// we may need to remove children that are outside of the viewport.
if (endIndex != -1) {
return traceChildren[traceIndex].filter(index => {
return index <= endIndex;
});
}
return traceChildren[traceIndex];
},
isExpanded: traceIndex => {
return this.state.expanded.has(traceIndex);
},
onExpand: traceIndex => {
const { expanded } = this.state;
expanded.add(traceIndex);
this.setState({ expanded });
},
onCollapse: traceIndex => {
const { expanded } = this.state;
expanded.delete(traceIndex);
this.setState({ expanded });
},
focused: selectedTraceIndex,
onFocus: traceIndex => {
this.props.selectTrace(traceIndex);
},
shown: selectedTraceIndex,
renderItem: (traceIndex, _depth, isFocused, arrow, _isExpanded) => {
const trace = allTraces[traceIndex];
const type = trace[TRACER_FIELDS_INDEXES.TYPE];
if (type == "event") {
// Trace for DOM Events are always top level trace (and do not need margin/indent)
const eventName = trace[TRACER_FIELDS_INDEXES.EVENT_NAME];
const eventType = getEventClassNameFromTraceEventName(eventName);
return div(
{
className: "trace-line",
},
arrow,
div(
{
className: `tracer-dom-event ${eventType}${
selectedTraceIndex == traceIndex ? " selected" : ""
}`,
onDoubleClick: () => {
this.focusOnTrace(traceIndex);
},
},
eventName
)
);
}
if (type == "dom-mutation") {
// Trace for DOM Mutations are always a leaf and don't have children.
const mutationType = trace[TRACER_FIELDS_INDEXES.DOM_MUTATION_TYPE];
return div(
{
className: `tracer-dom-mutation${
selectedTraceIndex == trace ? " selected" : ""
}`,
},
`DOM Mutation | ${mutationType}`
);
}
if (type == "exit") {
return null;
}
let className = "";
if (selectedTraceIndex) {
let idx = selectedTraceIndex;
let onStack = false;
while ((idx = traceParents[idx])) {
if (idx == traceIndex) {
onStack = true;
break;
}
}
if (onStack) {
className += " onstack";
}
}
const frameIndex = trace[TRACER_FIELDS_INDEXES.FRAME_INDEX];
const frame = this.props.frames[frameIndex];
return div(
{
className: "trace-line",
onDoubleClick: () => {
this.focusOnTrace(traceIndex);
},
},
arrow,
FrameView({
className,
showFunctionName: true,
showAnonymousFunctionName: true,
frame,
sourceMapURLService: window.sourceMapURLService,
})
);
},
});
}
onSliderClick(event) {
const { top, height } = this.refs.sliceSlider.getBoundingClientRect();
const yInSlider = event.clientY - top;
const mousePositionRatio = yInSlider / height;
const index =
this.state.startIndex +
Math.floor(mousePositionRatio * this.state.renderedTraceCount);
this.props.selectTrace(index);
}
searchInputOnChange = e => {
// Support multiple search strings being comma separated,
// ignore any extra white space and do a case insensitive search,
// ignore empty search strings,
const searchStrings = e.target.value
.split(",")
.map(search => search.trim().toLowerCase())
.filter(search => !!search.length);
if (searchStrings.length) {
this.setState({
searchStrings,
});
} else {
this.setState({
searchStrings: null,
});
}
};
renderSearchInput() {
return React.createElement(SearchInput, {
query: this.state.query,
count: 0,
placeholder: "Search DOM Events (comma separated list)",
size: "small",
showErrorEmoji: false,
isLoading: false,
onChange: this.searchInputOnChange,
onKeyDown: () => {},
showClose: false,
showExcludePatterns: false,
showSearchModifiers: false,
searchOptions: {},
});
}
onSliderWheel(event) {
const direction = event.deltaY > 0 ? 1 : -1;
const scrolledDelta = Math.abs(event.deltaY) * 0.01;
let { startIndex, endIndex } = this.state;
if (isMacOS ? event.metaKey : event.ctrlKey) {
// Handle zooming it/out as we are either using CtrlOrMeta+Wheel or zooming via the touchpad
// Compute the ratio (a percentage) of the position where the mouse or touch started zooming from
const { top, height } = this.refs.sliceSlider.getBoundingClientRect();
const yInSlider = event.clientY - top;
const zoomOriginRatio = yInSlider / height;
// Compute the number of indexes we should add or remove to both indexes
const shift = Math.floor(
Math.max(this.state.renderedTraceCount * scrolledDelta, 2) * direction
);
// Use the origin ratio in order to try to zoom where the cursor is
// and distribute the shift between start and end according to its position.
startIndex -= shift * zoomOriginRatio;
if (endIndex == -1) {
endIndex = this.props.traceCount + shift * (1 - zoomOriginRatio);
} else {
endIndex += shift * (1 - zoomOriginRatio);
}
} else {
// Handle scrolling up/down as We are doing a simple scroll via wheel or touchpad
// Avoid scrolling if we already at top or bottomn
if (
(direction < 0 && startIndex == 0) ||
(direction > 0 && endIndex == -1)
) {
return;
}
// Compute the number of indexes we should add or remove to both indexes
const shift =
Math.max(1, this.state.renderedTraceCount * scrolledDelta) * direction;
startIndex += shift;
if (endIndex == -1) {
endIndex = this.props.traceCount + shift;
} else {
endIndex += shift;
}
}
// Normalize the computed indexes.
// start can't be lower than zero
startIndex = Math.max(0, startIndex);
if (endIndex != -1) {
// end can't be lower than start + 1
endIndex = Math.max(startIndex + 1, endIndex);
// end also can't be higher than the total number of traces
if (endIndex >= this.props.traceCount) {
// -1 means, there is no end filtering
endIndex = -1;
}
}
this.updateIndexes({
startIndex,
endIndex,
});
}
updateIndexes({ startIndex, endIndex }, nextProps = this.props) {
const renderedTraceCount =
(endIndex == -1 ? nextProps.traceCount : endIndex) - startIndex;
this.setState({
startIndex,
endIndex,
renderedTraceCount,
});
if (this.tooltip) {
this.tooltip.hide();
}
}
focusOnTrace(traceIndex) {
const lastTraceIndex = findLastTraceIndex(
this.props.traceChildren,
traceIndex
);
this.updateIndexes({
startIndex: traceIndex,
endIndex: lastTraceIndex,
});
}
resetZoom() {
this.updateIndexes({
startIndex: 0,
endIndex: -1,
});
}
tracePositionInPercent(traceIndex) {
return Math.round(
((traceIndex - this.state.startIndex) / this.state.renderedTraceCount) *
100
);
}
renderMutationsInSlider() {
const { mutationTraces, allTraces } = this.props;
const { startIndex, endIndex } = this.state;
const displayedMutationTraces = [];
for (const traceIndex of mutationTraces) {
if (
traceIndex >= startIndex &&
(endIndex == -1 || traceIndex <= endIndex)
) {
displayedMutationTraces.push(traceIndex);
}
}
return displayedMutationTraces.map(traceIndex => {
const symbol = {
add: "+",
attributes: "=",
remove: "-",
};
const trace = allTraces[traceIndex];
const mutationType = trace[TRACER_FIELDS_INDEXES.DOM_MUTATION_TYPE];
return div(
{
className: `tracer-slider-mutation`,
"data-trace-index": traceIndex,
style: {
top: `${this.tracePositionInPercent(traceIndex)}%`,
},
onClick: event => {
event.preventDefault();
event.stopPropagation();
this.props.selectTrace(traceIndex);
},
},
symbol[mutationType]
);
});
}
renderEventsInSlider() {
const { topTraces, allTraces, traceChildren } = this.props;
const { startIndex, endIndex } = this.state;
const displayedTraceEvents = [];
for (const traceIndex of topTraces) {
// Match the last event index in order to allow showing partial event
// which may not be complete at the beginning of the record when we are zoomed.
const lastTraceIndex = findLastTraceIndex(traceChildren, traceIndex);
if (
lastTraceIndex >= startIndex &&
(endIndex == -1 || traceIndex <= endIndex)
) {
displayedTraceEvents.push(traceIndex);
}
}
return displayedTraceEvents.map(traceIndex => {
const eventPositionInPercent = this.tracePositionInPercent(traceIndex);
const lastTraceIndex = findLastTraceIndex(traceChildren, traceIndex);
const eventHeightInPercent = Math.round(
((lastTraceIndex - traceIndex) / this.state.renderedTraceCount) * 100
);
const trace = allTraces[traceIndex];
if (trace[TRACER_FIELDS_INDEXES.TYPE] != "event") {
return null;
}
const eventName = trace[TRACER_FIELDS_INDEXES.EVENT_NAME];
const eventType = getEventClassNameFromTraceEventName(eventName);
return div({
className: `tracer-slider-event ${eventType}`,
"data-trace-index": traceIndex,
style: {
top: `${eventPositionInPercent}%`,
height: `${Math.max(
Math.min(eventHeightInPercent, 100 - eventPositionInPercent),
1
)}%`,
},
onClick: event => {
event.preventDefault();
event.stopPropagation();
this.props.selectTrace(traceIndex);
},
onDoubleClick: () => {
this.focusOnTrace(traceIndex);
},
});
});
}
renderVerticalSliders() {
if (!this.props.traceCount) {
// Always return the top element so that componentDidMount can register its wheel listener
return div({
className: "tracer-timeline hidden",
ref: "timeline",
onWheel: this.onSliderWheel,
});
}
const { selectedTraceIndex } = this.props;
const { startIndex, endIndex } = this.state;
let selectedHighlightHeight;
if (selectedTraceIndex > startIndex + this.state.renderedTraceCount) {
selectedHighlightHeight = 100;
} else if (selectedTraceIndex < startIndex) {
selectedHighlightHeight = 0;
} else {
selectedHighlightHeight = this.tracePositionInPercent(selectedTraceIndex);
}
const classnames = [];
if (startIndex > 0) {
classnames.push("cut-start");
}
if (endIndex != -1) {
classnames.push("cut-end");
}
if (selectedTraceIndex) {
if (selectedTraceIndex < startIndex) {
classnames.push("selected-before");
} else if (endIndex != -1 && selectedTraceIndex > endIndex) {
classnames.push("selected-after");
}
}
return div(
{
className: "tracer-timeline",
ref: "timeline",
onWheel: this.onSliderWheel,
},
div(
{
className: `tracer-slider-box ${classnames.join(" ")}`,
},
div(
{
className: "tracer-slice-slider ",
ref: "sliceSlider",
onClick: this.onSliderClick,
style: {
"--slider-bar-progress": `${selectedHighlightHeight}%`,
},
},
selectedTraceIndex
? div({
className: "tracer-slider-bar",
})
: null,
selectedTraceIndex &&
selectedTraceIndex >= startIndex &&
selectedTraceIndex <= startIndex + this.state.renderedTraceCount
? div({
className: "tracer-slider-position",
})
: null,
this.renderEventsInSlider(),
this.renderMutationsInSlider()
)
)
);
}
render() {
const isZoomed = this.state.renderedTraceCount != this.props.traceCount;
return div(
{
className: "tracer-container",
style: {
"--tree-node-height": `${TREE_NODE_HEIGHT}px`,
},
},
div(
{ className: "tracer-toolbar" },
this.props.traceCount == 0
? div(
{
className: "tracer-experimental-notice",
},
"This panel is experimental. It may change, regress, be dropped or replaced."
)
: null,
this.renderSearchInput()
),
isZoomed
? div(
{
className: "tracer-timeline-toolbar",
},
button(
{
className: "tracer-reset-zoom",
onClick: this.resetZoom,
},
"Reset zoom"
)
)
: null,
this.renderVerticalSliders(),
this.renderTree()
);
}
}
/**
* Walk through the call tree to find the very last children frame
* and return its trace index.
*
* @param {Object} traceChildren
* The reducer data containing children trace indexes for all the traces.
* @param {Number} traceIndex
*/
function findLastTraceIndex(traceChildren, traceIndex) {
const children = traceChildren[traceIndex];
if (!children.length) {
return traceIndex;
}
return findLastTraceIndex(traceChildren, children.at(-1));
}
/**
* Store in the `results` attribute all following siblings for a given trace,
* as well as for its parents, that, recursively up to the top traces.
*
* @param {Object} traceParents
* The reducer data containing parent trace index for all the traces.
* @param {Object} traceChildren
* The reducer data containing children trace indexes for all the traces.
* @param {Number} traceIndex
* @param {Array} results
*/
function collectAllSiblings(traceParents, traceChildren, traceIndex, results) {
const parentIndex = traceParents[traceIndex];
if (parentIndex != null) {
const parentChildren = traceChildren[parentIndex];
const indexInItsParent = parentChildren.indexOf(traceIndex);
const siblingTraces = parentChildren.slice(indexInItsParent + 1);
if (siblingTraces.length) {
results.push(...siblingTraces);
}
collectAllSiblings(traceParents, traceChildren, parentIndex, results);
}
}
/**
* Given the TRACER_FIELDS_INDEXES.EVENT_NAME field of a trace,
* return the classname to use for a given event trace.
*
* @param {String} eventName
*/
function getEventClassNameFromTraceEventName(eventName) {
let eventType = "other";
// `eventName` looks like this: `DOM | ${domEventName}`
// Use a space before each event name in order to be sure to match the beginning
// of the dom event name.
if (eventName.includes(" mouse") || eventName.includes(" click")) {
eventType = "mouse";
} else if (eventName.includes(" key")) {
eventType = "key";
}
return eventType;
}
const mapStateToProps = state => {
return {
isTracing: getIsCurrentlyTracing(state),
topTraces: getTopTraces(state),
allTraces: getAllTraces(state),
traceChildren: getTraceChildren(state),
traceParents: getTraceParents(state),
frames: getTraceFrames(state),
mutationTraces: getAllMutationTraces(state),
traceCount: getAllTraceCount(state),
selectedTraceIndex: getSelectedTraceIndex(state),
};
};
export default connect(mapStateToProps, {
selectTrace: actions.selectTrace,
})(Tracer);

View File

@ -7,30 +7,24 @@ import PropTypes from "devtools/client/shared/vendor/react-prop-types";
import actions from "../../actions/index";
import { getSelectedPrimaryPaneTab } from "../../selectors/index";
import { prefs, features } from "../../utils/prefs";
import { prefs } from "../../utils/prefs";
import { connect } from "devtools/client/shared/vendor/react-redux";
import { primaryPaneTabs } from "../../constants";
import Outline from "./Outline";
import SourcesTree from "./SourcesTree";
import ProjectSearch from "./ProjectSearch";
import Tracer from "./Tracer";
const AppErrorBoundary = require("resource://devtools/client/shared/components/AppErrorBoundary.js");
const {
TabPanel,
Tabs,
} = require("resource://devtools/client/shared/components/tabs/Tabs.js");
// Note that the following list should follow the same order as displayed
const tabs = [
primaryPaneTabs.SOURCES,
primaryPaneTabs.OUTLINE,
primaryPaneTabs.PROJECT_SEARCH,
];
if (features.javascriptTracing) {
tabs.push(primaryPaneTabs.TRACER);
}
class PrimaryPanes extends Component {
constructor(props) {
@ -118,30 +112,7 @@ class PrimaryPanes extends Component {
title: L10N.getStr("search.header"),
},
React.createElement(ProjectSearch, null)
),
features.javascriptTracing
? React.createElement(
TabPanel,
{
id: "tracer-tab",
key: `tracer-tab${
selectedTab === primaryPaneTabs.TRACER ? "-selected" : ""
}`,
className: "tab tracer-tab",
title: L10N.getStr("tracer.header"),
},
// As the tracer is an application on its own (and is prototypish)
// let's encapsulate it to track its own exceptions.
React.createElement(
AppErrorBoundary,
{
componentName: "Debugger",
panel: "JavaScript Tracer",
},
React.createElement(Tracer)
)
)
: null
)
)
);
}

View File

@ -12,5 +12,4 @@ CompiledModules(
"ProjectSearch.js",
"SourcesTree.js",
"SourcesTreeItem.js",
"Tracer.js",
)

View File

@ -50,9 +50,7 @@ export class SearchInput extends Component {
super(props);
this.state = {
history: [],
excludePatterns: this.props.showSearchModifiers
? props.searchOptions.excludePatterns
: null,
excludePatterns: props.searchOptions.excludePatterns,
};
}

View File

@ -12,7 +12,6 @@ export const primaryPaneTabs = {
SOURCES: "sources",
OUTLINE: "outline",
PROJECT_SEARCH: "project",
TRACER: "tracer",
};
export const markerTypes = {

View File

@ -37,7 +37,6 @@
@import url("chrome://devtools/content/debugger/src/components/PrimaryPanes/OutlineFilter.css");
@import url("chrome://devtools/content/debugger/src/components/PrimaryPanes/ProjectSearch.css");
@import url("chrome://devtools/content/debugger/src/components/PrimaryPanes/Sources.css");
@import url("chrome://devtools/content/debugger/src/components/PrimaryPanes/Tracer.css");
@import url("chrome://devtools/content/debugger/src/components/QuickOpenModal.css");
@import url("chrome://devtools/content/debugger/src/components/SecondaryPanes/Breakpoints/Breakpoints.css");
@import url("chrome://devtools/content/debugger/src/components/SecondaryPanes/CommandBar.css");

View File

@ -25,7 +25,6 @@ import eventListenerBreakpoints, {
initialEventListenerState,
} from "./event-listeners";
import exceptions, { initialExceptionsState } from "./exceptions";
import tracerFrames from "./tracer-frames";
import { objectInspector } from "devtools/client/shared/components/reps/index";
@ -53,7 +52,6 @@ export function initialState() {
objectInspector: objectInspector.reducer.initialOIState(),
eventListenerBreakpoints: initialEventListenerState(),
exceptions: initialExceptionsState(),
tracerFrames: {},
};
}
@ -75,5 +73,4 @@ export default {
objectInspector: objectInspector.reducer.default,
eventListenerBreakpoints,
exceptions,
tracerFrames,
};

View File

@ -22,6 +22,5 @@ CompiledModules(
"sources-tree.js",
"tabs.js",
"threads.js",
"tracer-frames.js",
"ui.js",
)

View File

@ -1,233 +0,0 @@
/* 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/>. */
const {
TRACER_FIELDS_INDEXES,
} = require("resource://devtools/server/actors/tracer.js");
function initialState() {
return {
// These fields are mutable as they are large arrays and UI will rerender based on their size
// The three next array are always of the same size.
// List of all trace resources, as defined by the server codebase (See the TracerActor)
mutableTraces: [],
// Array of arrays. This is of the same size as mutableTraces.
// Store the indexes within mutableTraces of each children matching the same index in mutableTraces.
mutableChildren: [],
// Indexes of parents within mutableTraces.
mutableParents: [],
// Frames are also a trace resources, but they are stored in a dedicated array.
mutableFrames: [],
// List of indexes within mutableTraces of top level trace, without any parent.
mutableTopTraces: [],
// List of all trace resources indexes within mutableTraces which are about dom mutations
mutableMutationTraces: [],
// Index of the currently selected trace within `mutableTraces`.
selectedTraceIndex: null,
};
}
function update(state = initialState(), action) {
switch (action.type) {
case "TRACING_TOGGLED": {
if (action.enabled) {
return initialState();
}
return state;
}
case "TRACING_CLEAR": {
return initialState();
}
case "ADD_TRACES": {
addTraces(state, action.traces);
return { ...state };
}
case "SELECT_TRACE": {
if (
action.traceIndex < 0 ||
action.traceIndex >= state.mutableTraces.length
) {
return state;
}
return {
...state,
selectedTraceIndex: action.traceIndex,
};
}
case "SET_SELECTED_LOCATION": {
// Traces are reference to the generated location only, so ignore any original source being selected
// and wait for SET_GENERATED_SELECTED_LOCATION instead.
if (action.location.source.isOriginal) return state;
// Ignore if the currently selected trace matches the new location.
if (
state.selectedTrace &&
locationMatchTrace(action.location, state.selectedTrace)
) {
return state;
}
// Lookup for a trace matching the newly selected location
for (const trace of state.mutableTraces) {
if (locationMatchTrace(action.location, trace)) {
return {
...state,
selectedTrace: trace,
};
}
}
return {
...state,
selectedTrace: null,
};
}
case "SET_GENERATED_SELECTED_LOCATION": {
// When selecting an original location, we have to wait for the newly selected original location
// to be mapped to a generated location so that we can find a matching trace.
// Ignore if the currently selected trace matches the new location.
if (
state.selectedTrace &&
locationMatchTrace(action.generatedLocation, state.selectedTrace)
) {
return state;
}
// Lookup for a trace matching the newly selected location
for (const trace of state.mutableTraces) {
if (locationMatchTrace(action.generatedLocation, trace)) {
return {
...state,
selectedTrace: trace,
};
}
}
return {
...state,
selectedTrace: null,
};
}
case "CLEAR_SELECTED_LOCATION": {
return {
...state,
selectedTrace: null,
};
}
}
return state;
}
function addTraces(state, traces) {
const {
mutableTraces,
mutableMutationTraces,
mutableFrames,
mutableTopTraces,
mutableChildren,
mutableParents,
} = state;
function matchParent(traceIndex, depth) {
// The very last element is the one matching traceIndex,
// so pick the one added just before.
// We consider that traces are reported by the server in the execution order.
let idx = mutableTraces.length - 2;
while (idx != null) {
const trace = mutableTraces[idx];
if (!trace) {
break;
}
const currentDepth = trace[TRACER_FIELDS_INDEXES.DEPTH];
if (currentDepth < depth) {
mutableChildren[idx].push(traceIndex);
mutableParents.push(idx);
return;
}
idx = mutableParents[idx];
}
// If no parent was found, flag it as top level trace
mutableTopTraces.push(traceIndex);
mutableParents.push(null);
}
for (const traceResource of traces) {
// For now, only consider traces from the top level target/thread
if (!traceResource.targetFront.isTopLevel) {
continue;
}
const type = traceResource[TRACER_FIELDS_INDEXES.TYPE];
switch (type) {
case "frame": {
// Store the object used by SmartTraces
mutableFrames.push({
functionDisplayName: traceResource[TRACER_FIELDS_INDEXES.FRAME_NAME],
source: traceResource[TRACER_FIELDS_INDEXES.FRAME_URL],
sourceId: traceResource[TRACER_FIELDS_INDEXES.FRAME_SOURCEID],
line: traceResource[TRACER_FIELDS_INDEXES.FRAME_LINE],
column: traceResource[TRACER_FIELDS_INDEXES.FRAME_COLUMN],
});
break;
}
case "enter": {
const traceIndex = mutableTraces.length;
mutableTraces.push(traceResource);
mutableChildren.push([]);
const depth = traceResource[TRACER_FIELDS_INDEXES.DEPTH];
matchParent(traceIndex, depth);
break;
}
case "exit": {
// The sidebar doesn't use this information yet
break;
}
case "dom-mutation": {
const traceIndex = mutableTraces.length;
mutableTraces.push(traceResource);
mutableChildren.push([]);
mutableMutationTraces.push(traceIndex);
const depth = traceResource[TRACER_FIELDS_INDEXES.DEPTH];
matchParent(traceIndex, depth);
break;
}
case "event": {
const traceIndex = mutableTraces.length;
mutableTraces.push(traceResource);
mutableChildren.push([]);
mutableParents.push(null);
mutableTopTraces.push(traceIndex);
break;
}
}
}
}
function locationMatchTrace(location, trace) {
return (
trace.sourceId == location.sourceActor.id &&
trace.lineNumber == location.line &&
trace.columnNumber == location.column
);
}
export default update;

View File

@ -26,7 +26,6 @@ export * from "./sources-tree";
export * from "./sources";
export * from "./tabs";
export * from "./threads";
export * from "./tracer";
export * from "./ui";
export {
getVisibleBreakpoints,

View File

@ -26,7 +26,6 @@ CompiledModules(
"sources.js",
"tabs.js",
"threads.js",
"tracer.js",
"visibleBreakpoints.js",
"visibleColumnBreakpoints.js",
"ui.js",

View File

@ -54,7 +54,3 @@ export function getThread(state, threadActor) {
export function getIsThreadCurrentlyTracing(state, thread) {
return state.threads.mutableTracingThreads.has(thread);
}
export function getIsCurrentlyTracing(state) {
return state.threads.mutableTracingThreads.size > 0;
}

View File

@ -1,28 +0,0 @@
/* 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/>. */
export function getSelectedTraceIndex(state) {
return state.tracerFrames?.selectedTraceIndex;
}
export function getTopTraces(state) {
return state.tracerFrames?.mutableTopTraces || [];
}
export function getAllTraces(state) {
return state.tracerFrames?.mutableTraces || [];
}
export function getTraceChildren(state) {
return state.tracerFrames?.mutableChildren || [];
}
export function getTraceParents(state) {
return state.tracerFrames?.mutableParents || [];
}
export function getTraceFrames(state) {
return state.tracerFrames?.mutableFrames || [];
}
export function getAllMutationTraces(state) {
return state.tracerFrames?.mutableMutationTraces || [];
}
export function getAllTraceCount(state) {
return state.tracerFrames?.mutableTraces.length || 0;
}

View File

@ -292,11 +292,6 @@ skip-if = [
"tsan", # Bug 1832135
]
["browser_dbg-javascript-tracer-sidebar.js"]
skip-if = [
"tsan", # Bug 1832135
]
["browser_dbg-javascript-tracer-values.js"]
skip-if = [
"tsan", # Bug 1832135

View File

@ -17,9 +17,15 @@ add_task(async function testTracingFunctionReturn() {
await toggleJsTracerMenuItem(dbg, "#jstracer-menu-item-function-return");
info("Enable tracing with function returns, but without values");
await toggleJsTracer(dbg.toolbox);
const topLevelThreadActorID =
dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID;
info("Wait for tracing to be enabled");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
invokeInTab("foo");
await hasConsoleMessage(dbg, "⟶ interpreter λ foo");
await hasConsoleMessage(dbg, "⟶ interpreter λ bar");
@ -28,11 +34,20 @@ add_task(async function testTracingFunctionReturn() {
await toggleJsTracer(dbg.toolbox);
info("Wait for tracing to be disabled");
await waitForState(dbg, () => {
return !dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
await toggleJsTracerMenuItem(dbg, "#jstracer-menu-item-log-values");
info("Re-enable with returned values");
await toggleJsTracer(dbg.toolbox);
info("Wait for tracing to be re-enabled with logging of returned values");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
invokeInTab("foo");
await hasConsoleMessage(dbg, "⟶ interpreter λ foo");
@ -55,6 +70,9 @@ add_task(async function testTracingFunctionReturn() {
info("Stop tracing");
await toggleJsTracer(dbg.toolbox);
await waitForState(dbg, () => {
return !dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
info("Toggle the two settings to the default value");
await toggleJsTracerMenuItem(dbg, "#jstracer-menu-item-log-values");

View File

@ -54,7 +54,12 @@ add_task(async function testTracingOnNextInteraction() {
);
AccessibilityUtils.resetEnv();
await hasConsoleMessage(dbg, "Started tracing to Web Console");
let topLevelThreadActorID =
dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID;
info("Wait for tracing to be enabled");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
await hasConsoleMessage(dbg, "λ onmousedown");
await hasConsoleMessage(dbg, "λ onclick");
@ -80,9 +85,15 @@ add_task(async function testTracingOnNextInteraction() {
await hasConsoleMessage(dbg, "λ foo");
ok(true, "foo was traced as expected");
info("Stop tracing");
await toggleJsTracer(dbg.toolbox);
topLevelThreadActorID =
dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID;
info("Wait for tracing to be disabled");
await waitForState(dbg, () => {
return !dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
is(
traceButton.getAttribute("aria-pressed"),
"false",
@ -105,9 +116,17 @@ add_task(async function testInteractionBetweenDebuggerAndConsole() {
"data:text/html," + encodeURIComponent(`<script>${jsCode}</script>`)
);
info("Enable the tracing via the toolbox button");
info("Enable the tracing via the debugger button");
await toggleJsTracer(dbg.toolbox);
const topLevelThreadActorID =
dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID;
info("Wait for tracing to be enabled");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
await hasConsoleMessage(dbg, "Started tracing to Web Console");
invokeInTab("foo");
await hasConsoleMessage(dbg, "λ foo");
@ -117,8 +136,10 @@ add_task(async function testInteractionBetweenDebuggerAndConsole() {
let msg = await evaluateExpressionInConsole(hud, ":trace", "console-api");
is(msg.textContent.trim(), "Stopped tracing");
const button = dbg.toolbox.doc.getElementById("command-button-jstracer");
await waitFor(() => !button.classList.contains("checked"));
ok(
!dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID),
"Tracing is also reported as disabled in the debugger"
);
info(
"Clear the console output from the first tracing session started from the debugger"
@ -133,17 +154,24 @@ add_task(async function testInteractionBetweenDebuggerAndConsole() {
msg = await evaluateExpressionInConsole(hud, ":trace", "console-api");
is(msg.textContent.trim(), "Started tracing to Web Console");
info("Wait for tracing to be also enabled in toolbox button");
await waitFor(() => button.classList.contains("checked"));
info("Wait for tracing to be also enabled in the debugger");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
ok(true, "Debugger also reports the tracing in progress");
invokeInTab("foo");
await hasConsoleMessage(dbg, "λ foo");
info("Disable the tracing via the debugger button");
// togglejsTracer will assert that the console logged the "stopped tracing" message
await toggleJsTracer(dbg.toolbox);
info("Wait for tracing to be disabled per toolbox button");
await waitFor(() => !button.classList.contains("checked"));
info("Wait for tracing to be disabled per debugger button");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
info("Also wait for stop message in the console");
await hasConsoleMessage(dbg, "Stopped tracing");
});

View File

@ -22,15 +22,15 @@ add_task(async function testTracingOnNextLoad() {
let traceButton = dbg.toolbox.doc.getElementById("command-button-jstracer");
await toggleJsTracerMenuItem(dbg, "#jstracer-menu-item-next-load");
await toggleJsTracer(dbg.toolbox);
ok(
!traceButton.classList.contains("pending"),
"Before toggling the trace button, it has no particular state"
);
await toggleJsTracerMenuItem(dbg, "#jstracer-menu-item-next-load");
await toggleJsTracer(dbg.toolbox);
info(
"Wait for the split console to be automatically displayed when toggling this setting"
);
@ -70,8 +70,12 @@ add_task(async function testTracingOnNextLoad() {
// Reload the page to trigger the tracer
await reload(dbg);
let topLevelThreadActorID =
dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID;
info("Wait for tracing to be enabled after page reload");
await hasConsoleMessage(dbg, "Started tracing to Web Console");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
is(
traceButton.getAttribute("aria-pressed"),
"true",
@ -90,9 +94,14 @@ add_task(async function testTracingOnNextLoad() {
"The code ran before the reload isn't logged"
);
info("Toggle OFF the tracing");
await toggleJsTracer(dbg.toolbox);
topLevelThreadActorID =
dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID;
info("Wait for tracing to be disabled");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
await waitFor(() => {
return !traceButton.classList.contains("active");
}, "The tracer button is no longer active after stop request");

View File

@ -1,98 +0,0 @@
/* 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/>. */
// Tests the Javascript Tracing feature.
"use strict";
add_task(async function () {
// This is preffed off for now, so ensure turning it on
await pushPref("devtools.debugger.features.javascript-tracing", true);
const dbg = await initDebugger("doc-scripts.html");
info("Force the log method to be the debugger sidebar");
await toggleJsTracerMenuItem(dbg, "#jstracer-menu-item-debugger-sidebar");
info("Enable the tracing");
await toggleJsTracer(dbg.toolbox);
is(
dbg.selectors.getSelectedPrimaryPaneTab(),
"tracer",
"The tracer sidebar is automatically shown on start"
);
const topLevelThreadActorID =
dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID;
info("Wait for tracing to be enabled");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
const tracerMessage = findElementWithSelector(
dbg,
"#tracer-tab-panel .tracer-message"
);
is(tracerMessage.textContent, "Waiting for the first JavaScript executions");
invokeInTab("main");
info("Wait for the call tree to appear in the tracer panel");
const tree = await waitForElementWithSelector(dbg, "#tracer-tab-panel .tree");
info("Wait for the expected traces to appear in the call tree");
const traces = await waitFor(() => {
const elements = tree.querySelectorAll(".trace-line");
if (elements.length == 3) {
return elements;
}
return false;
});
is(traces[0].textContent, "λ main simple1.js:1:16");
is(traces[1].textContent, "λ foo simple2.js:1:12");
is(traces[2].textContent, "λ bar simple2.js:3:4");
// Trigger a click in the content page to verify we do trace DOM events
BrowserTestUtils.synthesizeMouseAtCenter(
"button",
{},
gBrowser.selectedBrowser
);
const clickTrace = await waitFor(() =>
tree.querySelector(".tracer-dom-event")
);
is(clickTrace.textContent, "DOM | click");
await BrowserTestUtils.synthesizeKey("x", {}, gBrowser.selectedBrowser);
const keyTrace = await waitFor(() => {
const elts = tree.querySelectorAll(".tracer-dom-event");
if (elts.length == 2) {
return elts[1];
}
return false;
});
is(keyTrace.textContent, "DOM | keypress");
// Assert the final content of the tree before stopping
const finalTreeSize = 7;
is(tree.querySelectorAll(".trace-line").length, finalTreeSize);
// Test Disabling tracing
info("Disable the tracing");
await toggleJsTracer(dbg.toolbox);
info("Wait for tracing to be disabled");
await waitForState(dbg, () => {
return !dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
invokeInTab("inline_script2");
// Let some time for the tracer to appear if we failed disabling the tracing
await wait(1000);
info("Reset back to the default value");
await toggleJsTracerMenuItem(dbg, "#jstracer-menu-item-console");
});

View File

@ -18,6 +18,13 @@ add_task(async function testTracingValues() {
await toggleJsTracer(dbg.toolbox);
const topLevelThreadActorID =
dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID;
info("Wait for tracing to be enabled");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
invokeInTab("foo");
await hasConsoleMessage(dbg, "λ foo()");

View File

@ -14,9 +14,22 @@ add_task(async function testTracingWorker() {
const dbg = await initDebugger("doc-scripts.html");
info("Instantiate a worker");
const { targetCommand } = dbg.toolbox.commands;
let onAvailable;
const onNewTarget = new Promise(resolve => {
onAvailable = ({ targetFront }) => {
resolve(targetFront);
};
});
await targetCommand.watchTargets({
types: [targetCommand.TYPES.FRAME],
onAvailable,
});
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
content.worker = new content.Worker("simple-worker.js");
});
info("Wait for the worker target");
const workerTarget = await onNewTarget;
await waitFor(
() => findAllElements(dbg, "threadsPaneItems").length == 2,
@ -27,6 +40,12 @@ add_task(async function testTracingWorker() {
info("Enable tracing on all threads");
await toggleJsTracer(dbg.toolbox);
info("Wait for tracing to be enabled for the worker");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(
workerTarget.threadFront.actorID
);
});
// `timer` is called within the worker via a setInterval of 1 second
await hasConsoleMessage(dbg, "setIntervalCallback");

View File

@ -28,6 +28,13 @@ add_task(async function () {
info("Enable the tracing");
await toggleJsTracer(dbg.toolbox);
const topLevelThreadActorID =
dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID;
info("Wait for tracing to be enabled");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
ok(
dbg.toolbox.splitConsole,
"Split console is automatically opened when tracing to the console"
@ -127,6 +134,11 @@ add_task(async function () {
// Test Disabling tracing
info("Disable the tracing");
await toggleJsTracer(dbg.toolbox);
info("Wait for tracing to be disabled");
await waitForState(dbg, () => {
return !dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
await hasConsoleMessage(dbg, "Stopped tracing");
invokeInTab("inline_script2");
@ -146,6 +158,13 @@ add_task(async function () {
info("Re-enable the tracing after navigation");
await toggleJsTracer(dbg.toolbox);
const newTopLevelThread =
dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID;
info("Wait for tracing to be re-enabled");
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(newTopLevelThread);
});
invokeInTab("logMessage");
await hasConsoleMessage(dbg, "λ logMessage");
@ -211,8 +230,12 @@ add_task(async function testPageKeyShortcut() {
const dbg = await initDebuggerWithAbsoluteURL("data:text/html,key-shortcut");
const button = dbg.toolbox.doc.getElementById("command-button-jstracer");
ok(!button.classList.contains("checked"), "The trace button is off on start");
const topLevelThreadActorID =
dbg.toolbox.commands.targetCommand.targetFront.threadFront.actorID;
ok(
!dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID),
"Tracing is disabled on debugger opening"
);
info(
"Focus the page in order to assert that the page keeps the focus when enabling the tracer"
@ -239,7 +262,9 @@ add_task(async function testPageKeyShortcut() {
});
info("Wait for tracing to be enabled");
await waitFor(() => button.classList.contains("checked"));
await waitForState(dbg, () => {
return dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
is(
Services.focus.focusedElement,
@ -257,7 +282,9 @@ add_task(async function testPageKeyShortcut() {
});
info("Wait for tracing to be disabled");
await waitFor(() => !button.classList.contains("checked"));
await waitForState(dbg, () => {
return !dbg.selectors.getIsThreadCurrentlyTracing(topLevelThreadActorID);
});
});
add_task(async function testPageKeyShortcutWithoutDebugger() {

View File

@ -70,7 +70,7 @@ add_task(async function testProjectSearchCloseOnNavigation() {
// Wait for the search to be updated against the new page
await waitForSearchResults(dbg, 5);
is(getExpandedResultsCount(dbg), 30);
is(getExpandedResultsCount(dbg), 29);
ok(
!refreshButton.classList.contains("highlight"),
"Refresh button is no longer highlighted after refreshing the search"

View File

@ -30,7 +30,6 @@
// try to set a breakpoint on the line `var x = 3;` above.
// See Bug 1592839.
inline_script2 = function () { var x = 5; };
window.onkeypress = function keyListener() { };
</script>
</body>
</html>

View File

@ -646,22 +646,6 @@ exports.ToolboxButtons = [
const menu = new Menu();
const options = toolbox.commands.tracerCommand.getTracingOptions();
const { logMethod } = options;
menu.append(
new MenuItem({
id: "jstracer-menu-item-debugger-sidebar",
label: l10n(
"toolbox.buttons.jstracer.menu-item.trace-to-debugger-sidebar"
),
checked: logMethod == TRACER_LOG_METHODS.DEBUGGER_SIDEBAR,
type: "radio",
click: () => {
Services.prefs.setStringPref(
"devtools.debugger.javascript-tracing-log-method",
TRACER_LOG_METHODS.DEBUGGER_SIDEBAR
);
},
})
);
menu.append(
new MenuItem({
id: "jstracer-menu-item-console",

View File

@ -711,9 +711,6 @@ Toolbox.prototype = {
const { logMethod } = this.commands.tracerCommand.getTracingOptions();
if (logMethod == TRACER_LOG_METHODS.CONSOLE) {
await this.openSplitConsole({ focusConsoleInput: false });
} else if (logMethod == TRACER_LOG_METHODS.DEBUGGER_SIDEBAR) {
const panel = await this.selectTool("jsdebugger");
panel.showTracerSidebar();
}
},

View File

@ -318,7 +318,6 @@ devtools.jar:
content/debugger/src/components/PrimaryPanes/OutlineFilter.css (debugger/src/components/PrimaryPanes/OutlineFilter.css)
content/debugger/src/components/PrimaryPanes/ProjectSearch.css (debugger/src/components/PrimaryPanes/ProjectSearch.css)
content/debugger/src/components/PrimaryPanes/Sources.css (debugger/src/components/PrimaryPanes/Sources.css)
content/debugger/src/components/PrimaryPanes/Tracer.css (debugger/src/components/PrimaryPanes/Tracer.css)
content/debugger/src/components/SecondaryPanes/Breakpoints/Breakpoints.css (debugger/src/components/SecondaryPanes/Breakpoints/Breakpoints.css)
content/debugger/src/components/SecondaryPanes/CommandBar.css (debugger/src/components/SecondaryPanes/CommandBar.css)
content/debugger/src/components/SecondaryPanes/EventListeners.css (debugger/src/components/SecondaryPanes/EventListeners.css)

View File

@ -900,9 +900,6 @@ outline.header=Outline
# LOCALIZATION NOTE (search.header): Search left sidebar header
search.header=Search
# LOCALIZATION NOTE (tracer.header): Tracer left sidebar header
tracer.header=Tracer
# LOCALIZATION NOTE (outline.placeholder): Placeholder text for the filter input
# element
outline.placeholder=Filter functions

View File

@ -255,11 +255,6 @@ toolbox.buttons.jstracer = JavaScript Tracer (%S)
# The next keys starting with "trace" were moved from an existing file
# they do not follow the typical toolbox.* naming in order to preserve existing translations.
# LOCALIZATION NOTE (toolbox.buttons.jstracer.menu-item.trace-to-debugger-sidebar): The label that is displayed in the context menu
# of the trace button in the toolbox toolbar.
# This is used to force logging JavaScript traces in the dedicated Debugger sidebar.
toolbox.buttons.jstracer.menu-item.trace-to-debugger-sidebar=Trace in the debugger sidebar
# LOCALIZATION NOTE (traceInWebConsole): The label that is displayed in the context menu
# of the trace button in the toolbox toolbar.
# This is used to force logging JavaScript traces in the Web Console.

View File

@ -459,10 +459,6 @@ webconsole.message.commands.copyValueToClipboard=String was copied to clipboard.
# Label displayed when :trace command was executed and the JavaScript tracer started to log to the web console.
webconsole.message.commands.startTracingToWebConsole=Started tracing to Web Console
# LOCALIZATION NOTE (webconsole.message.commands.startTracingToDebuggerSidebar)
# Label displayed when :trace command was executed and the JavaScript tracer started to log to the debugger sidebar.
webconsole.message.commands.startTracingToDebuggerSidebar=Started tracing to Debugger Sidebar
# LOCALIZATION NOTE (webconsole.message.commands.startTracingToStdout)
# Label displayed when :trace command was executed and the JavaScript tracer started to log to stdout.
webconsole.message.commands.startTracingToStdout=Started tracing to stdout

View File

@ -259,13 +259,10 @@ class Frame extends Component {
return {
...sourceElConfig,
onClick: e => {
// We always need to prevent the default behavior of <a> link
e.preventDefault();
if (onClick) {
e.stopPropagation();
e.stopPropagation();
onClick(generatedLocation);
}
onClick(generatedLocation);
},
href: source,
draggable: false,

View File

@ -300,10 +300,7 @@ class Tree extends Component {
}
// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.autoExpandDepth != this.props.autoExpandDepth) {
this.setState({ seen: new Set() });
}
UNSAFE_componentWillReceiveProps() {
this._autoExpand();
this._updateHeight();
}
@ -319,10 +316,8 @@ class Tree extends Component {
);
}
componentDidUpdate(prevProps) {
if (prevProps.shown != this.props.shown) {
this._scrollItemIntoView();
}
componentDidUpdate() {
this._scrollItemIntoView();
}
componentWillUnmount() {
@ -503,7 +498,7 @@ class Tree extends Component {
if (scrollTop >= elementTop + itemHeight) {
scrollTo = elementTop;
} else if (scrollTop + clientHeight <= elementTop) {
scrollTo = elementTop;
scrollTo = elementTop + itemHeight - clientHeight;
}
if (scrollTo != undefined) {
@ -1023,8 +1018,7 @@ class TreeNodeClass extends Component {
"data-depth": this.props.depth,
style: {
padding: 0,
// This helps the CSS compute a margin based on the depth.
"--tree-node-depth": this.props.depth,
margin: 0,
},
},

View File

@ -91,11 +91,11 @@ window.onload = async function () {
await forceRender(tree);
isRenderedTree(document.body.textContent, [
"---K:false",
"---L:false",
"--F:false",
"--G:false",
"-C:false",
"--H:false",
"--I:false",
], "Should render shown item correctly");
info("Test mid item shown when it's already rendered.");
@ -103,11 +103,11 @@ window.onload = async function () {
await forceRender(tree);
isRenderedTree(document.body.textContent, [
"---L:false",
"--F:false",
"--G:false",
"-C:false",
"--H:false",
"--I:false",
], "Should render shown item correctly");
info("Test item that is not in traversal.");
@ -115,11 +115,11 @@ window.onload = async function () {
await forceRender(tree);
isRenderedTree(document.body.textContent, [
"---L:false",
"--F:false",
"--G:false",
"-C:false",
"--H:false",
"--I:false",
], "Should render without changes");
info("Test item that is already shown.");

View File

@ -2391,46 +2391,7 @@ async function unregisterServiceWorker(workerUrl) {
/**
* Toggle the JavavaScript tracer via its toolbox toolbar button.
*/
async function toggleJsTracer(toolbox) {
const { isTracingEnabled } = toolbox.commands.tracerCommand;
const { logMethod, traceOnNextInteraction, traceOnNextLoad } =
toolbox.commands.tracerCommand.getTracingOptions();
function toggleJsTracer(toolbox) {
const toolbarButton = toolbox.doc.getElementById("command-button-jstracer");
toolbarButton.click();
const {
TRACER_LOG_METHODS,
} = require("resource://devtools/shared/specs/tracer.js");
if (logMethod != TRACER_LOG_METHODS.CONSOLE) {
return;
}
// We were tracing and just requested to stop it.
// Wait for the stop message to appear in the console before clearing its content.
// This simplifies writting tests toggling the tracer ON multiple times and checking
// for the display of traces in the console.
if (isTracingEnabled) {
const { hud } = await toolbox.getPanel("webconsole");
info("Wait for tracing to be disabled");
await waitFor(() =>
[...hud.ui.outputNode.querySelectorAll(".message")].some(msg =>
msg.textContent.includes("Stopped tracing")
)
);
hud.ui.clearOutput();
await waitFor(
() => hud.ui.outputNode.querySelectorAll(".message").length === 0
);
} else {
// We are enabling the tracing to the console, and the console may not be opened just yet.
const { hud } = await toolbox.getPanelWhenReady("webconsole");
if (!traceOnNextInteraction && !traceOnNextLoad) {
await waitFor(() =>
[...hud.ui.outputNode.querySelectorAll(".message")].some(msg =>
msg.textContent.includes("Started tracing to Web Console")
)
);
}
}
}

View File

@ -24,13 +24,6 @@ loader.lazyRequireGetter(
true
);
loader.lazyRequireGetter(
this,
"TRACER_LOG_METHODS",
"resource://devtools/shared/specs/tracer.js",
true
);
// URL Regex, common idioms:
//
// Lead-in (URL):
@ -519,17 +512,13 @@ function transformTracerStateResource(stateResource) {
const { targetFront, enabled, logMethod, timeStamp, reason } = stateResource;
let message;
if (enabled) {
if (logMethod == TRACER_LOG_METHODS.STDOUT) {
if (logMethod == "stdout") {
message = l10n.getStr("webconsole.message.commands.startTracingToStdout");
} else if (logMethod == "console") {
message = l10n.getStr(
"webconsole.message.commands.startTracingToWebConsole"
);
} else if (logMethod == TRACER_LOG_METHODS.DEBUGGER_SIDEBAR) {
message = l10n.getStr(
"webconsole.message.commands.startTracingToDebuggerSidebar"
);
} else if (logMethod == TRACER_LOG_METHODS.PROFILER) {
} else if (logMethod == "profiler") {
message = l10n.getStr(
"webconsole.message.commands.startTracingToProfiler"
);

View File

@ -36,12 +36,6 @@ loader.lazyRequireGetter(
true
);
const ZoomKeys = require("resource://devtools/client/shared/zoom-keys.js");
loader.lazyRequireGetter(
this,
"TRACER_LOG_METHODS",
"resource://devtools/shared/specs/tracer.js",
true
);
const PREF_SIDEBAR_ENABLED = "devtools.webconsole.sidebarToggle";
const PREF_BROWSERTOOLBOX_SCOPE = "devtools.browsertoolbox.scope";
@ -478,8 +472,6 @@ class WebConsoleUI {
return;
}
const { logMethod } = this.hud.commands.tracerCommand.getTracingOptions();
const messages = [];
for (const resource of resources) {
const { TYPES } = this.hud.resourceCommand;
@ -521,12 +513,6 @@ class WebConsoleUI {
continue;
}
if (
resource.resourceType === TYPES.JSTRACER_TRACE &&
logMethod != TRACER_LOG_METHODS.CONSOLE
) {
continue;
}
if (resource.resourceType === TYPES.NETWORK_EVENT_STACKTRACE) {
this.networkDataProvider?.onStackTraceAvailable(resource);
continue;

View File

@ -38,35 +38,17 @@ loader.lazyRequireGetter(
true
);
// Indexes of each data type within the array describing a trace
// Indexes of each data type within the array describing a frame
exports.TRACER_FIELDS_INDEXES = {
// This is shared with all the data types
TYPE: 0,
// Frame traces are slightly special and do not share any field with the other data types
FRAME_IMPLEMENTATION: 1,
FRAME_NAME: 2,
FRAME_SOURCEID: 3,
FRAME_LINE: 4,
FRAME_COLUMN: 5,
FRAME_URL: 6,
// These fields are shared with all but frame data types
PREFIX: 1,
FRAME_INDEX: 2,
TIMESTAMP: 3,
DEPTH: 4,
EVENT_NAME: 5,
ENTER_ARGS: 5,
EXIT_PARENT_FRAME_ID: 5,
EXIT_RETURNED_VALUE: 6,
EXIT_WHY: 7,
DOM_MUTATION_TYPE: 5,
DOM_MUTATION_ELEMENT: 6,
};
const VALID_LOG_METHODS = Object.values(TRACER_LOG_METHODS);
@ -116,7 +98,6 @@ class TracerActor extends Actor {
* Options used to configure JavaScriptTracer.
* See `JavaScriptTracer.startTracing`.
*/
// eslint-disable-next-line complexity
startTracing(options = {}) {
if (options.logMethod && !VALID_LOG_METHODS.includes(options.logMethod)) {
throw new Error(
@ -159,9 +140,6 @@ class TracerActor extends Actor {
ListenerClass = StdoutTracingListener;
break;
case TRACER_LOG_METHODS.CONSOLE:
case TRACER_LOG_METHODS.DEBUGGER_SIDEBAR:
// Console and debugger sidebar are both using JSTRACE_STATE/JSTRACE_TRACE resources
// to receive tracing data.
ListenerClass = ResourcesTracingListener;
break;
case TRACER_LOG_METHODS.PROFILER:

View File

@ -6,13 +6,6 @@
const EventEmitter = require("resource://devtools/shared/event-emitter.js");
loader.lazyRequireGetter(
this,
"TRACER_LOG_METHODS",
"resource://devtools/shared/specs/tracer.js",
true
);
class TracerCommand extends EventEmitter {
constructor({ commands }) {
super();
@ -48,6 +41,9 @@ class TracerCommand extends EventEmitter {
if (resource.resourceType != this.#resourceCommand.TYPES.JSTRACER_STATE) {
continue;
}
this.isTracingActive = resource.enabled;
// In case the tracer is started without the DevTools frontend, also force it to be reported as enabled
this.isTracingEnabled = resource.enabled;
// Clear the list of collected frames each time we start a new tracer record.
// The tracer will reset its frame counter to zero on stop, but on the frontend
@ -56,17 +52,6 @@ class TracerCommand extends EventEmitter {
resource.targetFront.getJsTracerCollectedFramesArray().length = 0;
}
if (
resource.enabled == this.isTracingActive &&
resource.enabled == this.isTracingEnabled
) {
continue;
}
this.isTracingActive = resource.enabled;
// In case the tracer is started without the DevTools frontend, also force it to be reported as enabled
this.isTracingEnabled = resource.enabled;
this.emit("toggle");
}
};
@ -79,17 +64,11 @@ class TracerCommand extends EventEmitter {
* Configuration object.
*/
getTracingOptions() {
const logMethod = Services.prefs.getStringPref(
"devtools.debugger.javascript-tracing-log-method",
""
);
return {
logMethod,
// Force enabling DOM Mutation logging as soon as we selected the sidebar log output
traceDOMMutations:
logMethod == TRACER_LOG_METHODS.DEBUGGER_SIDEBAR
? ["add", "attributes", "remove"]
: null,
logMethod: Services.prefs.getStringPref(
"devtools.debugger.javascript-tracing-log-method",
""
),
traceValues: Services.prefs.getBoolPref(
"devtools.debugger.javascript-tracing-values",
false

View File

@ -15,7 +15,6 @@ types.addDictType("tracer.start.options", {
traceValues: "boolean",
traceOnNextInteraction: "boolean",
traceOnNextLoad: "boolean",
traceDOMMutations: "nullable:array:string",
});
const tracerSpec = generateActorSpec({
@ -36,7 +35,6 @@ const tracerSpec = generateActorSpec({
exports.tracerSpec = tracerSpec;
const TRACER_LOG_METHODS = {
DEBUGGER_SIDEBAR: "debugger-sidebar",
STDOUT: "stdout",
CONSOLE: "console",
PROFILER: "profiler",