Bug 1827382 - [devtools] Migrate tracer from JSM to ESM. r=devtools-reviewers,nchevobbe

Differential Revision: https://phabricator.services.mozilla.com/D202437
This commit is contained in:
Alexandre Poirot 2024-03-26 08:29:21 +00:00
parent 522fd9ad0a
commit d10de08d0d
11 changed files with 115 additions and 125 deletions

View file

@ -60,7 +60,7 @@ function JSTracerTrace(props) {
// Attributes specific to function call returns
returnedValue,
relatedTraceId,
// See tracer.jsm FRAME_EXIT_REASONS
// See tracer.sys.mjs FRAME_EXIT_REASONS
why,
// Attributes specific to DOM Mutations

View file

@ -8,13 +8,10 @@ const {
TYPES: { JSTRACER_STATE },
} = require("resource://devtools/server/actors/resources/index.js");
// Bug 1827382, as this module can be used from the worker thread,
// the following JSM may be loaded by the worker loader until
// we have proper support for ESM from workers.
const {
addTracingListener,
removeTracingListener,
} = require("resource://devtools/server/tracer/tracer.jsm");
const { JSTracer } = ChromeUtils.importESModule(
"resource://devtools/server/tracer/tracer.sys.mjs",
{ global: "contextual" }
);
const { LOG_METHODS } = require("resource://devtools/server/actors/tracer.js");
const Targets = require("resource://devtools/server/actors/targets/index.js");
@ -42,7 +39,7 @@ class TracingStateWatcher {
this.tracingListener = {
onTracingToggled: this.onTracingToggled.bind(this),
};
addTracingListener(this.tracingListener);
JSTracer.addTracingListener(this.tracingListener);
}
/**
@ -52,7 +49,7 @@ class TracingStateWatcher {
if (!this.tracingListener) {
return;
}
removeTracingListener(this.tracingListener);
JSTracer.removeTracingListener(this.tracingListener);
}
/**

View file

@ -4,16 +4,14 @@
"use strict";
// Bug 1827382, as this module can be used from the worker thread,
// the following JSM may be loaded by the worker loader until
// we have proper support for ESM from workers.
const {
startTracing,
stopTracing,
addTracingListener,
removeTracingListener,
NEXT_INTERACTION_MESSAGE,
} = require("resource://devtools/server/tracer/tracer.jsm");
const lazy = {};
ChromeUtils.defineESModuleGetters(
lazy,
{
JSTracer: "resource://devtools/server/tracer/tracer.sys.mjs",
},
{ global: "contextual" }
);
const { Actor } = require("resource://devtools/shared/protocol.js");
const { tracerSpec } = require("resource://devtools/shared/specs/tracer.js");
@ -136,10 +134,10 @@ class TracerActor extends Actor {
onTracingPending: this.onTracingPending.bind(this),
onTracingDOMMutation: this.onTracingDOMMutation.bind(this),
};
addTracingListener(this.tracingListener);
lazy.JSTracer.addTracingListener(this.tracingListener);
this.traceValues = !!options.traceValues;
try {
startTracing({
lazy.JSTracer.startTracing({
global: this.targetActor.window || this.targetActor.workerGlobal,
prefix: options.prefix || "",
// Enable receiving the `currentDOMEvent` being passed to `onTracingFrame`
@ -170,10 +168,10 @@ class TracerActor extends Actor {
return;
}
// Remove before stopping to prevent receiving the stop notification
removeTracingListener(this.tracingListener);
lazy.JSTracer.removeTracingListener(this.tracingListener);
this.tracingListener = null;
stopTracing();
lazy.JSTracer.stopTracing();
this.logMethod = null;
}
@ -230,7 +228,7 @@ class TracerActor extends Actor {
if (consoleMessageWatcher) {
consoleMessageWatcher.emitMessages([
{
arguments: [NEXT_INTERACTION_MESSAGE],
arguments: [lazy.JSTracer.NEXT_INTERACTION_MESSAGE],
styles: [],
level: "jstracer",
chromeContext: false,
@ -510,7 +508,7 @@ class TracerActor extends Actor {
* A string to be displayed as a prefix of any logged frame.
* @param {String} options.why
* A string to explain why the function stopped.
* See tracer.jsm's FRAME_EXIT_REASONS.
* See tracer.sys.mjs's FRAME_EXIT_REASONS.
* @param {Debugger.Object|primitive} options.rv
* The returned value. It can be the returned value, or the thrown exception.
* It is either a primitive object, otherwise it is a Debugger.Object for any other JS Object type.

View file

@ -11,13 +11,6 @@ loader.lazyRequireGetter(
true
);
loader.lazyRequireGetter(
this,
["DOM_MUTATIONS"],
"resource://devtools/server/tracer/tracer.jsm",
true
);
loader.lazyGetter(this, "l10n", () => {
return new Localization(
[
@ -27,6 +20,16 @@ loader.lazyGetter(this, "l10n", () => {
true
);
});
const lazy = {};
ChromeUtils.defineESModuleGetters(
lazy,
{
JSTracer: "resource://devtools/server/tracer/tracer.sys.mjs",
},
{ global: "contextual" }
);
const USAGE_STRING_MAPPING = {
block: "webconsole-commands-usage-block",
trace: "webconsole-commands-usage-trace3",
@ -888,7 +891,7 @@ WebConsoleCommandsManager.register({
} else if (typeof args["dom-mutations"] == "string") {
// Otherwise consider the value as coma seperated list and remove any white space.
traceDOMMutations = args["dom-mutations"].split(",").map(e => e.trim());
const acceptedValues = Object.values(DOM_MUTATIONS);
const acceptedValues = Object.values(lazy.JSTracer.DOM_MUTATIONS);
if (!traceDOMMutations.every(e => acceptedValues.includes(e))) {
throw new Error(
`:trace --dom-mutations only accept a list of strings whose values can be: ${acceptedValues}`

View file

@ -4,7 +4,7 @@
# 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/.
DevToolsModules("tracer.jsm")
DevToolsModules("tracer.sys.mjs")
XPCSHELL_TESTS_MANIFESTS += ["tests/xpcshell/xpcshell.toml"]
if CONFIG["MOZ_BUILD_APP"] != "mobile/android":

View file

@ -1,6 +1,6 @@
"use strict";
/* global global, loadSubScript */
/* global global */
try {
// For some reason WorkerDebuggerGlobalScope.global doesn't expose JS variables
@ -8,8 +8,11 @@ try {
const dbg = new Debugger(global);
const [debuggee] = dbg.getDebuggees();
/* global startTracing, stopTracing, addTracingListener, removeTracingListener */
loadSubScript("resource://devtools/server/tracer/tracer.jsm");
const { JSTracer } = ChromeUtils.importESModule(
"resource://devtools/server/tracer/tracer.sys.mjs",
{ global: "contextual" }
);
const frames = [];
const listener = {
onTracingFrame(args) {
@ -19,13 +22,13 @@ try {
return true;
},
};
addTracingListener(listener);
startTracing({ global, prefix: "testWorkerPrefix" });
JSTracer.addTracingListener(listener);
JSTracer.startTracing({ global, prefix: "testWorkerPrefix" });
debuggee.executeInGlobal("foo()");
stopTracing();
removeTracingListener(listener);
JSTracer.stopTracing();
JSTracer.removeTracingListener(listener);
// Send the frames to the main thread to do the assertions there.
postMessage(JSON.stringify(frames));

View file

@ -17,12 +17,10 @@ add_task(async function testTracingWorker() {
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
const {
addTracingListener,
removeTracingListener,
startTracing,
stopTracing,
} = ChromeUtils.import("resource://devtools/server/tracer/tracer.jsm");
const { JSTracer } = ChromeUtils.importESModule(
"resource://devtools/server/tracer/tracer.sys.mjs",
{ global: "shared" }
);
// We have to fake opening DevTools otherwise DebuggerNotificationObserver wouldn't work
// and the tracer wouldn't be able to trace the DOM events.
@ -35,10 +33,10 @@ add_task(async function testTracingWorker() {
},
};
info("Register a tracing listener");
addTracingListener(listener);
JSTracer.addTracingListener(listener);
info("Start tracing the iframe");
startTracing({ global: content, traceDOMEvents: true });
JSTracer.startTracing({ global: content, traceDOMEvents: true });
info("Dispatch a click event on the iframe");
EventUtils.synthesizeMouseAtCenter(
@ -58,8 +56,8 @@ add_task(async function testTracingWorker() {
is(lastFrame.formatedDisplayName, "λ bar");
is(lastFrame.currentDOMEvent, "setTimeoutCallback");
stopTracing();
removeTracingListener(listener);
JSTracer.stopTracing();
JSTracer.removeTracingListener(listener);
ChromeUtils.notifyDevToolsClosed();
});

View file

@ -3,8 +3,10 @@
"use strict";
const { addTracingListener, removeTracingListener, startTracing, stopTracing } =
ChromeUtils.import("resource://devtools/server/tracer/tracer.jsm");
const { JSTracer } = ChromeUtils.importESModule(
"resource://devtools/server/tracer/tracer.sys.mjs",
{ global: "shared" }
);
add_task(async function () {
// Because this test uses evalInSandbox, we need to tweak the following prefs
@ -30,13 +32,13 @@ add_task(async function testTracingContentGlobal() {
};
info("Register a tracing listener");
addTracingListener(listener);
JSTracer.addTracingListener(listener);
const sandbox = Cu.Sandbox("https://example.com");
Cu.evalInSandbox("function bar() {}; function foo() {bar()};", sandbox);
info("Start tracing");
startTracing({ global: sandbox, prefix: "testContentPrefix" });
JSTracer.startTracing({ global: sandbox, prefix: "testContentPrefix" });
Assert.equal(toggles.length, 1);
Assert.equal(toggles[0], true);
@ -56,7 +58,7 @@ add_task(async function testTracingContentGlobal() {
Assert.ok(lastFrame.frame);
info("Stop tracing");
stopTracing();
JSTracer.stopTracing();
Assert.equal(toggles.length, 2);
Assert.equal(toggles[1], false);
@ -65,19 +67,19 @@ add_task(async function testTracingContentGlobal() {
Assert.equal(frames.length, 0);
info("Start tracing again, and recall code");
startTracing({ global: sandbox, prefix: "testContentPrefix" });
JSTracer.startTracing({ global: sandbox, prefix: "testContentPrefix" });
sandbox.foo();
info("New traces are logged");
Assert.equal(frames.length, 2);
info("Unregister the listener and recall code");
removeTracingListener(listener);
JSTracer.removeTracingListener(listener);
sandbox.foo();
info("No more traces are logged");
Assert.equal(frames.length, 2);
info("Stop tracing");
stopTracing();
JSTracer.stopTracing();
});
add_task(async function testTracingJSMGlobal() {
@ -103,10 +105,10 @@ add_task(async function testTracingJSMGlobal() {
);
info("Register a tracing listener");
addTracingListener(listenerSandbox.listener);
JSTracer.addTracingListener(listenerSandbox.listener);
info("Start tracing");
startTracing({ global: null, prefix: "testPrefix" });
JSTracer.startTracing({ global: null, prefix: "testPrefix" });
Assert.equal(listenerSandbox.toggles.length, 1);
Assert.equal(listenerSandbox.toggles[0], true);
@ -131,11 +133,11 @@ add_task(async function testTracingJSMGlobal() {
Assert.ok(lastFrame.frame);
info("Stop tracing");
stopTracing();
JSTracer.stopTracing();
Assert.equal(listenerSandbox.toggles.length, 2);
Assert.equal(listenerSandbox.toggles[1], false);
removeTracingListener(listenerSandbox.listener);
JSTracer.removeTracingListener(listenerSandbox.listener);
});
add_task(async function testTracingValues() {
@ -153,7 +155,7 @@ add_task(async function testTracingValues() {
}
info("Start tracing");
startTracing({ global: sandbox, traceValues: true, loggingMethod });
JSTracer.startTracing({ global: sandbox, traceValues: true, loggingMethod });
info("Call some code");
sandbox.foo();
@ -167,7 +169,7 @@ add_task(async function testTracingValues() {
);
info("Stop tracing");
stopTracing();
JSTracer.stopTracing();
});
add_task(async function testTracingFunctionReturn() {
@ -185,7 +187,11 @@ add_task(async function testTracingFunctionReturn() {
}
info("Start tracing");
startTracing({ global: sandbox, traceFunctionReturn: true, loggingMethod });
JSTracer.startTracing({
global: sandbox,
traceFunctionReturn: true,
loggingMethod,
});
info("Call some code");
sandbox.foo();
@ -198,7 +204,7 @@ add_task(async function testTracingFunctionReturn() {
Assert.stringContains(logs[4], "λ foo return");
info("Stop tracing");
stopTracing();
JSTracer.stopTracing();
});
add_task(async function testTracingFunctionReturnAndValues() {
@ -216,7 +222,7 @@ add_task(async function testTracingFunctionReturnAndValues() {
}
info("Start tracing");
startTracing({
JSTracer.startTracing({
global: sandbox,
traceFunctionReturn: true,
traceValues: true,
@ -236,7 +242,7 @@ add_task(async function testTracingFunctionReturnAndValues() {
Assert.stringContains(logs[6], "λ foo return undefined");
info("Stop tracing");
stopTracing();
JSTracer.stopTracing();
});
add_task(async function testTracingStep() {
@ -274,7 +280,7 @@ foo();`;
}
info("Start tracing");
startTracing({
JSTracer.startTracing({
global: sandbox,
traceSteps: true,
loggingMethod,
@ -327,7 +333,7 @@ foo();`;
Assert.stringContains(logs[18], "file.js:5:3");
info("Stop tracing");
stopTracing();
JSTracer.stopTracing();
});
add_task(async function testTracingPauseOnStep() {
@ -348,7 +354,7 @@ add_task(async function testTracingPauseOnStep() {
}
info("Start tracing without pause");
startTracing({
JSTracer.startTracing({
global: sandbox,
loggingMethod,
});
@ -366,13 +372,13 @@ add_task(async function testTracingPauseOnStep() {
Assert.equal(sandbox.counter, 1);
info("Stop tracing");
stopTracing();
JSTracer.stopTracing();
logs.length = 0;
sandbox.counter = 0;
info("Start tracing with 0ms pause");
startTracing({
JSTracer.startTracing({
global: sandbox,
pauseOnStep: 0,
loggingMethod,
@ -415,13 +421,13 @@ add_task(async function testTracingPauseOnStep() {
Assert.equal(sandbox.counter, 1);
info("Stop tracing");
stopTracing();
JSTracer.stopTracing();
logs.length = 0;
sandbox.counter = 0;
info("Start tracing with 250ms pause");
startTracing({
JSTracer.startTracing({
global: sandbox,
pauseOnStep: 250,
loggingMethod,
@ -463,7 +469,7 @@ add_task(async function testTracingPauseOnStep() {
Assert.greater(Cu.now() - startTimestamp, 250);
info("Stop tracing");
stopTracing();
JSTracer.stopTracing();
});
add_task(async function testTracingFilterSourceUrl() {
@ -485,7 +491,7 @@ add_task(async function testTracingFilterSourceUrl() {
}
info("Start tracing");
startTracing({
JSTracer.startTracing({
global: sandbox,
filterFrameSourceUrl: "second",
loggingMethod,
@ -500,7 +506,7 @@ add_task(async function testTracingFilterSourceUrl() {
Assert.stringContains(logs[1], "second.js:1:18");
info("Stop tracing");
stopTracing();
JSTracer.stopTracing();
});
add_task(async function testTracingAllGlobals() {
@ -539,7 +545,7 @@ add_task(async function testTracingAllGlobals() {
const { loggingMethod, logs } = ignoredGlobal;
info("Start tracing on all globals");
startTracing({
JSTracer.startTracing({
traceAllGlobals: true,
loggingMethod,
});
@ -547,7 +553,7 @@ add_task(async function testTracingAllGlobals() {
// Call some code while being careful to not call anything else which may be traced
sandbox1.foo();
stopTracing();
JSTracer.stopTracing();
Assert.equal(logs.length, 4);
Assert.equal(logs[0], "Start tracing JavaScript\n");

View file

@ -17,17 +17,6 @@
* `JavaScriptTracer.onEnterFrame` method is hot codepath and should be reviewed accordingly.
*/
"use strict";
const EXPORTED_SYMBOLS = [
"startTracing",
"stopTracing",
"addTracingListener",
"removeTracingListener",
"NEXT_INTERACTION_MESSAGE",
"DOM_MUTATIONS",
];
const NEXT_INTERACTION_MESSAGE =
"Waiting for next user interaction before tracing (next mousedown or keydown event)";
@ -93,7 +82,8 @@ const customLazy = {
get DistinctCompartmentDebugger() {
const { addDebuggerToGlobal } = ChromeUtils.importESModule(
"resource://gre/modules/jsdebugger.sys.mjs"
"resource://gre/modules/jsdebugger.sys.mjs",
{ global: "contextual" }
);
const systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
const debuggerSandbox = Cu.Sandbox(systemPrincipal, {
@ -1088,12 +1078,11 @@ function syncPause(duration) {
});
}
// This JSM may be execute as CommonJS when loaded in the worker thread
if (typeof module == "object") {
module.exports = {
startTracing,
stopTracing,
addTracingListener,
removeTracingListener,
};
}
export const JSTracer = {
startTracing,
stopTracing,
addTracingListener,
removeTracingListener,
NEXT_INTERACTION_MESSAGE,
DOM_MUTATIONS,
};

View file

@ -4,12 +4,10 @@
"use strict";
const {
startTracing,
addTracingListener,
stopTracing,
removeTracingListener,
} = require("resource://devtools/server/tracer/tracer.jsm");
const { JSTracer } = ChromeUtils.importESModule(
"resource://devtools/server/tracer/tracer.sys.mjs",
{ global: "shared" }
);
let lineToTrace;
@ -63,7 +61,7 @@ function traceFrame({ frame }) {
if (lineToTrace) {
if (lineNumber == lineToTrace) {
// Stop the first tracer started from `exports.start()` which was only waiting for the particular test script line to run
stopTracing();
JSTracer.stopTracing();
const { url } = script.source;
const filename = url.substr(url.lastIndexOf("/") + 1);
@ -78,7 +76,7 @@ function traceFrame({ frame }) {
traceSteps: true,
};
lineToTrace = null;
startTracing(tracerOptions);
JSTracer.startTracing(tracerOptions);
}
return false;
}
@ -154,13 +152,13 @@ exports.start = function (testGlobal, testUrl, line) {
// Only trace the running test and nothing else
filterFrameSourceUrl: testUrl,
};
startTracing(tracerOptions);
addTracingListener(tracingListener);
JSTracer.startTracing(tracerOptions);
JSTracer.addTracingListener(tracingListener);
};
exports.stop = function () {
stopTracing();
removeTracingListener(tracingListener);
JSTracer.stopTracing();
JSTracer.removeTracingListener(tracingListener);
};
function readURI(uri) {

View file

@ -4,12 +4,10 @@
"use strict";
const {
startTracing,
addTracingListener,
stopTracing,
removeTracingListener,
} = require("resource://devtools/server/tracer/tracer.jsm");
const { JSTracer } = ChromeUtils.importESModule(
"resource://devtools/server/tracer/tracer.sys.mjs",
{ global: "contextual" }
);
let testFileContent;
@ -69,13 +67,13 @@ exports.start = function (testGlobal, testUrl, pause) {
logStep(
`'\u21A6 ' symbol highlights what precise instruction is being called`
);
startTracing(tracerOptions);
addTracingListener(tracingListener);
JSTracer.startTracing(tracerOptions);
JSTracer.addTracingListener(tracingListener);
};
exports.stop = function () {
stopTracing();
removeTracingListener(tracingListener);
JSTracer.stopTracing();
JSTracer.removeTracingListener(tracingListener);
};
function readURI(uri) {