diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:34:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:34:50 +0000 |
commit | def92d1b8e9d373e2f6f27c366d578d97d8960c6 (patch) | |
tree | 2ef34b9ad8bb9a9220e05d60352558b15f513894 /devtools/shared/test-helpers | |
parent | Adding debian version 125.0.3-1. (diff) | |
download | firefox-def92d1b8e9d373e2f6f27c366d578d97d8960c6.tar.xz firefox-def92d1b8e9d373e2f6f27c366d578d97d8960c6.zip |
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/shared/test-helpers')
-rw-r--r-- | devtools/shared/test-helpers/moz.build | 1 | ||||
-rw-r--r-- | devtools/shared/test-helpers/test-line-tracer.js | 180 | ||||
-rw-r--r-- | devtools/shared/test-helpers/test-stepper.js | 18 |
3 files changed, 189 insertions, 10 deletions
diff --git a/devtools/shared/test-helpers/moz.build b/devtools/shared/test-helpers/moz.build index 2c14b6a7b7..c5f6c26292 100644 --- a/devtools/shared/test-helpers/moz.build +++ b/devtools/shared/test-helpers/moz.build @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. DevToolsModules( + "test-line-tracer.js", "test-stepper.js", "tracked-objects.sys.mjs", ) diff --git a/devtools/shared/test-helpers/test-line-tracer.js b/devtools/shared/test-helpers/test-line-tracer.js new file mode 100644 index 0000000000..a53b94bb48 --- /dev/null +++ b/devtools/shared/test-helpers/test-line-tracer.js @@ -0,0 +1,180 @@ +/* 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 { JSTracer } = ChromeUtils.importESModule( + "resource://devtools/server/tracer/tracer.sys.mjs", + { global: "shared" } +); + +let lineToTrace; + +const fileContents = new Map(); + +function getFileContent(url) { + let content = fileContents.get(url); + if (content) { + return content; + } + content = readURI(url).split("\n"); + fileContents.set(url, content); + return content; +} + +function isNestedFrame(frame, topFrame) { + if (frame.older) { + // older will be a Debugger.Frame + while ((frame = frame.older)) { + if (frame == topFrame) { + return true; + } + } + } else if (frame.olderSavedFrame) { + // olderSavedFrame will be a SavedStack object + frame = frame.olderSavedFrame; + const { lineNumber, columnNumber } = topFrame.script.getOffsetMetadata( + top.offset + ); + while ((frame = frame.parent || frame.asyncParent)) { + if ( + frame.source == topFrame.script.source.url && + frame.line == lineNumber && + frame.column == columnNumber + ) { + return true; + } + } + } + return false; +} + +// Store the top most frame running at `lineToTrace` line. +// We will then log all frames which are children of this top one. +let initialFrame = null; +let previousSourceUrl = null; + +function traceFrame({ frame }) { + const { script } = frame; + const { lineNumber, columnNumber } = script.getOffsetMetadata(frame.offset); + 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 + JSTracer.stopTracing(); + + const { url } = script.source; + const filename = url.substr(url.lastIndexOf("/") + 1); + const line = getFileContent(url)[lineNumber - 1]; + logStep(`Start tracing ${filename} @ ${lineNumber} :: ${line}`); + previousSourceUrl = url; + // Restart a new tracer which would go track all the globals and not restrict to the test script. + const tracerOptions = { + // Ensure tracing all globals in this thread + traceAllGlobals: true, + // Ensure tracing each execution within functions (and not only function calls) + traceSteps: true, + }; + lineToTrace = null; + JSTracer.startTracing(tracerOptions); + } + return false; + } + // We executed the test line we wanted to trace and now log all frames via a second tracer instance + + // First pick up the very first executed frame, so that we can trace all nested frame from this one. + if (!initialFrame) { + initialFrame = frame; + } else if (initialFrame.terminated) { + // If the traced top frame completed its execution, stop tracing. + // Note that terminated will only be true once any possibly asynchronous work of the traced function + // is done executing. + logStep("End of execution"); + exports.stop(); + return false; + } else if (!initialFrame.onStack) { + // If we are done executing the traced Frame, it will be declared out of the stack. + // By we should keep tracing as, if the traced Frame involves async work, it may be later restored onto the stack. + return false; + } else if (frame != initialFrame && !isNestedFrame(frame, initialFrame)) { + // Then, only log frame which ultimately related to this first frame we picked. + // Because of asynchronous calls and concurrent event loops, we may have in-between frames + // that we ignore which relates to another event loop and another top frame. + // + // Note that the tracer may notify us about the exact same Frame object multiple times. + // (its offset/location will change, but the object will be the same) + return false; + } + + const { url } = script.source; + + // Print the full source URL each time we start tracing a new source + if (previousSourceUrl && previousSourceUrl !== url) { + logStep(""); + logStep(url); + // Log a grey line separator + logStep(`\x1b[2m` + `\u2500`.repeat(url.length) + `\x1b[0m`); + previousSourceUrl = url; + } + + const line = getFileContent(url)[lineNumber - 1]; + // Grey out the beginning of the line, before frame's column, + // and display an arrow before displaying the rest of the line. + const code = + "\x1b[2m" + + line.substr(0, columnNumber - 1) + + "\x1b[0m" + + "\u21A6 " + + line.substr(columnNumber - 1); + + const position = (lineNumber + ":" + columnNumber).padEnd(7); + logStep(`${position} \u007C ${code}`); + + // Disable builtin tracer logging + return false; +} + +function logStep(message) { + dump(` \x1b[2m[STEP]\x1b[0m ${message}\n`); +} + +const tracingListener = { + onTracingFrame: traceFrame, + onTracingFrameStep: traceFrame, +}; + +exports.start = function (testGlobal, testUrl, line) { + lineToTrace = line; + const tracerOptions = { + global: testGlobal, + // Ensure tracing each execution within functions (and not only function calls) + traceSteps: true, + // Only trace the running test and nothing else + filterFrameSourceUrl: testUrl, + }; + JSTracer.startTracing(tracerOptions); + JSTracer.addTracingListener(tracingListener); +}; + +exports.stop = function () { + JSTracer.stopTracing(); + JSTracer.removeTracingListener(tracingListener); +}; + +function readURI(uri) { + const { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs", + { global: "contextual" } + ); + const stream = NetUtil.newChannel({ + uri: NetUtil.newURI(uri, "UTF-8"), + loadUsingSystemPrincipal: true, + }).open(); + const count = stream.available(); + const data = NetUtil.readInputStreamToString(stream, count, { + charset: "UTF-8", + }); + + stream.close(); + return data; +} diff --git a/devtools/shared/test-helpers/test-stepper.js b/devtools/shared/test-helpers/test-stepper.js index 314a687dbf..856276db00 100644 --- a/devtools/shared/test-helpers/test-stepper.js +++ b/devtools/shared/test-helpers/test-stepper.js @@ -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) { |