diff options
Diffstat (limited to '')
-rw-r--r-- | devtools/platform/jsdebugger.sys.mjs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/devtools/platform/jsdebugger.sys.mjs b/devtools/platform/jsdebugger.sys.mjs new file mode 100644 index 0000000000..a4af1fdbc3 --- /dev/null +++ b/devtools/platform/jsdebugger.sys.mjs @@ -0,0 +1,94 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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/. */ + +/* + * This is the js module for Debugger. Import it like so: + * const { addDebuggerToGlobal } = ChromeUtils.importESModule( + * "resource://gre/modules/jsdebugger.sys.mjs" + * ); + * addDebuggerToGlobal(globalThis); + * + * This will create a 'Debugger' object, which provides an interface to debug + * JavaScript code running in other compartments in the same process, on the + * same thread. + * + * For documentation on the API, see: + * https://developer.mozilla.org/en-US/docs/Tools/Debugger-API + */ + +const init = Cc["@mozilla.org/jsdebugger;1"].createInstance(Ci.IJSDebugger); + +export function addDebuggerToGlobal(global) { + init.addClass(global); + initPromiseDebugging(global); +} + +// Defines the Debugger in a sandbox global in a separate compartment. This +// ensures the debugger and debuggee are in different compartments. +export function addSandboxedDebuggerToGlobal(global) { + const sb = Cu.Sandbox(global, { freshCompartment: true }); + addDebuggerToGlobal(sb); + global.Debugger = sb.Debugger; +} + +function initPromiseDebugging(global) { + if (global.Debugger.Object.prototype.PromiseDebugging) { + return; + } + + // If the PromiseDebugging object doesn't have all legacy functions, we're + // using the new accessors on Debugger.Object already. + if (!PromiseDebugging.getDependentPromises) { + return; + } + + // Otherwise, polyfill them using PromiseDebugging. + global.Debugger.Object.prototype.PromiseDebugging = PromiseDebugging; + global.eval(polyfillSource); +} + +const polyfillSource = ` + Object.defineProperty(Debugger.Object.prototype, "promiseState", { + get() { + const state = this.PromiseDebugging.getState(this.unsafeDereference()); + return { + state: state.state, + value: this.makeDebuggeeValue(state.value), + reason: this.makeDebuggeeValue(state.reason) + }; + } + }); + Object.defineProperty(Debugger.Object.prototype, "promiseLifetime", { + get() { + return this.PromiseDebugging.getPromiseLifetime(this.unsafeDereference()); + } + }); + Object.defineProperty(Debugger.Object.prototype, "promiseTimeToResolution", { + get() { + return this.PromiseDebugging.getTimeToSettle(this.unsafeDereference()); + } + }); + Object.defineProperty(Debugger.Object.prototype, "promiseDependentPromises", { + get() { + let promises = this.PromiseDebugging.getDependentPromises(this.unsafeDereference()); + return promises.map(p => this.makeDebuggeeValue(p)); + } + }); + Object.defineProperty(Debugger.Object.prototype, "promiseAllocationSite", { + get() { + return this.PromiseDebugging.getAllocationStack(this.unsafeDereference()); + } + }); + Object.defineProperty(Debugger.Object.prototype, "promiseResolutionSite", { + get() { + let state = this.promiseState.state; + if (state === "fulfilled") { + return this.PromiseDebugging.getFullfillmentStack(this.unsafeDereference()); + } else { + return this.PromiseDebugging.getRejectionStack(this.unsafeDereference()); + } + } + }); +`; |