Bug 1323845: Part 2c - Lazy init API global only when APIs are first loaded. r?aswan
MozReview-Commit-ID: B1bbiM0j5gT
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -655,16 +655,17 @@ this.ExtensionData = class {
}
this.manifest = manifestData.manifest;
this.apiNames = manifestData.apiNames;
this.dependencies = manifestData.dependencies;
this.permissions = manifestData.permissions;
this.type = manifestData.type;
+ await this.apiManager.lazyInit();
this.webAccessibleResources = manifestData.webAccessibleResources.map(res => new MatchGlob(res));
this.whiteListedHosts = new MatchPatternSet(manifestData.originPermissions);
return this.manifest;
}
localizeMessage(...args) {
return this.localeData.localizeMessage(...args);
--- a/toolkit/components/extensions/ExtensionCommon.jsm
+++ b/toolkit/components/extensions/ExtensionCommon.jsm
@@ -940,17 +940,16 @@ class SchemaAPIManager extends EventEmit
* "content" - A content process.
* "devtools" - A devtools process.
* "proxy" - A proxy script process.
* @param {SchemaRoot} schema
*/
constructor(processType, schema) {
super();
this.processType = processType;
- this.global = this._createExtGlobal();
this.schema = schema;
this.modules = new Map();
this.modulePaths = {children: new Map(), modules: new Set()};
this.manifestKeys = new Map();
this.eventModules = new DefaultMap(() => new Set());
this._modulesJSONLoaded = false;
@@ -1178,16 +1177,18 @@ class SchemaAPIManager extends EventEmit
loadModule(name) {
let module = this.modules.get(name);
if (module.loaded) {
return this.global[name];
}
this._checkLoadModule(module, name);
+ this.initGlobal();
+
Services.scriptloader.loadSubScript(module.url, this.global, "UTF-8");
module.loaded = true;
return this.global[name];
}
/**
* aSynchronously loads an API module, if not already loaded, and
@@ -1205,16 +1206,17 @@ class SchemaAPIManager extends EventEmit
}
if (module.asyncLoaded) {
return module.asyncLoaded;
}
this._checkLoadModule(module, name);
module.asyncLoaded = ChromeUtils.compileScript(module.url).then(script => {
+ this.initGlobal();
script.executeInGlobal(this.global);
module.loaded = true;
return this.global[name];
});
return module.asyncLoaded;
@@ -1259,17 +1261,17 @@ class SchemaAPIManager extends EventEmit
_checkLoadModule(module, name) {
if (!module) {
throw new Error(`Module '${name}' does not exist`);
}
if (module.asyncLoaded) {
throw new Error(`Module '${name}' currently being lazily loaded`);
}
- if (this.global[name]) {
+ if (this.global && this.global[name]) {
throw new Error(`Module '${name}' conflicts with existing global property`);
}
}
/**
* Create a global object that is used as the shared global for all ext-*.js
* scripts that are loaded via `loadScript`.
@@ -1307,16 +1309,22 @@ class SchemaAPIManager extends EventEmit
XPCOMUtils.defineLazyModuleGetters(global, {
ExtensionUtils: "resource://gre/modules/ExtensionUtils.jsm",
XPCOMUtils: "resource://gre/modules/XPCOMUtils.jsm",
});
return global;
}
+ initGlobal() {
+ if (!this.global) {
+ this.global = this._createExtGlobal();
+ }
+ }
+
/**
* Load an ext-*.js script. The script runs in its own scope, if it wishes to
* share state with another script it can assign to the `global` variable. If
* it wishes to communicate with this API manager, use `extensions`.
*
* @param {string} scriptUrl The URL of the ext-*.js script.
*/
loadScript(scriptUrl) {
--- a/toolkit/components/extensions/ExtensionPageChild.jsm
+++ b/toolkit/components/extensions/ExtensionPageChild.jsm
@@ -68,32 +68,34 @@ var apiManager = new class extends Schem
constructor() {
super("addon", Schemas);
this.initialized = false;
}
lazyInit() {
if (!this.initialized) {
this.initialized = true;
+ this.initGlobal();
for (let [/* name */, value] of XPCOMUtils.enumerateCategoryEntries(CATEGORY_EXTENSION_SCRIPTS_ADDON)) {
this.loadScript(value);
}
}
}
}();
var devtoolsAPIManager = new class extends SchemaAPIManager {
constructor() {
super("devtools", Schemas);
this.initialized = false;
}
lazyInit() {
if (!this.initialized) {
this.initialized = true;
+ this.initGlobal();
for (let [/* name */, value] of XPCOMUtils.enumerateCategoryEntries(CATEGORY_EXTENSION_SCRIPTS_DEVTOOLS)) {
this.loadScript(value);
}
}
}
}();
class ExtensionBaseContextChild extends BaseContext {
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -130,16 +130,17 @@ let apiManager = new class extends Schem
scriptURLs.push(value);
}
let promise = (async () => {
let scripts = await Promise.all(scriptURLs.map(url => ChromeUtils.compileScript(url)));
this.initModuleData(await modulesPromise);
+ this.initGlobal();
for (let script of scripts) {
script.executeInGlobal(this.global);
}
// Load order matters here. The base manifest defines types which are
// extended by other schemas, so needs to be loaded first.
return Schemas.load(BASE_SCHEMA, AppConstants.DEBUG).then(() => {
let promises = [];