1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 * This module defines custom globals injected in all our modules and also
9 * pseudo modules that aren't separate files but just dynamically set values.
11 * As it does so, the module itself doesn't have access to these globals,
12 * nor the pseudo modules. Be careful to avoid loading any other js module as
13 * they would also miss them.
16 const { Cu, Cc, Ci } = require("chrome");
17 const promise = require("resource://gre/modules/Promise.jsm").Promise;
18 const jsmScope = require("resource://devtools/shared/Loader.jsm");
19 const { Services } = require("resource://gre/modules/Services.jsm");
21 const systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
23 // Steal various globals only available in JSM scope (and not Sandbox one)
27 DebuggerNotificationObserver,
34 StructuredCloneHolder,
36 } = Cu.getGlobalForObject(jsmScope);
38 // Create a single Sandbox to access global properties needed in this module.
39 // Sandbox are memory expensive, so we should create as little as possible.
40 const debuggerSandbox = Cu.Sandbox(systemPrincipal, {
41 // This sandbox is also reused for ChromeDebugger implementation.
42 // As we want to load the `Debugger` API for debugging chrome contexts,
43 // we have to ensure loading it in a distinct compartment from its debuggee.
44 freshCompartment: true,
46 wantGlobalProperties: [
90 * Defines a getter on a specified object that will be created upon first use.
93 * The object to define the lazy getter on.
95 * The name of the getter to define on object.
97 * A function that returns what the getter should return. This will
98 * only ever be called once.
100 function defineLazyGetter(object, name, lambda) {
101 Object.defineProperty(object, name, {
103 // Redefine this accessor property as a data property.
104 // Delete it first, to rule out "too much recursion" in case object is
105 // a proxy whose defineProperty handler might unwittingly trigger this
108 const value = lambda.apply(object);
109 Object.defineProperty(object, name, {
123 * Defines a getter on a specified object for a service. The service will not
124 * be obtained until first use.
127 * The object to define the lazy getter on.
129 * The name of the getter to define on object for the service.
131 * The contract used to obtain the service.
132 * @param interfaceName
133 * The name of the interface to query the service to.
135 function defineLazyServiceGetter(object, name, contract, interfaceName) {
136 defineLazyGetter(object, name, function() {
137 return Cc[contract].getService(Ci[interfaceName]);
142 * Defines a getter on a specified object for a module. The module will not
143 * be imported until first use. The getter allows to execute setup and
144 * teardown code (e.g. to register/unregister to services) and accepts
145 * a proxy object which acts on behalf of the module until it is imported.
148 * The object to define the lazy getter on.
150 * The name of the getter to define on object for the module.
152 * The URL used to obtain the module.
154 * The name of the symbol exported by the module.
155 * This parameter is optional and defaults to name.
157 * A function that is executed when the proxy is set up.
158 * This will only ever be called once.
160 * A function that is executed when the module has been imported to
161 * run optional teardown procedures on the proxy object.
162 * This will only ever be called once.
164 * An object which acts on behalf of the module to be imported until
165 * the module has been imported.
167 function defineLazyModuleGetter(
178 if (typeof preLambda === "function") {
179 preLambda.apply(proxy);
182 defineLazyGetter(object, name, function() {
185 temp = ChromeUtils.import(resource);
187 if (typeof postLambda === "function") {
188 postLambda.apply(proxy);
191 Cu.reportError("Failed to load module " + resource + ".");
194 return temp[symbol || name];
199 * Define a getter property on the given object that requires the given
200 * module. This enables delaying importing modules until the module is
204 * The object to define the property on.
205 * @param String property
207 * @param String module
209 * @param Boolean destructure
210 * Pass true if the property name is a member of the module's exports.
212 function lazyRequireGetter(obj, property, module, destructure) {
213 Object.defineProperty(obj, property, {
215 // Redefine this accessor property as a data property.
216 // Delete it first, to rule out "too much recursion" in case obj is
217 // a proxy whose defineProperty handler might unwittingly trigger this
219 delete obj[property];
220 const value = destructure
221 ? require(module)[property]
222 : require(module || property);
223 Object.defineProperty(obj, property, {
236 // List of pseudo modules exposed to all devtools modules.
239 DebuggerNotificationObserver,
242 // Expose "chrome" Promise, which aren't related to any document
243 // and so are never frozen, even if the browser loader module which
244 // pull it is destroyed. See bug 1402779.
246 Services: Object.create(Services),
250 defineLazyGetter(exports.modules, "Debugger", () => {
251 const global = Cu.getGlobalForObject(this);
252 // Debugger may already have been added.
253 if (global.Debugger) {
254 return global.Debugger;
256 const { addDebuggerToGlobal } = ChromeUtils.import(
257 "resource://gre/modules/jsdebugger.jsm"
259 addDebuggerToGlobal(global);
260 return global.Debugger;
263 defineLazyGetter(exports.modules, "ChromeDebugger", () => {
264 const { addDebuggerToGlobal } = ChromeUtils.import(
265 "resource://gre/modules/jsdebugger.jsm"
267 addDebuggerToGlobal(debuggerSandbox);
268 return debuggerSandbox.Debugger;
271 defineLazyGetter(exports.modules, "InspectorUtils", () => {
272 return InspectorUtils;
275 defineLazyGetter(exports.modules, "Timer", () => {
279 } = require("resource://gre/modules/Timer.jsm");
280 // Do not return Cu.import result, as DevTools loader would freeze Timer.jsm globals...
287 defineLazyGetter(exports.modules, "xpcInspector", () => {
288 return Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
291 // List of all custom globals exposed to devtools modules.
292 // Changes here should be mirrored to devtools/.eslintrc.
300 // Make sure `define` function exists. This allows defining some modules
301 // in AMD format while retaining CommonJS compatibility through this hook.
302 // JSON Viewer needs modules in AMD format, as it currently uses RequireJS
303 // from a content document and can't access our usual loaders. So, any
304 // modules shared with the JSON Viewer should include a define wrapper:
306 // // Make this available to both AMD and CJS environments
307 // define(function(require, exports, module) {
311 // Bug 1248830 will work out a better plan here for our content module
312 // loading needs, especially as we head towards devtools.html.
314 factory(this.require, this.exports, this.module);
327 lazyGetter: defineLazyGetter,
328 lazyImporter: defineLazyModuleGetter,
329 lazyServiceGetter: defineLazyServiceGetter,
330 lazyRequireGetter: lazyRequireGetter,
331 // Defined by Loader.jsm
335 reportError: Cu.reportError,
336 StructuredCloneHolder,
342 // DevTools loader copy globals property descriptors on each module global
343 // object so that we have to memoize them from here in order to instantiate each
345 // `globals` is a cache object on which we put all global values
346 // and we set getters on `exports.globals` returning `globals` values.
348 function lazyGlobal(name, getter) {
349 defineLazyGetter(globals, name, getter);
350 Object.defineProperty(exports.globals, name, {
352 return globals[name];
359 // Lazily define a few things so that the corresponding jsms are only loaded
361 lazyGlobal("clearTimeout", () => {
362 return require("resource://gre/modules/Timer.jsm").clearTimeout;
364 lazyGlobal("setTimeout", () => {
365 return require("resource://gre/modules/Timer.jsm").setTimeout;
367 lazyGlobal("clearInterval", () => {
368 return require("resource://gre/modules/Timer.jsm").clearInterval;
370 lazyGlobal("setInterval", () => {
371 return require("resource://gre/modules/Timer.jsm").setInterval;
373 lazyGlobal("WebSocket", () => {
374 return Services.appShell.hiddenDOMWindow.WebSocket;
376 lazyGlobal("indexedDB", () => {
377 return require("devtools/shared/indexed-db").createDevToolsIndexedDB(
382 const inspectorGlobals = {
387 for (const [name, value] of Object.entries(inspectorGlobals)) {
388 lazyGlobal(name, () => {