summaryrefslogtreecommitdiffstats
path: root/devtools/server/actors/tracer.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server/actors/tracer.js')
-rw-r--r--devtools/server/actors/tracer.js154
1 files changed, 131 insertions, 23 deletions
diff --git a/devtools/server/actors/tracer.js b/devtools/server/actors/tracer.js
index 028d084584..bf759cee5f 100644
--- a/devtools/server/actors/tracer.js
+++ b/devtools/server/actors/tracer.js
@@ -129,29 +129,40 @@ class TracerActor extends Actor {
this.tracingListener = {
onTracingFrame: this.onTracingFrame.bind(this),
+ onTracingFrameStep: this.onTracingFrameStep.bind(this),
onTracingFrameExit: this.onTracingFrameExit.bind(this),
onTracingInfiniteLoop: this.onTracingInfiniteLoop.bind(this),
onTracingToggled: this.onTracingToggled.bind(this),
onTracingPending: this.onTracingPending.bind(this),
+ onTracingDOMMutation: this.onTracingDOMMutation.bind(this),
};
addTracingListener(this.tracingListener);
this.traceValues = !!options.traceValues;
- startTracing({
- global: this.targetActor.window || this.targetActor.workerGlobal,
- prefix: options.prefix || "",
- // Enable receiving the `currentDOMEvent` being passed to `onTracingFrame`
- traceDOMEvents: true,
- // Enable tracing function arguments as well as returned values
- traceValues: !!options.traceValues,
- // Enable tracing only on next user interaction
- traceOnNextInteraction: !!options.traceOnNextInteraction,
- // Notify about frame exit / function call returning
- traceFunctionReturn: !!options.traceFunctionReturn,
- // Ignore frames beyond the given depth
- maxDepth: options.maxDepth,
- // Stop the tracing after a number of top level frames
- maxRecords: options.maxRecords,
- });
+ try {
+ startTracing({
+ global: this.targetActor.window || this.targetActor.workerGlobal,
+ prefix: options.prefix || "",
+ // Enable receiving the `currentDOMEvent` being passed to `onTracingFrame`
+ traceDOMEvents: true,
+ // Enable tracing DOM Mutations
+ traceDOMMutations: options.traceDOMMutations,
+ // Enable tracing function arguments as well as returned values
+ traceValues: !!options.traceValues,
+ // Enable tracing only on next user interaction
+ traceOnNextInteraction: !!options.traceOnNextInteraction,
+ // Notify about frame exit / function call returning
+ traceFunctionReturn: !!options.traceFunctionReturn,
+ // Ignore frames beyond the given depth
+ maxDepth: options.maxDepth,
+ // Stop the tracing after a number of top level frames
+ maxRecords: options.maxRecords,
+ });
+ } catch (e) {
+ // If startTracing throws, it probably rejected one of its options and we should
+ // unregister the tracing listener.
+ this.stopTracing();
+ throw e;
+ }
}
stopTracing() {
@@ -188,12 +199,10 @@ class TracerActor extends Actor {
*
* @param {Boolean} enabled
* True if the tracer starts tracing, false it it stops.
- * @param {String} reason
- * Optional string to justify why the tracer stopped.
* @return {Boolean}
* Return true, if the JavaScriptTracer should log a message to stdout.
*/
- onTracingToggled(enabled, reason) {
+ onTracingToggled(enabled) {
// stopTracing will clear `logMethod`, so compute this before calling it.
const shouldLogToStdout = this.logMethod == LOG_METHODS.STDOUT;
@@ -266,11 +275,111 @@ class TracerActor extends Actor {
}
/**
+ * Called by JavaScriptTracer class when a new mutation happened on any DOM Element.
+ *
+ * @param {Object} options
+ * @param {Number} options.depth
+ * Represents the depth of the frame in the call stack.
+ * @param {String} options.prefix
+ * A string to be displayed as a prefix of any logged frame.
+ * @param {nsIStackFrame} options.caller
+ * The JS Callsite which caused this mutation.
+ * @param {String} options.type
+ * Type of DOM Mutation:
+ * - "add": Node being added,
+ * - "attributes": Node whose attributes changed,
+ * - "remove": Node being removed,
+ * @param {DOMNode} options.element
+ * The DOM Node related to the current mutation.
+ */
+ onTracingDOMMutation({ depth, prefix, type, caller, element }) {
+ // Delegate to JavaScriptTracer to log to stdout
+ if (this.logMethod == LOG_METHODS.STDOUT) {
+ return true;
+ }
+
+ if (this.logMethod == LOG_METHODS.CONSOLE) {
+ const dbgObj = makeDebuggeeValue(this.targetActor, element);
+ this.throttledTraces.push({
+ resourceType: JSTRACER_TRACE,
+ prefix,
+ timeStamp: ChromeUtils.dateNow(),
+
+ filename: caller?.filename,
+ lineNumber: caller?.lineNumber,
+ columnNumber: caller?.columnNumber,
+ sourceId: caller.sourceId,
+
+ depth,
+ mutationType: type,
+ mutationElement: createValueGripForTarget(this.targetActor, dbgObj),
+ });
+ this.throttleEmitTraces();
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * Called by JavaScriptTracer class on each step of a function call.
+ *
+ * @param {Object} options
+ * @param {Debugger.Frame} options.frame
+ * A descriptor object for the JavaScript frame.
+ * @param {Number} options.depth
+ * Represents the depth of the frame in the call stack.
+ * @param {String} options.prefix
+ * A string to be displayed as a prefix of any logged frame.
+ * @return {Boolean}
+ * Return true, if the JavaScriptTracer should log the step to stdout.
+ */
+ onTracingFrameStep({ frame, depth, prefix }) {
+ const { script } = frame;
+ const { lineNumber, columnNumber } = script.getOffsetMetadata(frame.offset);
+ const url = script.source.url;
+
+ // NOTE: Debugger.Script.prototype.getOffsetMetadata returns
+ // columnNumber in 1-based.
+ // Convert to 0-based, while keeping the wasm's column (1) as is.
+ // (bug 1863878)
+ const columnBase = script.format === "wasm" ? 0 : 1;
+
+ // Ignore blackboxed sources
+ if (
+ this.sourcesManager.isBlackBoxed(
+ url,
+ lineNumber,
+ columnNumber - columnBase
+ )
+ ) {
+ return false;
+ }
+
+ if (this.logMethod == LOG_METHODS.STDOUT) {
+ // By returning true, we let JavaScriptTracer class log the message to stdout.
+ return true;
+ }
+
+ if (this.logMethod == LOG_METHODS.CONSOLE) {
+ this.throttledTraces.push({
+ resourceType: JSTRACER_TRACE,
+ prefix,
+ timeStamp: ChromeUtils.dateNow(),
+
+ depth,
+ filename: url,
+ lineNumber,
+ columnNumber: columnNumber - columnBase,
+ sourceId: script.source.id,
+ });
+ this.throttleEmitTraces();
+ }
+
+ return false;
+ }
+ /**
* Called by JavaScriptTracer class when a new JavaScript frame is executed.
*
- * @param {Number} frameId
- * Unique identifier for the current frame.
- * This should match a frame notified via onTracingFrameExit.
* @param {Debugger.Frame} frame
* A descriptor object for the JavaScript frame.
* @param {Number} depth
@@ -287,7 +396,6 @@ class TracerActor extends Actor {
* Return true, if the JavaScriptTracer should log the frame to stdout.
*/
onTracingFrame({
- frameId,
frame,
depth,
formatedDisplayName,