jsdebugger.sys.mjs (3276B)
1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* 7 * This is the js module for Debugger. Import it like so: 8 * const { addDebuggerToGlobal } = ChromeUtils.importESModule( 9 * "resource://gre/modules/jsdebugger.sys.mjs" 10 * ); 11 * addDebuggerToGlobal(globalThis); 12 * 13 * This will create a 'Debugger' object, which provides an interface to debug 14 * JavaScript code running in other compartments in the same process, on the 15 * same thread. 16 * 17 * For documentation on the API, see: 18 * https://developer.mozilla.org/en-US/docs/Tools/Debugger-API 19 */ 20 21 const init = Cc["@mozilla.org/jsdebugger;1"].createInstance(Ci.IJSDebugger); 22 23 export function addDebuggerToGlobal(global) { 24 init.addClass(global); 25 initPromiseDebugging(global); 26 } 27 28 // Defines the Debugger in a sandbox global in a separate compartment. This 29 // ensures the debugger and debuggee are in different compartments. 30 export function addSandboxedDebuggerToGlobal(global) { 31 const sb = Cu.Sandbox(global, { freshCompartment: true }); 32 addDebuggerToGlobal(sb); 33 global.Debugger = sb.Debugger; 34 } 35 36 function initPromiseDebugging(global) { 37 if (global.Debugger.Object.prototype.PromiseDebugging) { 38 return; 39 } 40 41 // If the PromiseDebugging object doesn't have all legacy functions, we're 42 // using the new accessors on Debugger.Object already. 43 if (!PromiseDebugging.getDependentPromises) { 44 return; 45 } 46 47 // Otherwise, polyfill them using PromiseDebugging. 48 global.Debugger.Object.prototype.PromiseDebugging = PromiseDebugging; 49 global.eval(polyfillSource); 50 } 51 52 const polyfillSource = ` 53 Object.defineProperty(Debugger.Object.prototype, "promiseState", { 54 get() { 55 const state = this.PromiseDebugging.getState(this.unsafeDereference()); 56 return { 57 state: state.state, 58 value: this.makeDebuggeeValue(state.value), 59 reason: this.makeDebuggeeValue(state.reason) 60 }; 61 } 62 }); 63 Object.defineProperty(Debugger.Object.prototype, "promiseLifetime", { 64 get() { 65 return this.PromiseDebugging.getPromiseLifetime(this.unsafeDereference()); 66 } 67 }); 68 Object.defineProperty(Debugger.Object.prototype, "promiseTimeToResolution", { 69 get() { 70 return this.PromiseDebugging.getTimeToSettle(this.unsafeDereference()); 71 } 72 }); 73 Object.defineProperty(Debugger.Object.prototype, "promiseDependentPromises", { 74 get() { 75 let promises = this.PromiseDebugging.getDependentPromises(this.unsafeDereference()); 76 return promises.map(p => this.makeDebuggeeValue(p)); 77 } 78 }); 79 Object.defineProperty(Debugger.Object.prototype, "promiseAllocationSite", { 80 get() { 81 return this.PromiseDebugging.getAllocationStack(this.unsafeDereference()); 82 } 83 }); 84 Object.defineProperty(Debugger.Object.prototype, "promiseResolutionSite", { 85 get() { 86 let state = this.promiseState.state; 87 if (state === "fulfilled") { 88 return this.PromiseDebugging.getFullfillmentStack(this.unsafeDereference()); 89 } else { 90 return this.PromiseDebugging.getRejectionStack(this.unsafeDereference()); 91 } 92 } 93 }); 94 `;