Bug 1566457 - Remove unused provider logic from Loader.jsm. r=jdescottes

We used to have another provider which would load module via file:// URI,
directly from the disk. But the progress on artifact builds and ./mach build faster
made this obsolete and has been removed a long time ago.
We still have a lot of abstraction to support this non-existent feature.

Differential Revision: https://phabricator.services.mozilla.com/D38284

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Alexandre Poirot 2019-07-18 12:25:05 +00:00
parent c9648fef81
commit 438498ee47
19 changed files with 178 additions and 235 deletions

View File

@ -11,8 +11,9 @@ var gClient, gThreadFront;
var gNewChromeSource = promise.defer();
var { DevToolsLoader } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
var customLoader = new DevToolsLoader();
customLoader.invisibleToDebugger = true;
var customLoader = new DevToolsLoader({
invisibleToDebugger: true,
});
var { DebuggerServer } = customLoader.require("devtools/server/main");
var { DebuggerClient } = require("devtools/shared/client/debugger-client");

View File

@ -118,8 +118,9 @@ BrowserToolboxProcess.prototype = {
// This allows us to safely use the tools against even the actors and
// DebuggingServer itself, especially since we can mark this loader as
// invisible to the debugger (unlike the usual loader settings).
this.loader = new DevToolsLoader();
this.loader.invisibleToDebugger = true;
this.loader = new DevToolsLoader({
invisibleToDebugger: true,
});
const { DebuggerServer } = this.loader.require("devtools/server/main");
const { SocketListener } = this.loader.require(
"devtools/shared/security/socket"

View File

@ -8,8 +8,9 @@ let tracker;
const { DevToolsLoader } = ChromeUtils.import(
"resource://devtools/shared/Loader.jsm"
);
const loader = new DevToolsLoader();
loader.invisibleToDebugger = true;
const loader = new DevToolsLoader({
invisibleToDebugger: true,
});
const { allocationTracker } = loader.require(
"chrome://mochitests/content/browser/devtools/shared/test-helpers/allocation-tracker"
);

View File

@ -80,8 +80,9 @@ async function testMainProcess() {
const { DevToolsLoader } = ChromeUtils.import(
"resource://devtools/shared/Loader.jsm"
);
const customLoader = new DevToolsLoader();
customLoader.invisibleToDebugger = true;
const customLoader = new DevToolsLoader({
invisibleToDebugger: true,
});
const { DebuggerServer } = customLoader.require("devtools/server/main");
const { DebuggerClient } = require("devtools/shared/client/debugger-client");

View File

@ -20,7 +20,7 @@ add_task(async function() {
// Retrieve the browser loader dedicated to the Debugger.
const debuggerLoader = panel.panelWin.getBrowserLoaderForWindow();
const loaders = [loader.provider.loader, debuggerLoader.loader];
const loaders = [loader.loader, debuggerLoader.loader];
runMetricsTest({
filterString: "devtools/client/debugger",

View File

@ -18,7 +18,7 @@ add_task(async function() {
await openNewTabAndToolbox(TEST_URL, "inspector");
// The inspector does not use a dedicated browser loader.
const loaders = [loader.provider.loader];
const loaders = [loader.loader];
runMetricsTest({
filterString: "devtools/client/inspector",

View File

@ -20,7 +20,7 @@ add_task(async function() {
// Retrieve the browser loader dedicated to the Netmonitor.
const netmonitorLoader = panel.panelWin.getBrowserLoaderForWindow();
const loaders = [loader.provider.loader, netmonitorLoader.loader];
const loaders = [loader.loader, netmonitorLoader.loader];
runMetricsTest({
filterString: "devtools/client/netmonitor",

View File

@ -20,7 +20,7 @@ add_task(async function() {
// Retrieve the browser loader dedicated to the WebConsole.
const webconsoleLoader = panel._frameWindow.getBrowserLoaderForWindow();
const loaders = [loader.provider.loader, webconsoleLoader.loader];
const loaders = [loader.loader, webconsoleLoader.loader];
runMetricsTest({
filterString: "devtools/client/webconsole",

View File

@ -25,8 +25,9 @@ if (DEBUG_ALLOCATIONS) {
const { DevToolsLoader } = ChromeUtils.import(
"resource://devtools/shared/Loader.jsm"
);
const loader = new DevToolsLoader();
loader.invisibleToDebugger = true;
const loader = new DevToolsLoader({
invisibleToDebugger: true,
});
const { allocationTracker } = loader.require(
"devtools/shared/test-helpers/allocation-tracker"

View File

@ -158,8 +158,9 @@ HUDService.prototype = {
const { DevToolsLoader } = ChromeUtils.import(
"resource://devtools/shared/Loader.jsm"
);
const loader = new DevToolsLoader();
loader.freshCompartment = true;
const loader = new DevToolsLoader({
freshCompartment: true,
});
const { DebuggerServer } = loader.require("devtools/server/main");
DebuggerServer.init();

View File

@ -32,8 +32,9 @@ function setupServer(mm) {
// Init a custom, invisible DebuggerServer, in order to not pollute the
// debugger with all devtools modules, nor break the debugger itself with
// using it in the same process.
gLoader = new DevToolsLoader();
gLoader.invisibleToDebugger = true;
gLoader = new DevToolsLoader({
invisibleToDebugger: true,
});
const { DebuggerServer } = gLoader.require("devtools/server/main");
DebuggerServer.init();

View File

@ -29,8 +29,9 @@ try {
const { DevToolsLoader } = ChromeUtils.import(
"resource://devtools/shared/Loader.jsm"
);
loader = new DevToolsLoader();
loader.invisibleToDebugger = true;
loader = new DevToolsLoader({
invisibleToDebugger: true,
});
customLoader = true;
} else {
// Otherwise, use the shared loader.

View File

@ -29,8 +29,9 @@ add_task(async function test() {
const { DevToolsLoader } = ChromeUtils.import(
"resource://devtools/shared/Loader.jsm"
);
const customLoader = new DevToolsLoader();
customLoader.invisibleToDebugger = true;
const customLoader = new DevToolsLoader({
invisibleToDebugger: true,
});
const { DebuggerServer } = customLoader.require("devtools/server/main");
DebuggerServer.init();

View File

@ -24,123 +24,135 @@ this.EXPORTED_SYMBOLS = [
"StructuredCloneHolder",
];
/**
* Providers are different strategies for loading the devtools.
*/
/**
* Used when the tools should be loaded from the Firefox package itself.
* This is the default case.
*/
function BuiltinProvider() {}
BuiltinProvider.prototype = {
load: function() {
const paths = {
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
devtools: "resource://devtools",
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
acorn: "resource://devtools/shared/acorn",
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
"acorn/util/walk": "resource://devtools/shared/acorn/walk.js",
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
// Allow access to xpcshell test items from the loader.
"xpcshell-test": "resource://test",
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
// Allow access to locale data using paths closer to what is
// used in the source tree.
"devtools/client/locales": "chrome://devtools/locale",
"devtools/shared/locales": "chrome://devtools-shared/locale",
"devtools/startup/locales": "chrome://devtools-startup/locale",
"toolkit/locales": "chrome://global/locale",
};
// When creating a Loader invisible to the Debugger, we have to ensure
// using only modules and not depend on any JSM. As everything that is
// not loaded with Loader isn't going to respect `invisibleToDebugger`.
// But we have to keep using Promise.jsm for other loader to prevent
// breaking unhandled promise rejection in tests.
if (this.invisibleToDebugger) {
paths.promise = "resource://gre/modules/Promise-backend.js";
}
this.loader = new Loader({
paths,
invisibleToDebugger: this.invisibleToDebugger,
freshCompartment: this.freshCompartment,
sandboxName: "DevTools (Module loader)",
requireHook: (id, require) => {
if (id.startsWith("raw!") || id.startsWith("theme-loader!")) {
return requireRawId(id, require);
}
return require(id);
},
});
},
unload: function(reason) {
unload(this.loader, reason);
delete this.loader;
},
};
var gNextLoaderID = 0;
/**
* The main devtools API. The standard instance of this loader is exported as
* |devtools| below, but if a fresh copy of the loader is needed, then a new
* |loader| below, but if a fresh copy of the loader is needed, then a new
* one can also be created.
*
* The two following boolean flags are used to control the sandboxes into
* which the modules are loaded.
* @param invisibleToDebugger boolean
* If true, the modules won't be visible by the Debugger API.
* This typically allows to hide server modules from the debugger panel.
* @param freshCompartment boolean
* If true, the modules will be forced to be loaded in a distinct
* compartment. It is typically used to load the modules in a distinct
* system compartment, different from the main one, which is shared by
* all JSMs, XPCOMs and modules loaded with this flag set to true.
* We use this in order to debug modules loaded in this shared system
* compartment. The debugger actor has to be running in a distinct
* compartment than the context it is debugging.
*/
this.DevToolsLoader = function DevToolsLoader() {
this.require = this.require.bind(this);
this.DevToolsLoader = function DevToolsLoader({
invisibleToDebugger = false,
freshCompartment = false,
} = {}) {
const paths = {
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
devtools: "resource://devtools",
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
acorn: "resource://devtools/shared/acorn",
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
"acorn/util/walk": "resource://devtools/shared/acorn/walk.js",
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
// Allow access to xpcshell test items from the loader.
"xpcshell-test": "resource://test",
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
// Allow access to locale data using paths closer to what is
// used in the source tree.
"devtools/client/locales": "chrome://devtools/locale",
"devtools/shared/locales": "chrome://devtools-shared/locale",
"devtools/startup/locales": "chrome://devtools-startup/locale",
"toolkit/locales": "chrome://global/locale",
};
// When creating a Loader invisible to the Debugger, we have to ensure
// using only modules and not depend on any JSM. As everything that is
// not loaded with Loader isn't going to respect `invisibleToDebugger`.
// But we have to keep using Promise.jsm for other loader to prevent
// breaking unhandled promise rejection in tests.
if (invisibleToDebugger) {
paths.promise = "resource://gre/modules/Promise-backend.js";
}
this.loader = new Loader({
paths,
invisibleToDebugger,
freshCompartment,
sandboxName: "DevTools (Module loader)",
requireHook: (id, require) => {
if (id.startsWith("raw!") || id.startsWith("theme-loader!")) {
return requireRawId(id, require);
}
return require(id);
},
});
this.require = Require(this.loader, { id: "devtools" });
// Fetch custom pseudo modules and globals
const { modules, globals } = this.require("devtools/shared/builtin-modules");
// When creating a Loader for the browser toolbox, we have to use
// Promise-backend.js, as a Loader module. Instead of Promise.jsm which
// can't be flagged as invisible to debugger.
if (invisibleToDebugger) {
delete modules.promise;
}
// Register custom pseudo modules to the current loader instance
for (const id in modules) {
const uri = resolveURI(id, this.loader.mapping);
this.loader.modules[uri] = {
get exports() {
return modules[id];
},
};
}
// Register custom globals to the current loader instance
Object.defineProperties(
this.loader.globals,
Object.getOwnPropertyDescriptors(globals)
);
// Define the loader id for these two usecases:
// * access via the JSM (this.id)
// let { loader } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
// loader.id
this.id = gNextLoaderID++;
// * access via module's `loader` global
// loader.id
globals.loader.id = this.id;
// Expose lazy helpers on `loader`
// ie. when you use it like that from a JSM:
// let { loader } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
// loader.lazyGetter(...);
this.lazyGetter = globals.loader.lazyGetter;
this.lazyImporter = globals.loader.lazyImporter;
this.lazyServiceGetter = globals.loader.lazyServiceGetter;
this.lazyRequireGetter = globals.loader.lazyRequireGetter;
// When replaying, modify the require hook to allow the ReplayInspector to
// replace chrome interfaces with alternatives that understand the proxies
// created for objects in the recording/replaying process.
if (globals.isReplaying) {
const oldHook = this.loader.requireHook;
const ReplayInspector = this.require(
"devtools/server/actors/replay/inspector"
);
this.loader.requireHook = ReplayInspector.wrapRequireHook(oldHook);
}
};
DevToolsLoader.prototype = {
destroy: function(reason = "shutdown") {
if (this._provider) {
this._provider.unload(reason);
delete this._provider;
}
},
get provider() {
if (!this._provider) {
this._loadProvider();
}
return this._provider;
},
_provider: null,
get id() {
if (this._id) {
return this._id;
}
this._id = ++gNextLoaderID;
return this._id;
},
/**
* A dummy version of require, in case a provider hasn't been chosen yet when
* this is first called. This will then be replaced by the real version.
* @see setProvider
*/
require: function() {
if (!this._provider) {
this._loadProvider();
}
return this.require.apply(this, arguments);
},
/**
* A dummy version of lazyRequireGetter, in case a provider hasn't been chosen yet when
* this is first called. This will then be replaced by the real version.
* @see setProvider
*/
lazyRequireGetter: function() {
if (!this._provider) {
this._loadProvider();
}
return this.lazyRequireGetter.apply(this, arguments);
unload(this.loader, reason);
delete this.loader;
},
/**
@ -150,85 +162,10 @@ DevToolsLoader.prototype = {
isLoaderPluginId: function(id) {
return id.startsWith("raw!");
},
};
/**
* Override the provider used to load the tools.
*/
setProvider: function(provider) {
if (provider === this._provider) {
return;
}
if (this._provider) {
delete this.require;
this._provider.unload("newprovider");
}
this._provider = provider;
// Pass through internal loader settings specific to this loader instance
this._provider.invisibleToDebugger = this.invisibleToDebugger;
this._provider.freshCompartment = this.freshCompartment;
this._provider.load();
this.require = Require(this._provider.loader, { id: "devtools" });
// Fetch custom pseudo modules and globals
const { modules, globals } = this.require(
"devtools/shared/builtin-modules"
);
// When creating a Loader for the browser toolbox, we have to use
// Promise-backend.js, as a Loader module. Instead of Promise.jsm which
// can't be flagged as invisible to debugger.
if (this.invisibleToDebugger) {
delete modules.promise;
}
// Register custom pseudo modules to the current loader instance
const loader = this._provider.loader;
for (const id in modules) {
const uri = resolveURI(id, loader.mapping);
loader.modules[uri] = {
get exports() {
return modules[id];
},
};
}
// Register custom globals to the current loader instance
globals.loader.id = this.id;
Object.defineProperties(
loader.globals,
Object.getOwnPropertyDescriptors(globals)
);
// Expose lazy helpers on loader
this.lazyGetter = globals.loader.lazyGetter;
this.lazyImporter = globals.loader.lazyImporter;
this.lazyServiceGetter = globals.loader.lazyServiceGetter;
this.lazyRequireGetter = globals.loader.lazyRequireGetter;
// When replaying, modify the require hook to allow the ReplayInspector to
// replace chrome interfaces with alternatives that understand the proxies
// created for objects in the recording/replaying process.
if (globals.isReplaying) {
const oldHook = this._provider.loader.requireHook;
const ReplayInspector = this.require(
"devtools/server/actors/replay/inspector"
);
this._provider.loader.requireHook = ReplayInspector.wrapRequireHook(
oldHook
);
}
},
/**
* Choose a default tools provider based on the preferences.
*/
_loadProvider: function() {
this.setProvider(new BuiltinProvider());
},
// Export the standard instance of DevToolsLoader used by the tools.
this.loader = new DevToolsLoader({
/**
* Sets whether the compartments loaded by this instance should be invisible
* to the debugger. Invisibility is needed for loaders that support debugging
@ -239,9 +176,6 @@ DevToolsLoader.prototype = {
* @see devtools/client/framework/ToolboxProcess.jsm
*/
invisibleToDebugger: Services.appinfo.name !== "Firefox",
};
// Export the standard instance of DevToolsLoader used by the tools.
this.loader = new DevToolsLoader();
});
this.require = this.loader.require;

View File

@ -9,9 +9,10 @@
const { DevToolsLoader } = ChromeUtils.import(
"resource://devtools/shared/Loader.jsm"
);
const loader = new DevToolsLoader();
loader.invisibleToDebugger = true;
loader.freshCompartment = true;
const loader = new DevToolsLoader({
invisibleToDebugger: true,
freshCompartment: true,
});
const { allocationTracker } = loader.require(
"chrome://mochitests/content/browser/devtools/shared/test-helpers/allocation-tracker"
);

View File

@ -17,6 +17,6 @@ function run_test() {
Assert.ok(indent1 !== indent2);
Assert.ok(loader1._provider !== loader2._provider);
Assert.ok(loader1._provider.loader !== loader2._provider.loader);
Assert.ok(loader1.loader !== loader2.loader);
Assert.ok(loader1.id !== loader2.id);
}

View File

@ -18,12 +18,13 @@ function run_test() {
}
function visible_loader() {
const loader = new DevToolsLoader();
loader.invisibleToDebugger = false;
const loader = new DevToolsLoader({
invisibleToDebugger: false,
});
loader.require("devtools/shared/indentation");
const dbg = new Debugger();
const sandbox = loader._provider.loader.sharedGlobalSandbox;
const sandbox = loader.loader.sharedGlobalSandbox;
try {
dbg.addDebuggee(sandbox);
@ -40,12 +41,13 @@ function visible_loader() {
}
function invisible_loader() {
const loader = new DevToolsLoader();
loader.invisibleToDebugger = true;
const loader = new DevToolsLoader({
invisibleToDebugger: true,
});
loader.require("devtools/shared/indentation");
const dbg = new Debugger();
const sandbox = loader._provider.loader.sharedGlobalSandbox;
const sandbox = loader.loader.sharedGlobalSandbox;
try {
dbg.addDebuggee(sandbox);
@ -59,8 +61,6 @@ function invisible_loader() {
// into it.
const promise = loader.require("promise");
const promiseModule =
loader._provider.loader.modules[
"resource://gre/modules/Promise-backend.js"
];
loader.loader.modules["resource://gre/modules/Promise-backend.js"];
Assert.equal(promise, promiseModule.exports);
}

View File

@ -3,16 +3,14 @@
"use strict";
const { devtools } = ChromeUtils.import(
"resource://devtools/shared/Loader.jsm"
);
const { loader } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
// Test devtools.lazyRequireGetter
function run_test() {
const name = "asyncUtils";
const path = "devtools/shared/async-utils";
const o = {};
devtools.lazyRequireGetter(o, name, path);
loader.lazyRequireGetter(o, name, path);
const asyncUtils = require(path);
// XXX: do_check_eq only works on primitive types, so we have this
// do_check_true of an equality expression.
@ -21,18 +19,18 @@ function run_test() {
// A non-main loader should get a new object via |lazyRequireGetter|, just
// as it would via a direct |require|.
const o2 = {};
const loader = new DevToolsLoader();
const loader2 = new DevToolsLoader();
// We have to init the loader by loading any module before
// lazyRequireGetter is available
loader.require("devtools/shared/DevToolsUtils");
loader2.require("devtools/shared/DevToolsUtils");
loader.lazyRequireGetter(o2, name, path);
loader2.lazyRequireGetter(o2, name, path);
Assert.ok(o2.asyncUtils !== asyncUtils);
// A module required via a non-main loader that then uses |lazyRequireGetter|
// should also get the same object from that non-main loader.
const exposeLoader = loader.require("xpcshell-test/exposeLoader");
const exposeLoader = loader2.require("xpcshell-test/exposeLoader");
const o3 = exposeLoader.exerciseLazyRequire(name, path);
Assert.ok(o3.asyncUtils === o2.asyncUtils);
}

View File

@ -1010,8 +1010,9 @@ DevToolsStartup.prototype = {
// actors and DebuggingServer itself, especially since we can mark
// serverLoader as invisible to the debugger (unlike the usual loader
// settings).
const serverLoader = new DevToolsLoader();
serverLoader.invisibleToDebugger = true;
const serverLoader = new DevToolsLoader({
invisibleToDebugger: true,
});
const { DebuggerServer: debuggerServer } = serverLoader.require(
"devtools/server/main"
);