builtin-modules.js (6735B)
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/. */ 4 5 "use strict"; 6 7 /** 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. 10 * 11 * Note that some globals are being defined by base-loader.sys.mjs via wantGlobalProperties property. 12 * 13 * As it does so, the module itself doesn't have access to these globals, 14 * nor the pseudo modules. Be careful to avoid loading any other js module as 15 * they would also miss them. 16 */ 17 18 const systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal(); 19 20 /** 21 * Defines a getter on a specified object that will be created upon first use. 22 * 23 * @param object 24 * The object to define the lazy getter on. 25 * @param name 26 * The name of the getter to define on object. 27 * @param lambda 28 * A function that returns what the getter should return. This will 29 * only ever be called once. 30 */ 31 function defineLazyGetter(object, name, lambda) { 32 Object.defineProperty(object, name, { 33 get() { 34 // Redefine this accessor property as a data property. 35 // Delete it first, to rule out "too much recursion" in case object is 36 // a proxy whose defineProperty handler might unwittingly trigger this 37 // getter again. 38 delete object[name]; 39 const value = lambda.apply(object); 40 Object.defineProperty(object, name, { 41 value, 42 writable: true, 43 configurable: true, 44 enumerable: true, 45 }); 46 return value; 47 }, 48 configurable: true, 49 enumerable: true, 50 }); 51 } 52 53 /** 54 * Defines a getter on a specified object for a service. The service will not 55 * be obtained until first use. 56 * 57 * @param object 58 * The object to define the lazy getter on. 59 * @param name 60 * The name of the getter to define on object for the service. 61 * @param contract 62 * The contract used to obtain the service. 63 * @param interfaceName 64 * The name of the interface to query the service to. 65 */ 66 function defineLazyServiceGetter(object, name, contract, interfaceName) { 67 defineLazyGetter(object, name, function () { 68 return Cc[contract].getService(Ci[interfaceName]); 69 }); 70 } 71 72 /** 73 * Define a getter property on the given object that requires the given 74 * module. This enables delaying importing modules until the module is 75 * actually used. 76 * 77 * Several getters can be defined at once by providing an array of 78 * properties and enabling destructuring. 79 * 80 * @param {object} obj 81 * The object to define the property on. 82 * @param {string | Array<string>} properties 83 * String: Name of the property for the getter. 84 * Array<String>: When destructure is true, properties can be an array of 85 * strings to create several getters at once. 86 * @param {string} module 87 * The module path. 88 * @param {boolean} destructure 89 * Pass true if the property name is a member of the module's exports. 90 */ 91 function lazyRequireGetter(obj, properties, module, destructure) { 92 if (Array.isArray(properties) && !destructure) { 93 throw new Error( 94 "Pass destructure=true to call lazyRequireGetter with an array of properties" 95 ); 96 } 97 98 if (!Array.isArray(properties)) { 99 properties = [properties]; 100 } 101 102 for (const property of properties) { 103 defineLazyGetter(obj, property, () => { 104 return destructure 105 ? require(module)[property] 106 : require(module || property); 107 }); 108 } 109 } 110 111 // List of pseudo modules exposed to all devtools modules. 112 exports.modules = { 113 HeapSnapshot, 114 // Expose "chrome" Promise, which aren't related to any document 115 // and so are never frozen, even if the browser loader module which 116 // pull it is destroyed. See bug 1402779. 117 Promise, 118 }; 119 120 defineLazyGetter(exports.modules, "Debugger", () => { 121 const global = Cu.getGlobalForObject(this); 122 // Debugger may already have been added. 123 if (global.Debugger) { 124 return global.Debugger; 125 } 126 const { addDebuggerToGlobal } = ChromeUtils.importESModule( 127 "resource://gre/modules/jsdebugger.sys.mjs", 128 { global: "contextual" } 129 ); 130 addDebuggerToGlobal(global); 131 return global.Debugger; 132 }); 133 134 defineLazyGetter(exports.modules, "ChromeDebugger", () => { 135 // Sandbox are memory expensive, so we should create as little as possible. 136 const debuggerSandbox = Cu.Sandbox(systemPrincipal, { 137 // This sandbox is used for the ChromeDebugger implementation. 138 // As we want to load the `Debugger` API for debugging chrome contexts, 139 // we have to ensure loading it in a distinct compartment from its debuggee. 140 freshCompartment: true, 141 }); 142 143 const { addDebuggerToGlobal } = ChromeUtils.importESModule( 144 "resource://gre/modules/jsdebugger.sys.mjs", 145 { global: "contextual" } 146 ); 147 addDebuggerToGlobal(debuggerSandbox); 148 return debuggerSandbox.Debugger; 149 }); 150 151 defineLazyGetter(exports.modules, "xpcInspector", () => { 152 return Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector); 153 }); 154 155 // List of all custom globals exposed to devtools modules. 156 // Changes here should be mirrored to devtools/.eslintrc. 157 exports.globals = { 158 isWorker: false, 159 loader: { 160 lazyGetter: defineLazyGetter, 161 lazyServiceGetter: defineLazyServiceGetter, 162 lazyRequireGetter, 163 // Defined by Loader.sys.mjs 164 id: null, 165 }, 166 }; 167 // DevTools loader copy globals property descriptors on each module global 168 // object so that we have to memoize them from here in order to instantiate each 169 // global only once. 170 // `globals` is a cache object on which we put all global values 171 // and we set getters on `exports.globals` returning `globals` values. 172 const globals = {}; 173 function lazyGlobal(name, getter) { 174 defineLazyGetter(globals, name, getter); 175 Object.defineProperty(exports.globals, name, { 176 get() { 177 return globals[name]; 178 }, 179 configurable: true, 180 enumerable: true, 181 }); 182 } 183 184 // Lazily define a few things so that the corresponding modules are only loaded 185 // when used. 186 lazyGlobal("clearTimeout", () => { 187 return ChromeUtils.importESModule("resource://gre/modules/Timer.sys.mjs", { 188 global: "contextual", 189 }).clearTimeout; 190 }); 191 lazyGlobal("setTimeout", () => { 192 return ChromeUtils.importESModule("resource://gre/modules/Timer.sys.mjs", { 193 global: "contextual", 194 }).setTimeout; 195 }); 196 lazyGlobal("clearInterval", () => { 197 return ChromeUtils.importESModule("resource://gre/modules/Timer.sys.mjs", { 198 global: "contextual", 199 }).clearInterval; 200 }); 201 lazyGlobal("setInterval", () => { 202 return ChromeUtils.importESModule("resource://gre/modules/Timer.sys.mjs", { 203 global: "contextual", 204 }).setInterval; 205 });