diff options
Diffstat (limited to 'tools/addon-sdk-1.3/packages/api-utils/lib/e10s.js')
-rw-r--r-- | tools/addon-sdk-1.3/packages/api-utils/lib/e10s.js | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/tools/addon-sdk-1.3/packages/api-utils/lib/e10s.js b/tools/addon-sdk-1.3/packages/api-utils/lib/e10s.js new file mode 100644 index 0000000..4a9acd8 --- /dev/null +++ b/tools/addon-sdk-1.3/packages/api-utils/lib/e10s.js @@ -0,0 +1,245 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma <atul@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +let {Cc, Ci, Cr} = require('chrome'); + +let url = require("./url"); +let file = require("./file"); +let errors = require("./errors"); + +let jetpackService = Cc["@mozilla.org/jetpack/service;1"] + .getService(Ci.nsIJetpackService); + +function AddonProcess(jetpack) { + var syncListeners = {}; + + this.on = function(name, cb) { + jetpack.registerReceiver(name, function() { + try { + // Intentionally do not return the return value of + // the function; we want developers to use registerCall() for that. + cb.apply(undefined, arguments); + } catch (e) { + console.exception(e); + } + }); + }; + + this.registerCall = function(name, cb) { + if (name in syncListeners) + throw new Error("call already registered for '" + name + "'"); + syncListeners[name] = true; + jetpack.registerReceiver(name, errors.catchAndReturn(cb)); + }; + + this.send = function() { + return jetpack.sendMessage.apply(this, arguments); + }; + + this.createHandle = function() { + return jetpack.createHandle(); + }; + + this.destroy = function() { + try { + jetpack.destroy(); + } catch (e if e.result == Cr.NS_ERROR_NOT_INITIALIZED) {} + }; +} + +function makeScriptFrom(fs, moduleURL) { + // TODO: Why can't we just return fs.getFile(moduleURL) here? + return { + filename: moduleURL, + contents: fs.getFile(moduleURL).contents + }; +} + +var defaultConsole = console; + +exports.AddonProcess = function createAddonProcess(options) { + if (!options) + options = {}; + + var jetpack = jetpackService.createJetpack(); + var process = new AddonProcess(jetpack); + var registeredModules = {}; + + var console = options.console || defaultConsole; + var pkg = options.packaging || packaging; + + // Whenever our add-on is disabled or uninstalled, we want to + // destroy the remote process. + + require("./unload").when(function() { + process.destroy(); + process = null; + }); + + // Set up message receivers that the remote process will use to + // communicate with us. + + ['log', 'debug', 'info', 'warn', 'error'].forEach(function(method) { + process.on("console:" + method, function(name, args) { + console[method].apply(console, args); + }); + }); + + function remoteException(exception) { + return { + toString: function toString() { + return "Error: " + this.message; + }, + __proto__: exception + }; + } + + process.on("quit", function(name, status) { + if (options.quit) + options.quit(status); + }); + + process.on("console:trace", function(name, exception) { + var traceback = require("./traceback"); + var stack = traceback.fromException(remoteException(exception)); + console.log(traceback.format(stack.slice(0, -2))); + }); + + process.on("console:exception", function(name, exception) { + console.exception(remoteException(exception)); + }); + + jetpack.registerReceiver("dump", function(name, msg) { + dump(msg); + }); + + jetpack.registerReceiver( + "core:exception", + function(name, exception) { + console.log("An exception occurred in the child Jetpack process."); + console.exception(remoteException(exception)); + }); + + process.registerCall( + "require", + function(name, base, path) { + var loader = options.loader; + var parentFS = loader.fs; + var moduleURL = parentFS.resolveModule(base, path); + + if (!moduleURL) + return {code: "not-found"}; + + var moduleInfo = pkg.getModuleInfo(moduleURL); + var moduleName = path; + + function maybeImportAdapterModule() { + var adapterModuleName = moduleName + "-e10s-adapter"; + var adapterModuleURL = parentFS.resolveModule(base, + adapterModuleName); + var adapterModuleInfo = null; + if (adapterModuleURL) + adapterModuleInfo = pkg.getModuleInfo(adapterModuleURL); + + if (moduleInfo['e10s-adapter'] != adapterModuleURL) { + console.warn("Adapter module URL is " + adapterModuleURL + + " but expected " + moduleInfo['e10s-adapter']); + return {code: "error"}; + } + + if (adapterModuleInfo) { + // e10s adapter found! + try { + if (!(adapterModuleURL in registeredModules)) { + // This e10s adapter has already been loaded for this + // addon process, and we only really need to give it the + // absolute URL of the adapter. + registeredModules[adapterModuleURL] = true; + loader.require(adapterModuleName).register(process); + } + } catch (e) { + console.exception(e); + return {code: "error"}; + } + return { + code: "ok", + needsMessaging: true, + script: makeScriptFrom(parentFS, adapterModuleURL) + }; + } + + return null; + } + + if (moduleInfo) { + if (moduleInfo.needsChrome) { + return maybeImportAdapterModule() || {code: "access-denied"}; + } else { + + // Even if a module doesn't explicitly require chrome privileges, if + // an e10s adapter exists for it, use it, because said module might + // import other modules that require chrome. + // + // In the future we may want to look at the module's dependencies to + // determine whether importing an adapter is a better idea. + + return maybeImportAdapterModule() || { + code: "ok", + needsMessaging: false, + script: makeScriptFrom(parentFS, moduleURL) + }; + } + } else { + return maybeImportAdapterModule() || {code: "not-found"}; + } + }); + + var bootURL = require("self").data.url("bootstrap-remote-process.js"); + var bootFilename = url.toFilename(bootURL); + var bootJS = file.read(bootFilename); + + // The try ... catch is a workaround for bug 589308. + jetpack.evalScript('//@line 1 "' + bootFilename + '"\n' + + "try { " + bootJS + " } catch (e) { " + + "sendMessage('core:exception', e); }"); + + process.send("addInjectedSandboxScript", + require("./cuddlefish").shimsCode); + + return process; +}; |