Files
firefox/devtools/server/actors/utils/make-debugger.js
T
Alexandre Poirot ed2309ecf6 Bug 1616524 - [devtools] Revise eager evaluation implementation. r=devtools-reviewers,nchevobbe
There is no need to add all global to the side effect free Debugger.
We should only add the evaluation context globals.
In the typical case it will be the target global.
But for content process targets, it may be multiple globals, which we all need to register.

Also ensure clearing onNativeCall callback to be really sure this is disabled,
even if the Debugger is leaked for some unexpected reason.
Having this listener set may drastically slow down executions by disabling the JIT.
There was no known scenarios where it happened, but it is to be extra safe.

Also simplified a few things in evalWithDebugger as eslint started complaining about its complexity.

Differential Revision: https://phabricator.services.mozilla.com/D195021
2023-12-02 08:07:14 +00:00

123 lines
4.3 KiB
JavaScript

/* 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 EventEmitter = require("resource://devtools/shared/event-emitter.js");
const Debugger = require("Debugger");
const {
reportException,
} = require("resource://devtools/shared/DevToolsUtils.js");
/**
* Multiple actors that use a |Debugger| instance come in a few versions, each
* with a different set of debuggees. One version for content tabs (globals
* within a tab), one version for chrome debugging (all globals), and sometimes
* a third version for addon debugging (chrome globals the addon is loaded in
* and content globals the addon injects scripts into). The |makeDebugger|
* function helps us avoid repeating the logic for finding and maintaining the
* correct set of globals for a given |Debugger| instance across each version of
* all of our actors.
*
* The |makeDebugger| function expects a single object parameter with the
* following properties:
*
* @param Function findDebuggees
* Called with one argument: a |Debugger| instance. This function should
* return an iterable of globals to be added to the |Debugger|
* instance. The globals are the actual global objects and aren't wrapped
* in in a |Debugger.Object|.
*
* @param Function shouldAddNewGlobalAsDebuggee
* Called with one argument: a |Debugger.Object| wrapping a global
* object. This function must return |true| if the global object should
* be added as debuggee, and |false| otherwise.
*
* @returns Debugger
* Returns a |Debugger| instance that can manage its set of debuggee
* globals itself and is decorated with the |EventEmitter| class.
*
* Existing |Debugger| properties set on the returned |Debugger|
* instance:
*
* - onNewGlobalObject: The |Debugger| will automatically add new
* globals as debuggees if calling |shouldAddNewGlobalAsDebuggee|
* with the global returns true.
*
* - uncaughtExceptionHook: The |Debugger| already has an error
* reporter attached to |uncaughtExceptionHook|, so if any
* |Debugger| hooks fail, the error will be reported.
*
* New properties set on the returned |Debugger| instance:
*
* - addDebuggees: A function which takes no arguments. It adds all
* current globals that should be debuggees (as determined by
* |findDebuggees|) to the |Debugger| instance.
*/
module.exports = function makeDebugger({
findDebuggees,
shouldAddNewGlobalAsDebuggee,
} = {}) {
const dbg = new Debugger();
EventEmitter.decorate(dbg);
// By default, we disable asm.js and WASM debugging because of performance reason.
// Enabling asm.js debugging (allowUnobservedAsmJS=false) will make asm.js fallback to JS compiler
// and be debugging as a regular JS script.
dbg.allowUnobservedAsmJS = true;
// Enabling WASM debugging (allowUnobservedWasm=false) will make the engine compile WASM scripts
// into different machine code with debugging instructions. This significantly increase the memory usage of it.
dbg.allowUnobservedWasm = true;
dbg.uncaughtExceptionHook = reportDebuggerHookException;
const onNewGlobalObject = function (global) {
if (shouldAddNewGlobalAsDebuggee(global)) {
safeAddDebuggee(this, global);
}
};
dbg.onNewGlobalObject = onNewGlobalObject;
dbg.addDebuggees = function () {
for (const global of findDebuggees(this)) {
safeAddDebuggee(this, global);
}
};
dbg.disable = function () {
dbg.removeAllDebuggees();
dbg.onNewGlobalObject = undefined;
};
dbg.enable = function () {
dbg.addDebuggees();
dbg.onNewGlobalObject = onNewGlobalObject;
};
dbg.findDebuggees = function () {
return findDebuggees(dbg);
};
return dbg;
};
const reportDebuggerHookException = e => reportException("DBG-SERVER", e);
/**
* Add |global| as a debuggee to |dbg|, handling error cases.
*/
function safeAddDebuggee(dbg, global) {
let globalDO;
try {
globalDO = dbg.addDebuggee(global);
} catch (e) {
// Ignoring attempt to add the debugger's compartment as a debuggee.
return;
}
if (dbg.onNewDebuggee) {
dbg.onNewDebuggee(globalDO);
}
}